@phreshos/node 0.1.13 → 0.1.15
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 +31 -41
- package/dist/events.d.ts +4 -4
- package/dist/events.js +18 -29
- package/dist/main.d.ts +1 -1
- package/dist/main.js +1 -1
- package/dist/program-resources.d.ts +5 -5
- package/dist/program-resources.js +11 -25
- package/dist/representation.d.ts +99 -0
- package/dist/representation.js +340 -0
- package/dist/system.d.ts +1 -0
- package/dist/system.js +241 -285
- package/dist/traffic.d.ts +4 -4
- package/dist/traffic.js +14 -32
- package/dist/transport.d.ts +20 -10
- package/dist/transport.js +106 -124
- package/dist/websocket.d.ts +2 -0
- package/dist/websocket.js +15 -0
- package/package.json +4 -2
package/README.md
CHANGED
|
@@ -1,9 +1,22 @@
|
|
|
1
1
|
# `@phreshos/node`
|
|
2
2
|
|
|
3
|
-
Node.js access to a
|
|
3
|
+
Node.js access to a PhreshOS System and local Program projects.
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
[Documentation](https://docs.phreshos.com/sdks/node) ·
|
|
6
|
+
[System](https://docs.phreshos.com/system) ·
|
|
7
|
+
[First Program](https://docs.phreshos.com/first-program) ·
|
|
8
|
+
[Source](https://github.com/PhreshOS/node)
|
|
9
|
+
|
|
10
|
+
## Role
|
|
11
|
+
|
|
12
|
+
The Node SDK exposes the same complete System contract available inside Server
|
|
13
|
+
Endpoints. It adds only the lifecycle of an externally owned connection and the
|
|
14
|
+
`Project` authoring API for building, running, installing, and packaging local
|
|
15
|
+
Program projects.
|
|
16
|
+
|
|
17
|
+
The connection transport is not public API. Core owns the domain model, and the
|
|
18
|
+
System remains authoritative whether an operation can execute locally or must
|
|
19
|
+
cross the connection boundary.
|
|
7
20
|
|
|
8
21
|
## Installation
|
|
9
22
|
|
|
@@ -14,49 +27,21 @@ only connection lifecycle and project tooling.
|
|
|
14
27
|
| Bun | `bun add @phreshos/node` |
|
|
15
28
|
| Yarn | `yarn add @phreshos/node` |
|
|
16
29
|
|
|
17
|
-
## System
|
|
18
|
-
|
|
19
|
-
```ts
|
|
20
|
-
import { System } from "@phreshos/node"
|
|
21
|
-
|
|
22
|
-
const system = await System.connect()
|
|
23
|
-
const programs = await system.program.list()
|
|
24
|
-
|
|
25
|
-
await system.disconnect()
|
|
26
|
-
```
|
|
27
|
-
|
|
28
|
-
The transport is not public API. Code receives the same System, Program,
|
|
29
|
-
Process, Endpoint, Service, Window, storage, and upload handles used by the
|
|
30
|
-
Server SDK. `disconnect()` exists because external Node code owns the
|
|
31
|
-
connection.
|
|
32
|
-
|
|
33
|
-
## Project
|
|
34
|
-
|
|
35
30
|
```ts
|
|
36
31
|
import { Project, System } from "@phreshos/node"
|
|
37
32
|
|
|
38
|
-
const project = await Project.open()
|
|
39
33
|
const system = await System.connect()
|
|
34
|
+
const project = await Project.open()
|
|
40
35
|
|
|
41
|
-
for await (const event of await project.start(system
|
|
36
|
+
for await (const event of await project.start(system)) {
|
|
42
37
|
console.log(event)
|
|
43
38
|
}
|
|
44
39
|
|
|
45
40
|
await system.disconnect()
|
|
46
41
|
```
|
|
47
42
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
receives only the resulting Program definition.
|
|
51
|
-
|
|
52
|
-
`Project.dev()` starts and supervises a declared Client development command. It
|
|
53
|
-
assigns an available port when no URL is declared and provides the port and
|
|
54
|
-
public Program asset base through `PHRESHOS_CLIENT_PORT` and
|
|
55
|
-
`PHRESHOS_CLIENT_BASE`.
|
|
56
|
-
|
|
57
|
-
`Project.open()` starts from the current working directory by default.
|
|
58
|
-
`System.connect()` resolves an explicit System home, then `PHRESHOS_HOME`,
|
|
59
|
-
then the current owner's default System home.
|
|
43
|
+
See [Node SDK](https://docs.phreshos.com/sdks/node) for System connection and
|
|
44
|
+
Project lifecycle details.
|
|
60
45
|
|
|
61
46
|
## Development
|
|
62
47
|
|
|
@@ -65,14 +50,19 @@ bun install --frozen-lockfile
|
|
|
65
50
|
bun run verify
|
|
66
51
|
```
|
|
67
52
|
|
|
68
|
-
|
|
69
|
-
|
|
53
|
+
`verify` checks the types, builds the package, and runs the connection and
|
|
54
|
+
Project tests.
|
|
70
55
|
|
|
71
|
-
##
|
|
56
|
+
## Related repositories
|
|
72
57
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
58
|
+
- [`@phreshos/core`](https://github.com/PhreshOS/core) owns the shared System
|
|
59
|
+
and runtime contracts.
|
|
60
|
+
- [`@phreshos/server`](https://github.com/PhreshOS/server) exposes the same
|
|
61
|
+
System contract inside Server Endpoints.
|
|
62
|
+
- [`@phreshos/cli`](https://github.com/PhreshOS/cli) presents Project and System
|
|
63
|
+
operations as terminal commands.
|
|
64
|
+
- [PhreshOS System](https://github.com/PhreshOS/system) owns the connected
|
|
65
|
+
runtime.
|
|
76
66
|
|
|
77
67
|
## License
|
|
78
68
|
|
package/dist/events.d.ts
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import type { Cleanup, EventOptions, Subscribable } from "@phreshos/core";
|
|
2
|
-
type Wait = (event: string | null, signal: AbortSignal, timeout?: number) => Promise<unknown>;
|
|
3
2
|
type Failure = (error: Error) => void;
|
|
4
3
|
type Register<Message> = (subscriber: (message: Message) => unknown, impossible?: Failure) => Cleanup;
|
|
5
|
-
|
|
4
|
+
type Subscribe = (event: string | null, subscriber: (message: unknown) => unknown, impossible?: Failure) => Cleanup;
|
|
5
|
+
/** Adapts one live representation source into the shared Subscribable contract. */
|
|
6
6
|
export default class Events<Definitions extends object, Fallback = never> {
|
|
7
7
|
private readonly names;
|
|
8
|
-
private readonly
|
|
9
|
-
constructor(names: readonly string[],
|
|
8
|
+
private readonly register;
|
|
9
|
+
constructor(names: readonly string[], register: Subscribe);
|
|
10
10
|
readonly subscribe: Subscribable<Definitions, Fallback>["subscribe"];
|
|
11
11
|
readonly waitFor: Subscribable<Definitions, Fallback>["waitFor"];
|
|
12
12
|
readonly events: Subscribable<Definitions, Fallback>["events"];
|
package/dist/events.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
/** Adapts
|
|
1
|
+
/** Adapts one live representation source into the shared Subscribable contract. */
|
|
2
2
|
export default class Events {
|
|
3
3
|
names;
|
|
4
|
-
|
|
5
|
-
constructor(names,
|
|
4
|
+
register;
|
|
5
|
+
constructor(names, register) {
|
|
6
6
|
this.names = names;
|
|
7
|
-
this.
|
|
7
|
+
this.register = register;
|
|
8
8
|
}
|
|
9
9
|
subscribe = ((eventOrSubscriber, subscriber) => {
|
|
10
10
|
if (typeof eventOrSubscriber === "string")
|
|
@@ -19,9 +19,19 @@ export default class Events {
|
|
|
19
19
|
eventOrSubscriber({ event: capture.event, message: capture.payload });
|
|
20
20
|
});
|
|
21
21
|
});
|
|
22
|
-
waitFor = ((event, timeout) => {
|
|
23
|
-
|
|
24
|
-
|
|
22
|
+
waitFor = ((event, timeout = 10_000) => new Promise((resolve, reject) => {
|
|
23
|
+
let stop = () => undefined;
|
|
24
|
+
const timer = setTimeout(() => {
|
|
25
|
+
stop();
|
|
26
|
+
reject(new Error(`The "${event}" event did not occur before the timeout`));
|
|
27
|
+
}, timeout);
|
|
28
|
+
const finish = (work) => {
|
|
29
|
+
clearTimeout(timer);
|
|
30
|
+
stop();
|
|
31
|
+
work();
|
|
32
|
+
};
|
|
33
|
+
stop = this.listen(event, message => finish(() => resolve(message)), error => finish(() => reject(error)));
|
|
34
|
+
}));
|
|
25
35
|
events = ((eventOrOptions = {}, namedOptions = {}) => {
|
|
26
36
|
if (typeof eventOrOptions === "string") {
|
|
27
37
|
return stream((subscriber, impossible) => this.listen(eventOrOptions, subscriber, impossible), namedOptions);
|
|
@@ -39,22 +49,7 @@ export default class Events {
|
|
|
39
49
|
}, eventOrOptions);
|
|
40
50
|
});
|
|
41
51
|
listen(event, subscriber, impossible) {
|
|
42
|
-
|
|
43
|
-
void (async () => {
|
|
44
|
-
while (!controller.signal.aborted) {
|
|
45
|
-
try {
|
|
46
|
-
subscriber(await this.wait(event, controller.signal, 86_400_000));
|
|
47
|
-
}
|
|
48
|
-
catch (error) {
|
|
49
|
-
if (!controller.signal.aborted && timeout(error))
|
|
50
|
-
continue;
|
|
51
|
-
if (!controller.signal.aborted)
|
|
52
|
-
impossible?.(failure(error));
|
|
53
|
-
controller.abort();
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
})();
|
|
57
|
-
return () => controller.abort();
|
|
52
|
+
return this.register(event, subscriber, impossible);
|
|
58
53
|
}
|
|
59
54
|
}
|
|
60
55
|
export function stream(register, options = {}) {
|
|
@@ -109,9 +104,3 @@ export function stream(register, options = {}) {
|
|
|
109
104
|
}
|
|
110
105
|
})();
|
|
111
106
|
}
|
|
112
|
-
function timeout(error) {
|
|
113
|
-
return error instanceof Error && /timeout|timed out/i.test(error.message);
|
|
114
|
-
}
|
|
115
|
-
function failure(error) {
|
|
116
|
-
return error instanceof Error ? error : new Error(String(error));
|
|
117
|
-
}
|
package/dist/main.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export { gatewayAddress } from "./address.js";
|
|
2
2
|
export { ClientEndpoint, ClientService, Endpoint, Process, Program, ServerEndpoint, ServerService, System, type ProgramProcessRunEvent, type ProgramProcessRunOptions } from "./system.js";
|
|
3
|
-
export { Service, type ClientLaunch, type Launch, type Permission, type
|
|
3
|
+
export { Service, clientPermissionCatalog, isPermissionName, type ClientLaunch, type Launch, type Permission, type PermissionDefinition, type PermissionDefinitions, type PermissionInput, type PermissionName, type PermissionRequest, type PermissionValue, type PermissionValueDomain, type Permissions, type ProgramPermissions, type ProgramDefinition, type ServerLaunch, type ServiceKey, type ShellEvent, type ShellOptions, type ProgramStartup, type Storage, } from "@phreshos/core";
|
|
4
4
|
export { resolveHome } from "./home.js";
|
|
5
5
|
export { Project, type Manifest, type PackedProject, type ProjectMode, type ProjectOptions, type ProjectRunOptions } from "./project.js";
|
package/dist/main.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export { gatewayAddress } from "./address.js";
|
|
2
2
|
export { ClientEndpoint, ClientService, Endpoint, Process, Program, ServerEndpoint, ServerService, System } from "./system.js";
|
|
3
|
-
export { Service, } from "@phreshos/core";
|
|
3
|
+
export { Service, clientPermissionCatalog, isPermissionName, } from "@phreshos/core";
|
|
4
4
|
export { resolveHome } from "./home.js";
|
|
5
5
|
export { Project } from "./project.js";
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { type ProgramPermissions, type ProgramSql, type ProgramStore } from "@phreshos/core";
|
|
2
|
-
type
|
|
3
|
-
type
|
|
2
|
+
type Call = <Result = unknown>(event: string, ...values: unknown[]) => Promise<Result>;
|
|
3
|
+
type HandleAddress = Readonly<{
|
|
4
4
|
identity: string;
|
|
5
5
|
reference: string;
|
|
6
6
|
}>;
|
|
7
7
|
/** Program-owned key-value storage carried through the owner-local Gateway. */
|
|
8
|
-
export declare function programStore(
|
|
8
|
+
export declare function programStore(call: Call, handle: HandleAddress): ProgramStore;
|
|
9
9
|
/** Program-owned SQL capability carried through the owner-local Gateway. */
|
|
10
|
-
export declare function programSql(
|
|
10
|
+
export declare function programSql(call: Call, handle: HandleAddress, database: "database" | "logs"): ProgramSql;
|
|
11
11
|
/** Program permission management carried through the owner-local Gateway. */
|
|
12
|
-
export declare function programPermissions(
|
|
12
|
+
export declare function programPermissions(call: Call, handle: HandleAddress): ProgramPermissions;
|
|
13
13
|
export {};
|
|
@@ -1,15 +1,7 @@
|
|
|
1
|
-
import { parsePermission,
|
|
1
|
+
import { parsePermission, parsePermissions } from "@phreshos/core";
|
|
2
2
|
/** Program-owned key-value storage carried through the owner-local Gateway. */
|
|
3
|
-
export function programStore(
|
|
4
|
-
const operate = (storeOperation, key, value, ttl) =>
|
|
5
|
-
capability: "program",
|
|
6
|
-
operation: "store",
|
|
7
|
-
handle,
|
|
8
|
-
storeOperation,
|
|
9
|
-
key,
|
|
10
|
-
value,
|
|
11
|
-
ttl
|
|
12
|
-
});
|
|
3
|
+
export function programStore(call, handle) {
|
|
4
|
+
const operate = (storeOperation, key, value, ttl) => (call("/program/store", handle, storeOperation, key, value, ttl));
|
|
13
5
|
return {
|
|
14
6
|
get: (key) => operate("get", key),
|
|
15
7
|
set: (key, value, ttl) => operate("set", key, value, ttl),
|
|
@@ -19,29 +11,23 @@ export function programStore(request, handle) {
|
|
|
19
11
|
};
|
|
20
12
|
}
|
|
21
13
|
/** Program-owned SQL capability carried through the owner-local Gateway. */
|
|
22
|
-
export function programSql(
|
|
14
|
+
export function programSql(call, handle, database) {
|
|
23
15
|
return {
|
|
24
16
|
query(statement, ...rest) {
|
|
25
17
|
const [text, values] = written(statement, rest);
|
|
26
|
-
return
|
|
18
|
+
return call(`/program/${database}`, handle, text, values);
|
|
27
19
|
}
|
|
28
20
|
};
|
|
29
21
|
}
|
|
30
22
|
/** Program permission management carried through the owner-local Gateway. */
|
|
31
|
-
export function programPermissions(
|
|
32
|
-
const operate = (permissionOperation, name, permission) =>
|
|
33
|
-
capability: "program",
|
|
34
|
-
operation: "permissions",
|
|
35
|
-
handle,
|
|
36
|
-
permissionOperation,
|
|
37
|
-
name,
|
|
38
|
-
permission
|
|
39
|
-
});
|
|
23
|
+
export function programPermissions(call, handle) {
|
|
24
|
+
const operate = (permissionOperation, name, permission) => (call("/program/permissions", handle, permissionOperation, name, permission));
|
|
40
25
|
return {
|
|
41
|
-
async get(name) { return parsePermission(await operate("get", name)); },
|
|
26
|
+
async get(name) { return parsePermission(name, await operate("get", name)); },
|
|
42
27
|
async all() { return parsePermissions(await operate("all")); },
|
|
43
|
-
async
|
|
44
|
-
async
|
|
28
|
+
async allows(name, permission = true) { return await operate("allows", name, permission) === true; },
|
|
29
|
+
async set(name, permission) { await operate("set", name, permission); },
|
|
30
|
+
async delete(name) { await operate("delete", name); }
|
|
45
31
|
};
|
|
46
32
|
}
|
|
47
33
|
function written(statement, rest) {
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import type { Appearance, ClientDeclaration, EndpointDeclaration, ServiceKey, WindowGeometry, WindowLayer } from "@phreshos/core";
|
|
2
|
+
import type { GatewayConnection } from "./transport.js";
|
|
3
|
+
export interface ProgramState {
|
|
4
|
+
reference: string;
|
|
5
|
+
identity: string;
|
|
6
|
+
assetId: string;
|
|
7
|
+
installed: boolean;
|
|
8
|
+
name: string;
|
|
9
|
+
version: string | null;
|
|
10
|
+
description: string | null;
|
|
11
|
+
hasAgent: boolean;
|
|
12
|
+
server: EndpointDeclaration | null;
|
|
13
|
+
client: ClientDeclaration | null;
|
|
14
|
+
}
|
|
15
|
+
export interface WindowState {
|
|
16
|
+
title: string;
|
|
17
|
+
position: WindowGeometry["position"];
|
|
18
|
+
size: WindowGeometry["size"];
|
|
19
|
+
depth: number;
|
|
20
|
+
minimized: boolean;
|
|
21
|
+
layer: WindowLayer;
|
|
22
|
+
location: string;
|
|
23
|
+
}
|
|
24
|
+
export interface ProcessIdentityState {
|
|
25
|
+
reference: string;
|
|
26
|
+
identity: string;
|
|
27
|
+
name: string | null;
|
|
28
|
+
program: string;
|
|
29
|
+
options: Record<string, string>;
|
|
30
|
+
startedAt: Date;
|
|
31
|
+
}
|
|
32
|
+
export interface ProcessState extends ProcessIdentityState {
|
|
33
|
+
server: {
|
|
34
|
+
ready: boolean;
|
|
35
|
+
service: boolean;
|
|
36
|
+
} | null;
|
|
37
|
+
client: {
|
|
38
|
+
service: boolean;
|
|
39
|
+
sameOrigin: boolean;
|
|
40
|
+
window: WindowState;
|
|
41
|
+
} | null;
|
|
42
|
+
}
|
|
43
|
+
export type Observation = Readonly<{
|
|
44
|
+
scope: "endpoint";
|
|
45
|
+
process: string;
|
|
46
|
+
endpoint: "server" | "client";
|
|
47
|
+
event: string | null;
|
|
48
|
+
}> | Readonly<{
|
|
49
|
+
scope: "traffic";
|
|
50
|
+
process: string;
|
|
51
|
+
endpoint: "server" | "client";
|
|
52
|
+
kind: "publish" | "ask" | "answer";
|
|
53
|
+
event: string | null;
|
|
54
|
+
}> | Readonly<{
|
|
55
|
+
scope: "service";
|
|
56
|
+
key: ServiceKey;
|
|
57
|
+
kind: "events" | "lifecycle";
|
|
58
|
+
event: string | null;
|
|
59
|
+
}>;
|
|
60
|
+
type Listener = (...values: unknown[]) => unknown;
|
|
61
|
+
interface CommandEvent {
|
|
62
|
+
event?: string;
|
|
63
|
+
[key: string]: unknown;
|
|
64
|
+
}
|
|
65
|
+
/** A connection-owned, live representation of the authoritative System model. */
|
|
66
|
+
export default class SystemRepresentation {
|
|
67
|
+
private readonly connection;
|
|
68
|
+
readonly authorization: string;
|
|
69
|
+
readonly programs: Map<string, ProgramState>;
|
|
70
|
+
readonly processes: Map<string, ProcessState>;
|
|
71
|
+
appearance: Appearance;
|
|
72
|
+
private readonly listeners;
|
|
73
|
+
private readonly release;
|
|
74
|
+
constructor(connection: GatewayConnection);
|
|
75
|
+
activate(): void;
|
|
76
|
+
close(): void;
|
|
77
|
+
call<Result = unknown>(event: string, ...values: unknown[]): Promise<Result>;
|
|
78
|
+
on(event: string, listener: Listener): () => void;
|
|
79
|
+
follow(observation: Observation, listener: (event: string, value: unknown) => unknown, impossible?: (error: Error) => void): () => void;
|
|
80
|
+
/** Stream one Program command through the live LinkManager connection. */
|
|
81
|
+
command(operation: "install" | "uninstall" | "run", subject: ProgramAddress, value: unknown, signal?: AbortSignal): AsyncGenerator<CommandEvent, void, unknown>;
|
|
82
|
+
private followModel;
|
|
83
|
+
private arriveProgram;
|
|
84
|
+
private uninstallProgram;
|
|
85
|
+
private forgetProgram;
|
|
86
|
+
private createProcess;
|
|
87
|
+
private serverReady;
|
|
88
|
+
private changeEndpoint;
|
|
89
|
+
private exitProcess;
|
|
90
|
+
private changeWindow;
|
|
91
|
+
private emit;
|
|
92
|
+
}
|
|
93
|
+
export type ProgramAddress = Readonly<{
|
|
94
|
+
identity: string;
|
|
95
|
+
reference: string;
|
|
96
|
+
}>;
|
|
97
|
+
/** Read the immutable facts needed to retain one Process handle. */
|
|
98
|
+
export declare function processIdentityState(value: unknown): ProcessIdentityState;
|
|
99
|
+
export {};
|