@opengeni/sdk 0.46.0 → 0.52.1

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 (103) hide show
  1. package/README.md +94 -2
  2. package/dist/artifact-client.d.ts +20 -2
  3. package/dist/artifacts.d.ts +4 -0
  4. package/dist/artifacts.js +11 -0
  5. package/dist/artifacts.js.map +1 -0
  6. package/dist/chunk-FHI4DFIG.js +128 -0
  7. package/dist/chunk-FHI4DFIG.js.map +1 -0
  8. package/dist/chunk-FRJFNDIR.js +218 -0
  9. package/dist/chunk-FRJFNDIR.js.map +1 -0
  10. package/dist/{chunk-QKV5OCLJ.js → chunk-ILQZR5N6.js} +1380 -595
  11. package/dist/chunk-ILQZR5N6.js.map +1 -0
  12. package/dist/chunk-MZWTWOX6.js +661 -0
  13. package/dist/chunk-MZWTWOX6.js.map +1 -0
  14. package/dist/chunk-VWE2QIVO.js +1162 -0
  15. package/dist/chunk-VWE2QIVO.js.map +1 -0
  16. package/dist/chunk-VYCTL62C.js +230 -0
  17. package/dist/chunk-VYCTL62C.js.map +1 -0
  18. package/dist/client.d.ts +176 -20
  19. package/dist/codex-realtime-controller.d.ts +6 -6
  20. package/dist/codex-realtime-lifecycle.d.ts +1 -1
  21. package/dist/codex-realtime-v3.d.ts +3 -3
  22. package/dist/codex-realtime.d.ts +1 -1
  23. package/dist/company-profile.d.ts +100 -0
  24. package/dist/core.d.ts +5 -5
  25. package/dist/core.js +9 -4
  26. package/dist/desktop.d.ts +1 -1
  27. package/dist/editable-artifact-resources.d.ts +96 -0
  28. package/dist/editable-artifacts/browser-session.d.ts +35 -0
  29. package/dist/editable-artifacts/controller.d.ts +60 -0
  30. package/dist/editable-artifacts/errors.d.ts +23 -0
  31. package/dist/editable-artifacts/http-live-transport.d.ts +46 -0
  32. package/dist/editable-artifacts/index.d.ts +19 -0
  33. package/dist/editable-artifacts/pool.d.ts +15 -0
  34. package/dist/editable-artifacts/session.d.ts +96 -0
  35. package/dist/editable-artifacts/storage.d.ts +72 -0
  36. package/dist/editable-artifacts/types.d.ts +416 -0
  37. package/dist/editable-artifacts/worker/browser-client.d.ts +80 -0
  38. package/dist/editable-artifacts/worker/browser-entry.d.ts +6 -0
  39. package/dist/editable-artifacts/worker/kernel-adapter.d.ts +45 -0
  40. package/dist/editable-artifacts/worker/rpc-protocol.d.ts +92 -0
  41. package/dist/editable-artifacts/worker/runtime.d.ts +66 -0
  42. package/dist/editable-artifacts/worker/wire-codec.d.ts +52 -0
  43. package/dist/editable-artifacts-worker.d.ts +8 -0
  44. package/dist/editable-artifacts-worker.js +1708 -0
  45. package/dist/editable-artifacts-worker.js.map +1 -0
  46. package/dist/editable-artifacts.d.ts +6 -0
  47. package/dist/editable-artifacts.js +5954 -0
  48. package/dist/editable-artifacts.js.map +1 -0
  49. package/dist/gateway-realtime-transport.d.ts +1 -1
  50. package/dist/index.d.ts +41 -35
  51. package/dist/index.js +104 -68
  52. package/dist/index.js.map +1 -1
  53. package/dist/interaction.d.ts +885 -0
  54. package/dist/interaction.js +55 -0
  55. package/dist/interaction.js.map +1 -0
  56. package/dist/memory-slack-client.d.ts +13 -0
  57. package/dist/memory-slack-delivery.d.ts +99 -0
  58. package/dist/memory-slack.d.ts +4 -0
  59. package/dist/memory-slack.js +44 -0
  60. package/dist/memory-slack.js.map +1 -0
  61. package/dist/proxy.d.ts +3 -3
  62. package/dist/realtime.d.ts +12 -12
  63. package/dist/retained-artifacts.d.ts +12 -0
  64. package/dist/stream.d.ts +16 -1
  65. package/dist/terminal.d.ts +1 -1
  66. package/dist/transcription.d.ts +2 -2
  67. package/dist/types.d.ts +1203 -23
  68. package/dist/workspace-control-stream.d.ts +2 -2
  69. package/dist/workspace-state.d.ts +1 -1
  70. package/package.json +29 -3
  71. package/src/artifact-client.ts +129 -0
  72. package/src/artifacts.ts +17 -0
  73. package/src/client.ts +1801 -206
  74. package/src/company-profile.ts +92 -0
  75. package/src/editable-artifact-resources.ts +119 -0
  76. package/src/editable-artifacts/browser-session.ts +176 -0
  77. package/src/editable-artifacts/controller.ts +2632 -0
  78. package/src/editable-artifacts/errors.ts +52 -0
  79. package/src/editable-artifacts/http-live-transport.ts +1449 -0
  80. package/src/editable-artifacts/index.ts +175 -0
  81. package/src/editable-artifacts/pool.ts +81 -0
  82. package/src/editable-artifacts/session.ts +778 -0
  83. package/src/editable-artifacts/storage.ts +1718 -0
  84. package/src/editable-artifacts/types.ts +499 -0
  85. package/src/editable-artifacts/worker/browser-client.ts +1167 -0
  86. package/src/editable-artifacts/worker/browser-entry.ts +57 -0
  87. package/src/editable-artifacts/worker/kernel-adapter.ts +1039 -0
  88. package/src/editable-artifacts/worker/rpc-protocol.ts +622 -0
  89. package/src/editable-artifacts/worker/runtime.ts +1204 -0
  90. package/src/editable-artifacts/worker/wire-codec.ts +852 -0
  91. package/src/editable-artifacts-worker.ts +8 -0
  92. package/src/editable-artifacts.ts +6 -0
  93. package/src/index.ts +194 -0
  94. package/src/interaction.ts +1830 -0
  95. package/src/memory-slack-client.ts +71 -0
  96. package/src/memory-slack-delivery.ts +128 -0
  97. package/src/memory-slack.ts +19 -0
  98. package/src/retained-artifacts.ts +326 -0
  99. package/src/stream.ts +102 -4
  100. package/src/transcription.ts +2 -2
  101. package/src/types.ts +1430 -33
  102. package/src/workspace-control-stream.ts +15 -5
  103. package/dist/chunk-QKV5OCLJ.js.map +0 -1
