@miosa/sdk 1.2.4 → 1.2.6

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 (100) hide show
  1. package/README.md +75 -3
  2. package/dist/index.d.ts +323 -175
  3. package/dist/index.js +441 -386
  4. package/dist/index.js.map +1 -1
  5. package/package.json +1 -2
  6. package/src/client.ts +0 -293
  7. package/src/errors.ts +0 -136
  8. package/src/http.test.ts +0 -374
  9. package/src/http.ts +0 -390
  10. package/src/index.ts +0 -564
  11. package/src/resources/admin.ts +0 -359
  12. package/src/resources/analytics.ts +0 -60
  13. package/src/resources/api-keys.ts +0 -135
  14. package/src/resources/audit-log.ts +0 -64
  15. package/src/resources/benchmarks.ts +0 -104
  16. package/src/resources/builder-sessions.ts +0 -75
  17. package/src/resources/channels.ts +0 -143
  18. package/src/resources/checkpoints.ts +0 -225
  19. package/src/resources/command-center.ts +0 -73
  20. package/src/resources/community.ts +0 -103
  21. package/src/resources/completions.ts +0 -104
  22. package/src/resources/computer-auto-stop.ts +0 -43
  23. package/src/resources/computer-env.ts +0 -76
  24. package/src/resources/computer-logs.ts +0 -50
  25. package/src/resources/computer-osa.ts +0 -76
  26. package/src/resources/computer-ports.ts +0 -91
  27. package/src/resources/computer-terminal.ts +0 -61
  28. package/src/resources/computer-volumes.ts +0 -64
  29. package/src/resources/computer.ts +0 -551
  30. package/src/resources/computers.ts +0 -75
  31. package/src/resources/credits.ts +0 -43
  32. package/src/resources/cron-jobs.ts +0 -191
  33. package/src/resources/custom_domains.ts +0 -123
  34. package/src/resources/dashboard.ts +0 -49
  35. package/src/resources/databases.ts +0 -218
  36. package/src/resources/deployments.test.ts +0 -194
  37. package/src/resources/deployments.ts +0 -1060
  38. package/src/resources/desktop.ts +0 -134
  39. package/src/resources/docker-deploy.test.ts +0 -102
  40. package/src/resources/docker-deploy.ts +0 -183
  41. package/src/resources/egress.test.ts +0 -318
  42. package/src/resources/egressAudit.ts +0 -245
  43. package/src/resources/egressNetwork.ts +0 -450
  44. package/src/resources/egressSecrets.ts +0 -577
  45. package/src/resources/email.ts +0 -212
  46. package/src/resources/embeddings.ts +0 -36
  47. package/src/resources/events.ts +0 -296
  48. package/src/resources/exec.ts +0 -319
  49. package/src/resources/external-keys.ts +0 -79
  50. package/src/resources/files.test.ts +0 -339
  51. package/src/resources/files.ts +0 -220
  52. package/src/resources/flat-custom-domains.ts +0 -127
  53. package/src/resources/functions.ts +0 -178
  54. package/src/resources/governance.test.ts +0 -355
  55. package/src/resources/governance.ts +0 -528
  56. package/src/resources/health-checks.ts +0 -165
  57. package/src/resources/integrations.ts +0 -183
  58. package/src/resources/mcp.ts +0 -70
  59. package/src/resources/models.ts +0 -45
  60. package/src/resources/network_policy.ts +0 -73
  61. package/src/resources/open-computers/agents.ts +0 -91
  62. package/src/resources/open-computers/apps.ts +0 -102
  63. package/src/resources/open-computers/clusters.ts +0 -88
  64. package/src/resources/open-computers/desktop.ts +0 -34
  65. package/src/resources/open-computers/files.ts +0 -97
  66. package/src/resources/open-computers/hosts.ts +0 -85
  67. package/src/resources/open-computers/index.ts +0 -98
  68. package/src/resources/open-computers/jobs.ts +0 -75
  69. package/src/resources/open-computers/open_computers.test.ts +0 -288
  70. package/src/resources/open-computers/secrets.ts +0 -115
  71. package/src/resources/open-computers/terminal.ts +0 -33
  72. package/src/resources/open-computers/tunnels.ts +0 -87
  73. package/src/resources/open-computers/types.ts +0 -343
  74. package/src/resources/open-computers/workspaces.ts +0 -135
  75. package/src/resources/org-invites.ts +0 -189
  76. package/src/resources/phase1.test.ts +0 -187
  77. package/src/resources/project-auth.ts +0 -142
  78. package/src/resources/project-integrations.ts +0 -133
  79. package/src/resources/provider-defaults.ts +0 -89
  80. package/src/resources/quotas.ts +0 -77
  81. package/src/resources/regions.ts +0 -94
  82. package/src/resources/sandbox-processes.ts +0 -112
  83. package/src/resources/sandbox-shares.ts +0 -83
  84. package/src/resources/sandbox-templates.ts +0 -195
  85. package/src/resources/sandboxes.live.test.ts +0 -92
  86. package/src/resources/sandboxes.test.ts +0 -653
  87. package/src/resources/sandboxes.ts +0 -1433
  88. package/src/resources/settings.ts +0 -143
  89. package/src/resources/snapshots-standalone.ts +0 -51
  90. package/src/resources/storage.ts +0 -221
  91. package/src/resources/tenant-events.ts +0 -32
  92. package/src/resources/tenant.ts +0 -148
  93. package/src/resources/usage.ts +0 -85
  94. package/src/resources/volumes.ts +0 -117
  95. package/src/resources/webhooks.ts +0 -224
  96. package/src/resources/workspace-invites.ts +0 -188
  97. package/src/resources/workspace-members.test.ts +0 -121
  98. package/src/resources/workspace-members.ts +0 -143
  99. package/src/resources/workspaces.ts +0 -285
  100. package/src/types.ts +0 -463
