@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.
- package/README.md +75 -3
- package/dist/index.d.ts +323 -175
- package/dist/index.js +441 -386
- package/dist/index.js.map +1 -1
- package/package.json +1 -2
- package/src/client.ts +0 -293
- package/src/errors.ts +0 -136
- package/src/http.test.ts +0 -374
- package/src/http.ts +0 -390
- package/src/index.ts +0 -564
- package/src/resources/admin.ts +0 -359
- package/src/resources/analytics.ts +0 -60
- package/src/resources/api-keys.ts +0 -135
- package/src/resources/audit-log.ts +0 -64
- package/src/resources/benchmarks.ts +0 -104
- package/src/resources/builder-sessions.ts +0 -75
- package/src/resources/channels.ts +0 -143
- package/src/resources/checkpoints.ts +0 -225
- package/src/resources/command-center.ts +0 -73
- package/src/resources/community.ts +0 -103
- package/src/resources/completions.ts +0 -104
- package/src/resources/computer-auto-stop.ts +0 -43
- package/src/resources/computer-env.ts +0 -76
- package/src/resources/computer-logs.ts +0 -50
- package/src/resources/computer-osa.ts +0 -76
- package/src/resources/computer-ports.ts +0 -91
- package/src/resources/computer-terminal.ts +0 -61
- package/src/resources/computer-volumes.ts +0 -64
- package/src/resources/computer.ts +0 -551
- package/src/resources/computers.ts +0 -75
- package/src/resources/credits.ts +0 -43
- package/src/resources/cron-jobs.ts +0 -191
- package/src/resources/custom_domains.ts +0 -123
- package/src/resources/dashboard.ts +0 -49
- package/src/resources/databases.ts +0 -218
- package/src/resources/deployments.test.ts +0 -194
- package/src/resources/deployments.ts +0 -1060
- package/src/resources/desktop.ts +0 -134
- package/src/resources/docker-deploy.test.ts +0 -102
- package/src/resources/docker-deploy.ts +0 -183
- package/src/resources/egress.test.ts +0 -318
- package/src/resources/egressAudit.ts +0 -245
- package/src/resources/egressNetwork.ts +0 -450
- package/src/resources/egressSecrets.ts +0 -577
- package/src/resources/email.ts +0 -212
- package/src/resources/embeddings.ts +0 -36
- package/src/resources/events.ts +0 -296
- package/src/resources/exec.ts +0 -319
- package/src/resources/external-keys.ts +0 -79
- package/src/resources/files.test.ts +0 -339
- package/src/resources/files.ts +0 -220
- package/src/resources/flat-custom-domains.ts +0 -127
- package/src/resources/functions.ts +0 -178
- package/src/resources/governance.test.ts +0 -355
- package/src/resources/governance.ts +0 -528
- package/src/resources/health-checks.ts +0 -165
- package/src/resources/integrations.ts +0 -183
- package/src/resources/mcp.ts +0 -70
- package/src/resources/models.ts +0 -45
- package/src/resources/network_policy.ts +0 -73
- package/src/resources/open-computers/agents.ts +0 -91
- package/src/resources/open-computers/apps.ts +0 -102
- package/src/resources/open-computers/clusters.ts +0 -88
- package/src/resources/open-computers/desktop.ts +0 -34
- package/src/resources/open-computers/files.ts +0 -97
- package/src/resources/open-computers/hosts.ts +0 -85
- package/src/resources/open-computers/index.ts +0 -98
- package/src/resources/open-computers/jobs.ts +0 -75
- package/src/resources/open-computers/open_computers.test.ts +0 -288
- package/src/resources/open-computers/secrets.ts +0 -115
- package/src/resources/open-computers/terminal.ts +0 -33
- package/src/resources/open-computers/tunnels.ts +0 -87
- package/src/resources/open-computers/types.ts +0 -343
- package/src/resources/open-computers/workspaces.ts +0 -135
- package/src/resources/org-invites.ts +0 -189
- package/src/resources/phase1.test.ts +0 -187
- package/src/resources/project-auth.ts +0 -142
- package/src/resources/project-integrations.ts +0 -133
- package/src/resources/provider-defaults.ts +0 -89
- package/src/resources/quotas.ts +0 -77
- package/src/resources/regions.ts +0 -94
- package/src/resources/sandbox-processes.ts +0 -112
- package/src/resources/sandbox-shares.ts +0 -83
- package/src/resources/sandbox-templates.ts +0 -195
- package/src/resources/sandboxes.live.test.ts +0 -92
- package/src/resources/sandboxes.test.ts +0 -653
- package/src/resources/sandboxes.ts +0 -1433
- package/src/resources/settings.ts +0 -143
- package/src/resources/snapshots-standalone.ts +0 -51
- package/src/resources/storage.ts +0 -221
- package/src/resources/tenant-events.ts +0 -32
- package/src/resources/tenant.ts +0 -148
- package/src/resources/usage.ts +0 -85
- package/src/resources/volumes.ts +0 -117
- package/src/resources/webhooks.ts +0 -224
- package/src/resources/workspace-invites.ts +0 -188
- package/src/resources/workspace-members.test.ts +0 -121
- package/src/resources/workspace-members.ts +0 -143
- package/src/resources/workspaces.ts +0 -285
- 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
|
-
});
|