@rynx-ai/server 0.1.0 → 0.1.10-beta.2

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.
Files changed (65) hide show
  1. package/dist/browser-surface-control-queue.d.ts +42 -0
  2. package/dist/browser-surface-control-queue.js +187 -0
  3. package/dist/browser-surface-ws.d.ts +16 -0
  4. package/dist/browser-surface-ws.js +356 -0
  5. package/dist/control-api.d.ts +76 -4
  6. package/dist/control-api.js +3014 -133
  7. package/dist/control-web/assets/highlighted-body-OFNGDK62-DHu2g-rk.js +1 -0
  8. package/dist/control-web/assets/index-B6Pb5j9M.js +666 -0
  9. package/dist/control-web/assets/index-BU-_Qud_.css +32 -0
  10. package/dist/control-web/assets/inter-cyrillic-ext-wght-normal-BOeWTOD4.woff2 +0 -0
  11. package/dist/control-web/assets/inter-cyrillic-wght-normal-DqGufNeO.woff2 +0 -0
  12. package/dist/control-web/assets/inter-greek-ext-wght-normal-DlzME5K_.woff2 +0 -0
  13. package/dist/control-web/assets/inter-greek-wght-normal-CkhJZR-_.woff2 +0 -0
  14. package/dist/control-web/assets/inter-latin-ext-wght-normal-DO1Apj_S.woff2 +0 -0
  15. package/dist/control-web/assets/inter-latin-wght-normal-Dx4kXJAl.woff2 +0 -0
  16. package/dist/control-web/assets/inter-vietnamese-wght-normal-CBcvBZtf.woff2 +0 -0
  17. package/dist/control-web/assets/jetbrains-mono-cyrillic-wght-normal-D73BlboJ.woff2 +0 -0
  18. package/dist/control-web/assets/jetbrains-mono-greek-wght-normal-Bw9x6K1M.woff2 +0 -0
  19. package/dist/control-web/assets/jetbrains-mono-latin-ext-wght-normal-DBQx-q_a.woff2 +0 -0
  20. package/dist/control-web/assets/jetbrains-mono-latin-wght-normal-B9CIFXIH.woff2 +0 -0
  21. package/dist/control-web/assets/jetbrains-mono-vietnamese-wght-normal-Bt-aOZkq.woff2 +0 -0
  22. package/dist/control-web/assets/mermaid-GHXKKRXX-CSYzOmBR.js +131 -0
  23. package/dist/control-web/assets/rynx-wordmark-LL1QRYHD.png +0 -0
  24. package/dist/control-web/favicon.png +0 -0
  25. package/dist/control-web/favicon.svg +38 -0
  26. package/dist/control-web/index.html +16 -0
  27. package/dist/control-web-dist.d.ts +1 -1
  28. package/dist/control-web-dist.js +19 -14
  29. package/dist/desktop-browser-host.d.ts +170 -0
  30. package/dist/desktop-browser-host.js +1018 -0
  31. package/dist/direct-runtime-browser-inspect-server.d.ts +72 -0
  32. package/dist/direct-runtime-browser-inspect-server.js +749 -0
  33. package/dist/direct-runtime-browser-surface-server.d.ts +74 -0
  34. package/dist/direct-runtime-browser-surface-server.js +821 -0
  35. package/dist/direct-runtime-server.d.ts +143 -0
  36. package/dist/direct-runtime-server.js +1959 -0
  37. package/dist/emulator-surface-ws.d.ts +8 -0
  38. package/dist/emulator-surface-ws.js +198 -0
  39. package/dist/machine-session-service.d.ts +265 -0
  40. package/dist/machine-session-service.js +822 -0
  41. package/dist/provider-cli-host.d.ts +10 -0
  42. package/dist/provider-cli-host.js +1 -0
  43. package/dist/remote-runtime-dispatcher.d.ts +94 -0
  44. package/dist/remote-runtime-dispatcher.js +403 -0
  45. package/dist/remote-runtime-session-projection.d.ts +19 -0
  46. package/dist/remote-runtime-session-projection.js +566 -0
  47. package/dist/remote-runtime.d.ts +22 -0
  48. package/dist/remote-runtime.js +32 -0
  49. package/dist/runtime-web-auth.d.ts +26 -0
  50. package/dist/runtime-web-auth.js +132 -0
  51. package/dist/server.d.ts +364 -12
  52. package/dist/server.js +341 -100
  53. package/dist/session-browser-service.d.ts +248 -0
  54. package/dist/session-browser-service.js +772 -0
  55. package/dist/session-browser-surface-coordinator.d.ts +24 -0
  56. package/dist/session-browser-surface-coordinator.js +669 -0
  57. package/dist/session-emulator-service.d.ts +167 -0
  58. package/dist/session-emulator-service.js +464 -0
  59. package/dist/session-runtime-index.d.ts +23 -0
  60. package/dist/session-runtime-index.js +96 -0
  61. package/dist/session-terminal-host.d.ts +51 -0
  62. package/dist/session-terminal-host.js +270 -0
  63. package/dist/terminal-ws.d.ts +12 -20
  64. package/dist/terminal-ws.js +421 -97
  65. package/package.json +14 -7