package/src/http.ts DELETED
@@ -1,390 +0,0 @@
1
- import { MiosaError, NetworkError, TimeoutError } from "./errors.js";
2
- import type { MiosaErrorBody } from "./errors.js";
3
-
4
- // ─── Transport tuning ─────────────────────────────────────────────────────────
5
- //
6
- // Node's built-in ``fetch`` is backed by undici and already reuses connections
7
- // via HTTP/1.1 keep-alive. We additionally try to install a custom undici
8
- // ``Agent`` with HTTP/2 enabled so sequential calls can multiplex on a single
9
- // TLS session and skip the per-call handshake tax (~80-150 ms cold,
10
- // ~20-40 ms warm).
11
- //
12
- // undici is an optional dependency: when not installed, we fall back to the
13
- // default fetch dispatcher (still pooled, just HTTP/1.1).
14
-
15
- interface UndiciAgentOptions {
16
- keepAliveTimeout?: number;
17
- keepAliveMaxTimeout?: number;
18
- allowH2?: boolean;
19
- connections?: number;
20
- }
21
-
22
- interface UndiciModule {
23
- Agent: new (opts: UndiciAgentOptions) => unknown;
24
- setGlobalDispatcher: (dispatcher: unknown) => void;
25
- }
26
-
27
- let _h2Configured = false;
28
- let _h2Available = false;
29
- let _agentSingleton: unknown = null;
30
-
31
- async function ensureHttp2Agent(): Promise<void> {
32
- if (_h2Configured) return;
33
- _h2Configured = true;
34
- try {
35
- // Indirection through a variable specifier prevents TypeScript from
36
- // trying to resolve the optional ``undici`` module at compile time.
37
- const undiciSpecifier = "undici";
38
- const undici = (await import(
39
- /* @vite-ignore */ undiciSpecifier
40
- )) as unknown as UndiciModule;
41
- const agent = new undici.Agent({
42
- keepAliveTimeout: 60_000,
43
- keepAliveMaxTimeout: 600_000,
44
- allowH2: true,
45
- connections: 20,
46
- });
47
- undici.setGlobalDispatcher(agent);
48
- _agentSingleton = agent;
49
- _h2Available = true;
50
- } catch {
51
- // undici not installed (e.g. browser bundle, or user opted out).
52
- // Fall back to native fetch's default keep-alive pool.
53
- _h2Available = false;
54
- }
55
- }
56
-
57
- // Fire-and-forget at module load. Subsequent fetch() calls will pick up the
58
- // configured dispatcher. Tests can re-import and observe ``isHttp2Configured``.
59
- const _h2Bootstrap = ensureHttp2Agent();
60
-
61
- /** Exposed for tests — resolves after the HTTP/2 agent setup completes. */
62
- export function whenTransportReady(): Promise<void> {
63
- return _h2Bootstrap;
64
- }
65
-
66
- /** Exposed for tests — true iff undici with allowH2 was installed. */
67
- export function isHttp2Available(): boolean {
68
- return _h2Available;
69
- }
70
-
71
- /** Exposed for tests — the cached undici Agent (or null). */
72
- export function getDispatcher(): unknown {
73
- return _agentSingleton;
74
- }
75
-
76
- export interface RequestOptions {
77
- method?: string;
78
- headers?: Record<string, string>;
79
- body?: unknown;
80
- timeout?: number;
81
- /** Return raw Response instead of parsing JSON */
82
- rawResponse?: boolean;
83
- /** Send body as multipart/form-data */
84
- formData?: FormData;
85
- /** Expected response is binary */
86
- binary?: boolean;
87
- }
88
-
89
- export interface HttpClientConfig {
90
- baseUrl: string;
91
- apiKey: string;
92
- timeout: number;
93
- maxRetries: number;
94
- }
95
-
96
- const DEFAULT_TIMEOUT = 30_000;
97
- const DEFAULT_MAX_RETRIES = 3;
98
- const RETRY_STATUS = new Set([429, 500, 502, 503, 504]);
99
- const BASE_DELAY_MS = 500;
100
-
101
- function sleep(ms: number): Promise<void> {
102
- return new Promise((resolve) => setTimeout(resolve, ms));
103
- }
104
-
105
- function retryDelay(attempt: number, retryAfterHeader: string | null): number {
106
- if (retryAfterHeader !== null) {
107
- const seconds = parseInt(retryAfterHeader, 10);
108
- if (!isNaN(seconds)) return seconds * 1000;
109
- }
110
- return BASE_DELAY_MS * 2 ** attempt + Math.random() * 100;
111
- }
112
-
113
- export class HttpClient {
114
- /** Public for WebSocket clients that need to derive their own URL. */
115
- readonly baseUrl: string;
116
- /** Public for WebSocket clients that need to send the same auth. */
117
- readonly apiKey: string;
118
- private readonly timeout: number;
119
- private readonly maxRetries: number;
120
-
121
- constructor(config: HttpClientConfig) {
122
- this.baseUrl = config.baseUrl.replace(/\/$/, "");
123
- this.apiKey = config.apiKey;
124
- this.timeout = config.timeout ?? DEFAULT_TIMEOUT;
125
- this.maxRetries = config.maxRetries ?? DEFAULT_MAX_RETRIES;
126
- }
127
-
128
- private buildUrl(
129
- path: string,
130
- query?: Record<string, string | number | boolean | undefined>,
131
- ): string {
132
- const url = new URL(`${this.baseUrl}${path}`);
133
- if (query) {
134
- for (const [key, value] of Object.entries(query)) {
135
- if (value !== undefined) {
136
- url.searchParams.set(key, String(value));
137
- }
138
- }
139
- }
140
- return url.toString();
141
- }
142
-
143
- private baseHeaders(extra?: Record<string, string>): Record<string, string> {
144
- return {
145
- Authorization: `Bearer ${this.apiKey}`,
146
- Accept: "application/json",
147
- "User-Agent": "@miosa/sdk/1.0.0",
148
- ...extra,
149
- };
150
- }
151
-
152
- async request<T>(path: string, options: RequestOptions = {}): Promise<T> {
153
- const {
154
- method = "GET",
155
- body,
156
- formData,
157
- binary = false,
158
- timeout = this.timeout,
159
- } = options;
160
-
161
- let headers = this.baseHeaders(options.headers);
162
-
163
- let fetchBody: BodyInit | undefined;
164
- if (formData) {
165
- fetchBody = formData;
166
- // Let fetch set Content-Type with boundary for multipart
167
- } else if (body !== undefined) {
168
- headers = { ...headers, "Content-Type": "application/json" };
169
- fetchBody = JSON.stringify(body);
170
- }
171
-
172
- let lastError: MiosaError | undefined;
173
-
174
- for (let attempt = 0; attempt <= this.maxRetries; attempt++) {
175
- const controller = new AbortController();
176
- const timer = setTimeout(() => controller.abort(), timeout);
177
-
178
- try {
179
- const response = await fetch(this.buildUrl(path), {
180
- method,
181
- headers,
182
- // exactOptionalPropertyTypes requires null, not undefined, for body
183
- body: fetchBody ?? null,
184
- signal: controller.signal,
185
- });
186
-
187
- clearTimeout(timer);
188
-
189
- if (!response.ok) {
190
- const requestId = response.headers.get("x-request-id") ?? undefined;
191
- const retryAfter = response.headers.get("retry-after");
192
-
193
- let errorBody: MiosaErrorBody = {};
194
- try {
195
- errorBody = (await response.json()) as MiosaErrorBody;
196
- } catch {
197
- // body may not be JSON on 5xx errors
198
- }
199
-
200
- const error = MiosaError.fromResponse(
201
- response.status,
202
- errorBody,
203
- requestId,
204
- );
205
-
206
- if (RETRY_STATUS.has(response.status) && attempt < this.maxRetries) {
207
- lastError = error;
208
- await sleep(retryDelay(attempt, retryAfter));
209
- continue;
210
- }
211
-
212
- throw error;
213
- }
214
-
215
- if (binary) {
216
- const buffer = await response.arrayBuffer();
217
- return new Uint8Array(buffer) as unknown as T;
218
- }
219
-
220
- // 204 No Content
221
- if (response.status === 204) {
222
- return undefined as unknown as T;
223
- }
224
-
225
- return (await response.json()) as T;
226
- } catch (err) {
227
- clearTimeout(timer);
228
-
229
- if (err instanceof MiosaError) {
230
- throw err;
231
- }
232
-
233
- if (err instanceof DOMException && err.name === "AbortError") {
234
- throw new TimeoutError(
235
- `Request to ${path} timed out after ${timeout}ms`,
236
- );
237
- }
238
-
239
- if (err instanceof TypeError) {
240
- const networkErr = new NetworkError(
241
- `Network error reaching ${path}: ${err.message}`,
242
- err,
243
- );
244
- if (attempt < this.maxRetries) {
245
- lastError = networkErr;
246
- await sleep(retryDelay(attempt, null));
247
- continue;
248
- }
249
- throw networkErr;
250
- }
251
-
252
- throw err;
253
- }
254
- }
255
-
256
- // Exhausted retries
257
- throw (
258
- lastError ??
259
- new MiosaError("Max retries exceeded", 0, "MAX_RETRIES_EXCEEDED")
260
- );
261
- }
262
-
263
- async get<T>(
264
- path: string,
265
- query?: Record<string, string | number | boolean | undefined>,
266
- ): Promise<T> {
267
- let fullPath = path;
268
- if (query) {
269
- const params = new URLSearchParams();
270
- for (const [k, v] of Object.entries(query)) {
271
- if (v !== undefined && v !== null) params.set(k, String(v));
272
- }
273
- const qs = params.toString();
274
- if (qs) fullPath = `${path}${path.includes("?") ? "&" : "?"}${qs}`;
275
- }
276
- return this.request<T>(fullPath, { method: "GET" });
277
- }
278
-
279
- async post<T>(path: string, body?: unknown): Promise<T> {
280
- return this.request<T>(path, { method: "POST", body });
281
- }
282
-
283
- async patch<T>(path: string, body?: unknown): Promise<T> {
284
- return this.request<T>(path, { method: "PATCH", body });
285
- }
286
-
287
- async put<T>(path: string, body?: unknown): Promise<T> {
288
- return this.request<T>(path, { method: "PUT", body });
289
- }
290
-
291
- async delete<T>(path: string, body?: unknown): Promise<T> {
292
- return this.request<T>(path, { method: "DELETE", body });
293
- }
294
-
295
- async getBinary(path: string): Promise<Uint8Array> {
296
- return this.request<Uint8Array>(path, { method: "GET", binary: true });
297
- }
298
-
299
- async postFormData<T>(path: string, formData: FormData): Promise<T> {
300
- return this.request<T>(path, { method: "POST", formData });
301
- }
302
-
303
- /**
304
- * Open a Server-Sent Events stream. Returns an AsyncIterableIterator of
305
- * parsed event data objects. The caller is responsible for breaking the loop.
306
- */
307
- async *stream<T>(
308
- path: string,
309
- options: RequestOptions = {},
310
- ): AsyncIterableIterator<T> {
311
- const method = options.method ?? "GET";
312
- let headers = this.baseHeaders({
313
- Accept: "text/event-stream",
314
- ...options.headers,
315
- });
316
- let body: BodyInit | null = null;
317
- if (options.body !== undefined) {
318
- headers = { ...headers, "Content-Type": "application/json" };
319
- body = JSON.stringify(options.body);
320
- }
321
-
322
- const controller = new AbortController();
323
-
324
- let response: Response;
325
- try {
326
- response = await fetch(`${this.baseUrl}${path}`, {
327
- method,
328
- headers,
329
- body,
330
- signal: controller.signal,
331
- });
332
- } catch (err) {
333
- if (err instanceof TypeError) {
334
- throw new NetworkError(
335
- `Network error opening SSE stream: ${err.message}`,
336
- err,
337
- );
338
- }
339
- throw err;
340
- }
341
-
342
- if (!response.ok) {
343
- let errorBody: MiosaErrorBody = {};
344
- try {
345
- errorBody = (await response.json()) as MiosaErrorBody;
346
- } catch {
347
- // ignore
348
- }
349
- throw MiosaError.fromResponse(
350
- response.status,
351
- errorBody,
352
- response.headers.get("x-request-id") ?? undefined,
353
- );
354
- }
355
-
356
- if (!response.body) {
357
- throw new MiosaError("SSE stream has no body", 0, "NO_STREAM_BODY");
358
- }
359
-
360
- const reader = response.body.getReader();
361
- const decoder = new TextDecoder();
362
- let buffer = "";
363
-
364
- try {
365
- while (true) {
366
- const { done, value } = await reader.read();
367
- if (done) break;
368
-
369
- buffer += decoder.decode(value, { stream: true });
370
- const lines = buffer.split("\n");
371
- buffer = lines.pop() ?? "";
372
-
373
- for (const line of lines) {
374
- if (line.startsWith("data:")) {
375
- const raw = line.slice(5).trim();
376
- if (raw === "[DONE]" || raw === "") continue;
377
- try {
378
- yield JSON.parse(raw) as T;
379
- } catch {
380
- // skip malformed SSE data lines
381
- }
382
- }
383
- }
384
- }
385
- } finally {
386
- controller.abort();
387
- reader.releaseLock();
388
- }
389
- }
390
- }