@procedures/peer 0.10.0 → 0.12.0
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/CHANGELOG.md +78 -0
- package/README.md +46 -7
- package/dist/.tsbuildinfo +1 -1
- package/dist/host/faces.d.ts +78 -0
- package/dist/host/faces.d.ts.map +1 -0
- package/dist/host/faces.js +77 -0
- package/dist/host/faces.js.map +1 -0
- package/dist/host/index.d.ts +186 -0
- package/dist/host/index.d.ts.map +1 -0
- package/dist/host/index.js +257 -0
- package/dist/host/index.js.map +1 -0
- package/dist/host/tracking.d.ts +60 -0
- package/dist/host/tracking.d.ts.map +1 -0
- package/dist/host/tracking.js +162 -0
- package/dist/host/tracking.js.map +1 -0
- package/dist/index.d.ts +3 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -2
- package/dist/index.js.map +1 -1
- package/dist/lockfile.d.ts +21 -4
- package/dist/lockfile.d.ts.map +1 -1
- package/dist/lockfile.js +31 -7
- package/dist/lockfile.js.map +1 -1
- package/dist/peer/index.d.ts +43 -9
- package/dist/peer/index.d.ts.map +1 -1
- package/dist/peer/index.js +156 -241
- package/dist/peer/index.js.map +1 -1
- package/package.json +6 -9
- package/src/host/faces.ts +130 -0
- package/src/host/index.ts +434 -0
- package/src/host/tracking.ts +217 -0
- package/src/index.ts +38 -2
- package/src/lockfile.ts +39 -7
- package/src/peer/index.ts +172 -292
package/dist/peer/index.js
CHANGED
|
@@ -1,277 +1,192 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Peer Module
|
|
3
3
|
*
|
|
4
|
-
*
|
|
4
|
+
* A peer is a procedures host with a service of its own (CLI-7), for a process that has no service
|
|
5
|
+
* of its own: a test, or a host that a procedure starts (`server.create`). `createPeer()` builds it
|
|
6
|
+
* with `createProcedureHost()`: each HTTP or WebSocket transport of the options is a face on a
|
|
7
|
+
* listener of the host, and the listener is an `httpTransport` of `@mark1russell7/service/http`.
|
|
8
|
+
*
|
|
9
|
+
* - `start()` declares the parts in a service and starts `run()` of `@mark1russell7/service`, on
|
|
10
|
+
* a process port that installs no signal handler and never ends the process.
|
|
11
|
+
* - `stop()` asks the lifecycle for its shutdown, and waits for the end of its stages.
|
|
12
|
+
*
|
|
13
|
+
* A process that has a service of its own declares the parts of `createProcedureHost()` with
|
|
14
|
+
* `host.declare(svc)`, in place of a peer (decision D2). The peer has no listener, URL strategy,
|
|
15
|
+
* `/health` route or token check of its own.
|
|
5
16
|
*/
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
17
|
+
import { daemon, embeddedProcess, service } from "@mark1russell7/service";
|
|
18
|
+
import { hostPolicy, seconds, } from "@procedures/client";
|
|
19
|
+
import { defaultServerUrlStrategy, rpcServerUrlStrategy } from "@procedures/client/node";
|
|
20
|
+
import { createProcedureHost, httpFace, LOCAL_LISTENER_KNOBS, wsFace } from "../host/index.js";
|
|
21
|
+
import { originAllowed } from "./security.js";
|
|
22
|
+
// =============================================================================
|
|
23
|
+
// Implementation
|
|
24
|
+
// =============================================================================
|
|
8
25
|
/**
|
|
9
|
-
*
|
|
10
|
-
*
|
|
26
|
+
* The policy of a peer, with its one token. A transport token and a policy token must be the same:
|
|
27
|
+
* the one server examines one token for each face.
|
|
11
28
|
*/
|
|
12
|
-
function
|
|
13
|
-
const
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
path = path.slice(basePath.length);
|
|
29
|
+
function peerPolicy(options) {
|
|
30
|
+
const own = new Set(options.transports.flatMap((transport) => (transport.type !== "local" && transport.token !== undefined ? [transport.token] : [])));
|
|
31
|
+
const policyToken = options.policy?.token;
|
|
32
|
+
if (own.size > 1 || (own.size === 1 && policyToken !== undefined && !own.has(policyToken))) {
|
|
33
|
+
throw new Error("A peer has one token: give the same token to each transport, or give it only in the policy");
|
|
18
34
|
}
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
return
|
|
35
|
+
const token = [...own][0] ?? policyToken;
|
|
36
|
+
if (options.policy)
|
|
37
|
+
return token === policyToken ? options.policy : { ...options.policy, token };
|
|
38
|
+
return hostPolicy(token !== undefined ? { token } : {});
|
|
23
39
|
}
|
|
24
|
-
/** The
|
|
25
|
-
function
|
|
26
|
-
|
|
27
|
-
|
|
40
|
+
/** The options of the HTTP face of a transport: the rules of the peer before CLI-7, on `procedureHandler`. */
|
|
41
|
+
function httpOptionsOf(config, browser) {
|
|
42
|
+
return {
|
|
43
|
+
basePath: config.basePath ?? "/api",
|
|
44
|
+
// Off by default: before, every peer sent Access-Control-Allow-Origin: * (deep dive CLI-2)
|
|
45
|
+
cors: config.cors ?? false,
|
|
46
|
+
...(config.urlStrategy === "rpc" ? { urlStrategy: rpcServerUrlStrategy } : config.urlStrategy === "rest" ? { urlStrategy: defaultServerUrlStrategy } : {}),
|
|
47
|
+
// The browser checks follow the rule of the peer: loopback origins and the listed ones
|
|
48
|
+
allowedOrigins: browser.allowedOrigins ?? ((origin) => originAllowed(origin, config.corsOrigins)),
|
|
49
|
+
...(browser.allowedHosts !== undefined ? { allowedHosts: browser.allowedHosts } : {}),
|
|
50
|
+
// The RESTful strategy calls by GET
|
|
51
|
+
allowGet: browser.allowGet ?? config.urlStrategy === "rest",
|
|
52
|
+
...(config.bodyLimit !== undefined ? { bodyLimit: config.bodyLimit } : {}),
|
|
53
|
+
};
|
|
28
54
|
}
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
55
|
+
/** The options of the WebSocket face of a transport. */
|
|
56
|
+
function wsOptionsOf(config, browser) {
|
|
57
|
+
return {
|
|
58
|
+
path: config.path ?? "/ws",
|
|
59
|
+
allowedOrigins: browser.allowedOrigins ?? ((origin) => originAllowed(origin, config.origins)),
|
|
60
|
+
...(browser.allowedHosts !== undefined ? { allowedHosts: browser.allowedHosts } : {}),
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* The faces and the listeners of the transports. Two transports on one address and port share one
|
|
65
|
+
* listener. Loopback is the default address, so the whole registry (`shell.run`, `fs.write`) is
|
|
66
|
+
* not served on each interface (BUGS-2026-07 H19). Give `host: "0.0.0.0"` on purpose for the LAN.
|
|
67
|
+
*/
|
|
68
|
+
function facesOf(transports, browser) {
|
|
69
|
+
const faces = {};
|
|
70
|
+
const listeners = [];
|
|
71
|
+
const counts = { http: 0, websocket: 0 };
|
|
72
|
+
for (const transport of transports) {
|
|
73
|
+
if (transport.type === "local")
|
|
74
|
+
continue;
|
|
75
|
+
const kind = transport.type === "http" ? "http" : "ws";
|
|
76
|
+
const index = counts[transport.type]++;
|
|
77
|
+
const faceName = index === 0 ? kind : `${kind}${index + 1}`;
|
|
78
|
+
faces[faceName] =
|
|
79
|
+
transport.type === "http" ? httpFace(httpOptionsOf(transport, browser)) : wsFace(wsOptionsOf(transport, browser));
|
|
80
|
+
const port = transport.port ?? (transport.type === "http" ? 3000 : 3001);
|
|
81
|
+
const host = transport.host ?? "127.0.0.1";
|
|
82
|
+
const shared = port === 0 ? undefined : listeners.find((listener) => listener.port === port && listener.host === host);
|
|
83
|
+
if (shared)
|
|
84
|
+
shared.faces.push(faceName);
|
|
85
|
+
else
|
|
86
|
+
listeners.push({ name: faceName, port, host, faces: [faceName] });
|
|
87
|
+
}
|
|
88
|
+
return { faces, listen: listeners.map((listener) => ({ ...listener, knobs: LOCAL_LISTENER_KNOBS })) };
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* This function gives the options of a procedures host for the options of a peer: each HTTP or
|
|
92
|
+
* WebSocket transport is a face on a listener with `LOCAL_LISTENER_KNOBS`, and the peer has one
|
|
93
|
+
* token. `createPeer()` uses it, and so does `runProcedureHost()` of `@procedures/server` (CLI-8).
|
|
94
|
+
*/
|
|
95
|
+
export function peerHostOptions(options, name = "peer") {
|
|
96
|
+
const policy = peerPolicy(options);
|
|
97
|
+
const { faces, listen } = facesOf(options.transports, policy.browser);
|
|
98
|
+
const local = options.transports.some((transport) => transport.type === "local");
|
|
99
|
+
return {
|
|
100
|
+
name,
|
|
101
|
+
id: options.id,
|
|
102
|
+
policy,
|
|
103
|
+
faces,
|
|
104
|
+
listen,
|
|
105
|
+
autoRegister: options.autoRegister ?? true,
|
|
106
|
+
...(options.registry ? { registry: options.registry } : {}),
|
|
107
|
+
...(options.expose ? { expose: options.expose } : {}),
|
|
108
|
+
...(options.metrics !== undefined ? { metrics: options.metrics } : {}),
|
|
109
|
+
...(local ? { endpoints: [{ type: "local", address: "local://in-process" }] } : {}),
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
/** The cap of the stage `drain` of the profile `daemon`. */
|
|
113
|
+
const DAEMON_DRAIN = daemon.phases?.find((phase) => phase.name === "drain")?.cap ?? seconds(4);
|
|
114
|
+
/**
|
|
115
|
+
* The profile of the service of a peer, as data: the caps of `daemon`, and the cooperative abort at
|
|
116
|
+
* the start of the drain. Thus `stop()` aborts the calls in flight at once, as `stop()` without a
|
|
117
|
+
* grace did before (CLI-7). A repeat signal has no effect, and the port of a peer has no signal.
|
|
118
|
+
*/
|
|
119
|
+
export const PEER_PROFILE = Object.freeze({ ...daemon, cooperativeWindow: DAEMON_DRAIN, cooperativeFloor: "none" });
|
|
32
120
|
class PeerImpl {
|
|
33
121
|
id;
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
/** The WebSocket transports of the peer: the calls to its clients go over them (R24) */
|
|
39
|
-
wsTransports = [];
|
|
40
|
-
/** The HTTP servers that the peer made for its WebSocket transports: `stop()` closes them */
|
|
41
|
-
ownedServers = [];
|
|
42
|
-
registry;
|
|
43
|
-
startTime = Date.now();
|
|
44
|
-
/** The browser checks of the policy (an origin rule here replaces the peer's own rule). */
|
|
45
|
-
browser;
|
|
122
|
+
host;
|
|
123
|
+
profile;
|
|
124
|
+
life;
|
|
125
|
+
state = "new";
|
|
46
126
|
constructor(options) {
|
|
47
127
|
this.id = options.id;
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
this.transports = options.transports.map((transport) => transport.type === "local" || policy?.token === undefined || transport.token !== undefined
|
|
51
|
-
? transport
|
|
52
|
-
: { ...transport, token: policy.token });
|
|
53
|
-
this.registry = options.registry ?? PROCEDURE_REGISTRY;
|
|
54
|
-
this.browser = policy?.browser ?? {};
|
|
55
|
-
// Create procedure server. The metrics interceptor counts each call for host.metrics (R19).
|
|
56
|
-
const metrics = options.metrics === false ? undefined : metricsInterceptor();
|
|
57
|
-
const serverOptions = policy ? procedureServerOptions(policy, this.registry) : {};
|
|
58
|
-
const interceptors = [...(serverOptions.interceptors ?? []), ...(metrics ? [metrics.interceptor] : [])];
|
|
59
|
-
this.server = new ProcedureServer({
|
|
60
|
-
...serverOptions,
|
|
61
|
-
...(interceptors.length > 0 ? { interceptors } : {}),
|
|
62
|
-
autoRegister: options.autoRegister ?? true,
|
|
63
|
-
registry: this.registry,
|
|
64
|
-
...(options.expose ? { expose: options.expose } : {}),
|
|
65
|
-
});
|
|
66
|
-
// host.health, host.info and host.metrics: pinned on the server, not in the registry (R19)
|
|
67
|
-
this.server.registerProcedures(hostProcedures({
|
|
68
|
-
id: this.id,
|
|
69
|
-
startedAt: this.startTime,
|
|
70
|
-
server: this.server,
|
|
71
|
-
endpoints: () => this.getEndpoints(),
|
|
72
|
-
...(metrics ? { metrics } : {}),
|
|
73
|
-
}));
|
|
128
|
+
this.host = createProcedureHost(peerHostOptions(options));
|
|
129
|
+
this.profile = options.profile ?? PEER_PROFILE;
|
|
74
130
|
}
|
|
75
131
|
async start() {
|
|
76
|
-
if (this.started)
|
|
132
|
+
if (this.state === "started")
|
|
77
133
|
return;
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
134
|
+
if (this.state === "stopped")
|
|
135
|
+
throw new Error("This peer stopped. A peer starts one time: create a new peer.");
|
|
136
|
+
this.state = "started";
|
|
137
|
+
const svc = this.host.declare(service(this.id).profile(this.profile));
|
|
138
|
+
// No check gates the policies of a peer: it is ready from the end of its startup
|
|
139
|
+
if (!this.profile.readiness)
|
|
140
|
+
svc.readiness({ type: "debounce", interval: seconds(5), failAfter: 3, recoverAfter: 1 });
|
|
141
|
+
if (!this.profile.liveness)
|
|
142
|
+
svc.liveness({ type: "window", failAfter: seconds(45) });
|
|
143
|
+
if (!this.profile.startup)
|
|
144
|
+
svc.startup(seconds(30));
|
|
145
|
+
if (!this.profile.onRepeatSignal)
|
|
146
|
+
svc.onRepeatSignal("ignore");
|
|
147
|
+
// The port of a lifecycle in a process that another part owns (SYS-27): no signal handler, no
|
|
148
|
+
// hold of the process, and an exit that only records the code
|
|
149
|
+
const life = await svc.run({ process: embeddedProcess() });
|
|
150
|
+
if (life.state !== "running") {
|
|
151
|
+
// The startup failed: the lifecycle stops the parts that started, so no port stays open
|
|
152
|
+
this.state = "stopped";
|
|
153
|
+
await life.done;
|
|
154
|
+
throw new Error(life.errors.join("; ") || "The peer did not start");
|
|
88
155
|
}
|
|
89
|
-
this.
|
|
156
|
+
this.life = life;
|
|
90
157
|
}
|
|
91
|
-
async
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
await this.startHttpTransport(config);
|
|
95
|
-
break;
|
|
96
|
-
case "websocket":
|
|
97
|
-
await this.startWebSocketTransport(config);
|
|
98
|
-
break;
|
|
99
|
-
case "local":
|
|
100
|
-
// Local transport doesn't need network setup
|
|
101
|
-
this.endpoints.push({
|
|
102
|
-
type: "local",
|
|
103
|
-
address: "local://in-process",
|
|
104
|
-
});
|
|
105
|
-
break;
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
async startHttpTransport(config) {
|
|
109
|
-
// Dynamic import to avoid bundling express if not used
|
|
110
|
-
const express = (await import("express")).default;
|
|
111
|
-
const app = express();
|
|
112
|
-
// No body parser here: the transport reads the body itself, with bodyLimit, and accepts each
|
|
113
|
-
// JSON value (roadmap R5). Before, the strict parser of express refused a bare value (a
|
|
114
|
-
// number, a string, null) with 400, and its limit of 100 kB replaced bodyLimit.
|
|
115
|
-
const port = config.port ?? 3000;
|
|
116
|
-
// Loopback by default so the full procedure registry (incl. shell.run / fs.write) is not
|
|
117
|
-
// served unauthenticated on all interfaces. Pass host: "0.0.0.0" to expose on the LAN
|
|
118
|
-
// deliberately. See documentation/BUGS-2026-07.md (H19).
|
|
119
|
-
const host = config.host ?? "127.0.0.1";
|
|
120
|
-
const basePath = config.basePath ?? "/api";
|
|
121
|
-
// Host, origin and token checks (deep dive TRN-1, CLI-1, CLI-2). The health endpoints need no
|
|
122
|
-
// token: a client uses them to check that a lockfile's server is alive.
|
|
123
|
-
app.use((req, res, next) => {
|
|
124
|
-
if (!hostAllowed(host, req.headers.host) || !originAllowed(req.headers.origin, config.corsOrigins)) {
|
|
125
|
-
res.status(403).json({ error: "Forbidden: the host or the origin is not allowed", code: "FORBIDDEN" });
|
|
126
|
-
return;
|
|
127
|
-
}
|
|
128
|
-
const isHealth = req.path === "/health" || req.path === `${basePath}/health`;
|
|
129
|
-
if (!isHealth && req.method !== "OPTIONS" && !tokenMatches(config.token, bearerToken(req.headers.authorization))) {
|
|
130
|
-
res.status(401).json({ error: "Unauthorized: this server requires its token", code: "UNAUTHORIZED" });
|
|
131
|
-
return;
|
|
132
|
-
}
|
|
133
|
-
next();
|
|
134
|
-
});
|
|
135
|
-
// Health endpoint for container orchestration
|
|
136
|
-
app.get(`${basePath}/health`, (_req, res) => {
|
|
137
|
-
const procedureCount = this.registry.getAll().filter((p) => p.handler).length;
|
|
138
|
-
res.json({
|
|
139
|
-
status: "ok",
|
|
140
|
-
uptime: Date.now() - this.startTime,
|
|
141
|
-
procedures: procedureCount,
|
|
142
|
-
peerId: this.id,
|
|
143
|
-
});
|
|
144
|
-
});
|
|
145
|
-
// Also add at root /health for convenience
|
|
146
|
-
app.get("/health", (_req, res) => {
|
|
147
|
-
const procedureCount = this.registry.getAll().filter((p) => p.handler).length;
|
|
148
|
-
res.json({
|
|
149
|
-
status: "ok",
|
|
150
|
-
uptime: Date.now() - this.startTime,
|
|
151
|
-
procedures: procedureCount,
|
|
152
|
-
peerId: this.id,
|
|
153
|
-
});
|
|
154
|
-
});
|
|
155
|
-
// Select URL strategy based on config
|
|
156
|
-
// Default to patternUrlStrategy which matches the client's defaultUrlPattern
|
|
157
|
-
const urlStrategy = config.urlStrategy === "rpc"
|
|
158
|
-
? rpcServerUrlStrategy
|
|
159
|
-
: config.urlStrategy === "rest"
|
|
160
|
-
? defaultServerUrlStrategy
|
|
161
|
-
: patternUrlStrategy;
|
|
162
|
-
const httpTransport = new HttpServerTransport(this.server, {
|
|
163
|
-
app,
|
|
164
|
-
port,
|
|
165
|
-
host,
|
|
166
|
-
basePath,
|
|
167
|
-
// Off by default: before, every peer sent Access-Control-Allow-Origin: * (deep dive CLI-2)
|
|
168
|
-
cors: config.cors ?? false,
|
|
169
|
-
urlStrategy,
|
|
170
|
-
// The transport's browser checks follow the peer's rule: loopback origins and the listed
|
|
171
|
-
// ones (the token is required in any case). The RESTful strategy calls by GET.
|
|
172
|
-
allowedOrigins: this.browser.allowedOrigins ?? ((origin) => originAllowed(origin, config.corsOrigins)),
|
|
173
|
-
...(this.browser.allowedHosts ? { allowedHosts: this.browser.allowedHosts } : {}),
|
|
174
|
-
allowGet: this.browser.allowGet ?? config.urlStrategy === "rest",
|
|
175
|
-
...(config.bodyLimit !== undefined ? { bodyLimit: config.bodyLimit } : {}),
|
|
176
|
-
});
|
|
177
|
-
this.server.addTransport(httpTransport);
|
|
178
|
-
await httpTransport.start();
|
|
179
|
-
this.endpoints.push({
|
|
180
|
-
type: "http",
|
|
181
|
-
// The real port: with port 0 the system gives a free port
|
|
182
|
-
address: `http://${host === "0.0.0.0" ? "localhost" : host}:${httpTransport.port() ?? port}${basePath}`,
|
|
183
|
-
});
|
|
184
|
-
}
|
|
185
|
-
async startWebSocketTransport(config) {
|
|
186
|
-
// WebSocket transport requires an HTTP server to attach to
|
|
187
|
-
// For standalone WebSocket, we create an HTTP server first
|
|
188
|
-
const { createServer } = await import("http");
|
|
189
|
-
const port = config.port ?? 3001;
|
|
190
|
-
// Loopback by default so the full procedure registry (incl. shell.run / fs.write) is not
|
|
191
|
-
// served unauthenticated on all interfaces. Pass host: "0.0.0.0" to expose on the LAN
|
|
192
|
-
// deliberately. See documentation/BUGS-2026-07.md (H19).
|
|
193
|
-
const host = config.host ?? "127.0.0.1";
|
|
194
|
-
const path = config.path ?? "/ws";
|
|
195
|
-
const httpServer = createServer();
|
|
196
|
-
// Listen first, then attach the WebSocket server. A listen error (EADDRINUSE, EACCES) rejects:
|
|
197
|
-
// before, the error had no listener, so the process ended with an unhandled 'error' event
|
|
198
|
-
// (deep dive CLI-16).
|
|
199
|
-
await new Promise((resolve, reject) => {
|
|
200
|
-
const onError = (error) => {
|
|
201
|
-
reject(new Error(`The WebSocket server cannot listen on ${host}:${port}: ${error.message}`));
|
|
202
|
-
};
|
|
203
|
-
httpServer.once("error", onError);
|
|
204
|
-
httpServer.listen(port, host, () => {
|
|
205
|
-
httpServer.off("error", onError);
|
|
206
|
-
resolve();
|
|
207
|
-
});
|
|
208
|
-
});
|
|
209
|
-
const wsTransport = new WebSocketServerTransport(this.server, {
|
|
210
|
-
server: httpServer,
|
|
211
|
-
path,
|
|
212
|
-
allowedOrigins: this.browser.allowedOrigins ?? ((origin) => originAllowed(origin, config.origins)),
|
|
213
|
-
...(this.browser.allowedHosts ? { allowedHosts: this.browser.allowedHosts } : {}),
|
|
214
|
-
// Host, origin and token checks: before, any web page could open a connection and call
|
|
215
|
-
// procedures (cross-site WebSocket hijacking, deep dive TRN-1)
|
|
216
|
-
authenticate: (req) => {
|
|
217
|
-
const token = new URL(req.url ?? "/", "http://localhost").searchParams.get("token") ?? bearerToken(req.headers.authorization);
|
|
218
|
-
return (hostAllowed(host, req.headers.host) &&
|
|
219
|
-
originAllowed(req.headers.origin, config.origins) &&
|
|
220
|
-
tokenMatches(config.token, token));
|
|
221
|
-
},
|
|
222
|
-
});
|
|
223
|
-
this.server.addTransport(wsTransport);
|
|
224
|
-
try {
|
|
225
|
-
await wsTransport.start();
|
|
226
|
-
}
|
|
227
|
-
catch (error) {
|
|
228
|
-
httpServer.close();
|
|
229
|
-
throw error;
|
|
230
|
-
}
|
|
231
|
-
this.ownedServers.push(httpServer);
|
|
232
|
-
this.wsTransports.push(wsTransport);
|
|
233
|
-
this.endpoints.push({
|
|
234
|
-
type: "websocket",
|
|
235
|
-
address: `ws://${host === "0.0.0.0" ? "localhost" : host}:${listeningPort(httpServer) ?? port}${path}`,
|
|
236
|
-
});
|
|
237
|
-
}
|
|
238
|
-
async stop(options = {}) {
|
|
239
|
-
if (!this.started)
|
|
158
|
+
async stop(_options = {}) {
|
|
159
|
+
const life = this.life;
|
|
160
|
+
if (this.state !== "started" || life === undefined)
|
|
240
161
|
return;
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
const owned = this.ownedServers;
|
|
245
|
-
this.ownedServers = [];
|
|
246
|
-
await Promise.all(owned.map((httpServer) => new Promise((resolve) => {
|
|
247
|
-
httpServer.close(() => resolve());
|
|
248
|
-
httpServer.closeAllConnections();
|
|
249
|
-
})));
|
|
250
|
-
this.started = false;
|
|
251
|
-
this.endpoints = [];
|
|
252
|
-
this.wsTransports = [];
|
|
162
|
+
this.state = "stopped";
|
|
163
|
+
await life.shutdown("the peer stops");
|
|
164
|
+
await life.done;
|
|
253
165
|
}
|
|
254
166
|
getEndpoints() {
|
|
255
|
-
|
|
167
|
+
if (this.state !== "started" || this.life === undefined)
|
|
168
|
+
return [];
|
|
169
|
+
return this.host.info.endpoints().map((endpoint) => ({ type: endpoint.type, address: endpoint.address }));
|
|
256
170
|
}
|
|
257
171
|
getServer() {
|
|
258
|
-
return this.server;
|
|
172
|
+
return this.host.server;
|
|
173
|
+
}
|
|
174
|
+
getHost() {
|
|
175
|
+
return this.host;
|
|
259
176
|
}
|
|
260
177
|
connections() {
|
|
261
|
-
return this.
|
|
178
|
+
return this.host.connections();
|
|
262
179
|
}
|
|
263
180
|
clientFor(connectionId) {
|
|
264
|
-
|
|
265
|
-
if (!transport)
|
|
266
|
-
throw new Error(`Connection not found: ${connectionId}`);
|
|
267
|
-
return new Client({ transport: transport.transportFor(connectionId), throwOnError: true });
|
|
181
|
+
return this.host.clientFor(connectionId);
|
|
268
182
|
}
|
|
269
183
|
}
|
|
270
184
|
// =============================================================================
|
|
271
185
|
// Factory
|
|
272
186
|
// =============================================================================
|
|
273
187
|
/**
|
|
274
|
-
* Create a new peer instance
|
|
188
|
+
* Create a new peer instance: a procedures host with a service of its own, for a process that has
|
|
189
|
+
* no service of its own. A process with a service uses `createProcedureHost()` and `host.declare(svc)`.
|
|
275
190
|
*/
|
|
276
191
|
export async function createPeer(options) {
|
|
277
192
|
return new PeerImpl(options);
|
package/dist/peer/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/peer/index.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/peer/index.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://json.schemastore.org/package",
|
|
3
3
|
"name": "@procedures/peer",
|
|
4
|
-
"version": "0.
|
|
5
|
-
"description": "Serve procedures:
|
|
4
|
+
"version": "0.12.0",
|
|
5
|
+
"description": "Serve procedures: createProcedureHost() gives the parts of a service, with HTTP, WebSocket and MCP faces on one listener. Also peers, server.create, server.call and server.connections, and manifests.",
|
|
6
6
|
"keywords": [
|
|
7
7
|
"server",
|
|
8
8
|
"rpc",
|
|
@@ -67,23 +67,20 @@
|
|
|
67
67
|
"provenance": true
|
|
68
68
|
},
|
|
69
69
|
"devDependencies": {
|
|
70
|
-
"@procedures/fs": "0.
|
|
70
|
+
"@procedures/fs": "0.12.0",
|
|
71
71
|
"typescript": "^7.0.2",
|
|
72
72
|
"@types/node": "^22.0.0",
|
|
73
73
|
"@mark1russell7/cue": "^1.0.0",
|
|
74
|
-
"vitest": "^5.0.3"
|
|
75
|
-
"@types/express": "^5.0.6"
|
|
74
|
+
"vitest": "^5.0.3"
|
|
76
75
|
},
|
|
77
76
|
"client": {
|
|
78
77
|
"procedures": "./dist/register.js"
|
|
79
78
|
},
|
|
80
79
|
"dependencies": {
|
|
81
|
-
"@
|
|
80
|
+
"@mark1russell7/service": "^0.5.2",
|
|
81
|
+
"@procedures/client": "0.12.0",
|
|
82
82
|
"zod": "^4.6.5"
|
|
83
83
|
},
|
|
84
|
-
"optionalDependencies": {
|
|
85
|
-
"express": "^5.0.0"
|
|
86
|
-
},
|
|
87
84
|
"scripts": {
|
|
88
85
|
"build": "tsc -b",
|
|
89
86
|
"typecheck": "tsc --noEmit",
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The faces of the procedures host (CLI-7): HTTP, WebSocket, MCP and each face that a package adds.
|
|
3
|
+
*
|
|
4
|
+
* A face is a factory. The host gives it the handler of its calls, the server, the registry and
|
|
5
|
+
* the policy. The face gives what it mounts on a listener and its stop parts:
|
|
6
|
+
*
|
|
7
|
+
* - `handler`: a request handler for the mount list of a listener. The first match wins.
|
|
8
|
+
* - `upgrade`: an upgrade handler and the path that it takes.
|
|
9
|
+
* - `parts`: a transport of the service, for a face that holds work outside its requests (the
|
|
10
|
+
* connections of WebSocket).
|
|
11
|
+
* - `endpoint`: the scheme and the path of the face, for `host.info`.
|
|
12
|
+
*
|
|
13
|
+
* `httpFace()` and `wsFace()` are the faces of this package, on `procedureHandler` and
|
|
14
|
+
* `upgradeHandler` of `@procedures/client/node`. `mcpFace()` of `@procedures/mcp-server` is the
|
|
15
|
+
* MCP face. A face of another package has the same shape, so the host needs no change for it.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
import type { IncomingMessage, ServerResponse as NodeResponse } from "node:http";
|
|
19
|
+
import type { Duplex } from "node:stream";
|
|
20
|
+
import type { TransportImpl } from "@mark1russell7/service";
|
|
21
|
+
import { Client, requestCredentials, type BrowserGuardOptions, type Clock, type HostPolicy, type ProcedureRegistry, type ProcedureServer } from "@procedures/client";
|
|
22
|
+
import { procedureHandler, upgradeHandler, type ProcedureHandlerOptions, type UpgradeHandlerOptions } from "@procedures/client/node";
|
|
23
|
+
import type { FaceHandler } from "./tracking.js";
|
|
24
|
+
|
|
25
|
+
/** What the host gives a face. */
|
|
26
|
+
export interface HostFaceContext {
|
|
27
|
+
/** The name of the face in the host: the first part of the route of each call. */
|
|
28
|
+
readonly name: string;
|
|
29
|
+
/** The handler of the calls of the face: each call goes through the request tracking of the service. */
|
|
30
|
+
readonly handler: FaceHandler;
|
|
31
|
+
readonly server: ProcedureServer;
|
|
32
|
+
readonly registry: ProcedureRegistry;
|
|
33
|
+
readonly policy: HostPolicy;
|
|
34
|
+
/** The clock of the host: the clock of the lifecycle. */
|
|
35
|
+
readonly clock: Clock;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/** The upgrade handler of a face, and the path or the function that tells which upgrades it takes. */
|
|
39
|
+
export interface HostFaceUpgrade {
|
|
40
|
+
readonly match: string | ((req: IncomingMessage) => boolean);
|
|
41
|
+
readonly handler: (req: IncomingMessage, socket: Duplex, head: Buffer) => unknown;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/** The scheme and the path of a face on a listener, for `host.info`. */
|
|
45
|
+
export interface HostFaceEndpoint {
|
|
46
|
+
/** The type of the endpoint in `host.info`: `http`, `websocket`, `mcp` or another name. */
|
|
47
|
+
readonly type: string;
|
|
48
|
+
readonly scheme: "http" | "ws";
|
|
49
|
+
readonly path: string;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/** What a face gives the host. */
|
|
53
|
+
export interface HostFace {
|
|
54
|
+
/** The request handler of the face. It gives true when it takes a request, and false for another request. */
|
|
55
|
+
readonly handler?: ((req: IncomingMessage, res: NodeResponse) => boolean) | undefined;
|
|
56
|
+
readonly upgrade?: HostFaceUpgrade | undefined;
|
|
57
|
+
/** The stop parts of the face: a transport of the service, with the name `<host>.<face>`. */
|
|
58
|
+
readonly parts?: TransportImpl | undefined;
|
|
59
|
+
readonly endpoint?: HostFaceEndpoint | undefined;
|
|
60
|
+
/** The ids of the connections of the face, for a face of connections (WebSocket). */
|
|
61
|
+
readonly connections?: (() => string[]) | undefined;
|
|
62
|
+
/** A client of one connection: its calls go to the procedures that the connected client serves. */
|
|
63
|
+
readonly clientFor?: ((connectionId: string) => Client | undefined) | undefined;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/** A face factory: the host calls it one time, with the context of the face. */
|
|
67
|
+
export type HostFaceFactory = (context: HostFaceContext) => HostFace;
|
|
68
|
+
|
|
69
|
+
/** The browser checks of the policy, as options of a face. The options of the face win over them. */
|
|
70
|
+
function browserOptions(browser: BrowserGuardOptions, http: boolean): BrowserGuardOptions {
|
|
71
|
+
return {
|
|
72
|
+
...(browser.allowedOrigins !== undefined ? { allowedOrigins: browser.allowedOrigins } : {}),
|
|
73
|
+
...(browser.allowedHosts !== undefined ? { allowedHosts: browser.allowedHosts } : {}),
|
|
74
|
+
...(http && browser.allowGet !== undefined ? { allowGet: browser.allowGet } : {}),
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* This function gives the HTTP face: `procedureHandler` of `@procedures/client/node`, under
|
|
80
|
+
* `options.basePath` (default `/api`). The browser checks of the policy apply, and the options win over them.
|
|
81
|
+
*/
|
|
82
|
+
export function httpFace(options: ProcedureHandlerOptions = {}): HostFaceFactory {
|
|
83
|
+
return (context) => {
|
|
84
|
+
const handler = procedureHandler(context.handler, { clock: context.clock, ...browserOptions(context.policy.browser, true), ...options });
|
|
85
|
+
return {
|
|
86
|
+
handler: (req, res) => handler(req, res),
|
|
87
|
+
endpoint: { type: "http", scheme: "http", path: handler.basePath },
|
|
88
|
+
};
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* This function gives the WebSocket face: `upgradeHandler` of `@procedures/client/node`, at
|
|
94
|
+
* `options.path` (default `/ws`).
|
|
95
|
+
*
|
|
96
|
+
* - The upgrade: a failed browser check gets 403. A connection that the server does not admit
|
|
97
|
+
* gets 401: the token check and the request hook of each call run on the credentials of the
|
|
98
|
+
* upgrade (`ProcedureServer.admits`). Thus no idle connection without credentials stays open.
|
|
99
|
+
* - The stop parts refuse new calls at the stop of the intake. In the drain, each connection
|
|
100
|
+
* closes when its calls end, so the drain of the listener does not wait for an idle connection.
|
|
101
|
+
*/
|
|
102
|
+
export function wsFace(options: UpgradeHandlerOptions = {}): HostFaceFactory {
|
|
103
|
+
return (context) => {
|
|
104
|
+
const { server } = context;
|
|
105
|
+
const admits = (req: IncomingMessage): Promise<boolean> =>
|
|
106
|
+
server.admits(requestCredentials({ headers: req.headers as Record<string, unknown>, url: req.url }, { tokenQuery: "token" }));
|
|
107
|
+
const upgrade = upgradeHandler(context.handler, { ...browserOptions(context.policy.browser, false), authenticate: admits, ...options });
|
|
108
|
+
const transport = upgrade.transport;
|
|
109
|
+
return {
|
|
110
|
+
upgrade: { match: upgrade.path, handler: upgrade },
|
|
111
|
+
parts: {
|
|
112
|
+
start: () => upgrade.start(),
|
|
113
|
+
stopIntake: () => upgrade.stopIntake(),
|
|
114
|
+
drain: async (deadline, signal) => {
|
|
115
|
+
await upgrade.drain(deadline, signal);
|
|
116
|
+
// The calls ended, or the cooperative abort came: the connections end in their protocol
|
|
117
|
+
await upgrade.close();
|
|
118
|
+
},
|
|
119
|
+
inFlight: () => upgrade.inFlight(),
|
|
120
|
+
close: () => upgrade.close(),
|
|
121
|
+
},
|
|
122
|
+
endpoint: { type: "websocket", scheme: "ws", path: upgrade.path },
|
|
123
|
+
connections: () => transport.getTrackedConnections().map((connection) => connection.id),
|
|
124
|
+
clientFor: (connectionId) =>
|
|
125
|
+
transport.getTrackedConnection(connectionId) === undefined
|
|
126
|
+
? undefined
|
|
127
|
+
: new Client({ transport: transport.transportFor(connectionId), throwOnError: true }),
|
|
128
|
+
};
|
|
129
|
+
};
|
|
130
|
+
}
|