@moxt-ai/mobius-sdk 0.0.3

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 (74) hide show
  1. package/README.md +31 -0
  2. package/dist/bot-owner-resources.d.ts +274 -0
  3. package/dist/bot-owner-resources.d.ts.map +1 -0
  4. package/dist/bot-owner-resources.js +748 -0
  5. package/dist/bot-owner-resources.js.map +1 -0
  6. package/dist/bot-resources.d.ts +152 -0
  7. package/dist/bot-resources.d.ts.map +1 -0
  8. package/dist/bot-resources.js +469 -0
  9. package/dist/bot-resources.js.map +1 -0
  10. package/dist/bot-service-client.d.ts +204 -0
  11. package/dist/bot-service-client.d.ts.map +1 -0
  12. package/dist/bot-service-client.js +587 -0
  13. package/dist/bot-service-client.js.map +1 -0
  14. package/dist/browser.d.ts +166 -0
  15. package/dist/browser.d.ts.map +1 -0
  16. package/dist/browser.js +379 -0
  17. package/dist/browser.js.map +1 -0
  18. package/dist/channel.d.ts +3 -0
  19. package/dist/channel.d.ts.map +1 -0
  20. package/dist/channel.js +3 -0
  21. package/dist/channel.js.map +1 -0
  22. package/dist/client.d.ts +116 -0
  23. package/dist/client.d.ts.map +1 -0
  24. package/dist/client.js +624 -0
  25. package/dist/client.js.map +1 -0
  26. package/dist/errors.d.ts +24 -0
  27. package/dist/errors.d.ts.map +1 -0
  28. package/dist/errors.js +47 -0
  29. package/dist/errors.js.map +1 -0
  30. package/dist/examples/browser.d.ts +13 -0
  31. package/dist/examples/browser.d.ts.map +1 -0
  32. package/dist/examples/browser.js +23 -0
  33. package/dist/examples/browser.js.map +1 -0
  34. package/dist/examples/moxt-server.d.ts +38 -0
  35. package/dist/examples/moxt-server.d.ts.map +1 -0
  36. package/dist/examples/moxt-server.js +81 -0
  37. package/dist/examples/moxt-server.js.map +1 -0
  38. package/dist/examples/node.d.ts +2 -0
  39. package/dist/examples/node.d.ts.map +1 -0
  40. package/dist/examples/node.js +20 -0
  41. package/dist/examples/node.js.map +1 -0
  42. package/dist/examples/platform-server.d.ts +2 -0
  43. package/dist/examples/platform-server.d.ts.map +1 -0
  44. package/dist/examples/platform-server.js +39 -0
  45. package/dist/examples/platform-server.js.map +1 -0
  46. package/dist/examples/workflow.d.ts +20 -0
  47. package/dist/examples/workflow.d.ts.map +1 -0
  48. package/dist/examples/workflow.js +76 -0
  49. package/dist/examples/workflow.js.map +1 -0
  50. package/dist/index.d.ts +10 -0
  51. package/dist/index.d.ts.map +1 -0
  52. package/dist/index.js +9 -0
  53. package/dist/index.js.map +1 -0
  54. package/dist/platform.d.ts +184 -0
  55. package/dist/platform.d.ts.map +1 -0
  56. package/dist/platform.js +434 -0
  57. package/dist/platform.js.map +1 -0
  58. package/dist/project-authentication.d.ts +239 -0
  59. package/dist/project-authentication.d.ts.map +1 -0
  60. package/dist/project-authentication.js +752 -0
  61. package/dist/project-authentication.js.map +1 -0
  62. package/dist/resources.d.ts +602 -0
  63. package/dist/resources.d.ts.map +1 -0
  64. package/dist/resources.js +1411 -0
  65. package/dist/resources.js.map +1 -0
  66. package/dist/server.d.ts +7 -0
  67. package/dist/server.d.ts.map +1 -0
  68. package/dist/server.js +7 -0
  69. package/dist/server.js.map +1 -0
  70. package/dist/service-client.d.ts +392 -0
  71. package/dist/service-client.d.ts.map +1 -0
  72. package/dist/service-client.js +1061 -0
  73. package/dist/service-client.js.map +1 -0
  74. package/package.json +92 -0
