@phreshos/node 0.1.7 → 0.1.8
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/events.d.ts +4 -1
- package/dist/events.js +1 -1
- package/dist/program-resources.d.ts +7 -0
- package/dist/program-resources.js +33 -0
- package/dist/storage.d.ts +2 -2
- package/dist/storage.js +19 -11
- package/dist/system.d.ts +2 -2
- package/dist/system.js +65 -0
- package/dist/traffic.d.ts +36 -0
- package/dist/traffic.js +101 -0
- package/package.json +2 -2
package/dist/events.d.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
import type { Subscribable } from "@phreshos/core";
|
|
1
|
+
import type { Cleanup, EventOptions, Subscribable } from "@phreshos/core";
|
|
2
2
|
type Wait = (event: string | null, signal: AbortSignal, timeout?: number) => Promise<unknown>;
|
|
3
|
+
type Failure = (error: Error) => void;
|
|
4
|
+
type Register<Message> = (subscriber: (message: Message) => unknown, impossible?: Failure) => Cleanup;
|
|
3
5
|
/** Adapts authoritative one-event waits into the shared Subscribable contract. */
|
|
4
6
|
export default class Events<Definitions extends object, Fallback = never> {
|
|
5
7
|
private readonly names;
|
|
@@ -10,4 +12,5 @@ export default class Events<Definitions extends object, Fallback = never> {
|
|
|
10
12
|
readonly events: Subscribable<Definitions, Fallback>["events"];
|
|
11
13
|
private listen;
|
|
12
14
|
}
|
|
15
|
+
export declare function stream<Message>(register: Register<Message>, options?: EventOptions): AsyncIterableIterator<Message>;
|
|
13
16
|
export {};
|
package/dist/events.js
CHANGED
|
@@ -57,7 +57,7 @@ export default class Events {
|
|
|
57
57
|
return () => controller.abort();
|
|
58
58
|
}
|
|
59
59
|
}
|
|
60
|
-
function stream(register, options = {}) {
|
|
60
|
+
export function stream(register, options = {}) {
|
|
61
61
|
const capacity = options.capacity ?? 64;
|
|
62
62
|
if (capacity !== Infinity && (!Number.isInteger(capacity) || capacity < 0)) {
|
|
63
63
|
throw new Error("An event queue capacity must be a non-negative integer or Infinity");
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { ProgramSql, ProgramStore } from "@phreshos/core";
|
|
2
|
+
type Request = (value: object) => Promise<unknown>;
|
|
3
|
+
/** Program-owned key-value storage carried through the owner-local Gateway. */
|
|
4
|
+
export declare function programStore(request: Request, program: string): ProgramStore;
|
|
5
|
+
/** Program-owned SQL capability carried through the owner-local Gateway. */
|
|
6
|
+
export declare function programSql(request: Request, program: string, database: "database" | "logs"): ProgramSql;
|
|
7
|
+
export {};
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/** Program-owned key-value storage carried through the owner-local Gateway. */
|
|
2
|
+
export function programStore(request, program) {
|
|
3
|
+
const operate = (storeOperation, key, value, ttl) => request({
|
|
4
|
+
capability: "program",
|
|
5
|
+
operation: "store",
|
|
6
|
+
program,
|
|
7
|
+
storeOperation,
|
|
8
|
+
key,
|
|
9
|
+
value,
|
|
10
|
+
ttl
|
|
11
|
+
});
|
|
12
|
+
return {
|
|
13
|
+
get: (key) => operate("get", key),
|
|
14
|
+
set: (key, value, ttl) => operate("set", key, value, ttl),
|
|
15
|
+
delete: (key) => operate("delete", key),
|
|
16
|
+
has: (key) => operate("has", key),
|
|
17
|
+
clear: () => operate("clear")
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
/** Program-owned SQL capability carried through the owner-local Gateway. */
|
|
21
|
+
export function programSql(request, program, database) {
|
|
22
|
+
return {
|
|
23
|
+
query(statement, ...rest) {
|
|
24
|
+
const [text, values] = written(statement, rest);
|
|
25
|
+
return request({ capability: "program", operation: "query", program, database, statement: text, values });
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
function written(statement, rest) {
|
|
30
|
+
if (typeof statement === "string")
|
|
31
|
+
return [statement, Array.isArray(rest[0]) ? rest[0] : []];
|
|
32
|
+
return [statement.raw.join("?"), rest];
|
|
33
|
+
}
|
package/dist/storage.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import type { Storage } from "@phreshos/core";
|
|
2
|
-
/** Create one filesystem implementation bounded beneath
|
|
3
|
-
export declare function filesystemStorage(
|
|
2
|
+
/** Create one filesystem implementation bounded beneath a resolved absolute root. */
|
|
3
|
+
export declare function filesystemStorage(source: string | (() => Promise<string>), label: string): Storage;
|
package/dist/storage.js
CHANGED
|
@@ -4,13 +4,21 @@ import { rm } from "node:fs/promises";
|
|
|
4
4
|
import { dirname, isAbsolute, join, relative, sep } from "node:path";
|
|
5
5
|
import { Readable } from "node:stream";
|
|
6
6
|
import { pipeline } from "node:stream/promises";
|
|
7
|
-
/** Create one filesystem implementation bounded beneath
|
|
8
|
-
export function filesystemStorage(
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
7
|
+
/** Create one filesystem implementation bounded beneath a resolved absolute root. */
|
|
8
|
+
export function filesystemStorage(source, label) {
|
|
9
|
+
let root = null;
|
|
10
|
+
const resolveRoot = () => {
|
|
11
|
+
if (!root)
|
|
12
|
+
root = Promise.resolve(typeof source === "string" ? source : source()).then(value => {
|
|
13
|
+
if (!isAbsolute(value))
|
|
14
|
+
throw new Error("A Storage root must be absolute");
|
|
15
|
+
return value;
|
|
16
|
+
});
|
|
17
|
+
return root;
|
|
18
|
+
};
|
|
19
|
+
const resolve = async (...parts) => contained(await resolveRoot(), parts);
|
|
12
20
|
async function stream(...parts) {
|
|
13
|
-
const destination = resolve(...parts);
|
|
21
|
+
const destination = await resolve(...parts);
|
|
14
22
|
const found = describe(destination);
|
|
15
23
|
if (!found)
|
|
16
24
|
throw new Error(`There is no ${parts.join("/")} in ${label}`);
|
|
@@ -20,7 +28,7 @@ export function filesystemStorage(root, label) {
|
|
|
20
28
|
}
|
|
21
29
|
async function write(...args) {
|
|
22
30
|
const parts = args.slice(0, -1);
|
|
23
|
-
const destination = resolve(...parts);
|
|
31
|
+
const destination = await resolve(...parts);
|
|
24
32
|
const temporary = join(dirname(destination), `.${randomUUID()}.writing`);
|
|
25
33
|
mkdirSync(dirname(destination), { recursive: true });
|
|
26
34
|
try {
|
|
@@ -38,15 +46,15 @@ export function filesystemStorage(root, label) {
|
|
|
38
46
|
async text(...parts) { return new Response(await stream(...parts)).text(); },
|
|
39
47
|
async json(...parts) { return JSON.parse(await new Response(await stream(...parts)).text()); },
|
|
40
48
|
write,
|
|
41
|
-
async stat(...parts) { return describe(resolve(...parts)); },
|
|
42
|
-
async list(...parts) { return readdirSync(resolve(...parts)).sort(); },
|
|
49
|
+
async stat(...parts) { return describe(await resolve(...parts)); },
|
|
50
|
+
async list(...parts) { return readdirSync(await resolve(...parts)).sort(); },
|
|
43
51
|
async delete(...parts) {
|
|
44
52
|
if (!parts.length)
|
|
45
53
|
throw new Error("Emptying a place is clear, not delete");
|
|
46
|
-
rmSync(resolve(...parts), { recursive: true, force: true });
|
|
54
|
+
rmSync(await resolve(...parts), { recursive: true, force: true });
|
|
47
55
|
},
|
|
48
56
|
async clear(...parts) {
|
|
49
|
-
const destination = resolve(...parts);
|
|
57
|
+
const destination = await resolve(...parts);
|
|
50
58
|
const found = describe(destination);
|
|
51
59
|
if (found && found.kind !== "directory")
|
|
52
60
|
throw new Error("Only a Storage directory can be cleared");
|
package/dist/system.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Client as CoreClient, ClientService as CoreClientService, Endpoint as CoreEndpoint, Process as CoreProcess, Program as CoreProgram, Server as CoreServer, ServerService as CoreServerService, type ProgramDefinition, type ProgramCommandChunk, type ServiceKey, type System as CoreSystem, type SystemClientEntity, type SystemEndpointEntity, type SystemProcessEntity, type SystemProcess, type SystemProgram, type SystemProgramEntity, type SystemServerEntity, type SystemUploads, type WritableAppearance } from "@phreshos/core";
|
|
1
|
+
import { Client as CoreClient, ClientService as CoreClientService, Endpoint as CoreEndpoint, Process as CoreProcess, Program as CoreProgram, Server as CoreServer, ServerService as CoreServerService, type ProgramDefinition, type ProgramCommandChunk, type ServiceKey, type System as CoreSystem, type SystemClientEntity, type SystemEndpointEntity, type SystemProcessEntity, type SystemProcess, type SystemProgram, type SystemProgramEntity, type SystemServerEntity, type SystemUploads, type Storage, type WritableAppearance } from "@phreshos/core";
|
|
2
2
|
export type ProgramProcessRunOptions = Readonly<{
|
|
3
3
|
signal?: AbortSignal;
|
|
4
4
|
}>;
|
|
@@ -14,7 +14,7 @@ export type ProgramProcessRunEvent = Readonly<{
|
|
|
14
14
|
}>;
|
|
15
15
|
/** One connected owner-local implementation of the shared System contract. */
|
|
16
16
|
export declare class System implements CoreSystem {
|
|
17
|
-
readonly storage:
|
|
17
|
+
readonly storage: Storage;
|
|
18
18
|
readonly appearance: WritableAppearance;
|
|
19
19
|
readonly program: SystemProgram;
|
|
20
20
|
readonly process: SystemProcess;
|
package/dist/system.js
CHANGED
|
@@ -5,6 +5,8 @@ import Events from "./events.js";
|
|
|
5
5
|
import HandleRegistry from "./handle-registry.js";
|
|
6
6
|
import { resolveHome } from "./home.js";
|
|
7
7
|
import { filesystemStorage } from "./storage.js";
|
|
8
|
+
import { programSql, programStore } from "./program-resources.js";
|
|
9
|
+
import { EndpointTrafficHandle, ServerTrafficHandle } from "./traffic.js";
|
|
8
10
|
import { openConnection, request, streamProgram } from "./transport.js";
|
|
9
11
|
import Uploads from "./uploads.js";
|
|
10
12
|
const systems = new WeakMap();
|
|
@@ -166,6 +168,11 @@ class ProgramHandle extends ProgramBase {
|
|
|
166
168
|
system;
|
|
167
169
|
reference;
|
|
168
170
|
identity;
|
|
171
|
+
data;
|
|
172
|
+
cache;
|
|
173
|
+
store;
|
|
174
|
+
logs;
|
|
175
|
+
database;
|
|
169
176
|
process;
|
|
170
177
|
startup;
|
|
171
178
|
snapshot;
|
|
@@ -178,6 +185,12 @@ class ProgramHandle extends ProgramBase {
|
|
|
178
185
|
}, signal).then(value => programEntityEvent(event, value))));
|
|
179
186
|
this.reference = snapshot.reference;
|
|
180
187
|
this.identity = snapshot.identity;
|
|
188
|
+
const request = (value) => transport(system).api(value);
|
|
189
|
+
this.data = filesystemStorage(() => programStoragePath(system, this.identity, "data"), `Program "${this.identity}" data`);
|
|
190
|
+
this.cache = filesystemStorage(() => programStoragePath(system, this.identity, "cache"), `Program "${this.identity}" cache`);
|
|
191
|
+
this.store = programStore(request, this.identity);
|
|
192
|
+
this.logs = programSql(request, this.identity, "logs");
|
|
193
|
+
this.database = programSql(request, this.identity, "database");
|
|
181
194
|
this.process = new ProgramProcesses(system, this);
|
|
182
195
|
this.startup = new ProgramStartup(system, this);
|
|
183
196
|
}
|
|
@@ -207,6 +220,12 @@ class ProgramHandle extends ProgramBase {
|
|
|
207
220
|
throw new Error("A Program handle cannot become another Program");
|
|
208
221
|
this.snapshot = snapshot;
|
|
209
222
|
}
|
|
223
|
+
async icon(size = "medium") {
|
|
224
|
+
const value = await transport(this.system).api({ capability: "program", operation: "icon", program: this.identity, size });
|
|
225
|
+
if (!Array.isArray(value) || value.some(byte => typeof byte !== "number"))
|
|
226
|
+
throw new Error("The System returned an invalid Program icon");
|
|
227
|
+
return new Blob([Uint8Array.from(value)], { type: "image/png" });
|
|
228
|
+
}
|
|
210
229
|
async agent() {
|
|
211
230
|
if (!this.hasAgent)
|
|
212
231
|
return null;
|
|
@@ -376,10 +395,22 @@ class ProcessHandle extends ProcessBase {
|
|
|
376
395
|
this.client = new ClientEndpoint(system, this);
|
|
377
396
|
}
|
|
378
397
|
program() { return programHandle(this.system, required(this.snapshot.programSnapshot, this.snapshot.program)); }
|
|
398
|
+
async parent() {
|
|
399
|
+
if (!await this.exists())
|
|
400
|
+
throw new Error(`Process "${this.identity}" no longer exists`);
|
|
401
|
+
if (this.snapshot.parent === null)
|
|
402
|
+
return null;
|
|
403
|
+
const parent = await this.system.process.find(this.snapshot.parent);
|
|
404
|
+
if (!parent)
|
|
405
|
+
throw new Error("The parent Process no longer exists");
|
|
406
|
+
return parent;
|
|
407
|
+
}
|
|
408
|
+
async option(name) { return this.snapshot.options[name]; }
|
|
379
409
|
async exit() {
|
|
380
410
|
await transport(this.system).control({ capability: "process", operation: "exit", input: { process: this.identity } });
|
|
381
411
|
}
|
|
382
412
|
async exited() { return await this.system.process.find(this.identity) === null; }
|
|
413
|
+
async exists() { return !await this.exited(); }
|
|
383
414
|
}
|
|
384
415
|
class EndpointOperations extends Events {
|
|
385
416
|
system;
|
|
@@ -431,6 +462,7 @@ class ServerEndpoint extends ServerBase {
|
|
|
431
462
|
system;
|
|
432
463
|
owner;
|
|
433
464
|
endpoint = "server";
|
|
465
|
+
traffic;
|
|
434
466
|
lifecycle;
|
|
435
467
|
base;
|
|
436
468
|
constructor(system, owner) {
|
|
@@ -438,6 +470,7 @@ class ServerEndpoint extends ServerBase {
|
|
|
438
470
|
this.system = system;
|
|
439
471
|
this.owner = owner;
|
|
440
472
|
this.base = new EndpointOperations(system, owner, "server");
|
|
473
|
+
this.traffic = new ServerTrafficHandle((value, signal) => transport(system).api(value, signal), owner.identity, "server", value => endpointFromReference(system, value));
|
|
441
474
|
this.lifecycle = this.base.lifecycle;
|
|
442
475
|
bindEvents(this, this.base);
|
|
443
476
|
}
|
|
@@ -463,12 +496,14 @@ class ServerEndpoint extends ServerBase {
|
|
|
463
496
|
}
|
|
464
497
|
class ClientEndpoint extends ClientBase {
|
|
465
498
|
endpoint = "client";
|
|
499
|
+
traffic;
|
|
466
500
|
lifecycle;
|
|
467
501
|
window;
|
|
468
502
|
base;
|
|
469
503
|
constructor(system, owner) {
|
|
470
504
|
super();
|
|
471
505
|
this.base = new EndpointOperations(system, owner, "client");
|
|
506
|
+
this.traffic = new EndpointTrafficHandle((value, signal) => transport(system).api(value, signal), owner.identity, "client", value => endpointFromReference(system, value));
|
|
472
507
|
this.lifecycle = this.base.lifecycle;
|
|
473
508
|
bindEvents(this, this.base);
|
|
474
509
|
this.window = new SystemWindow(system, owner);
|
|
@@ -645,6 +680,36 @@ function eventsOf(events) {
|
|
|
645
680
|
};
|
|
646
681
|
}
|
|
647
682
|
function chronological(left, right) { return left.startedAt.getTime() - right.startedAt.getTime(); }
|
|
683
|
+
async function programStoragePath(system, program, area) {
|
|
684
|
+
const value = await transport(system).api({ capability: "program", operation: "storagePath", program, area });
|
|
685
|
+
if (typeof value !== "string")
|
|
686
|
+
throw new Error("The System returned an invalid Program storage path");
|
|
687
|
+
return value;
|
|
688
|
+
}
|
|
689
|
+
function endpointFromReference(system, value) {
|
|
690
|
+
const reference = value;
|
|
691
|
+
if (!reference || (reference.kind !== "server" && reference.kind !== "client"))
|
|
692
|
+
throw new Error("The System returned an invalid Endpoint reference");
|
|
693
|
+
const owner = processHandle(system, snapshotFromReference(reference.process));
|
|
694
|
+
return reference.kind === "server" ? owner.server : owner.client;
|
|
695
|
+
}
|
|
696
|
+
function snapshotFromReference(reference) {
|
|
697
|
+
const owner = reference.program;
|
|
698
|
+
if (!owner || typeof owner.reference !== "string" || typeof owner.identity !== "string")
|
|
699
|
+
throw new Error("The System returned an invalid Process reference");
|
|
700
|
+
return {
|
|
701
|
+
reference: reference.reference,
|
|
702
|
+
identity: reference.identity,
|
|
703
|
+
name: reference.name,
|
|
704
|
+
program: owner.identity,
|
|
705
|
+
programSnapshot: owner,
|
|
706
|
+
parent: null,
|
|
707
|
+
options: reference.options,
|
|
708
|
+
startedAt: reference.startedAt,
|
|
709
|
+
server: { declared: owner.server !== null, running: reference.server !== null, service: reference.server?.service === true },
|
|
710
|
+
client: { declared: owner.client !== null, running: reference.client !== null, service: reference.client?.service === true }
|
|
711
|
+
};
|
|
712
|
+
}
|
|
648
713
|
function unknown(error, entity) { return error instanceof Error && error.message.startsWith(`Unknown ${entity}`); }
|
|
649
714
|
function required(value, identity = "") {
|
|
650
715
|
if (value !== undefined)
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { AnswerSubscriber, AskSubscriber, Cleanup, Endpoint, EventOptions, ServerTraffic, TrafficEvents, TrafficMessage } from "@phreshos/core";
|
|
2
|
+
import Events from "./events.js";
|
|
3
|
+
type Kind = "publish" | "ask" | "answer";
|
|
4
|
+
type Request = (value: object, signal?: AbortSignal) => Promise<unknown>;
|
|
5
|
+
type ResolveEndpoint = (value: unknown) => Endpoint;
|
|
6
|
+
/** Directed traffic originating from one canonical Endpoint. */
|
|
7
|
+
export declare class EndpointTrafficHandle<Definitions extends object = {}> extends Events<TrafficEvents<Definitions>, keyof Definitions extends never ? TrafficMessage : never> {
|
|
8
|
+
private readonly request;
|
|
9
|
+
private readonly process;
|
|
10
|
+
private readonly endpoint;
|
|
11
|
+
protected readonly resolveEndpoint: ResolveEndpoint;
|
|
12
|
+
constructor(request: Request, process: string, endpoint: "server" | "client", resolveEndpoint: ResolveEndpoint);
|
|
13
|
+
subscribeAsks<Payload = unknown>(subscriber: AskSubscriber<Payload>): Cleanup;
|
|
14
|
+
asks<Payload = unknown>(options?: EventOptions): AsyncIterableIterator<Readonly<{
|
|
15
|
+
event: string;
|
|
16
|
+
questionId: string;
|
|
17
|
+
message: Readonly<{
|
|
18
|
+
to: import("@phreshos/core").Server<{}>;
|
|
19
|
+
payload: Payload;
|
|
20
|
+
}>;
|
|
21
|
+
}>>;
|
|
22
|
+
protected follow<Capture>(kind: Kind, convert: (value: unknown) => Capture, subscriber: (capture: Capture) => unknown, impossible?: (error: Error) => void): Cleanup;
|
|
23
|
+
}
|
|
24
|
+
/** Directed traffic originating from one canonical Server. */
|
|
25
|
+
export declare class ServerTrafficHandle<Definitions extends object = {}> extends EndpointTrafficHandle<Definitions> implements ServerTraffic<Definitions> {
|
|
26
|
+
subscribeAnswers<Result = unknown>(subscriber: AnswerSubscriber<Result>): Cleanup;
|
|
27
|
+
answers<Result = unknown>(options?: EventOptions): AsyncIterableIterator<Readonly<{
|
|
28
|
+
event: string;
|
|
29
|
+
questionId: string;
|
|
30
|
+
message: Readonly<{
|
|
31
|
+
to: Endpoint<{}>;
|
|
32
|
+
outcome: import("@phreshos/core").Outcome<Result>;
|
|
33
|
+
}>;
|
|
34
|
+
}>>;
|
|
35
|
+
}
|
|
36
|
+
export {};
|
package/dist/traffic.js
ADDED
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import Events, { stream } from "./events.js";
|
|
2
|
+
/** Directed traffic originating from one canonical Endpoint. */
|
|
3
|
+
export class EndpointTrafficHandle extends Events {
|
|
4
|
+
request;
|
|
5
|
+
process;
|
|
6
|
+
endpoint;
|
|
7
|
+
resolveEndpoint;
|
|
8
|
+
constructor(request, process, endpoint, resolveEndpoint) {
|
|
9
|
+
super([], (event, signal, timeout) => request({
|
|
10
|
+
capability: "traffic",
|
|
11
|
+
operation: "wait",
|
|
12
|
+
process,
|
|
13
|
+
endpoint,
|
|
14
|
+
kind: "publish",
|
|
15
|
+
event,
|
|
16
|
+
timeout
|
|
17
|
+
}, signal).then(value => publication(value, resolveEndpoint, event === null)));
|
|
18
|
+
this.request = request;
|
|
19
|
+
this.process = process;
|
|
20
|
+
this.endpoint = endpoint;
|
|
21
|
+
this.resolveEndpoint = resolveEndpoint;
|
|
22
|
+
}
|
|
23
|
+
subscribeAsks(subscriber) {
|
|
24
|
+
return this.follow("ask", value => question(value, this.resolveEndpoint), subscriber);
|
|
25
|
+
}
|
|
26
|
+
asks(options) {
|
|
27
|
+
return stream((subscriber, impossible) => this.follow("ask", value => question(value, this.resolveEndpoint), subscriber, impossible), options);
|
|
28
|
+
}
|
|
29
|
+
follow(kind, convert, subscriber, impossible) {
|
|
30
|
+
const controller = new AbortController();
|
|
31
|
+
void (async () => {
|
|
32
|
+
while (!controller.signal.aborted) {
|
|
33
|
+
try {
|
|
34
|
+
const value = await this.request({
|
|
35
|
+
capability: "traffic",
|
|
36
|
+
operation: "wait",
|
|
37
|
+
process: this.process,
|
|
38
|
+
endpoint: this.endpoint,
|
|
39
|
+
kind,
|
|
40
|
+
event: null,
|
|
41
|
+
timeout: 86_400_000
|
|
42
|
+
}, controller.signal);
|
|
43
|
+
subscriber(convert(value));
|
|
44
|
+
}
|
|
45
|
+
catch (error) {
|
|
46
|
+
if (!controller.signal.aborted)
|
|
47
|
+
impossible?.(error instanceof Error ? error : new Error(String(error)));
|
|
48
|
+
controller.abort();
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
})();
|
|
52
|
+
return () => controller.abort();
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
/** Directed traffic originating from one canonical Server. */
|
|
56
|
+
export class ServerTrafficHandle extends EndpointTrafficHandle {
|
|
57
|
+
subscribeAnswers(subscriber) {
|
|
58
|
+
return this.follow("answer", value => answer(value, this.resolveEndpoint), subscriber);
|
|
59
|
+
}
|
|
60
|
+
answers(options) {
|
|
61
|
+
return stream((subscriber, impossible) => this.follow("answer", value => answer(value, this.resolveEndpoint), subscriber, impossible), options);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
function publication(value, resolve, captured) {
|
|
65
|
+
const received = traffic(value);
|
|
66
|
+
const message = directed(received.values[0], resolve);
|
|
67
|
+
return captured ? { event: received.event, payload: message } : message;
|
|
68
|
+
}
|
|
69
|
+
function question(value, resolve) {
|
|
70
|
+
const received = traffic(value);
|
|
71
|
+
if (typeof received.values[0] !== "string")
|
|
72
|
+
throw new Error("The System returned invalid question traffic");
|
|
73
|
+
return {
|
|
74
|
+
event: received.event,
|
|
75
|
+
questionId: received.values[0],
|
|
76
|
+
message: directed(received.values[1], resolve)
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
function answer(value, resolve) {
|
|
80
|
+
const received = traffic(value);
|
|
81
|
+
const raw = received.values[1];
|
|
82
|
+
if (typeof received.values[0] !== "string" || !raw || typeof raw !== "object")
|
|
83
|
+
throw new Error("The System returned invalid answer traffic");
|
|
84
|
+
return {
|
|
85
|
+
event: received.event,
|
|
86
|
+
questionId: received.values[0],
|
|
87
|
+
message: { to: resolve(raw.to), outcome: raw.outcome }
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
function directed(value, resolve) {
|
|
91
|
+
const raw = value;
|
|
92
|
+
if (!raw || typeof raw !== "object")
|
|
93
|
+
throw new Error("The System returned invalid Endpoint traffic");
|
|
94
|
+
return { to: resolve(raw.to), payload: raw.payload };
|
|
95
|
+
}
|
|
96
|
+
function traffic(value) {
|
|
97
|
+
const received = value;
|
|
98
|
+
if (!received || typeof received.event !== "string" || !Array.isArray(received.values))
|
|
99
|
+
throw new Error("The System returned invalid traffic");
|
|
100
|
+
return { event: received.event, values: received.values };
|
|
101
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@phreshos/node",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.8",
|
|
4
4
|
"description": "Node.js access to PhreshOS and Program projects.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/main.js",
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
"prepack": "node --run build"
|
|
37
37
|
},
|
|
38
38
|
"dependencies": {
|
|
39
|
-
"@phreshos/core": "^0.1.
|
|
39
|
+
"@phreshos/core": "^0.1.30",
|
|
40
40
|
"adm-zip": "^0.6.0",
|
|
41
41
|
"jiti": "^2.7.0"
|
|
42
42
|
},
|