Binary file
@@ -0,0 +1,38 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="-50.0 -171.5 934.1 934.1">
2
+ <style>
3
+ #mark { fill: #1b2635; }
4
+ @media (prefers-color-scheme: dark) { #mark { fill: #ffffff; } }
5
+ </style>
6
+ <g id="mark" transform="translate(0.000000,591.000000) scale(0.100000,-0.100000)" stroke="none">
7
+ <path d="M540 5884 c-36 -7 -107 -34 -159 -60 -166 -82 -285 -223 -350 -412
8
+ l-26 -77 0 -2380 0 -2380 23 -75 c72 -229 244 -398 477 -466 52 -15 117 -18
9
+ 480 -21 464 -5 483 -3 515 50 18 29 20 51 20 235 0 218 -6 247 -53 274 -16 10
10
+ -117 14 -389 18 -351 5 -368 6 -395 26 -15 11 -36 36 -46 55 -16 32 -17 157
11
+ -15 2291 l3 2257 21 28 c12 15 36 37 55 48 32 19 49 20 306 17 149 -2 311 -1
12
+ 360 3 81 7 90 10 120 40 l33 33 0 210 c0 116 -4 222 -10 236 -5 14 -24 35 -42
13
+ 46 -32 19 -50 20 -448 19 -314 0 -431 -4 -480 -15z"/>
14
+ <path d="M6878 5885 c-53 -29 -58 -54 -58 -283 0 -310 -26 -293 451 -292 379
15
+ 2 379 2 426 -70 l23 -33 0 -2249 c0 -2469 5 -2292 -61 -2339 l-34 -24 -365 -5
16
+ c-270 -4 -371 -8 -387 -18 -47 -27 -53 -56 -53 -272 0 -226 6 -251 65 -276 48
17
+ -20 784 -20 895 0 289 52 512 286 550 577 8 59 10 770 8 2404 -3 2190 -4 2323
18
+ -21 2379 -71 236 -240 411 -472 489 -56 19 -89 21 -500 24 -379 2 -444 1 -467
19
+ -12z"/>
20
+ <path d="M2217 4826 c-71 -26 -107 -79 -107 -153 1 -71 -12 -55 514 -653 501
21
+ -571 537 -610 576 -630 37 -19 60 -20 362 -20 293 0 327 2 363 19 74 34 115
22
+ 102 115 188 0 77 16 56 -480 653 -135 162 -296 357 -358 433 -63 75 -128 145
23
+ -145 155 -29 15 -73 17 -417 19 -307 2 -393 0 -423 -11z"/>
24
+ <path d="M5321 4829 c-18 -6 -44 -17 -57 -26 -28 -18 -240 -307 -843 -1148
25
+ -145 -203 -270 -386 -277 -405 -41 -111 28 -232 148 -261 35 -8 136 -10 336
26
+ -7 252 4 292 6 325 23 46 22 37 11 334 400 290 381 714 929 843 1090 l95 119
27
+ 0 66 c0 72 -16 104 -70 137 -28 17 -61 18 -415 20 -232 1 -398 -2 -419 -8z"/>
28
+ <path d="M3395 2851 c-33 -15 -74 -60 -215 -242 -96 -123 -315 -402 -485 -619
29
+ -469 -595 -561 -715 -575 -740 -18 -33 -8 -121 18 -157 44 -62 49 -63 484 -63
30
+ 362 0 396 2 434 19 37 17 106 105 590 747 302 401 567 754 589 784 37 51 40
31
+ 59 40 122 0 74 -16 105 -75 146 -33 22 -36 22 -399 22 -334 0 -370 -2 -406
32
+ -19z"/>
33
+ <path d="M4473 2479 c-130 -27 -209 -184 -147 -291 5 -9 216 -264 468 -568
34
+ 341 -410 469 -556 497 -571 36 -18 62 -19 434 -19 424 0 424 0 472 52 33 35
35
+ 48 104 34 154 -12 45 -90 138 -790 944 -124 143 -238 265 -259 277 -36 21 -48
36
+ 22 -359 25 -177 2 -334 0 -350 -3z"/>
37
+ </g>
38
+ </svg>
@@ -0,0 +1,16 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <!-- SVG favicon adapts to the OS theme (navy → white in dark mode); PNG is the fallback -->
7
+ <link rel="icon" type="image/svg+xml" href="/favicon.svg" />
8
+ <link rel="icon" type="image/png" href="/favicon.png" />
9
+ <title>rynx · control</title>
10
+ <script type="module" crossorigin src="/assets/index-B6Pb5j9M.js"></script>
11
+ <link rel="stylesheet" crossorigin href="/assets/index-BU-_Qud_.css">
12
+ </head>
13
+ <body>
14
+ <div id="root"></div>
15
+ </body>
16
+ </html>
@@ -3,4 +3,4 @@ import type { Context } from "koa";
3
3
  export declare function resolveControlWebDist(): string | null;
4
4
  /** Serve a static file from the SPA dir; missing non-asset paths fall back to
5
5
  * index.html (client-side routing), missing assets return 404. */
6
- export declare function sendSpaFile(ctx: Context, distDir: string): Promise<void>;
6
+ export declare function sendSpaFile(ctx: Context, distDir: string, basePath?: string): Promise<void>;
@@ -1,16 +1,15 @@
1
1
  /**
2
- * Locate + serve the built control-web SPA (`@rynx-ai/control-web/dist`). Resolving
3
- * the package's own `package.json` is robust across pnpm symlinks; the daemon
4
- * ships control-web as a dependency so the dist is present at runtime.
2
+ * Locate + serve the built control-web SPA. Published server packages embed the
3
+ * SPA under `dist/control-web`; source checkouts fall back to the sibling
4
+ * workspace build for development and tests.
5
5
  *
6
6
  * A tiny hand-rolled static sender (no extra dep) covers the SPA's needs:
7
7
  * `index.html` + hashed `assets/*`, with an index.html fallback for client paths.
8
8
  */
9
9
  import { existsSync } from "node:fs";
10
10
  import { readFile } from "node:fs/promises";
11
- import { createRequire } from "node:module";
12
11
  import { dirname, extname, join, resolve } from "node:path";
13
- const require = createRequire(import.meta.url);
12
+ import { fileURLToPath } from "node:url";
14
13
  const CONTENT_TYPES = {
15
14
  ".html": "text/html; charset=utf-8",
16
15
  ".js": "text/javascript; charset=utf-8",
@@ -24,19 +23,25 @@ const CONTENT_TYPES = {
24
23
  };
25
24
  /** Absolute path to the built SPA dir, or null when it hasn't been built. */
26
25
  export function resolveControlWebDist() {
27
- try {
28
- const pkgJson = require.resolve("@rynx-ai/control-web/package.json");
29
- const dist = join(dirname(pkgJson), "dist");
30
- return existsSync(join(dist, "index.html")) ? dist : null;
31
- }
32
- catch {
33
- return null;
26
+ const moduleDirectory = dirname(fileURLToPath(import.meta.url));
27
+ const candidates = [
28
+ join(moduleDirectory, "control-web"),
29
+ resolve(moduleDirectory, "../../control-web/dist"),
30
+ ];
31
+ for (const candidate of candidates) {
32
+ if (existsSync(join(candidate, "index.html"))) {
33
+ return candidate;
34
+ }
34
35
  }
36
+ return null;
35
37
  }
36
38
  /** Serve a static file from the SPA dir; missing non-asset paths fall back to
37
39
  * index.html (client-side routing), missing assets return 404. */
38
- export async function sendSpaFile(ctx, distDir) {
39
- const relative = ctx.path === "/" ? "index.html" : ctx.path.replace(/^\/+/, "");
40
+ export async function sendSpaFile(ctx, distDir, basePath = "/") {
41
+ const path = basePath !== "/" && ctx.path.startsWith(basePath)
42
+ ? ctx.path.slice(basePath.length) || "/"
43
+ : ctx.path;
44
+ const relative = path === "/" ? "index.html" : path.replace(/^\/+/, "");
40
45
  const target = resolve(distDir, relative);
41
46
  if (target !== distDir && !target.startsWith(distDir + "/")) {
42
47
  ctx.status = 403;
@@ -0,0 +1,170 @@
1
+ import type { Server as HttpServer } from "node:http";
2
+ import { parseDesktopBrowserHostSurfaceOpenResult, type DesktopBrowserHostClientFrame, type DesktopBrowserHostCommand, type DesktopBrowserHostHelloFrame, type DesktopBrowserHostLeaseFrame, type DesktopBrowserHostPresentation, type DesktopBrowserHostSurfaceCapability, type DesktopBrowserHostSurfaceFrame } from "@rynx-ai/protocol/desktop-browser-host";
3
+ import { WebSocket, WebSocketServer } from "ws";
4
+ import { SessionBrowserHostError, type SessionBrowserHost, type SessionBrowserHostCreateInput, type SessionBrowserHostEvent, type SessionBrowserHostHandle, type SessionBrowserHostSnapshot, type SessionBrowserHostSurfaceFrame, type SessionBrowserHostSurfaceOpenInput, type SessionBrowserHostSurfaceSource, type SessionBrowserHostSurfaceTrustedInput, type SessionBrowserHostSurfaceViewport } from "./session-browser-service.js";
5
+ export interface DesktopBrowserHostRegistryOptions {
6
+ commandTimeoutMilliseconds?: number;
7
+ now?: () => number;
8
+ idFactory?: () => string;
9
+ }
10
+ export interface AttachDesktopBrowserHostServerOptions {
11
+ registry: DesktopBrowserHostRegistry;
12
+ managementToken: string;
13
+ daemonInstanceId: string;
14
+ heartbeatIntervalMilliseconds?: number;
15
+ handshakeTimeoutMilliseconds?: number;
16
+ }
17
+ interface PendingCommand {
18
+ command: DesktopBrowserHostCommand;
19
+ deadlineUnixMilliseconds: number;
20
+ parseResult(value: unknown): unknown;
21
+ resolve(value: unknown): void;
22
+ reject(error: unknown): void;
23
+ timer: ReturnType<typeof setTimeout>;
24
+ }
25
+ interface DesktopBrowserLease {
26
+ leaseId: string;
27
+ daemonInstanceId: string;
28
+ hostInstanceId: string;
29
+ presentation: DesktopBrowserHostPresentation;
30
+ semanticPageBinding: boolean;
31
+ surface: DesktopBrowserHostSurfaceCapability;
32
+ socket: WebSocket;
33
+ pending: Map<string, PendingCommand>;
34
+ nextEventSequence: number;
35
+ detached: boolean;
36
+ }
37
+ /**
38
+ * The daemon-side physical Browser Host. It is safe to construct before the
39
+ * HTTP server exists; an authenticated desktop socket makes it live later.
40
+ */
41
+ export declare class DesktopBrowserHostRegistry implements SessionBrowserHost {
42
+ private readonly commandTimeoutMilliseconds;
43
+ private readonly now;
44
+ private readonly idFactory;
45
+ private readonly handles;
46
+ private readonly connectedListeners;
47
+ private readonly leases;
48
+ private idSequence;
49
+ constructor(options?: DesktopBrowserHostRegistryOptions);
50
+ get connected(): boolean;
51
+ get directConnected(): boolean;
52
+ /** Runs after a fresh lease frame has been queued to the Host. Listener
53
+ * failures are isolated from the authenticated Host handshake. */
54
+ onConnected(listener: () => void | Promise<void>): () => void;
55
+ createBrowser(input: SessionBrowserHostCreateInput): Promise<SessionBrowserHostHandle>;
56
+ deleteSessionData(sessionId: string): Promise<void>;
57
+ /** Attachment-only: installs one lease per presentation role. Existing
58
+ * generations stay pinned to their Host while new generations prefer the
59
+ * direct App-window Host. */
60
+ acceptConnection(socket: WebSocket, hello: DesktopBrowserHostHelloFrame, daemonInstanceId: string, heartbeatIntervalMilliseconds: number): DesktopBrowserHostLeaseFrame;
61
+ /** Attachment-only: validates lease scope before routing a client frame. */
62
+ receive(leaseId: string, frame: Exclude<DesktopBrowserHostClientFrame, DesktopBrowserHostHelloFrame>): void;
63
+ /** Attachment-only: routes a fully identity-bound image envelope to one active Surface. */
64
+ receiveBinary(leaseId: string, frame: DesktopBrowserHostSurfaceFrame): void;
65
+ /** Attachment-only and identity-fenced: an old close cannot clear a new lease. */
66
+ disconnect(leaseId: string, reason?: string): void;
67
+ commandForHandle<T>(handle: DesktopBrowserHandle, command: DesktopBrowserHostCommand, parseResult: (value: unknown) => T): Promise<T>;
68
+ forgetHandle(handle: DesktopBrowserHandle): void;
69
+ createId(label: string): string;
70
+ private requireLease;
71
+ private requireCurrentHandle;
72
+ private request;
73
+ private nextId;
74
+ private receiveReply;
75
+ private receiveEvent;
76
+ private rejectCommandsFor;
77
+ private failLease;
78
+ private detach;
79
+ private currentLease;
80
+ private currentLeases;
81
+ private leaseById;
82
+ private installedLease;
83
+ private installedLeaseById;
84
+ private isInstalledLease;
85
+ private isCurrentLease;
86
+ private retireOffscreenIfIdle;
87
+ }
88
+ export declare class DesktopBrowserHostProtocolError extends Error {
89
+ readonly closeCode: number;
90
+ constructor(message: string, closeCode?: number);
91
+ }
92
+ /** The only condition under which desktop-first composition may use Headless. */
93
+ export declare class DesktopBrowserHostAbsentError extends SessionBrowserHostError {
94
+ constructor();
95
+ }
96
+ export declare function attachDesktopBrowserHostServer(server: HttpServer, options: AttachDesktopBrowserHostServerOptions): WebSocketServer;
97
+ export declare function createDesktopFirstSessionBrowserHost(desktop: SessionBrowserHost, fallback: SessionBrowserHost): SessionBrowserHost;
98
+ declare class DesktopBrowserHandle implements SessionBrowserHostHandle {
99
+ private readonly registry;
100
+ private readonly lease;
101
+ readonly browserGeneration: number;
102
+ readonly executionBackend: "embedded-electron";
103
+ readonly capabilities: readonly string[];
104
+ readonly events: AsyncIterable<SessionBrowserHostEvent>;
105
+ readonly leaseId: string;
106
+ readonly sessionId: string;
107
+ available: boolean;
108
+ private closed;
109
+ private readonly surfaces;
110
+ private readonly openingSurfaces;
111
+ private readonly eventQueue;
112
+ constructor(registry: DesktopBrowserHostRegistry, lease: DesktopBrowserLease, input: SessionBrowserHostCreateInput, capabilities: readonly string[]);
113
+ getCdpEndpoint(): Promise<{
114
+ endpoint: string;
115
+ engineVersion: string;
116
+ pageTargetId?: string;
117
+ }>;
118
+ getPageCdpEndpoint(hostPageId: string): Promise<{
119
+ endpoint: string;
120
+ engineVersion: string;
121
+ }>;
122
+ openSurface(input: SessionBrowserHostSurfaceOpenInput): Promise<SessionBrowserHostSurfaceSource>;
123
+ snapshot(): Promise<SessionBrowserHostSnapshot>;
124
+ createPage(url?: string): Promise<void>;
125
+ closePage(hostPageId: string): Promise<void>;
126
+ activatePage(hostPageId: string): Promise<void>;
127
+ navigatePage(hostPageId: string, url: string): Promise<void>;
128
+ goBack(hostPageId: string): Promise<void>;
129
+ goForward(hostPageId: string): Promise<void>;
130
+ reload(hostPageId: string): Promise<void>;
131
+ bindPage(hostPageId: string, pageId: string): Promise<void>;
132
+ close(): Promise<void>;
133
+ pushEvent(event: SessionBrowserHostEvent): boolean;
134
+ markUnavailable(): void;
135
+ disconnect(reason: string): void;
136
+ receiveSurfaceFrame(frame: DesktopBrowserHostSurfaceFrame): void;
137
+ receiveSurfaceClosed(hostPageId: string, surfaceId: string, reason: string): void;
138
+ forgetSurface(surface: DesktopBrowserSurfaceSource): void;
139
+ private generationScope;
140
+ private pageScope;
141
+ private completed;
142
+ surfaceCompleted(command: DesktopBrowserHostCommand): Promise<unknown>;
143
+ private command;
144
+ }
145
+ declare class DesktopBrowserSurfaceSource implements SessionBrowserHostSurfaceSource {
146
+ private readonly handle;
147
+ readonly hostPageId: string;
148
+ readonly surfaceId: string;
149
+ readonly browserGeneration: number;
150
+ readonly format: DesktopBrowserHostSurfaceFrame["format"];
151
+ readonly frames: AsyncIterable<SessionBrowserHostSurfaceFrame>;
152
+ private readonly frameQueue;
153
+ private viewport;
154
+ private pendingFrameSequence;
155
+ private lastFrameSequence;
156
+ private inputSequence;
157
+ private driver;
158
+ private closed;
159
+ private closePromise;
160
+ constructor(handle: DesktopBrowserHandle, hostPageId: string, surfaceId: string, result: ReturnType<typeof parseDesktopBrowserHostSurfaceOpenResult>);
161
+ getViewport(): SessionBrowserHostSurfaceViewport;
162
+ setHumanDriver(driver: "desktop" | "stream"): Promise<void>;
163
+ dispatchTrustedInput(input: SessionBrowserHostSurfaceTrustedInput): Promise<void>;
164
+ close(): Promise<void>;
165
+ receiveFrame(frame: DesktopBrowserHostSurfaceFrame): void;
166
+ hostClosed(_reason: string): void;
167
+ hostDisconnected(): void;
168
+ private scope;
169
+ }
170
+ export {};