@@ -0,0 +1,1061 @@
1
+ import { decodeNativeSessionHistory, decodeNativeSessionResult, decodeSessionConfigUpdatedEvent, decodeSessionReadyEvent, decodeWorkspaceEntriesEvent, MOBIUS_API_PREFIX, MOBIUS_EVENT_FORMAT_VERSION, MOBIUS_SESSION_EVENT_STREAM_EVENT, MOBIUS_SESSION_EVENT_STREAM_MEDIA_TYPE, SessionPromptDisposition, } from "@moxt-ai/mobius-protocol";
2
+ import { MobiusApiError, MobiusCancellationError, MobiusConnectionError, MobiusError, MobiusProtocolError, MobiusTimeoutError, MobiusValidationError, } from "./errors.js";
3
+ import { decodeMobiusArtifact, decodeMobiusArtifactUpload, decodeMobiusAttempt, decodeMobiusAvailableArtifact, decodeMobiusBrowserCredential, decodeMobiusEventPage, decodeMobiusInteraction, decodeMobiusInteractionList, decodeMobiusMessagePage, decodeMobiusRuntimeList, decodeMobiusRuntimePairing, decodeMobiusRuntimePairingStatus, decodeMobiusServiceCapabilities, decodeMobiusSession, decodeMobiusSessionEvent, decodeMobiusSessionExport, decodeMobiusSessionPage, decodeMobiusSessionState, decodeMobiusToolCallDetail, decodeMobiusTurn, MobiusArtifactDownload, MobiusAvailableArtifact, MobiusPairedRuntimePairingStatus, MobiusRuntimePairingLifecycle, MobiusSessionAccess, } from "./resources.js";
4
+ const DEFAULT_OPERATION_TIMEOUT_MILLISECONDS = 20_000;
5
+ const DEFAULT_STREAM_CONNECTION_TIMEOUT_MILLISECONDS = 15_000;
6
+ const DEFAULT_STREAM_LIVENESS_TIMEOUT_MILLISECONDS = 45_000;
7
+ const DEFAULT_STREAM_RECONNECT_ATTEMPTS = 4;
8
+ const MAX_EVENT_BLOCK_LENGTH = 9 * 1024 * 1024;
9
+ export class StaticMobiusCredentialProvider {
10
+ #token;
11
+ constructor(token) {
12
+ this.#token = validateCredential(token);
13
+ }
14
+ credential = async (signal) => {
15
+ signal.throwIfAborted();
16
+ return this.#token;
17
+ };
18
+ }
19
+ function validateCredential(value) {
20
+ if (typeof value !== "string" ||
21
+ value.length < 1 ||
22
+ value.length > 4_096 ||
23
+ value.includes("\r") ||
24
+ value.includes("\n")) {
25
+ throw new MobiusValidationError("The Mobius credential is invalid");
26
+ }
27
+ return value;
28
+ }
29
+ class PlatformMobiusHttpTransport {
30
+ fetch = async (request) => await globalThis.fetch(request);
31
+ }
32
+ function validatePositiveInteger(value, name) {
33
+ if (!Number.isSafeInteger(value) || value < 1) {
34
+ throw new MobiusValidationError(`The ${name} is invalid`);
35
+ }
36
+ return value;
37
+ }
38
+ function normalizeEndpoint(value) {
39
+ let endpoint;
40
+ try {
41
+ endpoint = new URL(value);
42
+ }
43
+ catch (cause) {
44
+ throw new MobiusValidationError("The Mobius endpoint is invalid", {
45
+ cause,
46
+ });
47
+ }
48
+ if ((endpoint.protocol !== "http:" && endpoint.protocol !== "https:") ||
49
+ endpoint.username.length > 0 ||
50
+ endpoint.password.length > 0 ||
51
+ endpoint.search.length > 0 ||
52
+ endpoint.hash.length > 0) {
53
+ throw new MobiusValidationError("The Mobius endpoint is invalid");
54
+ }
55
+ if (endpoint.pathname === "/") {
56
+ endpoint.pathname = `${MOBIUS_API_PREFIX}/`;
57
+ }
58
+ else if (!endpoint.pathname.endsWith("/")) {
59
+ endpoint.pathname = `${endpoint.pathname}/`;
60
+ }
61
+ return endpoint;
62
+ }
63
+ function projectPath(projectId, resourcePath) {
64
+ if (!/^[a-zA-Z0-9][a-zA-Z0-9._:-]{0,127}$/.test(projectId)) {
65
+ throw new MobiusValidationError("The Mobius project identifier is invalid");
66
+ }
67
+ return `v1/projects/${encodeURIComponent(projectId)}/${resourcePath}`;
68
+ }
69
+ function sessionPath(projectId, sessionId, resourcePath) {
70
+ if (!/^[a-zA-Z0-9][a-zA-Z0-9._:-]{0,127}$/.test(sessionId)) {
71
+ throw new MobiusValidationError("The Mobius Session identifier is invalid");
72
+ }
73
+ return projectPath(projectId, `sessions/${encodeURIComponent(sessionId)}/${resourcePath}`);
74
+ }
75
+ function requestUrl(endpoint, path) {
76
+ return new URL(path, endpoint);
77
+ }
78
+ function isRecord(value) {
79
+ return typeof value === "object" && value !== null && !Array.isArray(value);
80
+ }
81
+ function record(value) {
82
+ if (!isRecord(value)) {
83
+ throw new MobiusProtocolError("The service returned an invalid error response");
84
+ }
85
+ return value;
86
+ }
87
+ async function responseValue(response) {
88
+ try {
89
+ return await response.json();
90
+ }
91
+ catch (cause) {
92
+ throw new MobiusProtocolError("The service returned invalid JSON", {
93
+ cause,
94
+ });
95
+ }
96
+ }
97
+ async function throwApiError(response) {
98
+ const value = record(await responseValue(response));
99
+ const error = record(value["error"]);
100
+ const code = error["code"];
101
+ const message = error["message"];
102
+ if (typeof code !== "string" || typeof message !== "string") {
103
+ throw new MobiusProtocolError("The service returned an invalid error response");
104
+ }
105
+ throw new MobiusApiError(code, message, response.status);
106
+ }
107
+ class RequestDeadline {
108
+ #controller = new AbortController();
109
+ #requestSignal;
110
+ #timeoutId;
111
+ #timedOut = false;
112
+ constructor(requestSignal, timeoutMilliseconds) {
113
+ this.#requestSignal = requestSignal;
114
+ if (requestSignal.aborted) {
115
+ this.#controller.abort(requestSignal.reason);
116
+ }
117
+ else {
118
+ requestSignal.addEventListener("abort", this.abortFromRequest, {
119
+ once: true,
120
+ });
121
+ }
122
+ this.#timeoutId = globalThis.setTimeout(this.abortFromTimeout, timeoutMilliseconds);
123
+ }
124
+ get signal() {
125
+ return this.#controller.signal;
126
+ }
127
+ finish = () => {
128
+ globalThis.clearTimeout(this.#timeoutId);
129
+ this.#requestSignal.removeEventListener("abort", this.abortFromRequest);
130
+ };
131
+ translate = (cause) => {
132
+ if (this.#requestSignal.aborted) {
133
+ throw new MobiusCancellationError({ cause });
134
+ }
135
+ if (this.#timedOut) {
136
+ throw new MobiusTimeoutError({ cause });
137
+ }
138
+ if (cause instanceof MobiusError) {
139
+ throw cause;
140
+ }
141
+ throw new MobiusConnectionError("The Mobius service could not be reached", {
142
+ cause,
143
+ });
144
+ };
145
+ abortFromRequest = () => {
146
+ this.#controller.abort(this.#requestSignal.reason);
147
+ };
148
+ abortFromTimeout = () => {
149
+ this.#timedOut = true;
150
+ this.#controller.abort(new Error("The Mobius operation timed out"));
151
+ };
152
+ }
153
+ class StreamConnection {
154
+ #closed = false;
155
+ #controller;
156
+ #hasActivity = false;
157
+ #livenessTimedOut = false;
158
+ #livenessTimeoutId;
159
+ #livenessTimeoutMilliseconds;
160
+ #release;
161
+ response;
162
+ constructor(response, controller, release, livenessTimeoutMilliseconds) {
163
+ this.#controller = controller;
164
+ this.#livenessTimeoutMilliseconds = livenessTimeoutMilliseconds;
165
+ this.#release = release;
166
+ this.response = response;
167
+ this.#livenessTimeoutId = globalThis.setTimeout(this.abortFromLivenessTimeout, this.#livenessTimeoutMilliseconds);
168
+ }
169
+ get hasActivity() {
170
+ return this.#hasActivity;
171
+ }
172
+ close = () => {
173
+ if (this.#closed) {
174
+ return;
175
+ }
176
+ this.#closed = true;
177
+ globalThis.clearTimeout(this.#livenessTimeoutId);
178
+ this.#controller.abort(new Error("The Mobius event connection closed"));
179
+ this.#release();
180
+ };
181
+ touch = () => {
182
+ if (this.#closed) {
183
+ return;
184
+ }
185
+ this.#hasActivity = true;
186
+ globalThis.clearTimeout(this.#livenessTimeoutId);
187
+ this.#livenessTimeoutId = globalThis.setTimeout(this.abortFromLivenessTimeout, this.#livenessTimeoutMilliseconds);
188
+ };
189
+ translateFailure = (cause) => {
190
+ if (this.#livenessTimedOut) {
191
+ throw new MobiusTimeoutError({ cause });
192
+ }
193
+ throw new MobiusConnectionError("The Mobius event stream was interrupted", {
194
+ cause,
195
+ });
196
+ };
197
+ abortFromLivenessTimeout = () => {
198
+ this.#livenessTimedOut = true;
199
+ this.#controller.abort(new Error("The Mobius event stream became inactive"));
200
+ };
201
+ }
202
+ export class MobiusRequestExecutor {
203
+ #authenticationProviderId;
204
+ #credentialProvider;
205
+ #endpoint;
206
+ #operationTimeoutMilliseconds;
207
+ #streamConnectionTimeoutMilliseconds;
208
+ #streamLivenessTimeoutMilliseconds;
209
+ #transport;
210
+ constructor(options) {
211
+ const authenticationProviderId = options.authenticationProviderId ?? "";
212
+ if (authenticationProviderId.length > 128 ||
213
+ authenticationProviderId.includes("\r") ||
214
+ authenticationProviderId.includes("\n")) {
215
+ throw new MobiusValidationError("The Mobius authentication provider identifier is invalid");
216
+ }
217
+ this.#authenticationProviderId = authenticationProviderId;
218
+ this.#credentialProvider = options.credentialProvider;
219
+ this.#endpoint = normalizeEndpoint(options.endpoint);
220
+ this.#operationTimeoutMilliseconds = validatePositiveInteger(options.operationTimeoutMilliseconds ?? DEFAULT_OPERATION_TIMEOUT_MILLISECONDS, "operation timeout");
221
+ this.#streamConnectionTimeoutMilliseconds = validatePositiveInteger(options.streamConnectionTimeoutMilliseconds ?? DEFAULT_STREAM_CONNECTION_TIMEOUT_MILLISECONDS, "stream connection timeout");
222
+ this.#streamLivenessTimeoutMilliseconds = validatePositiveInteger(options.streamLivenessTimeoutMilliseconds ?? DEFAULT_STREAM_LIVENESS_TIMEOUT_MILLISECONDS, "stream liveness timeout");
223
+ this.#transport = options.transport ?? new PlatformMobiusHttpTransport();
224
+ }
225
+ get = async (path, signal) => await this.request(path, "GET", "", false, signal);
226
+ post = async (path, body, signal) => {
227
+ const encoded = JSON.stringify(body);
228
+ if (typeof encoded !== "string") {
229
+ throw new MobiusValidationError("The Mobius request body is invalid");
230
+ }
231
+ return await this.request(path, "POST", encoded, true, signal);
232
+ };
233
+ put = async (path, body, signal) => {
234
+ const encoded = JSON.stringify(body);
235
+ if (typeof encoded !== "string") {
236
+ throw new MobiusValidationError("The Mobius request body is invalid");
237
+ }
238
+ return await this.request(path, "PUT", encoded, true, signal);
239
+ };
240
+ putBytes = async (path, bytes, mediaType, uploadToken, signal) => {
241
+ const deadline = new RequestDeadline(signal, this.#operationTimeoutMilliseconds);
242
+ try {
243
+ const credential = validateCredential(await this.#credentialProvider.credential(deadline.signal));
244
+ const headers = this.authenticationHeaders(credential, "application/json");
245
+ headers.set("content-type", mediaType);
246
+ headers.set("x-mobius-upload-token", validateCredential(uploadToken));
247
+ const response = await this.#transport.fetch(new Request(requestUrl(this.#endpoint, path), {
248
+ body: Uint8Array.from(bytes),
249
+ headers,
250
+ method: "PUT",
251
+ signal: deadline.signal,
252
+ }));
253
+ if (!response.ok) {
254
+ await throwApiError(response);
255
+ }
256
+ return await responseValue(response);
257
+ }
258
+ catch (cause) {
259
+ return deadline.translate(cause);
260
+ }
261
+ finally {
262
+ deadline.finish();
263
+ }
264
+ };
265
+ getBytes = async (path, artifact, signal) => {
266
+ const deadline = new RequestDeadline(signal, this.#operationTimeoutMilliseconds);
267
+ try {
268
+ const credential = validateCredential(await this.#credentialProvider.credential(deadline.signal));
269
+ const response = await this.#transport.fetch(new Request(requestUrl(this.#endpoint, path), {
270
+ headers: this.authenticationHeaders(credential, artifact.mediaType),
271
+ signal: deadline.signal,
272
+ }));
273
+ if (!response.ok) {
274
+ await throwApiError(response);
275
+ }
276
+ if (response.headers.get("content-type") !== artifact.mediaType ||
277
+ response.headers.get("x-mobius-artifact-id") !== artifact.artifactId ||
278
+ response.headers.get("x-mobius-sha256") !== artifact.sha256) {
279
+ throw new MobiusProtocolError("The service returned invalid artifact metadata");
280
+ }
281
+ return await readExactResponseBytes(response, artifact.byteLength, deadline.signal);
282
+ }
283
+ catch (cause) {
284
+ return deadline.translate(cause);
285
+ }
286
+ finally {
287
+ deadline.finish();
288
+ }
289
+ };
290
+ delete = async (path, signal) => await this.request(path, "DELETE", "", false, signal);
291
+ deleteEmpty = async (path, signal) => {
292
+ await this.requestEmpty(path, "DELETE", signal);
293
+ };
294
+ openEventStream = async (path, signal) => {
295
+ const controller = new AbortController();
296
+ let timedOut = false;
297
+ const abortFromRequest = () => controller.abort(signal.reason);
298
+ if (signal.aborted) {
299
+ abortFromRequest();
300
+ }
301
+ else {
302
+ signal.addEventListener("abort", abortFromRequest, { once: true });
303
+ }
304
+ const timeoutId = globalThis.setTimeout(() => {
305
+ timedOut = true;
306
+ controller.abort(new Error("The Mobius event stream timed out"));
307
+ }, this.#streamConnectionTimeoutMilliseconds);
308
+ const release = () => {
309
+ globalThis.clearTimeout(timeoutId);
310
+ signal.removeEventListener("abort", abortFromRequest);
311
+ };
312
+ let response;
313
+ try {
314
+ const credential = validateCredential(await this.#credentialProvider.credential(controller.signal));
315
+ response = await this.#transport.fetch(new Request(requestUrl(this.#endpoint, path), {
316
+ headers: this.authenticationHeaders(credential, MOBIUS_SESSION_EVENT_STREAM_MEDIA_TYPE),
317
+ signal: controller.signal,
318
+ }));
319
+ }
320
+ catch (cause) {
321
+ release();
322
+ if (signal.aborted) {
323
+ throw new MobiusCancellationError({ cause });
324
+ }
325
+ if (timedOut) {
326
+ throw new MobiusTimeoutError({ cause });
327
+ }
328
+ if (cause instanceof MobiusError) {
329
+ throw cause;
330
+ }
331
+ throw new MobiusConnectionError("The Mobius event stream could not connect", { cause });
332
+ }
333
+ if (!response.ok) {
334
+ try {
335
+ await throwApiError(response);
336
+ }
337
+ catch (cause) {
338
+ release();
339
+ if (signal.aborted) {
340
+ throw new MobiusCancellationError({ cause });
341
+ }
342
+ if (timedOut) {
343
+ throw new MobiusTimeoutError({ cause });
344
+ }
345
+ throw cause;
346
+ }
347
+ }
348
+ globalThis.clearTimeout(timeoutId);
349
+ const contentType = response.headers.get("content-type") ?? "";
350
+ if (!contentType.startsWith(MOBIUS_SESSION_EVENT_STREAM_MEDIA_TYPE) ||
351
+ response.headers.get("x-mobius-event-format") !== MOBIUS_EVENT_FORMAT_VERSION ||
352
+ response.body === null) {
353
+ controller.abort(new Error("The Mobius event stream is invalid"));
354
+ release();
355
+ throw new MobiusProtocolError("The service returned an invalid Session event stream");
356
+ }
357
+ return new StreamConnection(response, controller, release, this.#streamLivenessTimeoutMilliseconds);
358
+ };
359
+ request = async (path, method, body, hasBody, signal) => {
360
+ const deadline = new RequestDeadline(signal, this.#operationTimeoutMilliseconds);
361
+ try {
362
+ const credential = validateCredential(await this.#credentialProvider.credential(deadline.signal));
363
+ const headers = this.authenticationHeaders(credential, "application/json");
364
+ if (hasBody) {
365
+ headers.set("content-type", "application/json");
366
+ }
367
+ const response = await this.#transport.fetch(new Request(requestUrl(this.#endpoint, path), {
368
+ body: hasBody ? body : null,
369
+ headers,
370
+ method,
371
+ signal: deadline.signal,
372
+ }));
373
+ if (!response.ok) {
374
+ await throwApiError(response);
375
+ }
376
+ return await responseValue(response);
377
+ }
378
+ catch (cause) {
379
+ return deadline.translate(cause);
380
+ }
381
+ finally {
382
+ deadline.finish();
383
+ }
384
+ };
385
+ requestEmpty = async (path, method, signal) => {
386
+ const deadline = new RequestDeadline(signal, this.#operationTimeoutMilliseconds);
387
+ try {
388
+ const credential = validateCredential(await this.#credentialProvider.credential(deadline.signal));
389
+ const response = await this.#transport.fetch(new Request(requestUrl(this.#endpoint, path), {
390
+ headers: this.authenticationHeaders(credential, "application/json"),
391
+ method,
392
+ signal: deadline.signal,
393
+ }));
394
+ if (!response.ok) {
395
+ await throwApiError(response);
396
+ }
397
+ if (response.status !== 204) {
398
+ throw new MobiusProtocolError("The service returned an invalid empty response");
399
+ }
400
+ }
401
+ catch (cause) {
402
+ return deadline.translate(cause);
403
+ }
404
+ finally {
405
+ deadline.finish();
406
+ }
407
+ };
408
+ authenticationHeaders = (credential, accept) => {
409
+ const headers = new Headers({ accept, authorization: `Bearer ${credential}` });
410
+ if (this.#authenticationProviderId.length > 0) {
411
+ headers.set("x-mobius-oidc-provider", this.#authenticationProviderId);
412
+ }
413
+ return headers;
414
+ };
415
+ }
416
+ export async function readExactResponseBytes(response, expectedByteLength, signal) {
417
+ const declaredLength = response.headers.get("content-length");
418
+ if (declaredLength !== null &&
419
+ (!/^(0|[1-9][0-9]*)$/.test(declaredLength) || Number(declaredLength) !== expectedByteLength)) {
420
+ throw new MobiusProtocolError("The service returned an invalid artifact length");
421
+ }
422
+ const reader = response.body?.getReader();
423
+ if (reader === undefined) {
424
+ throw new MobiusProtocolError("The service returned no artifact content");
425
+ }
426
+ const chunks = [];
427
+ let byteLength = 0;
428
+ try {
429
+ while (true) {
430
+ signal.throwIfAborted();
431
+ const chunk = await reader.read();
432
+ signal.throwIfAborted();
433
+ if (chunk.done) {
434
+ break;
435
+ }
436
+ byteLength += chunk.value.byteLength;
437
+ if (byteLength > expectedByteLength) {
438
+ await reader.cancel("Artifact response exceeded its metadata");
439
+ throw new MobiusProtocolError("The service returned an oversized artifact");
440
+ }
441
+ chunks.push(chunk.value);
442
+ }
443
+ }
444
+ finally {
445
+ reader.releaseLock();
446
+ }
447
+ if (byteLength !== expectedByteLength) {
448
+ throw new MobiusProtocolError("The service returned an incomplete artifact");
449
+ }
450
+ const bytes = new Uint8Array(byteLength);
451
+ let offset = 0;
452
+ for (const chunk of chunks) {
453
+ bytes.set(chunk, offset);
454
+ offset += chunk.byteLength;
455
+ }
456
+ const digest = await crypto.subtle.digest("SHA-256", bytes);
457
+ signal.throwIfAborted();
458
+ const sha256 = Array.from(new Uint8Array(digest), (byte) => byte.toString(16).padStart(2, "0")).join("");
459
+ if (sha256 !== response.headers.get("x-mobius-sha256")) {
460
+ throw new MobiusProtocolError("The service returned artifact content with an invalid digest");
461
+ }
462
+ return bytes;
463
+ }
464
+ export class MobiusCapabilityResources {
465
+ #executor;
466
+ constructor(executor) {
467
+ this.#executor = executor;
468
+ }
469
+ read = async (signal) => decodeMobiusServiceCapabilities(await this.#executor.get("capabilities", signal));
470
+ }
471
+ export class MobiusArtifactResources {
472
+ #executor;
473
+ #projectId;
474
+ constructor(executor, projectId) {
475
+ this.#executor = executor;
476
+ this.#projectId = projectId;
477
+ }
478
+ createUpload = async (sessionId, request, signal) => decodeMobiusArtifactUpload(await this.#executor.post(sessionPath(this.#projectId, sessionId, "artifacts/uploads"), request, signal));
479
+ uploadContent = async (sessionId, upload, bytes, signal) => {
480
+ if (upload.sessionId !== sessionId || bytes.byteLength !== upload.byteLength) {
481
+ throw new MobiusValidationError("The artifact content does not match its upload authorization");
482
+ }
483
+ return decodeMobiusAvailableArtifact(await this.#executor.putBytes(sessionPath(this.#projectId, sessionId, `artifacts/${encodeURIComponent(upload.artifactId)}/content`), bytes, upload.mediaType, upload.uploadToken, signal));
484
+ };
485
+ read = async (sessionId, artifactId, signal) => decodeMobiusArtifact(await this.#executor.get(sessionPath(this.#projectId, sessionId, `artifacts/${encodeURIComponent(artifactId)}`), signal));
486
+ download = async (sessionId, artifactId, signal) => {
487
+ const artifact = await this.read(sessionId, artifactId, signal);
488
+ if (!(artifact instanceof MobiusAvailableArtifact)) {
489
+ throw new MobiusApiError("artifact_not_ready", "The artifact content is not available", 409);
490
+ }
491
+ const bytes = await this.#executor.getBytes(sessionPath(this.#projectId, sessionId, `artifacts/${encodeURIComponent(artifactId)}/content`), artifact, signal);
492
+ return new MobiusArtifactDownload(artifact, bytes);
493
+ };
494
+ }
495
+ export class MobiusCredentialResources {
496
+ #executor;
497
+ #projectId;
498
+ constructor(executor, projectId) {
499
+ this.#executor = executor;
500
+ this.#projectId = projectId;
501
+ }
502
+ issue = async (request, signal) => decodeMobiusBrowserCredential(await this.#executor.post(projectPath(this.#projectId, "browser-credentials"), request, signal));
503
+ revoke = async (credentialId, signal) => {
504
+ if (!/^[a-zA-Z0-9][a-zA-Z0-9._:-]{0,127}$/.test(credentialId)) {
505
+ throw new MobiusValidationError("The browser credential identifier is invalid");
506
+ }
507
+ await this.#executor.deleteEmpty(projectPath(this.#projectId, `browser-credentials/${encodeURIComponent(credentialId)}`), signal);
508
+ };
509
+ }
510
+ export class MobiusRuntimeResources {
511
+ #executor;
512
+ #projectId;
513
+ constructor(executor, projectId) {
514
+ this.#executor = executor;
515
+ this.#projectId = projectId;
516
+ }
517
+ list = async (signal) => decodeMobiusRuntimeList(await this.#executor.get(projectPath(this.#projectId, "runtimes"), signal));
518
+ listWorkspace = async (runtimeId, directoryId, signal) => decodeWorkspaceEntriesEvent(JSON.stringify(await this.#executor.post(projectPath(this.#projectId, `runtimes/${encodeURIComponent(runtimeId)}/workspace`), { directoryId }, signal)));
519
+ nativeSessions = async (runtimeId, request, signal) => decodeNativeSessionResult(JSON.stringify(await this.#executor.post(projectPath(this.#projectId, `runtimes/${encodeURIComponent(runtimeId)}/native-sessions`), request, signal)));
520
+ revoke = async (runtimeId, signal) => {
521
+ if (!/^[a-zA-Z0-9][a-zA-Z0-9._:-]{0,127}$/.test(runtimeId)) {
522
+ throw new MobiusValidationError("The Runtime identifier is invalid");
523
+ }
524
+ await this.#executor.deleteEmpty(projectPath(this.#projectId, `runtimes/${encodeURIComponent(runtimeId)}`), signal);
525
+ };
526
+ }
527
+ export class MobiusRuntimePairingResources {
528
+ #executor;
529
+ #projectId;
530
+ constructor(executor, projectId) {
531
+ this.#executor = executor;
532
+ this.#projectId = projectId;
533
+ }
534
+ create = async (request, signal) => decodeMobiusRuntimePairing(await this.#executor.post(projectPath(this.#projectId, "runtime-pairings"), request, signal));
535
+ read = async (pairingId, signal) => {
536
+ if (!/^[a-zA-Z0-9][a-zA-Z0-9._:-]{0,127}$/.test(pairingId)) {
537
+ throw new MobiusValidationError("The Runtime pairing identifier is invalid");
538
+ }
539
+ return decodeMobiusRuntimePairingStatus(await this.#executor.get(projectPath(this.#projectId, `runtime-pairings/${encodeURIComponent(pairingId)}`), signal));
540
+ };
541
+ waitUntilPaired = async (pairingId, options, signal) => {
542
+ const deadline = Date.now() + options.timeoutMilliseconds;
543
+ while (true) {
544
+ if (signal.aborted) {
545
+ throw new MobiusCancellationError({ cause: signal.reason });
546
+ }
547
+ const status = await this.read(pairingId, signal);
548
+ if (status instanceof MobiusPairedRuntimePairingStatus) {
549
+ return status;
550
+ }
551
+ if (status.status === MobiusRuntimePairingLifecycle.Expired) {
552
+ throw new MobiusApiError("runtime_pairing_expired", "The Runtime pairing expired", 410);
553
+ }
554
+ if (status.status === MobiusRuntimePairingLifecycle.Revoked) {
555
+ throw new MobiusApiError("runtime_pairing_revoked", "The Runtime pairing was revoked", 410);
556
+ }
557
+ const remaining = deadline - Date.now();
558
+ if (remaining <= 0) {
559
+ throw new MobiusTimeoutError();
560
+ }
561
+ await waitForPairingPoll(Math.min(options.pollIntervalMilliseconds, remaining), signal);
562
+ }
563
+ };
564
+ }
565
+ function waitForPairingPoll(milliseconds, signal) {
566
+ if (signal.aborted) {
567
+ return Promise.reject(new MobiusCancellationError({ cause: signal.reason }));
568
+ }
569
+ return new Promise((resolve, reject) => {
570
+ const timeout = globalThis.setTimeout(() => {
571
+ signal.removeEventListener("abort", cancel);
572
+ resolve();
573
+ }, milliseconds);
574
+ const cancel = () => {
575
+ globalThis.clearTimeout(timeout);
576
+ reject(new MobiusCancellationError({ cause: signal.reason }));
577
+ };
578
+ signal.addEventListener("abort", cancel, { once: true });
579
+ });
580
+ }
581
+ export class MobiusSessionResources {
582
+ #executor;
583
+ #projectId;
584
+ constructor(executor, projectId) {
585
+ this.#executor = executor;
586
+ this.#projectId = projectId;
587
+ }
588
+ create = async (request, signal) => decodeMobiusSession(await this.#executor.post(projectPath(this.#projectId, "sessions"), request, signal));
589
+ createAccess = async (sessionId, expiresInSeconds, signal) => new MobiusSessionAccess(await this.#executor.post(sessionPath(this.#projectId, sessionId, "access-credentials"), { expiresInSeconds }, signal));
590
+ prepare = async (sessionId, signal) => decodeSessionReadyEvent(JSON.stringify(await this.#executor.post(sessionPath(this.#projectId, sessionId, "prepare"), {}, signal)));
591
+ updateConfiguration = async (sessionId, request, signal) => decodeSessionConfigUpdatedEvent(JSON.stringify(await this.#executor.post(sessionPath(this.#projectId, sessionId, "configuration"), request, signal)));
592
+ configure = async (sessionId, request, signal) => decodeMobiusSession(await this.#executor.put(sessionPath(this.#projectId, sessionId, "binding"), request, signal));
593
+ delete = async (sessionId, signal) => decodeMobiusSessionState(await this.#executor.delete(sessionPath(this.#projectId, sessionId, "").slice(0, -1), signal));
594
+ export = async (sessionId, signal) => decodeMobiusSessionExport(await this.#executor.get(sessionPath(this.#projectId, sessionId, "export"), signal));
595
+ import = async (exported, targetBinding, signal) => decodeMobiusSession(await this.#executor.post(projectPath(this.#projectId, "session-imports"), {
596
+ formatVersion: exported.formatVersion,
597
+ session: exported.session,
598
+ targetBinding,
599
+ }, signal));
600
+ read = async (sessionId, signal) => decodeMobiusSession(await this.#executor.get(sessionPath(this.#projectId, sessionId, "").slice(0, -1), signal));
601
+ list = async (page, signal) => {
602
+ const path = requestUrl(new URL("https://mobius.invalid/"), projectPath(this.#projectId, "sessions"));
603
+ path.searchParams.set("limit", page.limit.toString());
604
+ if (page.cursor.length > 0) {
605
+ path.searchParams.set("cursor", page.cursor);
606
+ }
607
+ return decodeMobiusSessionPage(await this.#executor.get(`${path.pathname.slice(1)}${path.search}`, signal));
608
+ };
609
+ readMessages = async (sessionId, page, signal) => {
610
+ const path = requestUrl(new URL("https://mobius.invalid/"), sessionPath(this.#projectId, sessionId, "messages"));
611
+ path.searchParams.set("limit", page.limit.toString());
612
+ if (page.cursor.length > 0) {
613
+ path.searchParams.set("cursor", page.cursor);
614
+ }
615
+ return decodeMobiusMessagePage(await this.#executor.get(`${path.pathname.slice(1)}${path.search}`, signal));
616
+ };
617
+ readNativeHistory = async (sessionId, signal) => {
618
+ try {
619
+ return decodeNativeSessionHistory(await this.#executor.get(sessionPath(this.#projectId, sessionId, "native-history"), signal));
620
+ }
621
+ catch (cause) {
622
+ if (cause instanceof MobiusError) {
623
+ throw cause;
624
+ }
625
+ throw new MobiusProtocolError("The service returned invalid native Session history", { cause });
626
+ }
627
+ };
628
+ }
629
+ export class MobiusTurnResources {
630
+ #executor;
631
+ #projectId;
632
+ constructor(executor, projectId) {
633
+ this.#executor = executor;
634
+ this.#projectId = projectId;
635
+ }
636
+ submit = async (sessionId, request, signal) => decodeMobiusTurn(await this.#executor.post(sessionPath(this.#projectId, sessionId, "turns"), request, signal));
637
+ read = async (sessionId, turnId, signal) => decodeMobiusTurn(await this.#executor.get(sessionPath(this.#projectId, sessionId, `turns/${encodeURIComponent(turnId)}`), signal));
638
+ cancel = async (sessionId, turnId, request, signal) => decodeMobiusTurn(await this.#executor.post(sessionPath(this.#projectId, sessionId, `turns/${encodeURIComponent(turnId)}/cancel`), request, signal));
639
+ steer = async (sessionId, turnId, signal) => decodeMobiusTurn(await this.#executor.put(sessionPath(this.#projectId, sessionId, `turns/${encodeURIComponent(turnId)}/disposition`), { disposition: SessionPromptDisposition.Steer }, signal));
640
+ }
641
+ export class MobiusAttemptResources {
642
+ #executor;
643
+ #projectId;
644
+ constructor(executor, projectId) {
645
+ this.#executor = executor;
646
+ this.#projectId = projectId;
647
+ }
648
+ read = async (sessionId, attemptId, signal) => decodeMobiusAttempt(await this.#executor.get(sessionPath(this.#projectId, sessionId, `attempts/${encodeURIComponent(attemptId)}`), signal));
649
+ }
650
+ export class MobiusToolCallResources {
651
+ #executor;
652
+ #projectId;
653
+ constructor(executor, projectId) {
654
+ this.#executor = executor;
655
+ this.#projectId = projectId;
656
+ }
657
+ readDetail = async (sessionId, attemptId, toolCallId, signal) => decodeMobiusToolCallDetail(await this.#executor.get(sessionPath(this.#projectId, sessionId, `attempts/${encodeURIComponent(attemptId)}/tool-calls/${encodeURIComponent(toolCallId)}`), signal));
658
+ }
659
+ export class MobiusInteractionResources {
660
+ #executor;
661
+ #projectId;
662
+ constructor(executor, projectId) {
663
+ this.#executor = executor;
664
+ this.#projectId = projectId;
665
+ }
666
+ listPending = async (sessionId, signal) => decodeMobiusInteractionList(await this.#executor.get(sessionPath(this.#projectId, sessionId, "interactions"), signal));
667
+ read = async (sessionId, interactionId, signal) => decodeMobiusInteraction(await this.#executor.get(sessionPath(this.#projectId, sessionId, `interactions/${encodeURIComponent(interactionId)}`), signal));
668
+ respond = async (sessionId, interactionId, request, signal) => decodeMobiusInteraction(await this.#executor.post(sessionPath(this.#projectId, sessionId, `interactions/${encodeURIComponent(interactionId)}/responses`), request, signal));
669
+ }
670
+ export class MobiusEventSubscription {
671
+ #controller;
672
+ #executor;
673
+ #externalSignal;
674
+ #maximumReconnectAttempts;
675
+ #observer;
676
+ #path;
677
+ #cursorParameter;
678
+ #closed = false;
679
+ #cursor;
680
+ #hasSequence = false;
681
+ #lastSequence = 0n;
682
+ completed;
683
+ constructor(executor, path, cursor, observer, signal, controller, firstConnection, maximumReconnectAttempts, cursorParameter = "cursor") {
684
+ this.#cursor = cursor;
685
+ this.#controller = controller;
686
+ this.#executor = executor;
687
+ this.#externalSignal = signal;
688
+ this.#maximumReconnectAttempts = maximumReconnectAttempts;
689
+ this.#observer = observer;
690
+ this.#path = path;
691
+ this.#cursorParameter = cursorParameter;
692
+ if (this.#externalSignal.aborted) {
693
+ this.abortFromExternal();
694
+ }
695
+ else {
696
+ this.#externalSignal.addEventListener("abort", this.abortFromExternal, {
697
+ once: true,
698
+ });
699
+ }
700
+ this.completed = this.run(firstConnection).finally(() => {
701
+ this.#externalSignal.removeEventListener("abort", this.abortFromExternal);
702
+ });
703
+ }
704
+ get cursor() {
705
+ return this.#cursor;
706
+ }
707
+ close = () => {
708
+ if (this.#closed) {
709
+ return;
710
+ }
711
+ this.#closed = true;
712
+ this.#controller.abort(new Error("The Mobius event subscription closed"));
713
+ };
714
+ abortFromExternal = () => {
715
+ this.#controller.abort(this.#externalSignal.reason);
716
+ };
717
+ run = async (firstConnection) => {
718
+ let connection = firstConnection;
719
+ let reconnectAttempts = 0;
720
+ while (!this.#closed) {
721
+ try {
722
+ const stopped = await this.consume(connection);
723
+ connection.close();
724
+ if (stopped || this.#closed) {
725
+ this.#closed = true;
726
+ return;
727
+ }
728
+ throw new MobiusConnectionError("The Mobius event stream closed before the observer stopped it");
729
+ }
730
+ catch (cause) {
731
+ connection.close();
732
+ if (this.#closed) {
733
+ return;
734
+ }
735
+ if (connection.hasActivity) {
736
+ reconnectAttempts = 0;
737
+ }
738
+ try {
739
+ const recovery = await this.recover(cause, reconnectAttempts);
740
+ reconnectAttempts = recovery.attempts;
741
+ connection = recovery.connection;
742
+ }
743
+ catch (recoveryCause) {
744
+ if (this.#closed) {
745
+ return;
746
+ }
747
+ throw recoveryCause;
748
+ }
749
+ }
750
+ }
751
+ };
752
+ consume = async (connection) => {
753
+ const body = connection.response.body;
754
+ if (body === null) {
755
+ throw new MobiusProtocolError("The Mobius event stream has no body");
756
+ }
757
+ const reader = body.getReader();
758
+ const decoder = new TextDecoder();
759
+ let buffered = "";
760
+ try {
761
+ while (!this.#closed) {
762
+ const result = await reader.read();
763
+ if (result.done) {
764
+ buffered += decoder.decode();
765
+ if (buffered.trim().length > 0) {
766
+ throw new MobiusProtocolError("The Mobius event stream ended with an incomplete event");
767
+ }
768
+ return false;
769
+ }
770
+ connection.touch();
771
+ buffered += decoder.decode(result.value, { stream: true });
772
+ if (buffered.length > MAX_EVENT_BLOCK_LENGTH) {
773
+ throw new MobiusProtocolError("The Mobius event stream exceeded its event limit");
774
+ }
775
+ let boundary = buffered.indexOf("\n\n");
776
+ let boundaryLength = 2;
777
+ const carriageReturnBoundary = buffered.indexOf("\r\n\r\n");
778
+ if (carriageReturnBoundary >= 0 && (boundary < 0 || carriageReturnBoundary < boundary)) {
779
+ boundary = carriageReturnBoundary;
780
+ boundaryLength = 4;
781
+ }
782
+ while (boundary >= 0) {
783
+ const block = buffered.slice(0, boundary);
784
+ buffered = buffered.slice(boundary + boundaryLength);
785
+ if (await this.consumeBlock(block.replaceAll("\r\n", "\n"))) {
786
+ return true;
787
+ }
788
+ boundary = buffered.indexOf("\n\n");
789
+ boundaryLength = 2;
790
+ const nextCarriageReturnBoundary = buffered.indexOf("\r\n\r\n");
791
+ if (nextCarriageReturnBoundary >= 0 && (boundary < 0 || nextCarriageReturnBoundary < boundary)) {
792
+ boundary = nextCarriageReturnBoundary;
793
+ boundaryLength = 4;
794
+ }
795
+ }
796
+ }
797
+ return true;
798
+ }
799
+ catch (cause) {
800
+ if (this.#closed || this.#controller.signal.aborted) {
801
+ throw cause;
802
+ }
803
+ if (cause instanceof MobiusError) {
804
+ throw cause;
805
+ }
806
+ return connection.translateFailure(cause);
807
+ }
808
+ finally {
809
+ reader.releaseLock();
810
+ }
811
+ };
812
+ consumeBlock = async (block) => {
813
+ if (block.length === 0 || block.startsWith(":")) {
814
+ return false;
815
+ }
816
+ let eventName = "";
817
+ let eventId = "";
818
+ let data = "";
819
+ for (const line of block.split("\n")) {
820
+ if (line.startsWith("event:")) {
821
+ eventName = line.slice("event:".length).trimStart();
822
+ }
823
+ else if (line.startsWith("id:")) {
824
+ eventId = line.slice("id:".length).trimStart();
825
+ }
826
+ else if (line.startsWith("data:")) {
827
+ data += `${line.slice("data:".length).trimStart()}\n`;
828
+ }
829
+ else if (!line.startsWith(":")) {
830
+ throw new MobiusProtocolError("The Mobius event stream contains an invalid field");
831
+ }
832
+ }
833
+ if (eventName !== MOBIUS_SESSION_EVENT_STREAM_EVENT || data.length === 0) {
834
+ throw new MobiusProtocolError("The Mobius event stream contains an unsupported event");
835
+ }
836
+ let value;
837
+ try {
838
+ value = JSON.parse(data.slice(0, -1));
839
+ }
840
+ catch (cause) {
841
+ throw new MobiusProtocolError("The Mobius event stream contains invalid JSON", { cause });
842
+ }
843
+ const event = decodeMobiusSessionEvent(value);
844
+ if (event.cursor !== eventId) {
845
+ throw new MobiusProtocolError("The Mobius event identifier does not match its cursor");
846
+ }
847
+ const sequence = BigInt(event.sequence);
848
+ if (this.#hasSequence && sequence <= this.#lastSequence) {
849
+ return false;
850
+ }
851
+ if (this.#hasSequence && sequence !== this.#lastSequence + 1n) {
852
+ throw new MobiusProtocolError("The Mobius event stream contains a gap");
853
+ }
854
+ let shouldContinue;
855
+ try {
856
+ shouldContinue = await this.#observer.receive(event);
857
+ }
858
+ catch (cause) {
859
+ throw new MobiusError("event_observer_failed", "The Mobius event observer failed", { cause });
860
+ }
861
+ this.#cursor = event.cursor;
862
+ this.#hasSequence = true;
863
+ this.#lastSequence = sequence;
864
+ return !shouldContinue;
865
+ };
866
+ pathWithCursor = () => {
867
+ if (this.#cursor.length === 0) {
868
+ return this.#path;
869
+ }
870
+ return `${this.#path}?${this.#cursorParameter}=${encodeURIComponent(this.#cursor)}`;
871
+ };
872
+ recover = async (initialCause, completedAttempts) => {
873
+ this.throwIfTerminal(initialCause);
874
+ let attempts = completedAttempts;
875
+ let latestCause = initialCause;
876
+ while (attempts < this.#maximumReconnectAttempts) {
877
+ attempts += 1;
878
+ await this.reconnectDelay(attempts);
879
+ try {
880
+ return new MobiusEventStreamRecovery(await this.#executor.openEventStream(this.pathWithCursor(), this.#controller.signal), attempts);
881
+ }
882
+ catch (cause) {
883
+ latestCause = cause;
884
+ this.throwIfTerminal(cause);
885
+ }
886
+ }
887
+ throw new MobiusConnectionError("The Mobius event stream could not recover", { cause: latestCause });
888
+ };
889
+ throwIfTerminal = (cause) => {
890
+ if (this.#externalSignal.aborted) {
891
+ throw new MobiusCancellationError({ cause });
892
+ }
893
+ if (cause instanceof MobiusProtocolError ||
894
+ (cause instanceof MobiusApiError && cause.status < 500) ||
895
+ (cause instanceof MobiusError &&
896
+ !(cause instanceof MobiusConnectionError) &&
897
+ !(cause instanceof MobiusTimeoutError) &&
898
+ !(cause instanceof MobiusApiError))) {
899
+ throw cause;
900
+ }
901
+ };
902
+ reconnectDelay = async (attempt) => {
903
+ const delayMilliseconds = Math.min(250 * 2 ** (attempt - 1), 2_000);
904
+ await new Promise((resolve, reject) => {
905
+ const timeoutId = globalThis.setTimeout(() => {
906
+ this.#controller.signal.removeEventListener("abort", abort);
907
+ resolve();
908
+ }, delayMilliseconds);
909
+ const abort = () => {
910
+ globalThis.clearTimeout(timeoutId);
911
+ reject(new MobiusCancellationError());
912
+ };
913
+ this.#controller.signal.addEventListener("abort", abort, { once: true });
914
+ });
915
+ };
916
+ }
917
+ class MobiusEventStreamRecovery {
918
+ attempts;
919
+ connection;
920
+ constructor(connection, attempts) {
921
+ this.attempts = attempts;
922
+ this.connection = connection;
923
+ }
924
+ }
925
+ export class MobiusEventResources {
926
+ #executor;
927
+ #maximumReconnectAttempts;
928
+ #projectId;
929
+ #subscriptions = new Set();
930
+ constructor(executor, projectId, maximumReconnectAttempts) {
931
+ this.#executor = executor;
932
+ this.#maximumReconnectAttempts = maximumReconnectAttempts;
933
+ this.#projectId = projectId;
934
+ }
935
+ subscribe = async (sessionId, cursor, observer, signal) => {
936
+ if (cursor.length > 512) {
937
+ throw new MobiusValidationError("The Session event cursor is invalid");
938
+ }
939
+ const path = sessionPath(this.#projectId, sessionId, "events");
940
+ const streamPath = cursor.length === 0 ? path : `${path}?cursor=${encodeURIComponent(cursor)}`;
941
+ const controller = new AbortController();
942
+ const abortFromExternal = () => controller.abort(signal.reason);
943
+ if (signal.aborted) {
944
+ abortFromExternal();
945
+ }
946
+ else {
947
+ signal.addEventListener("abort", abortFromExternal, { once: true });
948
+ }
949
+ let firstConnection;
950
+ try {
951
+ firstConnection = await this.#executor.openEventStream(streamPath, controller.signal);
952
+ }
953
+ finally {
954
+ signal.removeEventListener("abort", abortFromExternal);
955
+ }
956
+ const subscription = new MobiusEventSubscription(this.#executor, path, cursor, observer, signal, controller, firstConnection, this.#maximumReconnectAttempts);
957
+ this.#subscriptions.add(subscription);
958
+ const remove = subscription.completed.finally(() => {
959
+ this.#subscriptions.delete(subscription);
960
+ });
961
+ void remove.catch(() => { });
962
+ return subscription;
963
+ };
964
+ list = async (sessionId, page, signal) => {
965
+ const path = requestUrl(new URL("https://mobius.invalid/"), sessionPath(this.#projectId, sessionId, "events"));
966
+ path.searchParams.set("limit", page.limit.toString());
967
+ if (page.cursor.length > 0) {
968
+ path.searchParams.set("cursor", page.cursor);
969
+ }
970
+ return decodeMobiusEventPage(await this.#executor.get(`${path.pathname.slice(1)}${path.search}`, signal));
971
+ };
972
+ close = () => {
973
+ for (const subscription of this.#subscriptions) {
974
+ subscription.close();
975
+ }
976
+ this.#subscriptions.clear();
977
+ };
978
+ }
979
+ export class MobiusFixedSessionEventResources {
980
+ #executor;
981
+ #maximumReconnectAttempts;
982
+ #subscriptions = new Set();
983
+ constructor(executor, maximumReconnectAttempts = DEFAULT_STREAM_RECONNECT_ATTEMPTS) {
984
+ this.#executor = executor;
985
+ this.#maximumReconnectAttempts = validatePositiveInteger(maximumReconnectAttempts, "stream reconnect attempt limit");
986
+ }
987
+ subscribe = async (cursor, observer, signal) => {
988
+ if (cursor.length > 512) {
989
+ throw new MobiusValidationError("The Session event cursor is invalid");
990
+ }
991
+ const path = "v1/client/session/events";
992
+ const streamPath = cursor.length === 0 ? path : `${path}?after=${encodeURIComponent(cursor)}`;
993
+ const controller = new AbortController();
994
+ const abortFromExternal = () => controller.abort(signal.reason);
995
+ if (signal.aborted) {
996
+ abortFromExternal();
997
+ }
998
+ else {
999
+ signal.addEventListener("abort", abortFromExternal, { once: true });
1000
+ }
1001
+ let firstConnection;
1002
+ try {
1003
+ firstConnection = await this.#executor.openEventStream(streamPath, controller.signal);
1004
+ }
1005
+ finally {
1006
+ signal.removeEventListener("abort", abortFromExternal);
1007
+ }
1008
+ const subscription = new MobiusEventSubscription(this.#executor, path, cursor, observer, signal, controller, firstConnection, this.#maximumReconnectAttempts, "after");
1009
+ this.#subscriptions.add(subscription);
1010
+ const remove = subscription.completed.finally(() => {
1011
+ this.#subscriptions.delete(subscription);
1012
+ });
1013
+ void remove.catch(() => { });
1014
+ return subscription;
1015
+ };
1016
+ list = async (page, signal) => {
1017
+ const query = new URLSearchParams({ limit: page.limit.toString() });
1018
+ if (page.cursor.length > 0) {
1019
+ query.set("after", page.cursor);
1020
+ }
1021
+ return decodeMobiusEventPage(await this.#executor.get(`v1/client/session/events?${query.toString()}`, signal));
1022
+ };
1023
+ close = () => {
1024
+ for (const subscription of this.#subscriptions) {
1025
+ subscription.close();
1026
+ }
1027
+ this.#subscriptions.clear();
1028
+ };
1029
+ }
1030
+ export class MobiusClient {
1031
+ artifacts;
1032
+ attempts;
1033
+ capabilities;
1034
+ credentials;
1035
+ events;
1036
+ interactions;
1037
+ runtimePairings;
1038
+ runtimes;
1039
+ sessions;
1040
+ turns;
1041
+ toolCalls;
1042
+ constructor(options) {
1043
+ const executor = new MobiusRequestExecutor(options);
1044
+ const reconnectAttempts = validatePositiveInteger(options.maxStreamReconnectAttempts ?? DEFAULT_STREAM_RECONNECT_ATTEMPTS, "stream reconnect attempt limit");
1045
+ this.artifacts = new MobiusArtifactResources(executor, options.projectId);
1046
+ this.attempts = new MobiusAttemptResources(executor, options.projectId);
1047
+ this.capabilities = new MobiusCapabilityResources(executor);
1048
+ this.credentials = new MobiusCredentialResources(executor, options.projectId);
1049
+ this.events = new MobiusEventResources(executor, options.projectId, reconnectAttempts);
1050
+ this.interactions = new MobiusInteractionResources(executor, options.projectId);
1051
+ this.runtimePairings = new MobiusRuntimePairingResources(executor, options.projectId);
1052
+ this.runtimes = new MobiusRuntimeResources(executor, options.projectId);
1053
+ this.sessions = new MobiusSessionResources(executor, options.projectId);
1054
+ this.turns = new MobiusTurnResources(executor, options.projectId);
1055
+ this.toolCalls = new MobiusToolCallResources(executor, options.projectId);
1056
+ }
1057
+ close = () => {
1058
+ this.events.close();
1059
+ };
1060
+ }
1061
+ //# sourceMappingURL=service-client.js.map