@miosa/sdk 1.2.5 → 1.2.7

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 (92) hide show
  1. package/README.md +107 -59
  2. package/dist/index.d.ts +513 -193
  3. package/dist/index.js +1266 -891
  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 -569
  11. package/src/resources/admin.ts +0 -348
  12. package/src/resources/analytics.ts +0 -60
  13. package/src/resources/api-keys.ts +0 -119
  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 -197
  37. package/src/resources/deployments.ts +0 -1208
  38. package/src/resources/desktop.ts +0 -134
  39. package/src/resources/devices.test.ts +0 -92
  40. package/src/resources/devices.ts +0 -291
  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/health-checks.ts +0 -165
  55. package/src/resources/integrations.ts +0 -183
  56. package/src/resources/mcp.ts +0 -70
  57. package/src/resources/models.ts +0 -45
  58. package/src/resources/network_policy.ts +0 -73
  59. package/src/resources/open-computers/agents.ts +0 -91
  60. package/src/resources/open-computers/apps.ts +0 -102
  61. package/src/resources/open-computers/clusters.ts +0 -88
  62. package/src/resources/open-computers/desktop.ts +0 -34
  63. package/src/resources/open-computers/files.ts +0 -97
  64. package/src/resources/open-computers/hosts.ts +0 -85
  65. package/src/resources/open-computers/index.ts +0 -98
  66. package/src/resources/open-computers/jobs.ts +0 -75
  67. package/src/resources/open-computers/open_computers.test.ts +0 -288
  68. package/src/resources/open-computers/secrets.ts +0 -115
  69. package/src/resources/open-computers/terminal.ts +0 -33
  70. package/src/resources/open-computers/tunnels.ts +0 -87
  71. package/src/resources/open-computers/types.ts +0 -343
  72. package/src/resources/open-computers/workspaces.ts +0 -135
  73. package/src/resources/org-invites.ts +0 -189
  74. package/src/resources/project-auth.ts +0 -142
  75. package/src/resources/project-integrations.ts +0 -133
  76. package/src/resources/provider-defaults.ts +0 -89
  77. package/src/resources/regions.ts +0 -94
  78. package/src/resources/sandbox-templates.ts +0 -195
  79. package/src/resources/sandboxes.live.test.ts +0 -92
  80. package/src/resources/sandboxes.test.ts +0 -655
  81. package/src/resources/sandboxes.ts +0 -1437
  82. package/src/resources/settings.ts +0 -143
  83. package/src/resources/snapshots-standalone.ts +0 -51
  84. package/src/resources/storage.ts +0 -221
  85. package/src/resources/tenant.ts +0 -66
  86. package/src/resources/usage.ts +0 -85
  87. package/src/resources/volumes.ts +0 -117
  88. package/src/resources/webhooks.ts +0 -239
  89. package/src/resources/workspace-invites.ts +0 -188
  90. package/src/resources/workspace-members.test.ts +0 -121
  91. package/src/resources/workspace-members.ts +0 -143
  92. package/src/types.ts +0 -463
