@phreshos/server 0.1.22 → 0.1.24

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 CHANGED
@@ -136,6 +136,9 @@ A Program owns its scoped Process capability:
136
136
  const processes = await program.process.list()
137
137
  const process = await program.process.find("worker")
138
138
  const created = await program.process.create({ name: "worker" })
139
+ for await (const event of program.process.run({ name: "temporary" }, { signal })) {
140
+ // started, output, exited
141
+ }
139
142
  const shared = await program.process.findOrCreate({
140
143
  name: "shared-server",
141
144
  server: true,
@@ -143,6 +146,11 @@ const shared = await program.process.findOrCreate({
143
146
  })
144
147
  ```
145
148
 
149
+ `run()` creates exactly one Process and yields its ordered `started`, `output`,
150
+ and `exited` lifecycle. Aborting its signal, returning early, or losing the
151
+ calling Server exits that Process; `create()` remains independent of the
152
+ caller.
153
+
146
154
  `findOrCreate()` is atomic at the authoritative Core. Concurrent equivalent
147
155
  launches converge on one named Process; a different launch for that name
148
156
  rejects instead of reconfiguring the existing Process.
@@ -172,7 +180,7 @@ if (program.hasAgent) console.log(await program.agent())
172
180
  asset-hosting address. Omitting the size selects `medium`.
173
181
 
174
182
  Installed Programs may persist one ordinary Process launch for the next system
175
- startup. This capability exists only in the Server SDK:
183
+ startup through the shared Program interface:
176
184
 
177
185
  ```ts
178
186
  await program.startup.enable({
package/dist/domain.d.ts CHANGED
@@ -74,11 +74,26 @@ export interface ProgramProcess extends Omit<CoreProgramProcess, "list" | "first
74
74
  find(identityOrName: string): Promise<Process | null>;
75
75
  /** Creates one Process of this Program. */
76
76
  create(launch?: Launch): Promise<Process>;
77
+ /** Runs one Process for exactly as long as its lifecycle iterator remains open. */
78
+ run(launch?: Launch, options?: ProgramProcessRunOptions): AsyncGenerator<ProgramProcessRunEvent, void, void>;
77
79
  /** Finds the named Process or atomically creates it with the same resolved launch. */
78
80
  findOrCreate(launch: Launch & Readonly<{
79
81
  name: string;
80
82
  }>): Promise<Process>;
81
83
  }
84
+ export type ProgramProcessRunEvent = Readonly<{
85
+ event: "started";
86
+ process: Process;
87
+ }> | (Readonly<{
88
+ event: "output";
89
+ }> & ProgramCommandChunk) | Readonly<{
90
+ event: "exited";
91
+ process: Process;
92
+ exit: Exit;
93
+ }>;
94
+ export type ProgramProcessRunOptions = Readonly<{
95
+ signal?: AbortSignal;
96
+ }>;
82
97
  /** Server-visible Process handle. */
83
98
  export interface Process<Events extends object = {}> extends CoreProcess<Events> {
84
99
  /** Permanent handle to this Process's Server. */
package/dist/domain.js CHANGED
@@ -134,6 +134,11 @@ class ProgramProcessHandle {
134
134
  const answer = await wire.request(["program-process-create", this.address, launch]);
135
135
  return process(answer[0]);
136
136
  }
137
+ async *run(launch = {}, options = {}) {
138
+ for await (const value of wire.stream(["run", this.address, launch], undefined, options.signal)) {
139
+ yield processRunEvent(value);
140
+ }
141
+ }
137
142
  async findOrCreate(launch) {
138
143
  const answer = await wire.request(["program-process-find-or-create", this.address, launch]);
139
144
  return process(answer[0]);
@@ -143,6 +148,21 @@ class ProgramProcessHandle {
143
148
  return answer[0];
144
149
  }
145
150
  }
151
+ function processRunEvent(value) {
152
+ const event = value;
153
+ if (event?.event === "started" && event.process) {
154
+ return Object.freeze({ event: "started", process: process(event.process) });
155
+ }
156
+ if (event?.event === "output" && (event.stream === "stdout" || event.stream === "stderr") && typeof event.text === "string") {
157
+ return Object.freeze({ event: "output", stream: event.stream, text: event.text });
158
+ }
159
+ if (event?.event === "exited" && event.process) {
160
+ const code = typeof event.exit?.code === "number" ? event.exit.code : null;
161
+ const signal = typeof event.exit?.signal === "string" ? event.exit.signal : null;
162
+ return Object.freeze({ event: "exited", process: process(event.process), exit: exit(code, signal) });
163
+ }
164
+ throw new Error("The System returned an invalid Process run event");
165
+ }
146
166
  /** Internal transport address for a Program handle created by this SDK. */
147
167
  export function programAddress(value) {
148
168
  if (!(value instanceof ProgramHandle))
package/dist/main.d.ts CHANGED
@@ -5,5 +5,5 @@ export { type ProgramStartup } from "./startup.js";
5
5
  export { type Storage } from "./storage.js";
6
6
  export { ClientServiceHandler, ServerServiceHandler } from "./service.js";
7
7
  export { ServiceHandler, type ClientServiceChannel, type ServerServiceChannel, type ServiceChannel, type ServiceKey, type ServiceLifecycleEvents } from "@phreshos/core";
8
- export { Client, Endpoint, Process, Program, Server, type Window, type ProgramProcess } from "./domain.js";
9
- export type { AnswerCapture, AnswerMessage, AnswerObserver, Askable, AskCapture, AskMessage, AskObserver, Capture, Captures, ClientTraffic, ClientDeclaration, Cleanup, DirectoryStat, EndpointDeclaration, EndpointTraffic, EntryStat, EventMessage, EventName, EventObserver, EventOptions, EventSubscriber, Exit, FileStat, Launch, LaunchClient, Layer, LogKind, LogRecord, LogSource, Message, OtherStat, Outcome, Position, ProgramEvents, ProgramPermission, ProgramProcessEvents, ProgramProcessExit, ProgramSql, ProgramStore, ProcessEvents, Publishable, SystemUploads, Upload, ServerTraffic, System, SystemProcess, SystemProcessEntity, SystemProcessEntityEvents, SystemProgram, SystemProgramEntity, SystemProgramProcess, SystemProgramProcessEvents, SystemEndpointEntity, SystemServerEntity, SystemClientEntity, ClientDescription, SystemProcessEvents, SystemProcessExit, SystemProgramEvents, SystemProgramUninstall, ProgramDescription, ServerDescription, Size, Subscribable, SubscribableEvents, SubscribableFallback, TimedAskable, TrafficCapture, TrafficEvents, TrafficMessage, Value, Appearance, AppearanceEvents, AppearanceSource, AppearanceSurface, ThemedValue, WritableAppearance, WindowEvents, WindowGeometry, WindowLayer, WindowState } from "@phreshos/core";
8
+ export { Client, Endpoint, Process, Program, Server, type Window, type ProgramProcess, type ProgramProcessRunEvent, type ProgramProcessRunOptions } from "./domain.js";
9
+ export type { AnswerCapture, AnswerMessage, AnswerObserver, Askable, AskCapture, AskMessage, AskObserver, Capture, Captures, ClientTraffic, ClientDeclaration, Cleanup, DirectoryStat, EndpointDeclaration, EndpointTraffic, EntryStat, EventMessage, EventName, EventObserver, EventOptions, EventSubscriber, Exit, FileStat, Launch, LaunchClient, Layer, LogKind, LogRecord, LogSource, Message, OtherStat, Outcome, Position, ProgramEvents, ProgramPermission, ProgramProcessEvents, ProgramProcessExit, ProgramSql, ProgramStore, ProcessEvents, Publishable, SystemUploads, Upload, ServerTraffic, System, SystemProcess, SystemProcessEntity, SystemProcessEntityEvents, SystemProgram, SystemProgramEntity, SystemProgramProcess, SystemProgramProcessEvents, SystemEndpointEntity, SystemServerEntity, SystemClientEntity, ClientDefinition, SystemProcessEvents, SystemProcessExit, SystemProgramEvents, SystemProgramUninstall, ProgramDefinition, ServerDefinition, Size, Subscribable, SubscribableEvents, SubscribableFallback, TimedAskable, TrafficCapture, TrafficEvents, TrafficMessage, Value, Appearance, AppearanceEvents, AppearanceSource, AppearanceSurface, ThemedValue, WritableAppearance, WindowEvents, WindowGeometry, WindowLayer, WindowState } from "@phreshos/core";
package/dist/system.js CHANGED
@@ -11,6 +11,10 @@ class ServerSystem {
11
11
  program = new ServerSystemProgram();
12
12
  process = new ServerSystemProcess();
13
13
  uploads = uploads;
14
+ async forceCreateProgram(source) {
15
+ const answer = await wire.request(["host-program-force-create", source]);
16
+ return program(answer[0]);
17
+ }
14
18
  service(key) { return prepareService(key); }
15
19
  }
16
20
  class ServerSystemProgram extends Events {
package/dist/wire.d.ts CHANGED
@@ -20,7 +20,7 @@ declare class Wire {
20
20
  request(values: unknown[], timeout?: number): Promise<unknown>;
21
21
  requestWithin(values: unknown[], deadline: Deadline): Promise<unknown>;
22
22
  /** Opens one long-running system operation and yields its ordered values. */
23
- stream(values: unknown[], timeout?: number): AsyncIterableIterator<unknown>;
23
+ stream(values: unknown[], timeout?: number, signal?: AbortSignal): AsyncIterableIterator<unknown>;
24
24
  /** Resolves this endpoint's Process address only for operations that need it. */
25
25
  identity(): Promise<{
26
26
  process: string;
package/dist/wire.js CHANGED
@@ -74,7 +74,7 @@ class Wire {
74
74
  });
75
75
  }
76
76
  /** Opens one long-running system operation and yields its ordered values. */
77
- stream(values, timeout = defaultTimeout) {
77
+ stream(values, timeout = defaultTimeout, signal) {
78
78
  const wire = this;
79
79
  return (async function* () {
80
80
  const question = randomUUID();
@@ -90,6 +90,15 @@ class Wire {
90
90
  state.wake = null;
91
91
  }, timeout)
92
92
  };
93
+ const abort = () => {
94
+ state.failure = signal?.reason instanceof Error ? signal.reason : new Error("The operation was cancelled");
95
+ state.wake?.();
96
+ state.wake = null;
97
+ };
98
+ if (signal?.aborted)
99
+ abort();
100
+ else
101
+ signal?.addEventListener("abort", abort, { once: true });
93
102
  wire.send("boundary", "expect", question);
94
103
  wire.streams.set(question, state);
95
104
  wire.send("end-host", "stream", question, ...values);
@@ -107,6 +116,7 @@ class Wire {
107
116
  }
108
117
  }
109
118
  finally {
119
+ signal?.removeEventListener("abort", abort);
110
120
  clearTimeout(state.timer);
111
121
  wire.streams.delete(question);
112
122
  wire.send("boundary", "forget", question);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@phreshos/server",
3
- "version": "0.1.22",
3
+ "version": "0.1.24",
4
4
  "description": "The SDK used by a Program's server 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.21"
50
+ "@phreshos/core": "^0.1.23"
51
51
  },
52
52
  "dependencies": {
53
53
  "@msgpack/msgpack": "^3.1.3"
54
54
  },
55
55
  "devDependencies": {
56
- "@phreshos/core": "^0.1.21",
56
+ "@phreshos/core": "^0.1.23",
57
57
  "@types/node": "^26.2.0",
58
58
  "typescript": "^6.0.3"
59
59
  }