@appport/server 1.0.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/dist/http.js ADDED
@@ -0,0 +1,318 @@
1
+ import { createStreamChunk, createStreamEnd, createStreamStart, decodeEnvelopeText, encodeEnvelope, errors, parseClientEnvelope, peekRequestId, UI_DISCOVERY_PATH, WELL_KNOWN_PATH } from "@appport/protocol";
2
+ import { AsyncChannel, toWireError } from "@appport/core/server-internal";
3
+ /**
4
+ * HTTP binding (specification §25, §26).
5
+ *
6
+ * One endpoint, `POST /appport`, carries every capability. Streams are answered
7
+ * as newline-delimited envelopes and events as Server-Sent Events, so a plain
8
+ * HTTP deployment still reaches conformance level 3 without WebSocket.
9
+ */
10
+ export const APPPORT_CONTENT_TYPE = "application/json";
11
+ export const NDJSON_CONTENT_TYPE = "application/x-ndjson";
12
+ export const SSE_CONTENT_TYPE = "text/event-stream";
13
+ /** Header carrying a session identifier. Deployments may use cookies instead. */
14
+ export const SESSION_HEADER = "x-appport-session";
15
+ export function originMatches(origin, allowed) {
16
+ if (origin === allowed)
17
+ return true;
18
+ if (!allowed.endsWith(":*"))
19
+ return false;
20
+ try {
21
+ const candidate = new URL(origin);
22
+ const pattern = new URL(allowed.slice(0, -2));
23
+ return candidate.protocol === pattern.protocol && candidate.hostname === pattern.hostname;
24
+ }
25
+ catch {
26
+ return false;
27
+ }
28
+ }
29
+ const STATUS_TABLE = {
30
+ INVALID_PROTOCOL: 400,
31
+ UNSUPPORTED_VERSION: 400,
32
+ INVALID_REQUEST: 400,
33
+ INVALID_INPUT: 400,
34
+ UNAUTHORIZED: 401,
35
+ FORBIDDEN: 403,
36
+ UNKNOWN_CAPABILITY: 404,
37
+ UNSUPPORTED_CAPABILITY_VERSION: 404,
38
+ NO_COMPATIBLE_MATERIALIZATION: 404,
39
+ NOT_FOUND: 404,
40
+ CONFLICT: 409,
41
+ PAYLOAD_TOO_LARGE: 413,
42
+ RATE_LIMITED: 429,
43
+ TIMEOUT: 504,
44
+ CANCELLED: 499,
45
+ STREAM_ERROR: 500,
46
+ INTERNAL_ERROR: 500
47
+ };
48
+ /** Transport-level failures that always produce a non-2xx status. */
49
+ const TRANSPORT_LEVEL = new Set([
50
+ "INVALID_PROTOCOL",
51
+ "UNSUPPORTED_VERSION",
52
+ "INVALID_REQUEST",
53
+ "UNAUTHORIZED",
54
+ "PAYLOAD_TOO_LARGE"
55
+ ]);
56
+ export function statusForError(code, mode = "mapped") {
57
+ if (mode === "protocol")
58
+ return TRANSPORT_LEVEL.has(code) ? (STATUS_TABLE[code] ?? 400) : 200;
59
+ return STATUS_TABLE[code] ?? 500;
60
+ }
61
+ export class HttpBinding {
62
+ server;
63
+ statusMode;
64
+ #cors;
65
+ #maxBodyBytes;
66
+ #allowedOrigins;
67
+ #allowedCapabilities;
68
+ constructor(options) {
69
+ this.server = options.server;
70
+ this.statusMode = options.statusMode ?? "mapped";
71
+ this.#cors = options.cors;
72
+ this.#maxBodyBytes = options.maxBodyBytes;
73
+ this.#allowedOrigins = options.allowedOrigins;
74
+ this.#allowedCapabilities = options.allowedCapabilities ? new Set(options.allowedCapabilities) : undefined;
75
+ }
76
+ /** True when this binding serves the given path. */
77
+ handles(path) {
78
+ const { request, manifest } = this.server.endpoints;
79
+ return (path === request ||
80
+ path === manifest ||
81
+ path === UI_DISCOVERY_PATH ||
82
+ path === WELL_KNOWN_PATH ||
83
+ path === `${request}/events`);
84
+ }
85
+ corsHeaders(origin) {
86
+ if (!this.#cors)
87
+ return {};
88
+ const allowed = this.#cors.origins === "*"
89
+ ? "*"
90
+ : origin && this.#cors.origins.some((allowed) => originMatches(origin, allowed))
91
+ ? origin
92
+ : undefined;
93
+ if (!allowed)
94
+ return {};
95
+ return {
96
+ "access-control-allow-origin": allowed,
97
+ "access-control-allow-methods": "POST, GET, OPTIONS",
98
+ "access-control-allow-headers": `content-type, ${SESSION_HEADER}`,
99
+ ...(this.#cors.credentials ? { "access-control-allow-credentials": "true" } : {}),
100
+ ...(allowed === "*" ? {} : { vary: "origin" })
101
+ };
102
+ }
103
+ async route(request) {
104
+ const cors = this.corsHeaders(request.headers?.["origin"]);
105
+ const json = (status, body) => ({
106
+ kind: "json",
107
+ status,
108
+ headers: { "content-type": APPPORT_CONTENT_TYPE, ...cors },
109
+ body
110
+ });
111
+ const origin = request.headers?.["origin"];
112
+ if (origin && this.#allowedOrigins && !this.#allowedOrigins.some((allowed) => originMatches(origin, allowed))) {
113
+ return json(403, { error: { code: "FORBIDDEN", message: "Browser origin is not allowed" } });
114
+ }
115
+ if (request.method === "OPTIONS") {
116
+ return { kind: "text", status: 204, headers: cors, body: "" };
117
+ }
118
+ const { request: endpoint, manifest } = this.server.endpoints;
119
+ if (request.method === "GET" && request.path === WELL_KNOWN_PATH) {
120
+ return json(200, this.server.discovery());
121
+ }
122
+ if (request.method === "GET" && request.path === manifest) {
123
+ return json(200, this.server.manifest());
124
+ }
125
+ if (request.method === "GET" && request.path === UI_DISCOVERY_PATH) {
126
+ const identity = await this.server.identify({
127
+ transport: "http",
128
+ ...(request.headers ? { headers: request.headers } : {}),
129
+ ...(request.headers?.[SESSION_HEADER] ? { sessionId: request.headers[SESSION_HEADER] } : {}),
130
+ ...(request.headers?.["origin"] ? { origin: request.headers["origin"] } : {})
131
+ });
132
+ const ui = this.server.uiDiscovery(identity);
133
+ return ui ? json(200, ui) : json(404, { error: { code: "NOT_FOUND", message: "No composable UI is advertised" } });
134
+ }
135
+ if (request.method === "GET" && request.path === `${endpoint}/events`) {
136
+ return this.#events(request, cors);
137
+ }
138
+ if (request.path !== endpoint) {
139
+ return json(404, { error: { code: "NOT_FOUND", message: "No AppPort endpoint at this path" } });
140
+ }
141
+ if (request.method !== "POST") {
142
+ return json(405, { error: { code: "INVALID_REQUEST", message: "The AppPort endpoint accepts POST" } });
143
+ }
144
+ const identity = await this.server.identify({
145
+ transport: "http",
146
+ ...(request.headers ? { headers: request.headers } : {}),
147
+ ...(request.headers?.[SESSION_HEADER] ? { sessionId: request.headers[SESSION_HEADER] } : {}),
148
+ ...(request.headers?.["origin"] ? { origin: request.headers["origin"] } : {})
149
+ });
150
+ let value;
151
+ try {
152
+ value = decodeEnvelopeText(request.body ?? "", this.#maxBodyBytes !== undefined ? { maxBytes: this.#maxBodyBytes } : {});
153
+ }
154
+ catch (error) {
155
+ const wire = toWireError(error, this.server.application.mode);
156
+ return {
157
+ kind: "json",
158
+ status: statusForError(wire.code, this.statusMode),
159
+ headers: { "content-type": APPPORT_CONTENT_TYPE, ...cors },
160
+ body: this.server.errorEnvelope(peekRequestId(value), error)
161
+ };
162
+ }
163
+ let envelope;
164
+ try {
165
+ envelope = parseClientEnvelope(value);
166
+ }
167
+ catch (error) {
168
+ const wire = toWireError(error, this.server.application.mode);
169
+ return {
170
+ kind: "json",
171
+ status: statusForError(wire.code, this.statusMode),
172
+ headers: { "content-type": APPPORT_CONTENT_TYPE, ...cors },
173
+ body: this.server.errorEnvelope(peekRequestId(value), error)
174
+ };
175
+ }
176
+ if ((envelope.type === "request" || envelope.type === "stream.request") && this.#allowedCapabilities && envelope.capability.name !== "appport.manifest" && envelope.capability.name !== "appport.ping" && !this.#allowedCapabilities.has(envelope.capability.name)) {
177
+ return {
178
+ kind: "json",
179
+ status: 403,
180
+ headers: { "content-type": APPPORT_CONTENT_TYPE, ...cors },
181
+ body: this.server.errorEnvelope(envelope.requestId, errors.forbidden(`${envelope.capability.name} is not exposed to this surface`), envelope.traceId)
182
+ };
183
+ }
184
+ if (envelope.type === "stream.request") {
185
+ return this.#stream(envelope, identity, cors, request.signal);
186
+ }
187
+ if (envelope.type !== "request") {
188
+ const error = errors.invalidRequest(`Envelope type "${envelope.type}" requires a duplex transport; use the WebSocket endpoint`);
189
+ return {
190
+ kind: "json",
191
+ status: statusForError("INVALID_REQUEST", this.statusMode),
192
+ headers: { "content-type": APPPORT_CONTENT_TYPE, ...cors },
193
+ body: this.server.errorEnvelope(peekRequestId(value), error)
194
+ };
195
+ }
196
+ const response = await this.server.handleUnary(envelope, { identity, transport: "http", allowedCapabilities: this.#allowedCapabilities });
197
+ const status = response.ok ? 200 : statusForError(response.error.code, this.statusMode);
198
+ return {
199
+ kind: "json",
200
+ status,
201
+ headers: { "content-type": APPPORT_CONTENT_TYPE, ...cors },
202
+ body: response
203
+ };
204
+ }
205
+ /** Streams a capability as newline-delimited AppPort envelopes. */
206
+ async #stream(envelope, identity, cors, signal) {
207
+ const abort = new AbortController();
208
+ signal?.addEventListener("abort", () => abort.abort(), { once: true });
209
+ let execution;
210
+ try {
211
+ execution = await this.server.application.handleStreamRequest(envelope, {
212
+ ...(identity.session ? { session: identity.session } : {}),
213
+ ...(identity.principal ? { principal: identity.principal } : {}),
214
+ transport: "http",
215
+ signal: abort.signal
216
+ });
217
+ }
218
+ catch (error) {
219
+ const wire = toWireError(error, this.server.application.mode);
220
+ return {
221
+ kind: "json",
222
+ status: statusForError(wire.code, this.statusMode),
223
+ headers: { "content-type": APPPORT_CONTENT_TYPE, ...cors },
224
+ body: this.server.errorEnvelope(envelope.requestId, error, envelope.traceId)
225
+ };
226
+ }
227
+ const streamId = execution.streamId;
228
+ const mode = this.server.application.mode;
229
+ async function* frames() {
230
+ yield `${encodeEnvelope(createStreamStart(envelope.requestId, streamId, envelope.traceId))}\n`;
231
+ let sequence = 0;
232
+ try {
233
+ for await (const chunk of execution.chunks) {
234
+ yield `${encodeEnvelope(createStreamChunk(streamId, sequence, chunk))}\n`;
235
+ sequence += 1;
236
+ }
237
+ yield `${encodeEnvelope(createStreamEnd(streamId))}\n`;
238
+ }
239
+ catch (error) {
240
+ yield `${encodeEnvelope(createStreamEnd(streamId, toWireError(error, mode)))}\n`;
241
+ }
242
+ }
243
+ return {
244
+ kind: "stream",
245
+ status: 200,
246
+ headers: { "content-type": NDJSON_CONTENT_TYPE, "cache-control": "no-store", ...cors },
247
+ frames: frames(),
248
+ cancel: () => {
249
+ execution.cancel("Client disconnected");
250
+ abort.abort();
251
+ }
252
+ };
253
+ }
254
+ /** Server-Sent Events endpoint carrying AppPort event envelopes (§17, §18). */
255
+ async #events(request, cors) {
256
+ const identity = await this.server.identify({
257
+ transport: "http",
258
+ ...(request.headers ? { headers: request.headers } : {}),
259
+ ...(request.headers?.[SESSION_HEADER] ? { sessionId: request.headers[SESSION_HEADER] } : {})
260
+ });
261
+ const names = (request.query?.get("events") ?? "*").split(",").map((name) => name.trim()).filter(Boolean);
262
+ const channel = new AsyncChannel(256);
263
+ const connection = this.server.createConnection({
264
+ transport: "http",
265
+ identity,
266
+ ...(this.#allowedCapabilities ? { allowedCapabilities: this.#allowedCapabilities } : {}),
267
+ send: (envelope) => {
268
+ void channel.push(envelope);
269
+ }
270
+ });
271
+ let index = 0;
272
+ for (const name of names) {
273
+ index += 1;
274
+ await connection.handle({
275
+ protocol: "appport/1",
276
+ type: "subscribe",
277
+ requestId: `req_sse_${index}`,
278
+ subscriptionId: `sub_sse_${index}`,
279
+ event: { name }
280
+ });
281
+ }
282
+ const release = () => {
283
+ this.server.releaseConnection(connection);
284
+ channel.end();
285
+ };
286
+ request.signal?.addEventListener("abort", release, { once: true });
287
+ async function* frames() {
288
+ yield ": appport event stream\n\n";
289
+ try {
290
+ for await (const envelope of channel) {
291
+ // Subscription acknowledgements stay out of the event stream.
292
+ if (envelope.type !== "event")
293
+ continue;
294
+ yield `id: ${envelope.eventId}\nevent: ${envelope.event.name}\ndata: ${encodeEnvelope(envelope)}\n\n`;
295
+ }
296
+ }
297
+ finally {
298
+ release();
299
+ }
300
+ }
301
+ return {
302
+ kind: "stream",
303
+ status: 200,
304
+ headers: {
305
+ "content-type": SSE_CONTENT_TYPE,
306
+ "cache-control": "no-store",
307
+ connection: "keep-alive",
308
+ ...cors
309
+ },
310
+ frames: frames(),
311
+ cancel: release
312
+ };
313
+ }
314
+ }
315
+ export function createHttpBinding(options) {
316
+ return new HttpBinding(options);
317
+ }
318
+ //# sourceMappingURL=http.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http.js","sourceRoot":"","sources":["../src/http.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * `@appport/server` — the server-side protocol runtime and its web bindings.
3
+ *
4
+ * Node-specific pieces (the `node:http` adapter and the WebSocket endpoint)
5
+ * live in `@appport/server/node` so this entry point stays runtime-neutral.
6
+ */
7
+ export * from "./server.js";
8
+ export * from "./connection.js";
9
+ export * from "./http.js";
10
+ export * from "./fetch.js";
11
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,cAAc,aAAa,CAAC;AAC5B,cAAc,iBAAiB,CAAC;AAChC,cAAc,WAAW,CAAC;AAC1B,cAAc,YAAY,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,11 @@
1
+ /**
2
+ * `@appport/server` — the server-side protocol runtime and its web bindings.
3
+ *
4
+ * Node-specific pieces (the `node:http` adapter and the WebSocket endpoint)
5
+ * live in `@appport/server/node` so this entry point stays runtime-neutral.
6
+ */
7
+ export * from "./server.js";
8
+ export * from "./connection.js";
9
+ export * from "./http.js";
10
+ export * from "./fetch.js";
11
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,cAAc,aAAa,CAAC;AAC5B,cAAc,iBAAiB,CAAC;AAChC,cAAc,WAAW,CAAC;AAC1B,cAAc,YAAY,CAAC"}
@@ -0,0 +1,4 @@
1
+ /** Node-specific server bindings: `node:http` adapter and WebSocket endpoint. */
2
+ export * from "./node.js";
3
+ export * from "./websocket.js";
4
+ //# sourceMappingURL=node-entry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"node-entry.d.ts","sourceRoot":"","sources":["../src/node-entry.ts"],"names":[],"mappings":"AAAA,iFAAiF;AACjF,cAAc,WAAW,CAAC;AAC1B,cAAc,gBAAgB,CAAC"}
@@ -0,0 +1,4 @@
1
+ /** Node-specific server bindings: `node:http` adapter and WebSocket endpoint. */
2
+ export * from "./node.js";
3
+ export * from "./websocket.js";
4
+ //# sourceMappingURL=node-entry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"node-entry.js","sourceRoot":"","sources":["../src/node-entry.ts"],"names":[],"mappings":"AAAA,iFAAiF;AACjF,cAAc,WAAW,CAAC;AAC1B,cAAc,gBAAgB,CAAC"}
package/dist/node.d.ts ADDED
@@ -0,0 +1,45 @@
1
+ import { type IncomingMessage, type Server, type ServerResponse } from "node:http";
2
+ import { HttpBinding, type HttpBindingOptions } from "./http.js";
3
+ import type { AppPortServer } from "./server.js";
4
+ /** Node HTTP request listener for the AppPort HTTP binding (§25). */
5
+ export declare function createNodeRequestListener(binding: HttpBinding): (request: IncomingMessage, response: ServerResponse) => void;
6
+ export declare function handleNodeRequest(binding: HttpBinding, request: IncomingMessage, response: ServerResponse): Promise<void>;
7
+ /** Attaches the AppPort WebSocket binding to a Node HTTP server (§27). */
8
+ export declare function attachWebSocket(httpServer: Server, server: AppPortServer, options?: {
9
+ path?: string;
10
+ maxMessageBytes?: number;
11
+ pingIntervalMs?: number;
12
+ allowedOrigins?: readonly string[];
13
+ allowedCapabilities?: readonly string[];
14
+ }): () => void;
15
+ export interface ServeOptions extends HttpBindingOptions {
16
+ port?: number;
17
+ host?: string;
18
+ /** Serve the WebSocket binding alongside HTTP. Defaults to true. */
19
+ websocket?: boolean;
20
+ pingIntervalMs?: number;
21
+ /** Handles requests the AppPort binding does not own (a UI, for example). */
22
+ fallback?: (request: IncomingMessage, response: ServerResponse) => void;
23
+ }
24
+ export interface RunningServer {
25
+ readonly url: string;
26
+ readonly port: number;
27
+ readonly httpServer: Server;
28
+ close(): Promise<void>;
29
+ }
30
+ /**
31
+ * Starts a Node HTTP server exposing the HTTP and WebSocket bindings against
32
+ * the same capability server — the configuration `appport dev` uses (§55).
33
+ */
34
+ export declare function serve(options: ServeOptions): Promise<RunningServer>;
35
+ export interface DesktopHostOptions {
36
+ server: AppPortServer;
37
+ host?: string;
38
+ port?: number;
39
+ transport?: "http" | "websocket" | "both";
40
+ allowedOrigins?: readonly string[];
41
+ allowedCapabilities?: readonly string[];
42
+ }
43
+ /** Hosts one desktop application's existing registry for browser clients. */
44
+ export declare function serveDesktopHost(options: DesktopHostOptions): Promise<RunningServer>;
45
+ //# sourceMappingURL=node.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"node.d.ts","sourceRoot":"","sources":["../src/node.ts"],"names":[],"mappings":"AAAA,OAAO,EAAoC,KAAK,eAAe,EAAE,KAAK,MAAM,EAAE,KAAK,cAAc,EAAE,MAAM,WAAW,CAAC;AAGrH,OAAO,EAAqB,WAAW,EAAiC,KAAK,kBAAkB,EAAwB,MAAM,WAAW,CAAC;AAEzI,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAEjD,qEAAqE;AACrE,wBAAgB,yBAAyB,CACvC,OAAO,EAAE,WAAW,GACnB,CAAC,OAAO,EAAE,eAAe,EAAE,QAAQ,EAAE,cAAc,KAAK,IAAI,CAI9D;AAcD,wBAAsB,iBAAiB,CACrC,OAAO,EAAE,WAAW,EACpB,OAAO,EAAE,eAAe,EACxB,QAAQ,EAAE,cAAc,GACvB,OAAO,CAAC,IAAI,CAAC,CAmDf;AAED,0EAA0E;AAC1E,wBAAgB,eAAe,CAC7B,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,aAAa,EACrB,OAAO,GAAE;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,eAAe,CAAC,EAAE,MAAM,CAAC;IAAC,cAAc,CAAC,EAAE,MAAM,CAAC;IAAC,cAAc,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAAC,mBAAmB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;CAAO,GAC9J,MAAM,IAAI,CA4DZ;AAED,MAAM,WAAW,YAAa,SAAQ,kBAAkB;IACtD,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,oEAAoE;IACpE,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,6EAA6E;IAC7E,QAAQ,CAAC,EAAE,CAAC,OAAO,EAAE,eAAe,EAAE,QAAQ,EAAE,cAAc,KAAK,IAAI,CAAC;CACzE;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB;AAED;;;GAGG;AACH,wBAAsB,KAAK,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,aAAa,CAAC,CA0CzE;AAED,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,aAAa,CAAC;IACtB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,GAAG,WAAW,GAAG,MAAM,CAAC;IAC1C,cAAc,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACnC,mBAAmB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CACzC;AAED,6EAA6E;AAC7E,wBAAsB,gBAAgB,CAAC,OAAO,EAAE,kBAAkB,GAAG,OAAO,CAAC,aAAa,CAAC,CAgB1F"}
package/dist/node.js ADDED
@@ -0,0 +1,190 @@
1
+ import { createServer as createHttpServer } from "node:http";
2
+ import { encodeEnvelope } from "@appport/protocol";
3
+ import { createHttpBinding, HttpBinding, originMatches, SESSION_HEADER } from "./http.js";
4
+ import { isWebSocketUpgrade, WebSocketPeer } from "./websocket.js";
5
+ /** Node HTTP request listener for the AppPort HTTP binding (§25). */
6
+ export function createNodeRequestListener(binding) {
7
+ return (request, response) => {
8
+ void handleNodeRequest(binding, request, response);
9
+ };
10
+ }
11
+ async function readBody(request, limit) {
12
+ const chunks = [];
13
+ let size = 0;
14
+ for await (const chunk of request) {
15
+ const buffer = chunk;
16
+ size += buffer.length;
17
+ if (size > limit)
18
+ throw new Error("payload too large");
19
+ chunks.push(buffer);
20
+ }
21
+ return Buffer.concat(chunks).toString("utf8");
22
+ }
23
+ export async function handleNodeRequest(binding, request, response) {
24
+ const url = new URL(request.url ?? "/", `http://${request.headers.host ?? "localhost"}`);
25
+ const controller = new AbortController();
26
+ request.on("aborted", () => controller.abort());
27
+ response.on("close", () => controller.abort());
28
+ let body = "";
29
+ if (request.method === "POST") {
30
+ try {
31
+ body = await readBody(request, 8 * 1024 * 1024);
32
+ }
33
+ catch {
34
+ response.writeHead(413, { "content-type": "application/json" });
35
+ response.end(JSON.stringify({ error: { code: "PAYLOAD_TOO_LARGE", message: "Request body is too large" } }));
36
+ return;
37
+ }
38
+ }
39
+ const httpRequest = {
40
+ method: request.method ?? "GET",
41
+ path: url.pathname,
42
+ query: url.searchParams,
43
+ headers: request.headers,
44
+ body,
45
+ signal: controller.signal
46
+ };
47
+ const outcome = await binding.route(httpRequest);
48
+ if (outcome.kind === "json") {
49
+ const payload = JSON.stringify(outcome.body);
50
+ response.writeHead(outcome.status, { ...outcome.headers, "content-length": Buffer.byteLength(payload) });
51
+ response.end(payload);
52
+ return;
53
+ }
54
+ if (outcome.kind === "text") {
55
+ response.writeHead(outcome.status, outcome.headers);
56
+ response.end(outcome.body);
57
+ return;
58
+ }
59
+ response.writeHead(outcome.status, outcome.headers);
60
+ response.on("close", () => outcome.cancel());
61
+ try {
62
+ for await (const frame of outcome.frames) {
63
+ if (response.writableEnded)
64
+ break;
65
+ if (!response.write(frame)) {
66
+ await new Promise((resolve) => response.once("drain", resolve));
67
+ }
68
+ }
69
+ }
70
+ finally {
71
+ if (!response.writableEnded)
72
+ response.end();
73
+ }
74
+ }
75
+ /** Attaches the AppPort WebSocket binding to a Node HTTP server (§27). */
76
+ export function attachWebSocket(httpServer, server, options = {}) {
77
+ const path = options.path ?? server.endpoints.websocket;
78
+ const onUpgrade = (request, socket, head) => {
79
+ const url = new URL(request.url ?? "/", `http://${request.headers.host ?? "localhost"}`);
80
+ if (url.pathname !== path || !isWebSocketUpgrade(request)) {
81
+ socket.end("HTTP/1.1 404 Not Found\r\n\r\n");
82
+ return;
83
+ }
84
+ const origin = request.headers.origin;
85
+ if (origin && options.allowedOrigins && !options.allowedOrigins.some((allowed) => originMatches(origin, allowed))) {
86
+ socket.end("HTTP/1.1 403 Forbidden\r\nContent-Type: application/json\r\n\r\n{\"error\":{\"code\":\"FORBIDDEN\",\"message\":\"Browser origin is not allowed\"}}");
87
+ return;
88
+ }
89
+ const peer = WebSocketPeer.accept(request, socket, head, options.maxMessageBytes !== undefined ? { maxMessageBytes: options.maxMessageBytes } : {});
90
+ if (!peer)
91
+ return;
92
+ const send = (envelope) => peer.send(encodeEnvelope(envelope));
93
+ const connection = server.createConnection({ transport: "websocket", send, ...(options.allowedCapabilities ? { allowedCapabilities: new Set(options.allowedCapabilities) } : {}) });
94
+ const authenticated = (async () => {
95
+ const identity = await server.identify({
96
+ transport: "websocket",
97
+ headers: request.headers,
98
+ ...(url.searchParams.get("session")
99
+ ? { sessionId: url.searchParams.get("session") }
100
+ : request.headers[SESSION_HEADER]
101
+ ? { sessionId: String(request.headers[SESSION_HEADER]) }
102
+ : {}),
103
+ ...(request.headers.origin ? { origin: request.headers.origin } : {})
104
+ });
105
+ connection.authenticate(identity);
106
+ return true;
107
+ })().catch(() => {
108
+ peer.close(1008, "authentication failed");
109
+ server.releaseConnection(connection);
110
+ return false;
111
+ });
112
+ const heartbeat = options.pingIntervalMs
113
+ ? setInterval(() => peer.ping(), options.pingIntervalMs)
114
+ : undefined;
115
+ heartbeat?.unref?.();
116
+ peer.onMessage = (message) => {
117
+ void authenticated.then((ready) => ready ? connection.accept(message) : undefined);
118
+ };
119
+ peer.onClose = () => {
120
+ if (heartbeat)
121
+ clearInterval(heartbeat);
122
+ server.releaseConnection(connection);
123
+ };
124
+ };
125
+ httpServer.on("upgrade", onUpgrade);
126
+ return () => httpServer.off("upgrade", onUpgrade);
127
+ }
128
+ /**
129
+ * Starts a Node HTTP server exposing the HTTP and WebSocket bindings against
130
+ * the same capability server — the configuration `appport dev` uses (§55).
131
+ */
132
+ export async function serve(options) {
133
+ const binding = createHttpBinding(options);
134
+ const listener = createNodeRequestListener(binding);
135
+ const httpServer = createHttpServer((request, response) => {
136
+ const url = new URL(request.url ?? "/", `http://${request.headers.host ?? "localhost"}`);
137
+ if (options.fallback && !binding.handles(url.pathname)) {
138
+ options.fallback(request, response);
139
+ return;
140
+ }
141
+ listener(request, response);
142
+ });
143
+ if (options.websocket !== false) {
144
+ attachWebSocket(httpServer, options.server, {
145
+ ...(options.pingIntervalMs !== undefined ? { pingIntervalMs: options.pingIntervalMs } : {}),
146
+ ...(options.allowedOrigins ? { allowedOrigins: options.allowedOrigins } : {}),
147
+ ...(options.allowedCapabilities ? { allowedCapabilities: options.allowedCapabilities } : {})
148
+ });
149
+ }
150
+ const port = options.port ?? 0;
151
+ const host = options.host ?? "127.0.0.1";
152
+ await new Promise((resolve) => httpServer.listen(port, host, resolve));
153
+ const address = httpServer.address();
154
+ const boundPort = typeof address === "object" && address ? address.port : port;
155
+ return {
156
+ url: `http://${host}:${boundPort}`,
157
+ port: boundPort,
158
+ httpServer,
159
+ close: async () => {
160
+ await options.server.close();
161
+ const closed = new Promise((resolve, reject) => httpServer.close((error) => (error ? reject(error) : resolve())));
162
+ // Long-lived responses (SSE, NDJSON streams) and idle keep-alive sockets
163
+ // would otherwise hold the server open until `keepAliveTimeout`.
164
+ httpServer.closeIdleConnections?.();
165
+ httpServer.closeAllConnections?.();
166
+ await closed;
167
+ }
168
+ };
169
+ }
170
+ /** Hosts one desktop application's existing registry for browser clients. */
171
+ export async function serveDesktopHost(options) {
172
+ const host = options.host ?? "127.0.0.1";
173
+ const origins = options.allowedOrigins ?? ["http://localhost:*", "http://127.0.0.1:*"];
174
+ const transport = options.transport ?? "both";
175
+ const running = await serve({
176
+ server: options.server,
177
+ host,
178
+ port: options.port ?? 0,
179
+ websocket: transport !== "http",
180
+ cors: { origins, credentials: true },
181
+ allowedOrigins: origins,
182
+ ...(options.allowedCapabilities ? { allowedCapabilities: options.allowedCapabilities } : {})
183
+ });
184
+ if (transport !== "websocket")
185
+ options.server.application.advertiseTransport({ kind: "http", endpoint: `${running.url}${options.server.endpoints.request}` });
186
+ if (transport !== "http")
187
+ options.server.application.advertiseTransport({ kind: "websocket", endpoint: `${running.url.replace("http://", "ws://")}${options.server.endpoints.websocket}` });
188
+ return running;
189
+ }
190
+ //# sourceMappingURL=node.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"node.js","sourceRoot":"","sources":["../src/node.ts"],"names":[],"mappings":"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"}