@@ -0,0 +1,661 @@
1
+ // src/interaction.ts
2
+ var INTERACTION_PROTOCOL_VERSION = 1;
3
+ var BROWSER_CONTROL_WEBSOCKET_PROTOCOL = "opengeni.browser.v1";
4
+ var COMPUTER_CONTROL_WEBSOCKET_PROTOCOL = "opengeni.computer.v1";
5
+ var BROWSER_CONTROL_WEBSOCKET_BEARER_PREFIX = "opengeni.auth.";
6
+ var BROWSER_CONTROL_MAX_FRAME_HEADER_BYTES = 64 * 1024;
7
+ var BROWSER_FRAME_MAX_BYTES = 24 * 1024 * 1024;
8
+ var BROWSER_FRAME_MAX_DIMENSION = 32768;
9
+ var BROWSER_FRAME_MAX_PIXELS = 1e8;
10
+ var OpenGeniInteractionClient = class {
11
+ attachedBrowsers;
12
+ browsers;
13
+ computers;
14
+ identities;
15
+ constructor(transport) {
16
+ this.attachedBrowsers = new AttachedBrowserDeviceCollection(transport);
17
+ this.browsers = new BrowserSessionCollection(transport);
18
+ this.computers = new ComputerSessionCollection(transport);
19
+ this.identities = new BrowserIdentityCollection(transport);
20
+ }
21
+ };
22
+ var AttachedBrowserDeviceCollection = class {
23
+ constructor(transport) {
24
+ this.transport = transport;
25
+ }
26
+ async list(workspaceId, options = {}) {
27
+ return await this.transport.listAttachedBrowsers(workspaceId, options);
28
+ }
29
+ device(workspaceId, deviceId) {
30
+ return new AttachedBrowserDeviceResource(this.transport, workspaceId, deviceId);
31
+ }
32
+ };
33
+ var AttachedBrowserDeviceResource = class {
34
+ constructor(transport, workspaceId, id) {
35
+ this.transport = transport;
36
+ this.workspaceId = workspaceId;
37
+ this.id = id;
38
+ }
39
+ async get(options = {}) {
40
+ return await this.transport.getAttachedBrowser(this.workspaceId, this.id, options);
41
+ }
42
+ };
43
+ var BrowserIdentityCollection = class {
44
+ constructor(transport) {
45
+ this.transport = transport;
46
+ }
47
+ async list(workspaceId, options = {}) {
48
+ return await this.transport.listBrowserIdentities(workspaceId, options);
49
+ }
50
+ identity(workspaceId, identityId) {
51
+ return new BrowserIdentityResource(this.transport, workspaceId, identityId);
52
+ }
53
+ async create(workspaceId, request, options = {}) {
54
+ const response = await this.transport.createBrowserIdentity(workspaceId, request, options);
55
+ return this.identity(workspaceId, response.identity.id);
56
+ }
57
+ };
58
+ var BrowserIdentityResource = class {
59
+ constructor(transport, workspaceId, id) {
60
+ this.transport = transport;
61
+ this.workspaceId = workspaceId;
62
+ this.id = id;
63
+ }
64
+ async get(options = {}) {
65
+ return await this.transport.getBrowserIdentity(this.workspaceId, this.id, options);
66
+ }
67
+ async revisions(options = {}) {
68
+ return await this.transport.listBrowserRevisions(this.workspaceId, this.id, options);
69
+ }
70
+ };
71
+ var BrowserSessionCollection = class {
72
+ constructor(transport) {
73
+ this.transport = transport;
74
+ }
75
+ async list(workspaceId, options = {}) {
76
+ return await this.transport.listBrowserSessions(workspaceId, options);
77
+ }
78
+ session(workspaceId, browserSessionId) {
79
+ return new BrowserSessionResource(this.transport, workspaceId, browserSessionId);
80
+ }
81
+ async open(workspaceId, request, options = {}) {
82
+ const response = await this.transport.createBrowserSession(workspaceId, request, options);
83
+ return this.session(workspaceId, response.session.id);
84
+ }
85
+ async currentOrOpen(options) {
86
+ const requestOptions = options.signal ? { signal: options.signal } : {};
87
+ const listed = await this.list(options.workspaceId, requestOptions);
88
+ const current = newestRelevantBrowser(listed.sessions, options.associationSessionId);
89
+ if (current) {
90
+ const resource = this.session(options.workspaceId, current.id);
91
+ if (current.lifecycle === "suspended") {
92
+ await resource.resume(
93
+ { operationId: options.operationId ?? crypto.randomUUID() },
94
+ requestOptions
95
+ );
96
+ }
97
+ return resource;
98
+ }
99
+ return await this.open(
100
+ options.workspaceId,
101
+ {
102
+ operationId: options.operationId ?? crypto.randomUUID(),
103
+ sessionId: options.associationSessionId,
104
+ ...options.name !== void 0 ? { name: options.name } : {},
105
+ ...options.initialUrl !== void 0 ? { initialUrl: options.initialUrl } : {},
106
+ ...options.headless !== void 0 ? { headless: options.headless } : {},
107
+ ...options.placement !== void 0 ? { placement: options.placement } : {},
108
+ ...options.identityId !== void 0 ? { identityId: options.identityId } : {},
109
+ ...options.baseRevisionId !== void 0 ? { baseRevisionId: options.baseRevisionId } : {},
110
+ ...options.linkedComputerSessionId !== void 0 ? { linkedComputerSessionId: options.linkedComputerSessionId } : {}
111
+ },
112
+ requestOptions
113
+ );
114
+ }
115
+ };
116
+ var BrowserSessionResource = class {
117
+ constructor(transport, workspaceId, id) {
118
+ this.transport = transport;
119
+ this.workspaceId = workspaceId;
120
+ this.id = id;
121
+ this.tabs = new BrowserTargetCollection(transport, workspaceId, id);
122
+ this.targets = this.tabs;
123
+ }
124
+ tabs;
125
+ /** Alias for hosts that prefer the protocol term. */
126
+ targets;
127
+ async get(options = {}) {
128
+ return await this.transport.getBrowserSession(this.workspaceId, this.id, options);
129
+ }
130
+ async observe(targetId, options = {}) {
131
+ return await this.transport.observeBrowserTarget(this.workspaceId, this.id, targetId, options);
132
+ }
133
+ async act(request, options = {}) {
134
+ return await this.transport.actInBrowser(this.workspaceId, this.id, request, options);
135
+ }
136
+ async receipt(operationId, options = {}) {
137
+ return await this.transport.getBrowserActionReceipt(
138
+ this.workspaceId,
139
+ this.id,
140
+ operationId,
141
+ options
142
+ );
143
+ }
144
+ async diagnostics(targetId, options = {}) {
145
+ return await this.transport.listBrowserDiagnostics(
146
+ this.workspaceId,
147
+ this.id,
148
+ targetId,
149
+ options
150
+ );
151
+ }
152
+ async attach(request, options = {}) {
153
+ return await this.transport.attachBrowserSession(this.workspaceId, this.id, request, options);
154
+ }
155
+ async heartbeat(options = {}) {
156
+ return await this.transport.heartbeatBrowserSession(this.workspaceId, this.id, options);
157
+ }
158
+ async publishRevision(request, options = {}) {
159
+ return await this.transport.publishBrowserRevision(this.workspaceId, this.id, request, options);
160
+ }
161
+ async suspend(request = {
162
+ operationId: crypto.randomUUID()
163
+ }, options = {}) {
164
+ return await this.transport.suspendBrowserSession(this.workspaceId, this.id, request, options);
165
+ }
166
+ async resume(request = {
167
+ operationId: crypto.randomUUID()
168
+ }, options = {}) {
169
+ return await this.transport.resumeBrowserSession(this.workspaceId, this.id, request, options);
170
+ }
171
+ async end(request = {
172
+ operationId: crypto.randomUUID()
173
+ }, options = {}) {
174
+ return await this.transport.endBrowserSession(this.workspaceId, this.id, request, options);
175
+ }
176
+ };
177
+ var BrowserTargetCollection = class {
178
+ constructor(transport, workspaceId, browserSessionId) {
179
+ this.transport = transport;
180
+ this.workspaceId = workspaceId;
181
+ this.browserSessionId = browserSessionId;
182
+ }
183
+ async list(options = {}) {
184
+ return await this.transport.listBrowserTargets(
185
+ this.workspaceId,
186
+ this.browserSessionId,
187
+ options
188
+ );
189
+ }
190
+ async open(url, options = {}) {
191
+ return await this.transport.openBrowserTarget(
192
+ this.workspaceId,
193
+ this.browserSessionId,
194
+ url === void 0 ? {} : { url },
195
+ options
196
+ );
197
+ }
198
+ async select(targetId, options = {}) {
199
+ return await this.transport.selectBrowserTarget(
200
+ this.workspaceId,
201
+ this.browserSessionId,
202
+ targetId,
203
+ options
204
+ );
205
+ }
206
+ async close(targetId, options = {}) {
207
+ return await this.transport.closeBrowserTarget(
208
+ this.workspaceId,
209
+ this.browserSessionId,
210
+ targetId,
211
+ options
212
+ );
213
+ }
214
+ };
215
+ var ComputerSessionCollection = class {
216
+ constructor(transport) {
217
+ this.transport = transport;
218
+ }
219
+ async list(workspaceId, options = {}) {
220
+ return await this.transport.listComputerSessions(workspaceId, options);
221
+ }
222
+ session(workspaceId, computerSessionId) {
223
+ return new ComputerSessionResource(this.transport, workspaceId, computerSessionId);
224
+ }
225
+ async open(workspaceId, request, options = {}) {
226
+ const response = await this.transport.createComputerSession(workspaceId, request, options);
227
+ return this.session(workspaceId, response.session.id);
228
+ }
229
+ async currentOrOpen(options) {
230
+ const requestOptions = options.signal ? { signal: options.signal } : {};
231
+ const listed = await this.list(options.workspaceId, requestOptions);
232
+ const current = newestRelevantComputer(listed.sessions, options.associationSessionId);
233
+ if (current) {
234
+ return this.session(options.workspaceId, current.id);
235
+ }
236
+ return await this.open(
237
+ options.workspaceId,
238
+ {
239
+ operationId: options.operationId ?? crypto.randomUUID(),
240
+ sessionId: options.associationSessionId,
241
+ ...options.name !== void 0 ? { name: options.name } : {},
242
+ ...options.placement !== void 0 ? { placement: options.placement } : {}
243
+ },
244
+ requestOptions
245
+ );
246
+ }
247
+ };
248
+ var ComputerSessionResource = class {
249
+ constructor(transport, workspaceId, id) {
250
+ this.transport = transport;
251
+ this.workspaceId = workspaceId;
252
+ this.id = id;
253
+ this.targets = new ComputerTargetCollection(transport, workspaceId, id);
254
+ this.apps = this.targets;
255
+ }
256
+ targets;
257
+ /** Native application/window targets are also the public app collection. */
258
+ apps;
259
+ async get(options = {}) {
260
+ return await this.transport.getComputerSession(this.workspaceId, this.id, options);
261
+ }
262
+ async observe(targetId, options = {}) {
263
+ return await this.transport.observeComputerTarget(this.workspaceId, this.id, targetId, options);
264
+ }
265
+ async act(request, options = {}) {
266
+ return await this.transport.actInComputer(this.workspaceId, this.id, request, options);
267
+ }
268
+ async receipt(operationId, options = {}) {
269
+ return await this.transport.getComputerActionReceipt(
270
+ this.workspaceId,
271
+ this.id,
272
+ operationId,
273
+ options
274
+ );
275
+ }
276
+ async attach(request, options = {}) {
277
+ return await this.transport.attachComputerSession(this.workspaceId, this.id, request, options);
278
+ }
279
+ async heartbeat(options = {}) {
280
+ return await this.transport.heartbeatComputerSession(this.workspaceId, this.id, options);
281
+ }
282
+ async end(request = { operationId: crypto.randomUUID() }, options = {}) {
283
+ return await this.transport.endComputerSession(this.workspaceId, this.id, request, options);
284
+ }
285
+ };
286
+ var ComputerTargetCollection = class {
287
+ constructor(transport, workspaceId, computerSessionId) {
288
+ this.transport = transport;
289
+ this.workspaceId = workspaceId;
290
+ this.computerSessionId = computerSessionId;
291
+ }
292
+ async list(options = {}) {
293
+ return await this.transport.listComputerTargets(
294
+ this.workspaceId,
295
+ this.computerSessionId,
296
+ options
297
+ );
298
+ }
299
+ };
300
+ function browserFrameSocketUrl(attachment, options = {}) {
301
+ if (attachment.stream.kind !== "direct_websocket") {
302
+ throw new Error("relay browser attachments are opened through the relay protocol");
303
+ }
304
+ const url = new URL(attachment.stream.url);
305
+ if (url.protocol === "http:") url.protocol = "ws:";
306
+ else if (url.protocol === "https:") url.protocol = "wss:";
307
+ else if (url.protocol !== "ws:" && url.protocol !== "wss:") {
308
+ throw new Error("browser frame attachment did not contain an HTTP or WebSocket URL");
309
+ }
310
+ if (options.format !== void 0) url.searchParams.set("format", options.format);
311
+ setBoundedIntegerQuery(url, "quality", options.quality, 1, 100);
312
+ setBoundedIntegerQuery(url, "maxWidth", options.maxWidth, 1, 4096);
313
+ setBoundedIntegerQuery(url, "maxHeight", options.maxHeight, 1, 4096);
314
+ setBoundedIntegerQuery(url, "everyNthFrame", options.everyNthFrame, 1, 60);
315
+ return url.toString();
316
+ }
317
+ function computerFrameSocketUrl(attachment, options = {}) {
318
+ if (attachment.stream.kind !== "direct_websocket") {
319
+ throw new Error("relay computer attachments are opened through the relay protocol");
320
+ }
321
+ const url = new URL(attachment.stream.url);
322
+ if (url.protocol === "http:") url.protocol = "ws:";
323
+ else if (url.protocol === "https:") url.protocol = "wss:";
324
+ else if (url.protocol !== "ws:" && url.protocol !== "wss:") {
325
+ throw new Error("computer frame attachment did not contain an HTTP or WebSocket URL");
326
+ }
327
+ if (options.format !== void 0) url.searchParams.set("format", options.format);
328
+ setBoundedIntegerQuery(url, "quality", options.quality, 1, 100);
329
+ setBoundedIntegerQuery(url, "maxWidth", options.maxWidth, 1, 4096);
330
+ setBoundedIntegerQuery(url, "maxHeight", options.maxHeight, 1, 4096);
331
+ setBoundedIntegerQuery(url, "everyNthFrame", options.everyNthFrame, 1, 60);
332
+ return url.toString();
333
+ }
334
+ function decodeBrowserFrameMessage(message) {
335
+ const bytes = message instanceof Uint8Array ? message : new Uint8Array(message);
336
+ if (bytes.byteLength < 5 || bytes.byteLength > 4 + BROWSER_CONTROL_MAX_FRAME_HEADER_BYTES + BROWSER_FRAME_MAX_BYTES) {
337
+ throw new Error("browser frame message is truncated or too large");
338
+ }
339
+ const metadataLength = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength).getUint32(
340
+ 0,
341
+ false
342
+ );
343
+ if (metadataLength < 1 || metadataLength > BROWSER_CONTROL_MAX_FRAME_HEADER_BYTES || metadataLength + 4 >= bytes.byteLength) {
344
+ throw new Error("browser frame metadata length is invalid");
345
+ }
346
+ let value;
347
+ try {
348
+ value = JSON.parse(
349
+ new TextDecoder("utf-8", { fatal: true }).decode(bytes.subarray(4, 4 + metadataLength))
350
+ );
351
+ } catch {
352
+ throw new Error("browser frame metadata is invalid JSON");
353
+ }
354
+ const metadata = parseBrowserFrameMetadata(value);
355
+ const data = bytes.slice(4 + metadataLength);
356
+ if (data.byteLength < 1 || data.byteLength > BROWSER_FRAME_MAX_BYTES) {
357
+ throw new Error("browser frame image is empty or too large");
358
+ }
359
+ const dimensions = imageDimensions(data, metadata.mediaType);
360
+ if (dimensions.width !== metadata.width || dimensions.height !== metadata.height) {
361
+ throw new Error("browser frame image dimensions do not match metadata");
362
+ }
363
+ return { ...metadata, data };
364
+ }
365
+ async function decodeComputerFrameMessage(message) {
366
+ const bytes = message instanceof Uint8Array ? message : new Uint8Array(message);
367
+ if (bytes.byteLength < 5 || bytes.byteLength > 4 + BROWSER_CONTROL_MAX_FRAME_HEADER_BYTES + BROWSER_FRAME_MAX_BYTES) {
368
+ throw new Error("computer frame message is truncated or too large");
369
+ }
370
+ const metadataLength = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength).getUint32(
371
+ 0,
372
+ false
373
+ );
374
+ if (metadataLength < 1 || metadataLength > BROWSER_CONTROL_MAX_FRAME_HEADER_BYTES || metadataLength + 4 >= bytes.byteLength) {
375
+ throw new Error("computer frame metadata length is invalid");
376
+ }
377
+ let value;
378
+ try {
379
+ value = JSON.parse(
380
+ new TextDecoder("utf-8", { fatal: true }).decode(bytes.subarray(4, 4 + metadataLength))
381
+ );
382
+ } catch {
383
+ throw new Error("computer frame metadata is invalid JSON");
384
+ }
385
+ const metadata = parseComputerFrameMetadata(value);
386
+ const data = bytes.slice(4 + metadataLength);
387
+ if (data.byteLength < 1 || data.byteLength > BROWSER_FRAME_MAX_BYTES) {
388
+ throw new Error("computer frame image is empty or too large");
389
+ }
390
+ const dimensions = imageDimensions(data, metadata.mediaType);
391
+ if (dimensions.width !== metadata.width || dimensions.height !== metadata.height) {
392
+ throw new Error("computer frame image dimensions do not match metadata");
393
+ }
394
+ if (await sha256Hex(data) !== metadata.sha256) {
395
+ throw new Error("computer frame digest does not match image");
396
+ }
397
+ return { ...metadata, data };
398
+ }
399
+ function parseBrowserFrameMetadata(value) {
400
+ if (!isRecord(value)) throw new Error("browser frame metadata is invalid");
401
+ const allowed = /* @__PURE__ */ new Set([
402
+ "frameId",
403
+ "browserSessionId",
404
+ "controllerGeneration",
405
+ "targetId",
406
+ "targetGeneration",
407
+ "documentGeneration",
408
+ "sequence",
409
+ "mediaType",
410
+ "width",
411
+ "height",
412
+ "deviceScaleFactor",
413
+ "scrollX",
414
+ "scrollY",
415
+ "capturedAt"
416
+ ]);
417
+ if (Object.keys(value).some((key) => !allowed.has(key))) {
418
+ throw new Error("browser frame metadata contains unknown fields");
419
+ }
420
+ const strings = [
421
+ "frameId",
422
+ "browserSessionId",
423
+ "controllerGeneration",
424
+ "targetId",
425
+ "targetGeneration",
426
+ "documentGeneration",
427
+ "mediaType",
428
+ "capturedAt"
429
+ ];
430
+ for (const key of strings) {
431
+ const item = value[key];
432
+ const max = key === "targetId" ? 512 : key === "capturedAt" ? 128 : 256;
433
+ if (typeof item !== "string" || item.length < 1 || utf8Bytes(item) > max) {
434
+ throw new Error("browser frame metadata is invalid");
435
+ }
436
+ }
437
+ const numbers = [
438
+ "sequence",
439
+ "width",
440
+ "height",
441
+ "deviceScaleFactor",
442
+ "scrollX",
443
+ "scrollY"
444
+ ];
445
+ for (const key of numbers) {
446
+ if (typeof value[key] !== "number" || !Number.isFinite(value[key])) {
447
+ throw new Error("browser frame metadata is invalid");
448
+ }
449
+ }
450
+ const metadata = value;
451
+ if (!Number.isSafeInteger(metadata.sequence) || metadata.sequence < 0 || !Number.isSafeInteger(metadata.width) || !Number.isSafeInteger(metadata.height)) {
452
+ throw new Error("browser frame metadata integers are invalid");
453
+ }
454
+ assertImageDimensions(metadata.width, metadata.height);
455
+ if (metadata.deviceScaleFactor <= 0 || metadata.deviceScaleFactor > 16 || Math.abs(metadata.scrollX) > 1e9 || Math.abs(metadata.scrollY) > 1e9) {
456
+ throw new Error("browser frame geometry metadata is invalid");
457
+ }
458
+ if (metadata.mediaType !== "image/jpeg" && metadata.mediaType !== "image/png") {
459
+ throw new Error("browser frame media type is invalid");
460
+ }
461
+ if (!isUuid(metadata.browserSessionId)) throw new Error("browser frame session id is invalid");
462
+ if (!/^[A-Za-z0-9][A-Za-z0-9._:-]*$/u.test(metadata.controllerGeneration)) {
463
+ throw new Error("browser frame controller generation is invalid");
464
+ }
465
+ if (!Number.isFinite(new Date(metadata.capturedAt).valueOf())) {
466
+ throw new Error("browser frame timestamp is invalid");
467
+ }
468
+ return metadata;
469
+ }
470
+ function parseComputerFrameMetadata(value) {
471
+ if (!isRecord(value)) throw new Error("computer frame metadata is invalid");
472
+ const allowed = /* @__PURE__ */ new Set([
473
+ "frameId",
474
+ "computerSessionId",
475
+ "controllerGeneration",
476
+ "targetId",
477
+ "targetGeneration",
478
+ "sequence",
479
+ "mediaType",
480
+ "width",
481
+ "height",
482
+ "capturedAt",
483
+ "sha256"
484
+ ]);
485
+ if (Object.keys(value).some((key) => !allowed.has(key))) {
486
+ throw new Error("computer frame metadata contains unknown fields");
487
+ }
488
+ const strings = [
489
+ "frameId",
490
+ "computerSessionId",
491
+ "controllerGeneration",
492
+ "targetId",
493
+ "targetGeneration",
494
+ "mediaType",
495
+ "capturedAt",
496
+ "sha256"
497
+ ];
498
+ for (const key of strings) {
499
+ const item = value[key];
500
+ const max = key === "targetId" ? 512 : key === "capturedAt" ? 128 : 256;
501
+ if (typeof item !== "string" || item.length < 1 || utf8Bytes(item) > max) {
502
+ throw new Error("computer frame metadata is invalid");
503
+ }
504
+ }
505
+ const metadata = value;
506
+ if (!Number.isSafeInteger(metadata.sequence) || metadata.sequence < 0 || !Number.isSafeInteger(metadata.width) || !Number.isSafeInteger(metadata.height)) {
507
+ throw new Error("computer frame metadata integers are invalid");
508
+ }
509
+ assertImageDimensions(metadata.width, metadata.height);
510
+ if (metadata.mediaType !== "image/jpeg" && metadata.mediaType !== "image/png") {
511
+ throw new Error("computer frame media type is invalid");
512
+ }
513
+ if (!isUuid(metadata.computerSessionId)) {
514
+ throw new Error("computer frame session id is invalid");
515
+ }
516
+ if (!/^[A-Za-z0-9][A-Za-z0-9._:-]*$/u.test(metadata.controllerGeneration)) {
517
+ throw new Error("computer frame controller generation is invalid");
518
+ }
519
+ if (!Number.isFinite(new Date(metadata.capturedAt).valueOf())) {
520
+ throw new Error("computer frame timestamp is invalid");
521
+ }
522
+ if (!/^[0-9a-f]{64}$/u.test(metadata.sha256)) {
523
+ throw new Error("computer frame digest is invalid");
524
+ }
525
+ return metadata;
526
+ }
527
+ function newestRelevantBrowser(sessions, associationSessionId) {
528
+ const live = sessions.filter(
529
+ (session) => !["ending", "ended", "failed", "lost"].includes(session.lifecycle) && session.associations.some((association) => association.sessionId === associationSessionId)
530
+ );
531
+ live.sort(
532
+ (left, right) => browserRelevance(right, associationSessionId) - browserRelevance(left, associationSessionId)
533
+ );
534
+ return live[0] ?? null;
535
+ }
536
+ function newestRelevantComputer(sessions, associationSessionId) {
537
+ const live = sessions.filter(
538
+ (session) => ["starting", "active", "restoring"].includes(session.lifecycle) && session.associations.some((association) => association.sessionId === associationSessionId)
539
+ );
540
+ live.sort(
541
+ (left, right) => computerRelevance(right, associationSessionId) - computerRelevance(left, associationSessionId)
542
+ );
543
+ return live[0] ?? null;
544
+ }
545
+ function browserRelevance(session, associationSessionId) {
546
+ const association = session.associations.filter((item) => item.sessionId === associationSessionId).map((item) => Date.parse(item.lastUsedAt)).filter(Number.isFinite).reduce((best, timestamp) => Math.max(best, timestamp), 0);
547
+ const used = Date.parse(session.lastUsedAt);
548
+ return Math.max(association, Number.isFinite(used) ? used : 0);
549
+ }
550
+ function computerRelevance(session, associationSessionId) {
551
+ const association = session.associations.filter((item) => item.sessionId === associationSessionId).map((item) => Date.parse(item.lastUsedAt)).filter(Number.isFinite).reduce((best, timestamp) => Math.max(best, timestamp), 0);
552
+ const used = Date.parse(session.lastUsedAt);
553
+ return Math.max(association, Number.isFinite(used) ? used : 0);
554
+ }
555
+ function setBoundedIntegerQuery(url, name, value, min, max) {
556
+ if (value === void 0) return;
557
+ if (!Number.isSafeInteger(value) || value < min || value > max) {
558
+ throw new Error(`browser frame ${name} must be an integer between ${min} and ${max}`);
559
+ }
560
+ url.searchParams.set(name, String(value));
561
+ }
562
+ function imageDimensions(data, mediaType) {
563
+ const dimensions = mediaType === "image/png" ? pngDimensions(data) : jpegDimensions(data);
564
+ assertImageDimensions(dimensions.width, dimensions.height);
565
+ return dimensions;
566
+ }
567
+ function assertImageDimensions(width, height) {
568
+ if (!Number.isSafeInteger(width) || !Number.isSafeInteger(height) || width < 1 || height < 1 || width > BROWSER_FRAME_MAX_DIMENSION || height > BROWSER_FRAME_MAX_DIMENSION || width * height > BROWSER_FRAME_MAX_PIXELS) {
569
+ throw new Error("browser image dimensions exceed their bounded envelope");
570
+ }
571
+ }
572
+ function pngDimensions(data) {
573
+ const signature = [137, 80, 78, 71, 13, 10, 26, 10];
574
+ if (data.byteLength < 24 || !signature.every((byte, index) => data[index] === byte) || String.fromCharCode(...data.slice(12, 16)) !== "IHDR") {
575
+ throw new Error("browser returned an invalid PNG image");
576
+ }
577
+ const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
578
+ return { width: view.getUint32(16), height: view.getUint32(20) };
579
+ }
580
+ function jpegDimensions(data) {
581
+ if (data.byteLength < 4 || data[0] !== 255 || data[1] !== 216) {
582
+ throw new Error("browser returned an invalid JPEG image");
583
+ }
584
+ let offset = 2;
585
+ while (offset + 3 < data.byteLength) {
586
+ if (data[offset] !== 255) {
587
+ offset += 1;
588
+ continue;
589
+ }
590
+ let marker = data[offset + 1];
591
+ while (marker === 255) {
592
+ offset += 1;
593
+ marker = data[offset + 1];
594
+ }
595
+ if (marker === 216 || marker === 217 || marker === 1 || marker >= 208 && marker <= 215) {
596
+ offset += 2;
597
+ continue;
598
+ }
599
+ if (offset + 3 >= data.byteLength) break;
600
+ const length = data[offset + 2] << 8 | data[offset + 3];
601
+ if (length < 2 || offset + 2 + length > data.byteLength) break;
602
+ if (isJpegStartOfFrame(marker)) {
603
+ if (length < 7 || offset + 8 >= data.byteLength) break;
604
+ return {
605
+ height: data[offset + 5] << 8 | data[offset + 6],
606
+ width: data[offset + 7] << 8 | data[offset + 8]
607
+ };
608
+ }
609
+ offset += 2 + length;
610
+ }
611
+ throw new Error("browser returned a JPEG without dimensions");
612
+ }
613
+ function isJpegStartOfFrame(marker) {
614
+ return marker >= 192 && marker <= 195 || marker >= 197 && marker <= 199 || marker >= 201 && marker <= 203 || marker >= 205 && marker <= 207;
615
+ }
616
+ function utf8Bytes(value) {
617
+ return new TextEncoder().encode(value).byteLength;
618
+ }
619
+ async function sha256Hex(value) {
620
+ const subtle = globalThis.crypto?.subtle;
621
+ if (!subtle) throw new Error("computer frame digest verification is unavailable");
622
+ const copy = new Uint8Array(value.byteLength);
623
+ copy.set(value);
624
+ const digest = new Uint8Array(await subtle.digest("SHA-256", copy));
625
+ return [...digest].map((byte) => byte.toString(16).padStart(2, "0")).join("");
626
+ }
627
+ function isUuid(value) {
628
+ return /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/iu.test(value);
629
+ }
630
+ function isRecord(value) {
631
+ return typeof value === "object" && value !== null && !Array.isArray(value);
632
+ }
633
+
634
+ export {
635
+ INTERACTION_PROTOCOL_VERSION,
636
+ BROWSER_CONTROL_WEBSOCKET_PROTOCOL,
637
+ COMPUTER_CONTROL_WEBSOCKET_PROTOCOL,
638
+ BROWSER_CONTROL_WEBSOCKET_BEARER_PREFIX,
639
+ BROWSER_CONTROL_MAX_FRAME_HEADER_BYTES,
640
+ BROWSER_FRAME_MAX_BYTES,
641
+ BROWSER_FRAME_MAX_DIMENSION,
642
+ BROWSER_FRAME_MAX_PIXELS,
643
+ OpenGeniInteractionClient,
644
+ AttachedBrowserDeviceCollection,
645
+ AttachedBrowserDeviceResource,
646
+ BrowserIdentityCollection,
647
+ BrowserIdentityResource,
648
+ BrowserSessionCollection,
649
+ BrowserSessionResource,
650
+ BrowserTargetCollection,
651
+ ComputerSessionCollection,
652
+ ComputerSessionResource,
653
+ ComputerTargetCollection,
654
+ browserFrameSocketUrl,
655
+ computerFrameSocketUrl,
656
+ decodeBrowserFrameMessage,
657
+ decodeComputerFrameMessage,
658
+ parseBrowserFrameMetadata,
659
+ parseComputerFrameMetadata
660
+ };
661
+ //# sourceMappingURL=chunk-MZWTWOX6.js.map