agent-web-os 0.4.0-beta.0 → 0.4.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.
@@ -0,0 +1,14 @@
1
+ import {
2
+ PackageManager,
3
+ Registry,
4
+ install,
5
+ parsePackageSpec
6
+ } from "./chunk-QV36H6BY.js";
7
+ import "./chunk-PR4QN5HX.js";
8
+ export {
9
+ PackageManager,
10
+ Registry,
11
+ install,
12
+ parsePackageSpec
13
+ };
14
+ //# sourceMappingURL=npm-C6N7BGOG.js.map
@@ -0,0 +1,329 @@
1
+ import {
2
+ BufferPolyfill,
3
+ EventEmitter,
4
+ setServerCloseCallback,
5
+ setServerListenCallback,
6
+ uint8ToBase64
7
+ } from "./chunk-L7KW6Y27.js";
8
+ import "./chunk-PR4QN5HX.js";
9
+
10
+ // node_modules/almostnode/src/server-bridge.ts
11
+ var _encoder = new TextEncoder();
12
+ var ServerBridge = class _ServerBridge extends EventEmitter {
13
+ static DEBUG = false;
14
+ servers = /* @__PURE__ */ new Map();
15
+ baseUrl;
16
+ options;
17
+ messageChannel = null;
18
+ serviceWorkerReady = false;
19
+ keepaliveInterval = null;
20
+ constructor(options = {}) {
21
+ super();
22
+ this.options = options;
23
+ if (typeof location !== "undefined") {
24
+ this.baseUrl = options.baseUrl || `${location.protocol}//${location.host}`;
25
+ } else {
26
+ this.baseUrl = options.baseUrl || "http://localhost";
27
+ }
28
+ setServerListenCallback((port, server) => {
29
+ this.registerServer(server, port);
30
+ });
31
+ setServerCloseCallback((port) => {
32
+ this.unregisterServer(port);
33
+ });
34
+ }
35
+ /**
36
+ * Register a server on a port
37
+ */
38
+ registerServer(server, port, hostname = "0.0.0.0") {
39
+ this.servers.set(port, { server, port, hostname });
40
+ const url = this.getServerUrl(port);
41
+ this.emit("server-ready", port, url);
42
+ if (this.options.onServerReady) {
43
+ this.options.onServerReady(port, url);
44
+ }
45
+ this.notifyServiceWorker("server-registered", { port, hostname });
46
+ }
47
+ /**
48
+ * Unregister a server
49
+ */
50
+ unregisterServer(port) {
51
+ this.servers.delete(port);
52
+ this.notifyServiceWorker("server-unregistered", { port });
53
+ }
54
+ /**
55
+ * Get server URL for a port
56
+ */
57
+ getServerUrl(port) {
58
+ return `${this.baseUrl}/__virtual__/${port}`;
59
+ }
60
+ /**
61
+ * Get all registered server ports
62
+ */
63
+ getServerPorts() {
64
+ return [...this.servers.keys()];
65
+ }
66
+ /**
67
+ * Handle an incoming request from Service Worker
68
+ */
69
+ async handleRequest(port, method, url, headers, body) {
70
+ const virtualServer = this.servers.get(port);
71
+ if (!virtualServer) {
72
+ return {
73
+ statusCode: 503,
74
+ statusMessage: "Service Unavailable",
75
+ headers: { "Content-Type": "text/plain" },
76
+ body: BufferPolyfill.from(`No server listening on port ${port}`)
77
+ };
78
+ }
79
+ try {
80
+ const bodyBuffer = body ? BufferPolyfill.from(new Uint8Array(body)) : void 0;
81
+ return await virtualServer.server.handleRequest(method, url, headers, bodyBuffer);
82
+ } catch (error) {
83
+ const message = error instanceof Error ? error.message : "Internal Server Error";
84
+ return {
85
+ statusCode: 500,
86
+ statusMessage: "Internal Server Error",
87
+ headers: { "Content-Type": "text/plain" },
88
+ body: BufferPolyfill.from(message)
89
+ };
90
+ }
91
+ }
92
+ /**
93
+ * Initialize Service Worker communication
94
+ * @param options - Configuration options for the service worker
95
+ * @param options.swUrl - Custom URL path to the service worker file (default: '/__sw__.js')
96
+ */
97
+ async initServiceWorker(options) {
98
+ if (!("serviceWorker" in navigator)) {
99
+ throw new Error("Service Workers not supported");
100
+ }
101
+ const swUrl = options?.swUrl ?? "/__sw__.js";
102
+ const controllerReady = navigator.serviceWorker.controller ? Promise.resolve() : new Promise((resolve) => {
103
+ navigator.serviceWorker.addEventListener("controllerchange", () => resolve(), { once: true });
104
+ });
105
+ const registration = await navigator.serviceWorker.register(swUrl, {
106
+ scope: "/"
107
+ });
108
+ const sw = registration.active || registration.waiting || registration.installing;
109
+ if (!sw) {
110
+ throw new Error("Service Worker registration failed");
111
+ }
112
+ await new Promise((resolve) => {
113
+ if (sw.state === "activated") {
114
+ resolve();
115
+ } else {
116
+ const handler = () => {
117
+ if (sw.state === "activated") {
118
+ sw.removeEventListener("statechange", handler);
119
+ resolve();
120
+ }
121
+ };
122
+ sw.addEventListener("statechange", handler);
123
+ }
124
+ });
125
+ this.messageChannel = new MessageChannel();
126
+ this.messageChannel.port1.onmessage = this.handleServiceWorkerMessage.bind(this);
127
+ sw.postMessage({ type: "init", port: this.messageChannel.port2 }, [
128
+ this.messageChannel.port2
129
+ ]);
130
+ await controllerReady;
131
+ const reinit = () => {
132
+ if (navigator.serviceWorker.controller) {
133
+ this.messageChannel = new MessageChannel();
134
+ this.messageChannel.port1.onmessage = this.handleServiceWorkerMessage.bind(this);
135
+ navigator.serviceWorker.controller.postMessage(
136
+ { type: "init", port: this.messageChannel.port2 },
137
+ [this.messageChannel.port2]
138
+ );
139
+ }
140
+ };
141
+ navigator.serviceWorker.addEventListener("controllerchange", reinit);
142
+ navigator.serviceWorker.addEventListener("message", (event) => {
143
+ if (event.data?.type === "sw-needs-init") {
144
+ reinit();
145
+ }
146
+ });
147
+ this.keepaliveInterval = setInterval(() => {
148
+ this.messageChannel?.port1.postMessage({ type: "keepalive" });
149
+ }, 2e4);
150
+ this.serviceWorkerReady = true;
151
+ this.emit("sw-ready");
152
+ }
153
+ /**
154
+ * Handle messages from Service Worker
155
+ */
156
+ async handleServiceWorkerMessage(event) {
157
+ const { type, id, data } = event.data;
158
+ _ServerBridge.DEBUG && console.log("[ServerBridge] SW message:", type, id, data?.url);
159
+ if (type === "request") {
160
+ const { port, method, url, headers, body, streaming } = data;
161
+ _ServerBridge.DEBUG && console.log("[ServerBridge] Handling request:", port, method, url, "streaming:", streaming);
162
+ if (streaming) {
163
+ _ServerBridge.DEBUG && console.log("[ServerBridge] \u{1F534} Will use streaming handler");
164
+ }
165
+ try {
166
+ if (streaming) {
167
+ await this.handleStreamingRequest(id, port, method, url, headers, body);
168
+ } else {
169
+ const response = await this.handleRequest(port, method, url, headers, body);
170
+ _ServerBridge.DEBUG && console.log("[ServerBridge] Response:", response.statusCode, "body length:", response.body?.length);
171
+ let bodyBase64 = "";
172
+ if (response.body && response.body.length > 0) {
173
+ const bytes = response.body instanceof Uint8Array ? response.body : new Uint8Array(0);
174
+ bodyBase64 = uint8ToBase64(bytes);
175
+ }
176
+ _ServerBridge.DEBUG && console.log("[ServerBridge] Sending response to SW, body base64 length:", bodyBase64.length);
177
+ this.messageChannel?.port1.postMessage({
178
+ type: "response",
179
+ id,
180
+ data: {
181
+ statusCode: response.statusCode,
182
+ statusMessage: response.statusMessage,
183
+ headers: response.headers,
184
+ bodyBase64
185
+ }
186
+ });
187
+ }
188
+ } catch (error) {
189
+ this.messageChannel?.port1.postMessage({
190
+ type: "response",
191
+ id,
192
+ error: error instanceof Error ? error.message : "Unknown error"
193
+ });
194
+ }
195
+ }
196
+ }
197
+ /**
198
+ * Handle a streaming request - sends chunks as they arrive
199
+ */
200
+ async handleStreamingRequest(id, port, method, url, headers, body) {
201
+ const virtualServer = this.servers.get(port);
202
+ if (!virtualServer) {
203
+ this.messageChannel?.port1.postMessage({
204
+ type: "stream-start",
205
+ id,
206
+ data: { statusCode: 503, statusMessage: "Service Unavailable", headers: {} }
207
+ });
208
+ this.messageChannel?.port1.postMessage({ type: "stream-end", id });
209
+ return;
210
+ }
211
+ const server = virtualServer.server;
212
+ if (typeof server.handleStreamingRequest === "function") {
213
+ _ServerBridge.DEBUG && console.log("[ServerBridge] \u{1F7E2} Server has streaming support, calling handleStreamingRequest");
214
+ const bodyBuffer = body ? BufferPolyfill.from(new Uint8Array(body)) : void 0;
215
+ await server.handleStreamingRequest(
216
+ method,
217
+ url,
218
+ headers,
219
+ bodyBuffer,
220
+ // onStart - called with headers
221
+ (statusCode, statusMessage, respHeaders) => {
222
+ _ServerBridge.DEBUG && console.log("[ServerBridge] \u{1F7E2} onStart called, sending stream-start");
223
+ this.messageChannel?.port1.postMessage({
224
+ type: "stream-start",
225
+ id,
226
+ data: { statusCode, statusMessage, headers: respHeaders }
227
+ });
228
+ },
229
+ // onChunk - called for each chunk
230
+ (chunk) => {
231
+ const bytes = typeof chunk === "string" ? _encoder.encode(chunk) : chunk;
232
+ const chunkBase64 = uint8ToBase64(bytes);
233
+ _ServerBridge.DEBUG && console.log("[ServerBridge] \u{1F7E1} onChunk called, sending stream-chunk, size:", chunkBase64.length);
234
+ this.messageChannel?.port1.postMessage({
235
+ type: "stream-chunk",
236
+ id,
237
+ data: { chunkBase64 }
238
+ });
239
+ },
240
+ // onEnd - called when response is complete
241
+ () => {
242
+ _ServerBridge.DEBUG && console.log("[ServerBridge] \u{1F7E2} onEnd called, sending stream-end");
243
+ this.messageChannel?.port1.postMessage({ type: "stream-end", id });
244
+ }
245
+ );
246
+ } else {
247
+ const bodyBuffer = body ? BufferPolyfill.from(new Uint8Array(body)) : void 0;
248
+ const response = await virtualServer.server.handleRequest(method, url, headers, bodyBuffer);
249
+ this.messageChannel?.port1.postMessage({
250
+ type: "stream-start",
251
+ id,
252
+ data: {
253
+ statusCode: response.statusCode,
254
+ statusMessage: response.statusMessage,
255
+ headers: response.headers
256
+ }
257
+ });
258
+ if (response.body && response.body.length > 0) {
259
+ const bytes = response.body instanceof Uint8Array ? response.body : new Uint8Array(0);
260
+ this.messageChannel?.port1.postMessage({
261
+ type: "stream-chunk",
262
+ id,
263
+ data: { chunkBase64: uint8ToBase64(bytes) }
264
+ });
265
+ }
266
+ this.messageChannel?.port1.postMessage({ type: "stream-end", id });
267
+ }
268
+ }
269
+ /**
270
+ * Send message to Service Worker
271
+ */
272
+ notifyServiceWorker(type, data) {
273
+ if (this.serviceWorkerReady && this.messageChannel) {
274
+ this.messageChannel.port1.postMessage({ type, data });
275
+ }
276
+ }
277
+ /**
278
+ * Create a mock request handler for testing without Service Worker
279
+ */
280
+ createFetchHandler() {
281
+ return async (request) => {
282
+ const url = new URL(request.url);
283
+ const match = url.pathname.match(/^\/__virtual__\/(\d+)(\/.*)?$/);
284
+ if (!match) {
285
+ throw new Error("Not a virtual server request");
286
+ }
287
+ const port = parseInt(match[1], 10);
288
+ const path = match[2] || "/";
289
+ const headers = {};
290
+ request.headers.forEach((value, key) => {
291
+ headers[key] = value;
292
+ });
293
+ let body;
294
+ if (request.method !== "GET" && request.method !== "HEAD") {
295
+ body = await request.arrayBuffer();
296
+ }
297
+ const response = await this.handleRequest(
298
+ port,
299
+ request.method,
300
+ path + url.search,
301
+ headers,
302
+ body
303
+ );
304
+ return new Response(response.body, {
305
+ status: response.statusCode,
306
+ statusText: response.statusMessage,
307
+ headers: response.headers
308
+ });
309
+ };
310
+ }
311
+ };
312
+ var globalBridge = null;
313
+ function getServerBridge(options) {
314
+ if (!globalBridge) {
315
+ globalBridge = new ServerBridge(options);
316
+ }
317
+ return globalBridge;
318
+ }
319
+ function resetServerBridge() {
320
+ globalBridge = null;
321
+ }
322
+ var server_bridge_default = ServerBridge;
323
+ export {
324
+ ServerBridge,
325
+ server_bridge_default as default,
326
+ getServerBridge,
327
+ resetServerBridge
328
+ };
329
+ //# sourceMappingURL=server-bridge-DZUJDQIT.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../node_modules/almostnode/src/server-bridge.ts"],"sourcesContent":["/**\n * Server Bridge\n * Connects Service Worker requests to virtual HTTP servers\n */\n\nimport {\n Server,\n ResponseData,\n setServerListenCallback,\n setServerCloseCallback,\n getServer,\n} from './shims/http';\nimport { EventEmitter } from './shims/events';\nimport { Buffer } from './shims/stream';\nimport { uint8ToBase64 } from './utils/binary-encoding';\n\nconst _encoder = new TextEncoder();\n\n/**\n * Interface for virtual servers that can be registered with the bridge\n */\nexport interface IVirtualServer {\n listening: boolean;\n address(): { port: number; address: string; family: string } | null;\n handleRequest(\n method: string,\n url: string,\n headers: Record<string, string>,\n body?: Buffer | string\n ): Promise<ResponseData>;\n}\n\nexport interface VirtualServer {\n server: Server | IVirtualServer;\n port: number;\n hostname: string;\n}\n\nexport interface BridgeOptions {\n baseUrl?: string;\n onServerReady?: (port: number, url: string) => void;\n}\n\nexport interface InitServiceWorkerOptions {\n /**\n * The URL path to the service worker file\n * @default '/__sw__.js'\n */\n swUrl?: string;\n}\n\n/**\n * Server Bridge manages virtual HTTP servers and routes requests\n */\nexport class ServerBridge extends EventEmitter {\n static DEBUG = false;\n private servers: Map<number, VirtualServer> = new Map();\n private baseUrl: string;\n private options: BridgeOptions;\n private messageChannel: MessageChannel | null = null;\n private serviceWorkerReady: boolean = false;\n private keepaliveInterval: ReturnType<typeof setInterval> | null = null;\n\n constructor(options: BridgeOptions = {}) {\n super();\n this.options = options;\n\n // Handle browser vs Node.js environment\n if (typeof location !== 'undefined') {\n this.baseUrl = options.baseUrl || `${location.protocol}//${location.host}`;\n } else {\n this.baseUrl = options.baseUrl || 'http://localhost';\n }\n\n // Set up auto-registration from http module\n setServerListenCallback((port, server) => {\n this.registerServer(server, port);\n });\n\n setServerCloseCallback((port) => {\n this.unregisterServer(port);\n });\n }\n\n /**\n * Register a server on a port\n */\n registerServer(server: Server | IVirtualServer, port: number, hostname: string = '0.0.0.0'): void {\n this.servers.set(port, { server, port, hostname });\n\n // Emit server-ready event\n const url = this.getServerUrl(port);\n this.emit('server-ready', port, url);\n\n if (this.options.onServerReady) {\n this.options.onServerReady(port, url);\n }\n\n // Notify service worker if connected\n this.notifyServiceWorker('server-registered', { port, hostname });\n }\n\n /**\n * Unregister a server\n */\n unregisterServer(port: number): void {\n this.servers.delete(port);\n this.notifyServiceWorker('server-unregistered', { port });\n }\n\n /**\n * Get server URL for a port\n */\n getServerUrl(port: number): string {\n return `${this.baseUrl}/__virtual__/${port}`;\n }\n\n /**\n * Get all registered server ports\n */\n getServerPorts(): number[] {\n return [...this.servers.keys()];\n }\n\n /**\n * Handle an incoming request from Service Worker\n */\n async handleRequest(\n port: number,\n method: string,\n url: string,\n headers: Record<string, string>,\n body?: ArrayBuffer\n ): Promise<ResponseData> {\n const virtualServer = this.servers.get(port);\n\n if (!virtualServer) {\n return {\n statusCode: 503,\n statusMessage: 'Service Unavailable',\n headers: { 'Content-Type': 'text/plain' },\n body: Buffer.from(`No server listening on port ${port}`),\n };\n }\n\n try {\n const bodyBuffer = body ? Buffer.from(new Uint8Array(body)) : undefined;\n return await virtualServer.server.handleRequest(method, url, headers, bodyBuffer);\n } catch (error) {\n const message = error instanceof Error ? error.message : 'Internal Server Error';\n return {\n statusCode: 500,\n statusMessage: 'Internal Server Error',\n headers: { 'Content-Type': 'text/plain' },\n body: Buffer.from(message),\n };\n }\n }\n\n /**\n * Initialize Service Worker communication\n * @param options - Configuration options for the service worker\n * @param options.swUrl - Custom URL path to the service worker file (default: '/__sw__.js')\n */\n async initServiceWorker(options?: InitServiceWorkerOptions): Promise<void> {\n if (!('serviceWorker' in navigator)) {\n throw new Error('Service Workers not supported');\n }\n\n const swUrl = options?.swUrl ?? '/__sw__.js';\n\n // Set up controllerchange listener BEFORE registration so we don't miss the event.\n // clients.claim() in the SW's activate handler fires controllerchange, and it can\n // happen before our activation wait completes.\n const controllerReady = navigator.serviceWorker.controller\n ? Promise.resolve()\n : new Promise<void>((resolve) => {\n navigator.serviceWorker.addEventListener('controllerchange', () => resolve(), { once: true });\n });\n\n // Register service worker\n const registration = await navigator.serviceWorker.register(swUrl, {\n scope: '/',\n });\n\n // Wait for service worker to be active\n const sw = registration.active || registration.waiting || registration.installing;\n\n if (!sw) {\n throw new Error('Service Worker registration failed');\n }\n\n await new Promise<void>((resolve) => {\n if (sw.state === 'activated') {\n resolve();\n } else {\n const handler = () => {\n if (sw.state === 'activated') {\n sw.removeEventListener('statechange', handler);\n resolve();\n }\n };\n sw.addEventListener('statechange', handler);\n }\n });\n\n // Set up message channel for communication\n this.messageChannel = new MessageChannel();\n this.messageChannel.port1.onmessage = this.handleServiceWorkerMessage.bind(this);\n\n // Send port to service worker\n sw.postMessage({ type: 'init', port: this.messageChannel.port2 }, [\n this.messageChannel.port2,\n ]);\n\n // Wait for SW to actually control this page (clients.claim() in SW activate handler)\n // Without this, fetch requests bypass the SW and go directly to the server\n await controllerReady;\n\n // Re-establish communication when the SW loses its port (idle termination)\n // or when the SW is replaced (new deployment). The SW sends 'sw-needs-init'\n // to all clients when a request arrives but mainPort is null.\n const reinit = () => {\n if (navigator.serviceWorker.controller) {\n this.messageChannel = new MessageChannel();\n this.messageChannel.port1.onmessage = this.handleServiceWorkerMessage.bind(this);\n navigator.serviceWorker.controller.postMessage(\n { type: 'init', port: this.messageChannel.port2 },\n [this.messageChannel.port2]\n );\n }\n };\n navigator.serviceWorker.addEventListener('controllerchange', reinit);\n navigator.serviceWorker.addEventListener('message', (event) => {\n if (event.data?.type === 'sw-needs-init') {\n reinit();\n }\n });\n\n // Keep the SW alive with periodic pings. Browsers terminate idle SWs\n // after ~30s, losing the MessageChannel port and all in-memory state.\n this.keepaliveInterval = setInterval(() => {\n this.messageChannel?.port1.postMessage({ type: 'keepalive' });\n }, 20_000);\n\n this.serviceWorkerReady = true;\n this.emit('sw-ready');\n }\n\n /**\n * Handle messages from Service Worker\n */\n private async handleServiceWorkerMessage(event: MessageEvent): Promise<void> {\n const { type, id, data } = event.data;\n\n ServerBridge.DEBUG && console.log('[ServerBridge] SW message:', type, id, data?.url);\n\n if (type === 'request') {\n const { port, method, url, headers, body, streaming } = data;\n\n ServerBridge.DEBUG && console.log('[ServerBridge] Handling request:', port, method, url, 'streaming:', streaming);\n if (streaming) {\n ServerBridge.DEBUG && console.log('[ServerBridge] 🔴 Will use streaming handler');\n }\n\n try {\n if (streaming) {\n // Handle streaming request\n await this.handleStreamingRequest(id, port, method, url, headers, body);\n } else {\n // Handle regular request\n const response = await this.handleRequest(port, method, url, headers, body);\n ServerBridge.DEBUG && console.log('[ServerBridge] Response:', response.statusCode, 'body length:', response.body?.length);\n\n // Convert body to base64 string to avoid structured cloning issues with Uint8Array\n let bodyBase64 = '';\n if (response.body && response.body.length > 0) {\n const bytes = response.body instanceof Uint8Array ? response.body : new Uint8Array(0);\n bodyBase64 = uint8ToBase64(bytes);\n }\n\n ServerBridge.DEBUG && console.log('[ServerBridge] Sending response to SW, body base64 length:', bodyBase64.length);\n\n this.messageChannel?.port1.postMessage({\n type: 'response',\n id,\n data: {\n statusCode: response.statusCode,\n statusMessage: response.statusMessage,\n headers: response.headers,\n bodyBase64: bodyBase64,\n },\n });\n }\n } catch (error) {\n this.messageChannel?.port1.postMessage({\n type: 'response',\n id,\n error: error instanceof Error ? error.message : 'Unknown error',\n });\n }\n }\n }\n\n /**\n * Handle a streaming request - sends chunks as they arrive\n */\n private async handleStreamingRequest(\n id: number,\n port: number,\n method: string,\n url: string,\n headers: Record<string, string>,\n body?: ArrayBuffer\n ): Promise<void> {\n const virtualServer = this.servers.get(port);\n\n if (!virtualServer) {\n this.messageChannel?.port1.postMessage({\n type: 'stream-start',\n id,\n data: { statusCode: 503, statusMessage: 'Service Unavailable', headers: {} },\n });\n this.messageChannel?.port1.postMessage({ type: 'stream-end', id });\n return;\n }\n\n // Check if the server supports streaming (has handleStreamingRequest method)\n const server = virtualServer.server as any;\n if (typeof server.handleStreamingRequest === 'function') {\n ServerBridge.DEBUG && console.log('[ServerBridge] 🟢 Server has streaming support, calling handleStreamingRequest');\n // Use streaming handler\n const bodyBuffer = body ? Buffer.from(new Uint8Array(body)) : undefined;\n\n await server.handleStreamingRequest(\n method,\n url,\n headers,\n bodyBuffer,\n // onStart - called with headers\n (statusCode: number, statusMessage: string, respHeaders: Record<string, string>) => {\n ServerBridge.DEBUG && console.log('[ServerBridge] 🟢 onStart called, sending stream-start');\n this.messageChannel?.port1.postMessage({\n type: 'stream-start',\n id,\n data: { statusCode, statusMessage, headers: respHeaders },\n });\n },\n // onChunk - called for each chunk\n (chunk: string | Uint8Array) => {\n const bytes = typeof chunk === 'string' ? _encoder.encode(chunk) : chunk;\n const chunkBase64 = uint8ToBase64(bytes);\n ServerBridge.DEBUG && console.log('[ServerBridge] 🟡 onChunk called, sending stream-chunk, size:', chunkBase64.length);\n this.messageChannel?.port1.postMessage({\n type: 'stream-chunk',\n id,\n data: { chunkBase64 },\n });\n },\n // onEnd - called when response is complete\n () => {\n ServerBridge.DEBUG && console.log('[ServerBridge] 🟢 onEnd called, sending stream-end');\n this.messageChannel?.port1.postMessage({ type: 'stream-end', id });\n }\n );\n } else {\n // Fall back to regular request handling\n const bodyBuffer = body ? Buffer.from(new Uint8Array(body)) : undefined;\n const response = await virtualServer.server.handleRequest(method, url, headers, bodyBuffer);\n\n // Send as a single stream\n this.messageChannel?.port1.postMessage({\n type: 'stream-start',\n id,\n data: {\n statusCode: response.statusCode,\n statusMessage: response.statusMessage,\n headers: response.headers,\n },\n });\n\n if (response.body && response.body.length > 0) {\n const bytes = response.body instanceof Uint8Array ? response.body : new Uint8Array(0);\n this.messageChannel?.port1.postMessage({\n type: 'stream-chunk',\n id,\n data: { chunkBase64: uint8ToBase64(bytes) },\n });\n }\n\n this.messageChannel?.port1.postMessage({ type: 'stream-end', id });\n }\n }\n\n /**\n * Send message to Service Worker\n */\n private notifyServiceWorker(type: string, data: unknown): void {\n if (this.serviceWorkerReady && this.messageChannel) {\n this.messageChannel.port1.postMessage({ type, data });\n }\n }\n\n /**\n * Create a mock request handler for testing without Service Worker\n */\n createFetchHandler(): (request: Request) => Promise<Response> {\n return async (request: Request): Promise<Response> => {\n const url = new URL(request.url);\n\n // Check if this is a virtual server request\n const match = url.pathname.match(/^\\/__virtual__\\/(\\d+)(\\/.*)?$/);\n if (!match) {\n throw new Error('Not a virtual server request');\n }\n\n const port = parseInt(match[1], 10);\n const path = match[2] || '/';\n\n // Build headers object\n const headers: Record<string, string> = {};\n request.headers.forEach((value, key) => {\n headers[key] = value;\n });\n\n // Get body if present\n let body: ArrayBuffer | undefined;\n if (request.method !== 'GET' && request.method !== 'HEAD') {\n body = await request.arrayBuffer();\n }\n\n // Handle request\n const response = await this.handleRequest(\n port,\n request.method,\n path + url.search,\n headers,\n body\n );\n\n // Convert to fetch Response\n return new Response(response.body, {\n status: response.statusCode,\n statusText: response.statusMessage,\n headers: response.headers,\n });\n };\n }\n}\n\n// Global bridge instance\nlet globalBridge: ServerBridge | null = null;\n\n/**\n * Get or create the global server bridge\n */\nexport function getServerBridge(options?: BridgeOptions): ServerBridge {\n if (!globalBridge) {\n globalBridge = new ServerBridge(options);\n }\n return globalBridge;\n}\n\n/**\n * Reset the global bridge (for testing)\n */\nexport function resetServerBridge(): void {\n globalBridge = null;\n}\n\nexport default ServerBridge;\n"],"mappings":";;;;;;;;;;AAgBA,IAAM,WAAW,IAAI,YAAY;AAsC1B,IAAM,eAAN,MAAM,sBAAqB,aAAa;AAAA,EAC7C,OAAO,QAAQ;AAAA,EACP,UAAsC,oBAAI,IAAI;AAAA,EAC9C;AAAA,EACA;AAAA,EACA,iBAAwC;AAAA,EACxC,qBAA8B;AAAA,EAC9B,oBAA2D;AAAA,EAEnE,YAAY,UAAyB,CAAC,GAAG;AACvC,UAAM;AACN,SAAK,UAAU;AAGf,QAAI,OAAO,aAAa,aAAa;AACnC,WAAK,UAAU,QAAQ,WAAW,GAAG,SAAS,QAAQ,KAAK,SAAS,IAAI;AAAA,IAC1E,OAAO;AACL,WAAK,UAAU,QAAQ,WAAW;AAAA,IACpC;AAGA,4BAAwB,CAAC,MAAM,WAAW;AACxC,WAAK,eAAe,QAAQ,IAAI;AAAA,IAClC,CAAC;AAED,2BAAuB,CAAC,SAAS;AAC/B,WAAK,iBAAiB,IAAI;AAAA,IAC5B,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA,EAKA,eAAe,QAAiC,MAAc,WAAmB,WAAiB;AAChG,SAAK,QAAQ,IAAI,MAAM,EAAE,QAAQ,MAAM,SAAS,CAAC;AAGjD,UAAM,MAAM,KAAK,aAAa,IAAI;AAClC,SAAK,KAAK,gBAAgB,MAAM,GAAG;AAEnC,QAAI,KAAK,QAAQ,eAAe;AAC9B,WAAK,QAAQ,cAAc,MAAM,GAAG;AAAA,IACtC;AAGA,SAAK,oBAAoB,qBAAqB,EAAE,MAAM,SAAS,CAAC;AAAA,EAClE;AAAA;AAAA;AAAA;AAAA,EAKA,iBAAiB,MAAoB;AACnC,SAAK,QAAQ,OAAO,IAAI;AACxB,SAAK,oBAAoB,uBAAuB,EAAE,KAAK,CAAC;AAAA,EAC1D;AAAA;AAAA;AAAA;AAAA,EAKA,aAAa,MAAsB;AACjC,WAAO,GAAG,KAAK,OAAO,gBAAgB,IAAI;AAAA,EAC5C;AAAA;AAAA;AAAA;AAAA,EAKA,iBAA2B;AACzB,WAAO,CAAC,GAAG,KAAK,QAAQ,KAAK,CAAC;AAAA,EAChC;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,cACJ,MACA,QACA,KACA,SACA,MACuB;AACvB,UAAM,gBAAgB,KAAK,QAAQ,IAAI,IAAI;AAE3C,QAAI,CAAC,eAAe;AAClB,aAAO;AAAA,QACL,YAAY;AAAA,QACZ,eAAe;AAAA,QACf,SAAS,EAAE,gBAAgB,aAAa;AAAA,QACxC,MAAM,eAAO,KAAK,+BAA+B,IAAI,EAAE;AAAA,MACzD;AAAA,IACF;AAEA,QAAI;AACF,YAAM,aAAa,OAAO,eAAO,KAAK,IAAI,WAAW,IAAI,CAAC,IAAI;AAC9D,aAAO,MAAM,cAAc,OAAO,cAAc,QAAQ,KAAK,SAAS,UAAU;AAAA,IAClF,SAAS,OAAO;AACd,YAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU;AACzD,aAAO;AAAA,QACL,YAAY;AAAA,QACZ,eAAe;AAAA,QACf,SAAS,EAAE,gBAAgB,aAAa;AAAA,QACxC,MAAM,eAAO,KAAK,OAAO;AAAA,MAC3B;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,kBAAkB,SAAmD;AACzE,QAAI,EAAE,mBAAmB,YAAY;AACnC,YAAM,IAAI,MAAM,+BAA+B;AAAA,IACjD;AAEA,UAAM,QAAQ,SAAS,SAAS;AAKhC,UAAM,kBAAkB,UAAU,cAAc,aAC5C,QAAQ,QAAQ,IAChB,IAAI,QAAc,CAAC,YAAY;AAC7B,gBAAU,cAAc,iBAAiB,oBAAoB,MAAM,QAAQ,GAAG,EAAE,MAAM,KAAK,CAAC;AAAA,IAC9F,CAAC;AAGL,UAAM,eAAe,MAAM,UAAU,cAAc,SAAS,OAAO;AAAA,MACjE,OAAO;AAAA,IACT,CAAC;AAGD,UAAM,KAAK,aAAa,UAAU,aAAa,WAAW,aAAa;AAEvE,QAAI,CAAC,IAAI;AACP,YAAM,IAAI,MAAM,oCAAoC;AAAA,IACtD;AAEA,UAAM,IAAI,QAAc,CAAC,YAAY;AACnC,UAAI,GAAG,UAAU,aAAa;AAC5B,gBAAQ;AAAA,MACV,OAAO;AACL,cAAM,UAAU,MAAM;AACpB,cAAI,GAAG,UAAU,aAAa;AAC5B,eAAG,oBAAoB,eAAe,OAAO;AAC7C,oBAAQ;AAAA,UACV;AAAA,QACF;AACA,WAAG,iBAAiB,eAAe,OAAO;AAAA,MAC5C;AAAA,IACF,CAAC;AAGD,SAAK,iBAAiB,IAAI,eAAe;AACzC,SAAK,eAAe,MAAM,YAAY,KAAK,2BAA2B,KAAK,IAAI;AAG/E,OAAG,YAAY,EAAE,MAAM,QAAQ,MAAM,KAAK,eAAe,MAAM,GAAG;AAAA,MAChE,KAAK,eAAe;AAAA,IACtB,CAAC;AAID,UAAM;AAKN,UAAM,SAAS,MAAM;AACnB,UAAI,UAAU,cAAc,YAAY;AACtC,aAAK,iBAAiB,IAAI,eAAe;AACzC,aAAK,eAAe,MAAM,YAAY,KAAK,2BAA2B,KAAK,IAAI;AAC/E,kBAAU,cAAc,WAAW;AAAA,UACjC,EAAE,MAAM,QAAQ,MAAM,KAAK,eAAe,MAAM;AAAA,UAChD,CAAC,KAAK,eAAe,KAAK;AAAA,QAC5B;AAAA,MACF;AAAA,IACF;AACA,cAAU,cAAc,iBAAiB,oBAAoB,MAAM;AACnE,cAAU,cAAc,iBAAiB,WAAW,CAAC,UAAU;AAC7D,UAAI,MAAM,MAAM,SAAS,iBAAiB;AACxC,eAAO;AAAA,MACT;AAAA,IACF,CAAC;AAID,SAAK,oBAAoB,YAAY,MAAM;AACzC,WAAK,gBAAgB,MAAM,YAAY,EAAE,MAAM,YAAY,CAAC;AAAA,IAC9D,GAAG,GAAM;AAET,SAAK,qBAAqB;AAC1B,SAAK,KAAK,UAAU;AAAA,EACtB;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,2BAA2B,OAAoC;AAC3E,UAAM,EAAE,MAAM,IAAI,KAAK,IAAI,MAAM;AAEjC,kBAAa,SAAS,QAAQ,IAAI,8BAA8B,MAAM,IAAI,MAAM,GAAG;AAEnF,QAAI,SAAS,WAAW;AACtB,YAAM,EAAE,MAAM,QAAQ,KAAK,SAAS,MAAM,UAAU,IAAI;AAExD,oBAAa,SAAS,QAAQ,IAAI,oCAAoC,MAAM,QAAQ,KAAK,cAAc,SAAS;AAChH,UAAI,WAAW;AACb,sBAAa,SAAS,QAAQ,IAAI,qDAA8C;AAAA,MAClF;AAEA,UAAI;AACF,YAAI,WAAW;AAEb,gBAAM,KAAK,uBAAuB,IAAI,MAAM,QAAQ,KAAK,SAAS,IAAI;AAAA,QACxE,OAAO;AAEL,gBAAM,WAAW,MAAM,KAAK,cAAc,MAAM,QAAQ,KAAK,SAAS,IAAI;AAC1E,wBAAa,SAAS,QAAQ,IAAI,4BAA4B,SAAS,YAAY,gBAAgB,SAAS,MAAM,MAAM;AAGxH,cAAI,aAAa;AACjB,cAAI,SAAS,QAAQ,SAAS,KAAK,SAAS,GAAG;AAC7C,kBAAM,QAAQ,SAAS,gBAAgB,aAAa,SAAS,OAAO,IAAI,WAAW,CAAC;AACpF,yBAAa,cAAc,KAAK;AAAA,UAClC;AAEA,wBAAa,SAAS,QAAQ,IAAI,8DAA8D,WAAW,MAAM;AAEjH,eAAK,gBAAgB,MAAM,YAAY;AAAA,YACrC,MAAM;AAAA,YACN;AAAA,YACA,MAAM;AAAA,cACJ,YAAY,SAAS;AAAA,cACrB,eAAe,SAAS;AAAA,cACxB,SAAS,SAAS;AAAA,cAClB;AAAA,YACF;AAAA,UACF,CAAC;AAAA,QACH;AAAA,MACF,SAAS,OAAO;AACd,aAAK,gBAAgB,MAAM,YAAY;AAAA,UACrC,MAAM;AAAA,UACN;AAAA,UACA,OAAO,iBAAiB,QAAQ,MAAM,UAAU;AAAA,QAClD,CAAC;AAAA,MACH;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,uBACZ,IACA,MACA,QACA,KACA,SACA,MACe;AACf,UAAM,gBAAgB,KAAK,QAAQ,IAAI,IAAI;AAE3C,QAAI,CAAC,eAAe;AAClB,WAAK,gBAAgB,MAAM,YAAY;AAAA,QACrC,MAAM;AAAA,QACN;AAAA,QACA,MAAM,EAAE,YAAY,KAAK,eAAe,uBAAuB,SAAS,CAAC,EAAE;AAAA,MAC7E,CAAC;AACD,WAAK,gBAAgB,MAAM,YAAY,EAAE,MAAM,cAAc,GAAG,CAAC;AACjE;AAAA,IACF;AAGA,UAAM,SAAS,cAAc;AAC7B,QAAI,OAAO,OAAO,2BAA2B,YAAY;AACvD,oBAAa,SAAS,QAAQ,IAAI,uFAAgF;AAElH,YAAM,aAAa,OAAO,eAAO,KAAK,IAAI,WAAW,IAAI,CAAC,IAAI;AAE9D,YAAM,OAAO;AAAA,QACX;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA;AAAA,QAEA,CAAC,YAAoB,eAAuB,gBAAwC;AAClF,wBAAa,SAAS,QAAQ,IAAI,+DAAwD;AAC1F,eAAK,gBAAgB,MAAM,YAAY;AAAA,YACrC,MAAM;AAAA,YACN;AAAA,YACA,MAAM,EAAE,YAAY,eAAe,SAAS,YAAY;AAAA,UAC1D,CAAC;AAAA,QACH;AAAA;AAAA,QAEA,CAAC,UAA+B;AAC9B,gBAAM,QAAQ,OAAO,UAAU,WAAW,SAAS,OAAO,KAAK,IAAI;AACnE,gBAAM,cAAc,cAAc,KAAK;AACvC,wBAAa,SAAS,QAAQ,IAAI,wEAAiE,YAAY,MAAM;AACrH,eAAK,gBAAgB,MAAM,YAAY;AAAA,YACrC,MAAM;AAAA,YACN;AAAA,YACA,MAAM,EAAE,YAAY;AAAA,UACtB,CAAC;AAAA,QACH;AAAA;AAAA,QAEA,MAAM;AACJ,wBAAa,SAAS,QAAQ,IAAI,2DAAoD;AACtF,eAAK,gBAAgB,MAAM,YAAY,EAAE,MAAM,cAAc,GAAG,CAAC;AAAA,QACnE;AAAA,MACF;AAAA,IACF,OAAO;AAEL,YAAM,aAAa,OAAO,eAAO,KAAK,IAAI,WAAW,IAAI,CAAC,IAAI;AAC9D,YAAM,WAAW,MAAM,cAAc,OAAO,cAAc,QAAQ,KAAK,SAAS,UAAU;AAG1F,WAAK,gBAAgB,MAAM,YAAY;AAAA,QACrC,MAAM;AAAA,QACN;AAAA,QACA,MAAM;AAAA,UACJ,YAAY,SAAS;AAAA,UACrB,eAAe,SAAS;AAAA,UACxB,SAAS,SAAS;AAAA,QACpB;AAAA,MACF,CAAC;AAED,UAAI,SAAS,QAAQ,SAAS,KAAK,SAAS,GAAG;AAC7C,cAAM,QAAQ,SAAS,gBAAgB,aAAa,SAAS,OAAO,IAAI,WAAW,CAAC;AACpF,aAAK,gBAAgB,MAAM,YAAY;AAAA,UACrC,MAAM;AAAA,UACN;AAAA,UACA,MAAM,EAAE,aAAa,cAAc,KAAK,EAAE;AAAA,QAC5C,CAAC;AAAA,MACH;AAEA,WAAK,gBAAgB,MAAM,YAAY,EAAE,MAAM,cAAc,GAAG,CAAC;AAAA,IACnE;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKQ,oBAAoB,MAAc,MAAqB;AAC7D,QAAI,KAAK,sBAAsB,KAAK,gBAAgB;AAClD,WAAK,eAAe,MAAM,YAAY,EAAE,MAAM,KAAK,CAAC;AAAA,IACtD;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,qBAA8D;AAC5D,WAAO,OAAO,YAAwC;AACpD,YAAM,MAAM,IAAI,IAAI,QAAQ,GAAG;AAG/B,YAAM,QAAQ,IAAI,SAAS,MAAM,+BAA+B;AAChE,UAAI,CAAC,OAAO;AACV,cAAM,IAAI,MAAM,8BAA8B;AAAA,MAChD;AAEA,YAAM,OAAO,SAAS,MAAM,CAAC,GAAG,EAAE;AAClC,YAAM,OAAO,MAAM,CAAC,KAAK;AAGzB,YAAM,UAAkC,CAAC;AACzC,cAAQ,QAAQ,QAAQ,CAAC,OAAO,QAAQ;AACtC,gBAAQ,GAAG,IAAI;AAAA,MACjB,CAAC;AAGD,UAAI;AACJ,UAAI,QAAQ,WAAW,SAAS,QAAQ,WAAW,QAAQ;AACzD,eAAO,MAAM,QAAQ,YAAY;AAAA,MACnC;AAGA,YAAM,WAAW,MAAM,KAAK;AAAA,QAC1B;AAAA,QACA,QAAQ;AAAA,QACR,OAAO,IAAI;AAAA,QACX;AAAA,QACA;AAAA,MACF;AAGA,aAAO,IAAI,SAAS,SAAS,MAAM;AAAA,QACjC,QAAQ,SAAS;AAAA,QACjB,YAAY,SAAS;AAAA,QACrB,SAAS,SAAS;AAAA,MACpB,CAAC;AAAA,IACH;AAAA,EACF;AACF;AAGA,IAAI,eAAoC;AAKjC,SAAS,gBAAgB,SAAuC;AACrE,MAAI,CAAC,cAAc;AACjB,mBAAe,IAAI,aAAa,OAAO;AAAA,EACzC;AACA,SAAO;AACT;AAKO,SAAS,oBAA0B;AACxC,iBAAe;AACjB;AAEA,IAAO,wBAAQ;","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agent-web-os",
3
- "version": "0.4.0-beta.0",
3
+ "version": "0.4.0",
4
4
  "description": "Browser-based bash + Node.js runtime with an observable in-memory filesystem",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",