package/src/http.test.ts DELETED
@@ -1,374 +0,0 @@
1
- import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
2
- import {
3
- AuthError,
4
- InsufficientCreditsError,
5
- MiosaError,
6
- NetworkError,
7
- NotFoundError,
8
- RateLimitError,
9
- TimeoutError,
10
- } from "./errors.js";
11
- import { HttpClient, isHttp2Available, whenTransportReady } from "./http.js";
12
-
13
- // Minimal fetch mock helpers
14
- function mockFetch(
15
- status: number,
16
- body: unknown,
17
- headers: Record<string, string> = {},
18
- ): void {
19
- const responseHeaders = new Headers({
20
- "content-type": "application/json",
21
- ...headers,
22
- });
23
- vi.stubGlobal(
24
- "fetch",
25
- vi.fn().mockResolvedValue({
26
- ok: status >= 200 && status < 300,
27
- status,
28
- headers: responseHeaders,
29
- json: () => Promise.resolve(body),
30
- arrayBuffer: () => Promise.resolve(new ArrayBuffer(0)),
31
- body: null,
32
- }),
33
- );
34
- }
35
-
36
- function mockFetchError(err: Error): void {
37
- vi.stubGlobal("fetch", vi.fn().mockRejectedValue(err));
38
- }
39
-
40
- function makeClient(
41
- overrides: Partial<ConstructorParameters<typeof HttpClient>[0]> = {},
42
- ): HttpClient {
43
- return new HttpClient({
44
- baseUrl: "https://api.miosa.ai/api/v1",
45
- apiKey: "msk_test_123",
46
- timeout: 5_000,
47
- maxRetries: 0, // no retries in unit tests by default
48
- ...overrides,
49
- });
50
- }
51
-
52
- describe("HttpClient", () => {
53
- beforeEach(() => {
54
- vi.useFakeTimers();
55
- });
56
-
57
- afterEach(() => {
58
- vi.restoreAllMocks();
59
- vi.useRealTimers();
60
- });
61
-
62
- describe("successful requests", () => {
63
- it("should send Authorization header with Bearer token", async () => {
64
- mockFetch(200, { id: "1" });
65
- const client = makeClient();
66
- await client.get("/computers");
67
-
68
- const [, init] = (fetch as ReturnType<typeof vi.fn>).mock.calls[0] as [
69
- string,
70
- RequestInit,
71
- ];
72
- const headers = init.headers as Record<string, string>;
73
- expect(headers["Authorization"]).toBe("Bearer msk_test_123");
74
- });
75
-
76
- it("should send Accept: application/json header", async () => {
77
- mockFetch(200, {});
78
- const client = makeClient();
79
- await client.get("/computers");
80
-
81
- const [, init] = (fetch as ReturnType<typeof vi.fn>).mock.calls[0] as [
82
- string,
83
- RequestInit,
84
- ];
85
- const headers = init.headers as Record<string, string>;
86
- expect(headers["Accept"]).toBe("application/json");
87
- });
88
-
89
- it("should parse and return JSON body on 200", async () => {
90
- const expected = { id: "abc", name: "test" };
91
- mockFetch(200, expected);
92
- const client = makeClient();
93
- const result = await client.get<typeof expected>("/computers/abc");
94
- expect(result).toEqual(expected);
95
- });
96
-
97
- it("should return undefined on 204 No Content", async () => {
98
- vi.stubGlobal(
99
- "fetch",
100
- vi.fn().mockResolvedValue({
101
- ok: true,
102
- status: 204,
103
- headers: new Headers(),
104
- json: () => Promise.reject(new Error("no body")),
105
- }),
106
- );
107
- const client = makeClient();
108
- const result = await client.delete("/computers/abc");
109
- expect(result).toBeUndefined();
110
- });
111
-
112
- it("should send JSON body on POST", async () => {
113
- mockFetch(201, { id: "new" });
114
- const client = makeClient();
115
- await client.post("/computers", { name: "my-vm" });
116
-
117
- const [, init] = (fetch as ReturnType<typeof vi.fn>).mock.calls[0] as [
118
- string,
119
- RequestInit,
120
- ];
121
- expect(init.method).toBe("POST");
122
- expect(init.body).toBe(JSON.stringify({ name: "my-vm" }));
123
- const headers = init.headers as Record<string, string>;
124
- expect(headers["Content-Type"]).toBe("application/json");
125
- });
126
-
127
- it("should append query params to GET URL", async () => {
128
- mockFetch(200, { data: [] });
129
- const client = makeClient();
130
- await client.get("/computers", { page: 2, per_page: 10 });
131
-
132
- const [url] = (fetch as ReturnType<typeof vi.fn>).mock.calls[0] as [
133
- string,
134
- ];
135
- expect(url).toContain("page=2");
136
- expect(url).toContain("per_page=10");
137
- });
138
-
139
- it("should omit undefined query params", async () => {
140
- mockFetch(200, { data: [] });
141
- const client = makeClient();
142
- await client.get("/computers", { page: undefined, per_page: 10 });
143
-
144
- const [url] = (fetch as ReturnType<typeof vi.fn>).mock.calls[0] as [
145
- string,
146
- ];
147
- // Match `page=` only as its own param (after `?` or `&`), so
148
- // `per_page=10` doesn't trip the assertion.
149
- expect(url).not.toMatch(/[?&]page=/);
150
- expect(url).toContain("per_page=10");
151
- });
152
- });
153
-
154
- describe("error mapping", () => {
155
- it("should throw AuthError on 401", async () => {
156
- mockFetch(401, {
157
- error: { code: "UNAUTHORIZED", message: "Invalid token" },
158
- });
159
- const client = makeClient();
160
- await expect(client.get("/me")).rejects.toBeInstanceOf(AuthError);
161
- });
162
-
163
- it("should throw AuthError on 403", async () => {
164
- mockFetch(403, {
165
- error: { code: "FORBIDDEN", message: "Access denied" },
166
- });
167
- const client = makeClient();
168
- await expect(client.get("/admin")).rejects.toBeInstanceOf(AuthError);
169
- });
170
-
171
- it("should throw NotFoundError on 404", async () => {
172
- mockFetch(404, {
173
- error: { code: "NOT_FOUND", message: "Computer not found" },
174
- });
175
- const client = makeClient();
176
- await expect(client.get("/computers/missing")).rejects.toBeInstanceOf(
177
- NotFoundError,
178
- );
179
- });
180
-
181
- it("should throw RateLimitError on 429", async () => {
182
- mockFetch(429, {
183
- error: { code: "RATE_LIMITED", message: "Too many requests" },
184
- });
185
- const client = makeClient();
186
- await expect(client.get("/computers")).rejects.toBeInstanceOf(
187
- RateLimitError,
188
- );
189
- });
190
-
191
- it("should throw InsufficientCreditsError on 402", async () => {
192
- mockFetch(402, {
193
- error: { code: "INSUFFICIENT_CREDITS", message: "No credits" },
194
- });
195
- const client = makeClient();
196
- await expect(client.post("/computers", {})).rejects.toBeInstanceOf(
197
- InsufficientCreditsError,
198
- );
199
- });
200
-
201
- it("should throw MiosaError with correct status on 500", async () => {
202
- mockFetch(500, {
203
- error: { code: "INTERNAL_ERROR", message: "Server error" },
204
- });
205
- const client = makeClient();
206
- const err = await client.get("/computers").catch((e: unknown) => e);
207
- expect(err).toBeInstanceOf(MiosaError);
208
- expect((err as MiosaError).status).toBe(500);
209
- });
210
-
211
- it("should include requestId from x-request-id header", async () => {
212
- mockFetch(
213
- 404,
214
- { error: { message: "Not found" } },
215
- { "x-request-id": "req_abc" },
216
- );
217
- const client = makeClient();
218
- const err = await client.get("/missing").catch((e: unknown) => e);
219
- expect((err as MiosaError).requestId).toBe("req_abc");
220
- });
221
- });
222
-
223
- describe("retry logic", () => {
224
- it("should retry on 429 up to maxRetries and then throw", async () => {
225
- const mockFn = vi.fn().mockResolvedValue({
226
- ok: false,
227
- status: 429,
228
- headers: new Headers({ "retry-after": "0" }),
229
- json: () => Promise.resolve({ error: { message: "rate limited" } }),
230
- });
231
- vi.stubGlobal("fetch", mockFn);
232
-
233
- const client = makeClient({ maxRetries: 2 });
234
-
235
- // Attach the rejection expectation BEFORE advancing fake timers —
236
- // otherwise the retry loop flushes and rejects during
237
- // `runAllTimersAsync`, and Vitest flags the rejection as unhandled.
238
- const promise = client.get("/computers");
239
- const assertion = expect(promise).rejects.toBeInstanceOf(RateLimitError);
240
- await vi.runAllTimersAsync();
241
- await assertion;
242
- expect(mockFn).toHaveBeenCalledTimes(3); // 1 initial + 2 retries
243
- });
244
-
245
- it("should retry on 503 and succeed on second attempt", async () => {
246
- const mockFn = vi
247
- .fn()
248
- .mockResolvedValueOnce({
249
- ok: false,
250
- status: 503,
251
- headers: new Headers(),
252
- json: () => Promise.resolve({ error: { message: "unavailable" } }),
253
- })
254
- .mockResolvedValueOnce({
255
- ok: true,
256
- status: 200,
257
- headers: new Headers(),
258
- json: () => Promise.resolve({ id: "recovered" }),
259
- });
260
- vi.stubGlobal("fetch", mockFn);
261
-
262
- const client = makeClient({ maxRetries: 2 });
263
- const promise = client.get<{ id: string }>("/computers");
264
- await vi.runAllTimersAsync();
265
-
266
- const result = await promise;
267
- expect(result.id).toBe("recovered");
268
- expect(mockFn).toHaveBeenCalledTimes(2);
269
- });
270
-
271
- it("should not retry on 400 validation errors", async () => {
272
- const mockFn = vi.fn().mockResolvedValue({
273
- ok: false,
274
- status: 400,
275
- headers: new Headers(),
276
- json: () => Promise.resolve({ error: { message: "bad request" } }),
277
- });
278
- vi.stubGlobal("fetch", mockFn);
279
-
280
- const client = makeClient({ maxRetries: 3 });
281
- await expect(client.post("/computers", {})).rejects.toBeInstanceOf(
282
- MiosaError,
283
- );
284
- expect(mockFn).toHaveBeenCalledTimes(1); // no retries
285
- });
286
- });
287
-
288
- describe("network errors", () => {
289
- it("should throw NetworkError on TypeError (connection refused)", async () => {
290
- mockFetchError(new TypeError("Failed to fetch"));
291
- const client = makeClient({ maxRetries: 0 });
292
- await expect(client.get("/computers")).rejects.toBeInstanceOf(
293
- NetworkError,
294
- );
295
- });
296
-
297
- it("should throw TimeoutError when AbortController fires", async () => {
298
- vi.stubGlobal(
299
- "fetch",
300
- vi
301
- .fn()
302
- .mockRejectedValue(
303
- Object.assign(
304
- new DOMException("The operation was aborted.", "AbortError"),
305
- {},
306
- ),
307
- ),
308
- );
309
- const client = makeClient({ maxRetries: 0 });
310
- await expect(client.get("/computers")).rejects.toBeInstanceOf(
311
- TimeoutError,
312
- );
313
- });
314
- });
315
- });
316
-
317
- describe("MiosaError", () => {
318
- it("should carry status, code, and message", () => {
319
- const err = new MiosaError("Something broke", 500, "INTERNAL_ERROR", {
320
- detail: true,
321
- });
322
- expect(err.status).toBe(500);
323
- expect(err.code).toBe("INTERNAL_ERROR");
324
- expect(err.message).toBe("Something broke");
325
- expect(err.details).toEqual({ detail: true });
326
- expect(err).toBeInstanceOf(Error);
327
- });
328
-
329
- it("fromResponse should map 401 → AuthError", () => {
330
- const err = MiosaError.fromResponse(401, {
331
- error: { message: "Unauthorized" },
332
- });
333
- expect(err).toBeInstanceOf(AuthError);
334
- });
335
-
336
- it("fromResponse should map 404 → NotFoundError", () => {
337
- const err = MiosaError.fromResponse(404, {
338
- error: { message: "Not found" },
339
- });
340
- expect(err).toBeInstanceOf(NotFoundError);
341
- expect(err.status).toBe(404);
342
- });
343
-
344
- it("fromResponse should map 429 → RateLimitError", () => {
345
- const err = MiosaError.fromResponse(429, {});
346
- expect(err).toBeInstanceOf(RateLimitError);
347
- });
348
-
349
- it("fromResponse should map 402 → InsufficientCreditsError", () => {
350
- const err = MiosaError.fromResponse(402, {});
351
- expect(err).toBeInstanceOf(InsufficientCreditsError);
352
- });
353
-
354
- it("fromResponse falls back to message key if no error object", () => {
355
- const err = MiosaError.fromResponse(500, {
356
- message: "raw message",
357
- code: "RAW",
358
- });
359
- expect(err.message).toBe("raw message");
360
- expect(err.code).toBe("RAW");
361
- });
362
- });
363
-
364
- describe("transport configuration", () => {
365
- it("should resolve whenTransportReady() without throwing", async () => {
366
- // The bootstrap promise must settle whether or not undici was found.
367
- await expect(whenTransportReady()).resolves.toBeUndefined();
368
- });
369
-
370
- it("isHttp2Available should return a boolean (no throw)", async () => {
371
- await whenTransportReady();
372
- expect(typeof isHttp2Available()).toBe("boolean");
373
- });
374
- });