@arker-ai/sdk 0.6.3 → 0.7.0
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/dist/{chunk-7BHPVQNG.js → chunk-4NHUAVXK.js} +132 -10
- package/dist/{chunk-35IEV6BU.js → chunk-YFJEL7PF.js} +1 -1
- package/dist/cli.cjs +132 -10
- package/dist/cli.js +1 -1
- package/dist/daytona.cjs +132 -10
- package/dist/daytona.js +2 -2
- package/dist/e2b.cjs +132 -10
- package/dist/e2b.js +2 -2
- package/dist/index.cjs +132 -10
- package/dist/index.d.cts +103 -2
- package/dist/index.d.ts +103 -2
- package/dist/index.js +1 -1
- package/dist/modal.cjs +132 -10
- package/dist/modal.js +2 -2
- package/package.json +2 -2
|
@@ -56,6 +56,7 @@ var Arker = class {
|
|
|
56
56
|
provider;
|
|
57
57
|
apiKey;
|
|
58
58
|
fetchImpl;
|
|
59
|
+
http2;
|
|
59
60
|
retry;
|
|
60
61
|
constructor(opts = {}) {
|
|
61
62
|
const apiKey = opts.apiKey ?? env("ARKER_API_KEY") ?? env("AUTH_KEY");
|
|
@@ -77,6 +78,7 @@ var Arker = class {
|
|
|
77
78
|
this.region = region ? normalizeRegion(region) : void 0;
|
|
78
79
|
this.provider = effectiveProvider;
|
|
79
80
|
this.fetchImpl = opts.fetch ?? globalThis.fetch;
|
|
81
|
+
this.http2 = opts.fetch === void 0;
|
|
80
82
|
this.retry = normalizeRetry(opts.retry);
|
|
81
83
|
if (!this.fetchImpl) throw new Error("fetch is required in this runtime");
|
|
82
84
|
}
|
|
@@ -137,7 +139,10 @@ var Arker = class {
|
|
|
137
139
|
egress: src.egress ?? null,
|
|
138
140
|
disk: src.disk ?? true,
|
|
139
141
|
durable: src.durable ?? null,
|
|
140
|
-
resources
|
|
142
|
+
resources,
|
|
143
|
+
// ARK-125: omit to inherit the source's policy; pass a doc to override
|
|
144
|
+
// (an empty `{ policies: [] }` clears to allow-all, NOT inherit).
|
|
145
|
+
policies: src.policies ?? null
|
|
141
146
|
};
|
|
142
147
|
const useBurst = sourceOrgId === ARKER_ORG_ID && src.sourceVmName !== void 0 && isBurstRef(src.sourceVmName);
|
|
143
148
|
const baseUrl = useBurst && this.burstBaseUrl ? this.burstBaseUrl : this.baseUrl;
|
|
@@ -232,30 +237,29 @@ var Arker = class {
|
|
|
232
237
|
if (value !== void 0) headers[key] = value;
|
|
233
238
|
}
|
|
234
239
|
}
|
|
235
|
-
|
|
240
|
+
let requestBody;
|
|
236
241
|
if (body !== void 0) {
|
|
237
242
|
headers["content-type"] = "application/json";
|
|
238
|
-
|
|
243
|
+
requestBody = JSON.stringify(withoutUndefined(body));
|
|
239
244
|
}
|
|
240
245
|
let lastStatus = 0;
|
|
241
246
|
let lastText = "";
|
|
242
247
|
let lastError;
|
|
243
248
|
for (let attempt = 0; attempt < this.retry.attempts; attempt++) {
|
|
244
249
|
try {
|
|
245
|
-
const
|
|
246
|
-
const text = await response.text();
|
|
250
|
+
const { status, ok, text } = await sendRequest(url, { method, headers, body: requestBody }, this.fetchImpl, this.http2);
|
|
247
251
|
const payload = parseJson(text);
|
|
248
252
|
const parsedError = extractError(payload);
|
|
249
|
-
lastStatus =
|
|
253
|
+
lastStatus = status;
|
|
250
254
|
lastText = text;
|
|
251
255
|
lastError = parsedError;
|
|
252
|
-
if (isRetryable(
|
|
256
|
+
if (isRetryable(status, parsedError) && attempt < this.retry.attempts - 1) {
|
|
253
257
|
await sleep(retryDelay(this.retry, attempt));
|
|
254
258
|
continue;
|
|
255
259
|
}
|
|
256
|
-
if (parsedError) throw new ArkerError(parsedError.code, parsedError.message,
|
|
257
|
-
if (!
|
|
258
|
-
throw new ArkerError("internal", lastText.slice(0, 300) || `HTTP ${
|
|
260
|
+
if (parsedError) throw new ArkerError(parsedError.code, parsedError.message, status);
|
|
261
|
+
if (!ok) {
|
|
262
|
+
throw new ArkerError("internal", lastText.slice(0, 300) || `HTTP ${status}`, status);
|
|
259
263
|
}
|
|
260
264
|
return payload;
|
|
261
265
|
} catch (error) {
|
|
@@ -467,6 +471,32 @@ var VM = class _VM {
|
|
|
467
471
|
async delete() {
|
|
468
472
|
return this._client._request("DELETE", vmPath(this.id), void 0, this.baseUrl);
|
|
469
473
|
}
|
|
474
|
+
// ── ARK-125 egress policy ────────────────────────────────────────
|
|
475
|
+
/**
|
|
476
|
+
* Read this VM's outbound egress policy document (ARK-125). Returns an
|
|
477
|
+
* empty doc (`{}`) when no policy is set.
|
|
478
|
+
*/
|
|
479
|
+
async getPolicies() {
|
|
480
|
+
return this._client._request("GET", `${vmPath(this.id)}/policies`, void 0, this.baseUrl);
|
|
481
|
+
}
|
|
482
|
+
/**
|
|
483
|
+
* Replace this VM's outbound egress policy with `doc` — an ordered,
|
|
484
|
+
* first-match-wins rule list. An empty doc (`{}` or `{ policies: [] }`)
|
|
485
|
+
* clears the policy to allow-all. Returns the stored policy plus the
|
|
486
|
+
* domains it escalates to MITM and any degrade warnings.
|
|
487
|
+
*
|
|
488
|
+
* await vm.setPolicies({
|
|
489
|
+
* policies: [
|
|
490
|
+
* { type: "network.outbound",
|
|
491
|
+
* match: { domains: ["github.com"], ports: [443] },
|
|
492
|
+
* action: "allow" },
|
|
493
|
+
* { type: "network.outbound", action: "deny" },
|
|
494
|
+
* ],
|
|
495
|
+
* });
|
|
496
|
+
*/
|
|
497
|
+
async setPolicies(doc) {
|
|
498
|
+
return this._client._request("PUT", `${vmPath(this.id)}/policies`, doc, this.baseUrl);
|
|
499
|
+
}
|
|
470
500
|
// ── Syncs: bindings of a filesystem into this VM at a path ────────
|
|
471
501
|
async listSyncs(opts = {}) {
|
|
472
502
|
return this._client._request("GET", buildQuery(`${vmPath(this.id)}/syncs`, {
|
|
@@ -518,6 +548,20 @@ var VM = class _VM {
|
|
|
518
548
|
async deleteSession(sessionId) {
|
|
519
549
|
return this._client._request("DELETE", `${vmPath(this.id)}/sessions/${pathSegment(sessionId)}`, void 0, this.baseUrl);
|
|
520
550
|
}
|
|
551
|
+
/**
|
|
552
|
+
* Update a session via `PATCH /v1/vms/{id}/sessions/{sid}`: resize its PTY
|
|
553
|
+
* (`cols`/`rows`) and/or set the idle `timeoutSecs`. Works whether or not a
|
|
554
|
+
* PTY is currently attached — the REST equivalent of {@link PtyConnection.resize}
|
|
555
|
+
* (which sends an in-band control frame on the live WebSocket).
|
|
556
|
+
*/
|
|
557
|
+
async updateSession(sessionId, update) {
|
|
558
|
+
return this._client._request(
|
|
559
|
+
"PATCH",
|
|
560
|
+
`${vmPath(this.id)}/sessions/${pathSegment(sessionId)}`,
|
|
561
|
+
{ cols: update.cols, rows: update.rows, timeout_secs: update.timeoutSecs },
|
|
562
|
+
this.baseUrl
|
|
563
|
+
);
|
|
564
|
+
}
|
|
521
565
|
async connectPty(options = {}) {
|
|
522
566
|
const sessionId = options.sessionId ?? sessionIdFrom(await this.createSession());
|
|
523
567
|
const useTicket = options.useTicket ?? !isNodeRuntime();
|
|
@@ -929,6 +973,84 @@ function base64ToBytes(text) {
|
|
|
929
973
|
function bufferConstructor() {
|
|
930
974
|
return globalThis.Buffer;
|
|
931
975
|
}
|
|
976
|
+
var http2Module;
|
|
977
|
+
function loadHttp2() {
|
|
978
|
+
return http2Module ??= (async () => {
|
|
979
|
+
const proc = globalThis.process;
|
|
980
|
+
if (!proc?.versions?.node) return null;
|
|
981
|
+
try {
|
|
982
|
+
return await import(
|
|
983
|
+
/* webpackIgnore: true */
|
|
984
|
+
/* @vite-ignore */
|
|
985
|
+
"http2"
|
|
986
|
+
);
|
|
987
|
+
} catch {
|
|
988
|
+
return null;
|
|
989
|
+
}
|
|
990
|
+
})();
|
|
991
|
+
}
|
|
992
|
+
var HTTP2_REQUEST_TIMEOUT_MS = 12e4;
|
|
993
|
+
var Http2Connection = class {
|
|
994
|
+
confirmed = false;
|
|
995
|
+
streams = 0;
|
|
996
|
+
session;
|
|
997
|
+
constructor(http2, origin) {
|
|
998
|
+
this.session = http2.connect(origin);
|
|
999
|
+
this.session.on("error", () => {
|
|
1000
|
+
});
|
|
1001
|
+
}
|
|
1002
|
+
get closed() {
|
|
1003
|
+
return this.session.closed || this.session.destroyed;
|
|
1004
|
+
}
|
|
1005
|
+
request(method, path, headers, body) {
|
|
1006
|
+
if (this.streams === 0) this.session.ref();
|
|
1007
|
+
this.streams++;
|
|
1008
|
+
return new Promise((resolve, reject) => {
|
|
1009
|
+
const stream = this.session.request({ ...headers, ":method": method, ":path": path });
|
|
1010
|
+
let status = 0;
|
|
1011
|
+
let text = "";
|
|
1012
|
+
stream.setEncoding("utf8");
|
|
1013
|
+
stream.setTimeout(HTTP2_REQUEST_TIMEOUT_MS, () => stream.destroy(new Error("HTTP/2 request timed out")));
|
|
1014
|
+
stream.on("response", (responseHeaders) => {
|
|
1015
|
+
this.confirmed = true;
|
|
1016
|
+
status = Number(responseHeaders[":status"]) || 0;
|
|
1017
|
+
});
|
|
1018
|
+
stream.on("data", (chunk) => {
|
|
1019
|
+
text += chunk;
|
|
1020
|
+
});
|
|
1021
|
+
stream.on("end", () => resolve({ status, ok: status >= 200 && status < 300, text }));
|
|
1022
|
+
stream.on("error", reject);
|
|
1023
|
+
stream.end(body);
|
|
1024
|
+
}).finally(() => {
|
|
1025
|
+
if (--this.streams === 0) this.session.unref();
|
|
1026
|
+
});
|
|
1027
|
+
}
|
|
1028
|
+
};
|
|
1029
|
+
var http2Connections = /* @__PURE__ */ new Map();
|
|
1030
|
+
async function sendRequest(url, init, fetchImpl, http2Enabled) {
|
|
1031
|
+
if (http2Enabled) {
|
|
1032
|
+
const http2 = await loadHttp2();
|
|
1033
|
+
if (http2) {
|
|
1034
|
+
const { origin, pathname, search } = new URL(url);
|
|
1035
|
+
const cached = http2Connections.get(origin);
|
|
1036
|
+
if (cached !== null) {
|
|
1037
|
+
let connection = cached;
|
|
1038
|
+
if (!connection || connection.closed) {
|
|
1039
|
+
connection = new Http2Connection(http2, origin);
|
|
1040
|
+
http2Connections.set(origin, connection);
|
|
1041
|
+
}
|
|
1042
|
+
try {
|
|
1043
|
+
return await connection.request(init.method, `${pathname}${search}`, init.headers, init.body);
|
|
1044
|
+
} catch (error) {
|
|
1045
|
+
if (connection.confirmed) throw error;
|
|
1046
|
+
http2Connections.set(origin, null);
|
|
1047
|
+
}
|
|
1048
|
+
}
|
|
1049
|
+
}
|
|
1050
|
+
}
|
|
1051
|
+
const response = await fetchImpl(url, init);
|
|
1052
|
+
return { status: response.status, ok: response.ok, text: await response.text() };
|
|
1053
|
+
}
|
|
932
1054
|
|
|
933
1055
|
export {
|
|
934
1056
|
CHUNK_SIZE,
|
package/dist/cli.cjs
CHANGED
|
@@ -89,6 +89,7 @@ var Arker = class {
|
|
|
89
89
|
provider;
|
|
90
90
|
apiKey;
|
|
91
91
|
fetchImpl;
|
|
92
|
+
http2;
|
|
92
93
|
retry;
|
|
93
94
|
constructor(opts = {}) {
|
|
94
95
|
const apiKey = opts.apiKey ?? env("ARKER_API_KEY") ?? env("AUTH_KEY");
|
|
@@ -110,6 +111,7 @@ var Arker = class {
|
|
|
110
111
|
this.region = region ? normalizeRegion(region) : void 0;
|
|
111
112
|
this.provider = effectiveProvider;
|
|
112
113
|
this.fetchImpl = opts.fetch ?? globalThis.fetch;
|
|
114
|
+
this.http2 = opts.fetch === void 0;
|
|
113
115
|
this.retry = normalizeRetry(opts.retry);
|
|
114
116
|
if (!this.fetchImpl) throw new Error("fetch is required in this runtime");
|
|
115
117
|
}
|
|
@@ -170,7 +172,10 @@ var Arker = class {
|
|
|
170
172
|
egress: src.egress ?? null,
|
|
171
173
|
disk: src.disk ?? true,
|
|
172
174
|
durable: src.durable ?? null,
|
|
173
|
-
resources
|
|
175
|
+
resources,
|
|
176
|
+
// ARK-125: omit to inherit the source's policy; pass a doc to override
|
|
177
|
+
// (an empty `{ policies: [] }` clears to allow-all, NOT inherit).
|
|
178
|
+
policies: src.policies ?? null
|
|
174
179
|
};
|
|
175
180
|
const useBurst = sourceOrgId === ARKER_ORG_ID && src.sourceVmName !== void 0 && isBurstRef(src.sourceVmName);
|
|
176
181
|
const baseUrl = useBurst && this.burstBaseUrl ? this.burstBaseUrl : this.baseUrl;
|
|
@@ -265,30 +270,29 @@ var Arker = class {
|
|
|
265
270
|
if (value !== void 0) headers[key] = value;
|
|
266
271
|
}
|
|
267
272
|
}
|
|
268
|
-
|
|
273
|
+
let requestBody;
|
|
269
274
|
if (body !== void 0) {
|
|
270
275
|
headers["content-type"] = "application/json";
|
|
271
|
-
|
|
276
|
+
requestBody = JSON.stringify(withoutUndefined(body));
|
|
272
277
|
}
|
|
273
278
|
let lastStatus = 0;
|
|
274
279
|
let lastText = "";
|
|
275
280
|
let lastError;
|
|
276
281
|
for (let attempt = 0; attempt < this.retry.attempts; attempt++) {
|
|
277
282
|
try {
|
|
278
|
-
const
|
|
279
|
-
const text = await response.text();
|
|
283
|
+
const { status, ok, text } = await sendRequest(url, { method, headers, body: requestBody }, this.fetchImpl, this.http2);
|
|
280
284
|
const payload = parseJson(text);
|
|
281
285
|
const parsedError = extractError(payload);
|
|
282
|
-
lastStatus =
|
|
286
|
+
lastStatus = status;
|
|
283
287
|
lastText = text;
|
|
284
288
|
lastError = parsedError;
|
|
285
|
-
if (isRetryable(
|
|
289
|
+
if (isRetryable(status, parsedError) && attempt < this.retry.attempts - 1) {
|
|
286
290
|
await sleep(retryDelay(this.retry, attempt));
|
|
287
291
|
continue;
|
|
288
292
|
}
|
|
289
|
-
if (parsedError) throw new ArkerError(parsedError.code, parsedError.message,
|
|
290
|
-
if (!
|
|
291
|
-
throw new ArkerError("internal", lastText.slice(0, 300) || `HTTP ${
|
|
293
|
+
if (parsedError) throw new ArkerError(parsedError.code, parsedError.message, status);
|
|
294
|
+
if (!ok) {
|
|
295
|
+
throw new ArkerError("internal", lastText.slice(0, 300) || `HTTP ${status}`, status);
|
|
292
296
|
}
|
|
293
297
|
return payload;
|
|
294
298
|
} catch (error) {
|
|
@@ -500,6 +504,32 @@ var VM = class _VM {
|
|
|
500
504
|
async delete() {
|
|
501
505
|
return this._client._request("DELETE", vmPath(this.id), void 0, this.baseUrl);
|
|
502
506
|
}
|
|
507
|
+
// ── ARK-125 egress policy ────────────────────────────────────────
|
|
508
|
+
/**
|
|
509
|
+
* Read this VM's outbound egress policy document (ARK-125). Returns an
|
|
510
|
+
* empty doc (`{}`) when no policy is set.
|
|
511
|
+
*/
|
|
512
|
+
async getPolicies() {
|
|
513
|
+
return this._client._request("GET", `${vmPath(this.id)}/policies`, void 0, this.baseUrl);
|
|
514
|
+
}
|
|
515
|
+
/**
|
|
516
|
+
* Replace this VM's outbound egress policy with `doc` — an ordered,
|
|
517
|
+
* first-match-wins rule list. An empty doc (`{}` or `{ policies: [] }`)
|
|
518
|
+
* clears the policy to allow-all. Returns the stored policy plus the
|
|
519
|
+
* domains it escalates to MITM and any degrade warnings.
|
|
520
|
+
*
|
|
521
|
+
* await vm.setPolicies({
|
|
522
|
+
* policies: [
|
|
523
|
+
* { type: "network.outbound",
|
|
524
|
+
* match: { domains: ["github.com"], ports: [443] },
|
|
525
|
+
* action: "allow" },
|
|
526
|
+
* { type: "network.outbound", action: "deny" },
|
|
527
|
+
* ],
|
|
528
|
+
* });
|
|
529
|
+
*/
|
|
530
|
+
async setPolicies(doc) {
|
|
531
|
+
return this._client._request("PUT", `${vmPath(this.id)}/policies`, doc, this.baseUrl);
|
|
532
|
+
}
|
|
503
533
|
// ── Syncs: bindings of a filesystem into this VM at a path ────────
|
|
504
534
|
async listSyncs(opts = {}) {
|
|
505
535
|
return this._client._request("GET", buildQuery(`${vmPath(this.id)}/syncs`, {
|
|
@@ -551,6 +581,20 @@ var VM = class _VM {
|
|
|
551
581
|
async deleteSession(sessionId) {
|
|
552
582
|
return this._client._request("DELETE", `${vmPath(this.id)}/sessions/${pathSegment(sessionId)}`, void 0, this.baseUrl);
|
|
553
583
|
}
|
|
584
|
+
/**
|
|
585
|
+
* Update a session via `PATCH /v1/vms/{id}/sessions/{sid}`: resize its PTY
|
|
586
|
+
* (`cols`/`rows`) and/or set the idle `timeoutSecs`. Works whether or not a
|
|
587
|
+
* PTY is currently attached — the REST equivalent of {@link PtyConnection.resize}
|
|
588
|
+
* (which sends an in-band control frame on the live WebSocket).
|
|
589
|
+
*/
|
|
590
|
+
async updateSession(sessionId, update) {
|
|
591
|
+
return this._client._request(
|
|
592
|
+
"PATCH",
|
|
593
|
+
`${vmPath(this.id)}/sessions/${pathSegment(sessionId)}`,
|
|
594
|
+
{ cols: update.cols, rows: update.rows, timeout_secs: update.timeoutSecs },
|
|
595
|
+
this.baseUrl
|
|
596
|
+
);
|
|
597
|
+
}
|
|
554
598
|
async connectPty(options = {}) {
|
|
555
599
|
const sessionId = options.sessionId ?? sessionIdFrom(await this.createSession());
|
|
556
600
|
const useTicket = options.useTicket ?? !isNodeRuntime();
|
|
@@ -962,6 +1006,84 @@ function base64ToBytes(text) {
|
|
|
962
1006
|
function bufferConstructor() {
|
|
963
1007
|
return globalThis.Buffer;
|
|
964
1008
|
}
|
|
1009
|
+
var http2Module;
|
|
1010
|
+
function loadHttp2() {
|
|
1011
|
+
return http2Module ??= (async () => {
|
|
1012
|
+
const proc = globalThis.process;
|
|
1013
|
+
if (!proc?.versions?.node) return null;
|
|
1014
|
+
try {
|
|
1015
|
+
return await import(
|
|
1016
|
+
/* webpackIgnore: true */
|
|
1017
|
+
/* @vite-ignore */
|
|
1018
|
+
"http2"
|
|
1019
|
+
);
|
|
1020
|
+
} catch {
|
|
1021
|
+
return null;
|
|
1022
|
+
}
|
|
1023
|
+
})();
|
|
1024
|
+
}
|
|
1025
|
+
var HTTP2_REQUEST_TIMEOUT_MS = 12e4;
|
|
1026
|
+
var Http2Connection = class {
|
|
1027
|
+
confirmed = false;
|
|
1028
|
+
streams = 0;
|
|
1029
|
+
session;
|
|
1030
|
+
constructor(http2, origin) {
|
|
1031
|
+
this.session = http2.connect(origin);
|
|
1032
|
+
this.session.on("error", () => {
|
|
1033
|
+
});
|
|
1034
|
+
}
|
|
1035
|
+
get closed() {
|
|
1036
|
+
return this.session.closed || this.session.destroyed;
|
|
1037
|
+
}
|
|
1038
|
+
request(method, path, headers, body) {
|
|
1039
|
+
if (this.streams === 0) this.session.ref();
|
|
1040
|
+
this.streams++;
|
|
1041
|
+
return new Promise((resolve, reject) => {
|
|
1042
|
+
const stream = this.session.request({ ...headers, ":method": method, ":path": path });
|
|
1043
|
+
let status = 0;
|
|
1044
|
+
let text = "";
|
|
1045
|
+
stream.setEncoding("utf8");
|
|
1046
|
+
stream.setTimeout(HTTP2_REQUEST_TIMEOUT_MS, () => stream.destroy(new Error("HTTP/2 request timed out")));
|
|
1047
|
+
stream.on("response", (responseHeaders) => {
|
|
1048
|
+
this.confirmed = true;
|
|
1049
|
+
status = Number(responseHeaders[":status"]) || 0;
|
|
1050
|
+
});
|
|
1051
|
+
stream.on("data", (chunk) => {
|
|
1052
|
+
text += chunk;
|
|
1053
|
+
});
|
|
1054
|
+
stream.on("end", () => resolve({ status, ok: status >= 200 && status < 300, text }));
|
|
1055
|
+
stream.on("error", reject);
|
|
1056
|
+
stream.end(body);
|
|
1057
|
+
}).finally(() => {
|
|
1058
|
+
if (--this.streams === 0) this.session.unref();
|
|
1059
|
+
});
|
|
1060
|
+
}
|
|
1061
|
+
};
|
|
1062
|
+
var http2Connections = /* @__PURE__ */ new Map();
|
|
1063
|
+
async function sendRequest(url, init, fetchImpl, http2Enabled) {
|
|
1064
|
+
if (http2Enabled) {
|
|
1065
|
+
const http2 = await loadHttp2();
|
|
1066
|
+
if (http2) {
|
|
1067
|
+
const { origin, pathname, search } = new URL(url);
|
|
1068
|
+
const cached = http2Connections.get(origin);
|
|
1069
|
+
if (cached !== null) {
|
|
1070
|
+
let connection = cached;
|
|
1071
|
+
if (!connection || connection.closed) {
|
|
1072
|
+
connection = new Http2Connection(http2, origin);
|
|
1073
|
+
http2Connections.set(origin, connection);
|
|
1074
|
+
}
|
|
1075
|
+
try {
|
|
1076
|
+
return await connection.request(init.method, `${pathname}${search}`, init.headers, init.body);
|
|
1077
|
+
} catch (error) {
|
|
1078
|
+
if (connection.confirmed) throw error;
|
|
1079
|
+
http2Connections.set(origin, null);
|
|
1080
|
+
}
|
|
1081
|
+
}
|
|
1082
|
+
}
|
|
1083
|
+
}
|
|
1084
|
+
const response = await fetchImpl(url, init);
|
|
1085
|
+
return { status: response.status, ok: response.ok, text: await response.text() };
|
|
1086
|
+
}
|
|
965
1087
|
|
|
966
1088
|
// src/cli.ts
|
|
967
1089
|
var import_meta = {};
|
package/dist/cli.js
CHANGED
package/dist/daytona.cjs
CHANGED
|
@@ -162,6 +162,7 @@ var Arker = class {
|
|
|
162
162
|
provider;
|
|
163
163
|
apiKey;
|
|
164
164
|
fetchImpl;
|
|
165
|
+
http2;
|
|
165
166
|
retry;
|
|
166
167
|
constructor(opts = {}) {
|
|
167
168
|
const apiKey = opts.apiKey ?? env("ARKER_API_KEY") ?? env("AUTH_KEY");
|
|
@@ -183,6 +184,7 @@ var Arker = class {
|
|
|
183
184
|
this.region = region ? normalizeRegion(region) : void 0;
|
|
184
185
|
this.provider = effectiveProvider;
|
|
185
186
|
this.fetchImpl = opts.fetch ?? globalThis.fetch;
|
|
187
|
+
this.http2 = opts.fetch === void 0;
|
|
186
188
|
this.retry = normalizeRetry(opts.retry);
|
|
187
189
|
if (!this.fetchImpl) throw new Error("fetch is required in this runtime");
|
|
188
190
|
}
|
|
@@ -243,7 +245,10 @@ var Arker = class {
|
|
|
243
245
|
egress: src.egress ?? null,
|
|
244
246
|
disk: src.disk ?? true,
|
|
245
247
|
durable: src.durable ?? null,
|
|
246
|
-
resources
|
|
248
|
+
resources,
|
|
249
|
+
// ARK-125: omit to inherit the source's policy; pass a doc to override
|
|
250
|
+
// (an empty `{ policies: [] }` clears to allow-all, NOT inherit).
|
|
251
|
+
policies: src.policies ?? null
|
|
247
252
|
};
|
|
248
253
|
const useBurst = sourceOrgId === ARKER_ORG_ID && src.sourceVmName !== void 0 && isBurstRef(src.sourceVmName);
|
|
249
254
|
const baseUrl = useBurst && this.burstBaseUrl ? this.burstBaseUrl : this.baseUrl;
|
|
@@ -338,30 +343,29 @@ var Arker = class {
|
|
|
338
343
|
if (value !== void 0) headers[key] = value;
|
|
339
344
|
}
|
|
340
345
|
}
|
|
341
|
-
|
|
346
|
+
let requestBody;
|
|
342
347
|
if (body !== void 0) {
|
|
343
348
|
headers["content-type"] = "application/json";
|
|
344
|
-
|
|
349
|
+
requestBody = JSON.stringify(withoutUndefined(body));
|
|
345
350
|
}
|
|
346
351
|
let lastStatus = 0;
|
|
347
352
|
let lastText = "";
|
|
348
353
|
let lastError;
|
|
349
354
|
for (let attempt = 0; attempt < this.retry.attempts; attempt++) {
|
|
350
355
|
try {
|
|
351
|
-
const
|
|
352
|
-
const text = await response.text();
|
|
356
|
+
const { status, ok, text } = await sendRequest(url, { method, headers, body: requestBody }, this.fetchImpl, this.http2);
|
|
353
357
|
const payload = parseJson(text);
|
|
354
358
|
const parsedError = extractError(payload);
|
|
355
|
-
lastStatus =
|
|
359
|
+
lastStatus = status;
|
|
356
360
|
lastText = text;
|
|
357
361
|
lastError = parsedError;
|
|
358
|
-
if (isRetryable(
|
|
362
|
+
if (isRetryable(status, parsedError) && attempt < this.retry.attempts - 1) {
|
|
359
363
|
await sleep(retryDelay(this.retry, attempt));
|
|
360
364
|
continue;
|
|
361
365
|
}
|
|
362
|
-
if (parsedError) throw new ArkerError(parsedError.code, parsedError.message,
|
|
363
|
-
if (!
|
|
364
|
-
throw new ArkerError("internal", lastText.slice(0, 300) || `HTTP ${
|
|
366
|
+
if (parsedError) throw new ArkerError(parsedError.code, parsedError.message, status);
|
|
367
|
+
if (!ok) {
|
|
368
|
+
throw new ArkerError("internal", lastText.slice(0, 300) || `HTTP ${status}`, status);
|
|
365
369
|
}
|
|
366
370
|
return payload;
|
|
367
371
|
} catch (error) {
|
|
@@ -573,6 +577,32 @@ var VM = class _VM {
|
|
|
573
577
|
async delete() {
|
|
574
578
|
return this._client._request("DELETE", vmPath(this.id), void 0, this.baseUrl);
|
|
575
579
|
}
|
|
580
|
+
// ── ARK-125 egress policy ────────────────────────────────────────
|
|
581
|
+
/**
|
|
582
|
+
* Read this VM's outbound egress policy document (ARK-125). Returns an
|
|
583
|
+
* empty doc (`{}`) when no policy is set.
|
|
584
|
+
*/
|
|
585
|
+
async getPolicies() {
|
|
586
|
+
return this._client._request("GET", `${vmPath(this.id)}/policies`, void 0, this.baseUrl);
|
|
587
|
+
}
|
|
588
|
+
/**
|
|
589
|
+
* Replace this VM's outbound egress policy with `doc` — an ordered,
|
|
590
|
+
* first-match-wins rule list. An empty doc (`{}` or `{ policies: [] }`)
|
|
591
|
+
* clears the policy to allow-all. Returns the stored policy plus the
|
|
592
|
+
* domains it escalates to MITM and any degrade warnings.
|
|
593
|
+
*
|
|
594
|
+
* await vm.setPolicies({
|
|
595
|
+
* policies: [
|
|
596
|
+
* { type: "network.outbound",
|
|
597
|
+
* match: { domains: ["github.com"], ports: [443] },
|
|
598
|
+
* action: "allow" },
|
|
599
|
+
* { type: "network.outbound", action: "deny" },
|
|
600
|
+
* ],
|
|
601
|
+
* });
|
|
602
|
+
*/
|
|
603
|
+
async setPolicies(doc) {
|
|
604
|
+
return this._client._request("PUT", `${vmPath(this.id)}/policies`, doc, this.baseUrl);
|
|
605
|
+
}
|
|
576
606
|
// ── Syncs: bindings of a filesystem into this VM at a path ────────
|
|
577
607
|
async listSyncs(opts = {}) {
|
|
578
608
|
return this._client._request("GET", buildQuery(`${vmPath(this.id)}/syncs`, {
|
|
@@ -624,6 +654,20 @@ var VM = class _VM {
|
|
|
624
654
|
async deleteSession(sessionId) {
|
|
625
655
|
return this._client._request("DELETE", `${vmPath(this.id)}/sessions/${pathSegment(sessionId)}`, void 0, this.baseUrl);
|
|
626
656
|
}
|
|
657
|
+
/**
|
|
658
|
+
* Update a session via `PATCH /v1/vms/{id}/sessions/{sid}`: resize its PTY
|
|
659
|
+
* (`cols`/`rows`) and/or set the idle `timeoutSecs`. Works whether or not a
|
|
660
|
+
* PTY is currently attached — the REST equivalent of {@link PtyConnection.resize}
|
|
661
|
+
* (which sends an in-band control frame on the live WebSocket).
|
|
662
|
+
*/
|
|
663
|
+
async updateSession(sessionId, update) {
|
|
664
|
+
return this._client._request(
|
|
665
|
+
"PATCH",
|
|
666
|
+
`${vmPath(this.id)}/sessions/${pathSegment(sessionId)}`,
|
|
667
|
+
{ cols: update.cols, rows: update.rows, timeout_secs: update.timeoutSecs },
|
|
668
|
+
this.baseUrl
|
|
669
|
+
);
|
|
670
|
+
}
|
|
627
671
|
async connectPty(options = {}) {
|
|
628
672
|
const sessionId = options.sessionId ?? sessionIdFrom(await this.createSession());
|
|
629
673
|
const useTicket = options.useTicket ?? !isNodeRuntime();
|
|
@@ -1035,6 +1079,84 @@ function base64ToBytes(text) {
|
|
|
1035
1079
|
function bufferConstructor() {
|
|
1036
1080
|
return globalThis.Buffer;
|
|
1037
1081
|
}
|
|
1082
|
+
var http2Module;
|
|
1083
|
+
function loadHttp2() {
|
|
1084
|
+
return http2Module ??= (async () => {
|
|
1085
|
+
const proc = globalThis.process;
|
|
1086
|
+
if (!proc?.versions?.node) return null;
|
|
1087
|
+
try {
|
|
1088
|
+
return await import(
|
|
1089
|
+
/* webpackIgnore: true */
|
|
1090
|
+
/* @vite-ignore */
|
|
1091
|
+
"http2"
|
|
1092
|
+
);
|
|
1093
|
+
} catch {
|
|
1094
|
+
return null;
|
|
1095
|
+
}
|
|
1096
|
+
})();
|
|
1097
|
+
}
|
|
1098
|
+
var HTTP2_REQUEST_TIMEOUT_MS = 12e4;
|
|
1099
|
+
var Http2Connection = class {
|
|
1100
|
+
confirmed = false;
|
|
1101
|
+
streams = 0;
|
|
1102
|
+
session;
|
|
1103
|
+
constructor(http2, origin) {
|
|
1104
|
+
this.session = http2.connect(origin);
|
|
1105
|
+
this.session.on("error", () => {
|
|
1106
|
+
});
|
|
1107
|
+
}
|
|
1108
|
+
get closed() {
|
|
1109
|
+
return this.session.closed || this.session.destroyed;
|
|
1110
|
+
}
|
|
1111
|
+
request(method, path, headers, body) {
|
|
1112
|
+
if (this.streams === 0) this.session.ref();
|
|
1113
|
+
this.streams++;
|
|
1114
|
+
return new Promise((resolve, reject) => {
|
|
1115
|
+
const stream = this.session.request({ ...headers, ":method": method, ":path": path });
|
|
1116
|
+
let status = 0;
|
|
1117
|
+
let text = "";
|
|
1118
|
+
stream.setEncoding("utf8");
|
|
1119
|
+
stream.setTimeout(HTTP2_REQUEST_TIMEOUT_MS, () => stream.destroy(new Error("HTTP/2 request timed out")));
|
|
1120
|
+
stream.on("response", (responseHeaders) => {
|
|
1121
|
+
this.confirmed = true;
|
|
1122
|
+
status = Number(responseHeaders[":status"]) || 0;
|
|
1123
|
+
});
|
|
1124
|
+
stream.on("data", (chunk) => {
|
|
1125
|
+
text += chunk;
|
|
1126
|
+
});
|
|
1127
|
+
stream.on("end", () => resolve({ status, ok: status >= 200 && status < 300, text }));
|
|
1128
|
+
stream.on("error", reject);
|
|
1129
|
+
stream.end(body);
|
|
1130
|
+
}).finally(() => {
|
|
1131
|
+
if (--this.streams === 0) this.session.unref();
|
|
1132
|
+
});
|
|
1133
|
+
}
|
|
1134
|
+
};
|
|
1135
|
+
var http2Connections = /* @__PURE__ */ new Map();
|
|
1136
|
+
async function sendRequest(url, init, fetchImpl, http2Enabled) {
|
|
1137
|
+
if (http2Enabled) {
|
|
1138
|
+
const http2 = await loadHttp2();
|
|
1139
|
+
if (http2) {
|
|
1140
|
+
const { origin, pathname, search } = new URL(url);
|
|
1141
|
+
const cached = http2Connections.get(origin);
|
|
1142
|
+
if (cached !== null) {
|
|
1143
|
+
let connection = cached;
|
|
1144
|
+
if (!connection || connection.closed) {
|
|
1145
|
+
connection = new Http2Connection(http2, origin);
|
|
1146
|
+
http2Connections.set(origin, connection);
|
|
1147
|
+
}
|
|
1148
|
+
try {
|
|
1149
|
+
return await connection.request(init.method, `${pathname}${search}`, init.headers, init.body);
|
|
1150
|
+
} catch (error) {
|
|
1151
|
+
if (connection.confirmed) throw error;
|
|
1152
|
+
http2Connections.set(origin, null);
|
|
1153
|
+
}
|
|
1154
|
+
}
|
|
1155
|
+
}
|
|
1156
|
+
}
|
|
1157
|
+
const response = await fetchImpl(url, init);
|
|
1158
|
+
return { status: response.status, ok: response.ok, text: await response.text() };
|
|
1159
|
+
}
|
|
1038
1160
|
|
|
1039
1161
|
// src/compat/arker-provider.ts
|
|
1040
1162
|
var DEFAULT_REGION = "aws-us-east-1";
|
package/dist/daytona.js
CHANGED
|
@@ -2,8 +2,8 @@ import {
|
|
|
2
2
|
assertSupportedObjectKeys,
|
|
3
3
|
createCompatSdk,
|
|
4
4
|
guardUnsupported
|
|
5
|
-
} from "./chunk-
|
|
6
|
-
import "./chunk-
|
|
5
|
+
} from "./chunk-YFJEL7PF.js";
|
|
6
|
+
import "./chunk-4NHUAVXK.js";
|
|
7
7
|
|
|
8
8
|
// src/daytona.ts
|
|
9
9
|
import { daytona as createDaytonaProvider } from "@computesdk/daytona";
|