tensorlake 0.5.143 → 0.5.148
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 +11 -159
- package/applications.cjs +3 -0
- package/applications.d.cts +1 -0
- package/applications.d.ts +1 -0
- package/applications.js +1 -0
- package/index.cjs +3 -0
- package/index.d.cts +1 -0
- package/index.d.ts +1 -0
- package/index.js +1 -0
- package/package.json +25 -68
- package/bin/function-executor.js +0 -8
- package/bin/tensorlake-create-sandbox-image.js +0 -9
- package/bin/tensorlake-deploy.cjs +0 -8
- package/bin/tensorlake-import-sandbox-image.js +0 -9
- package/bin/tensorlake-typescript-function-runner.js +0 -8
- package/dist/applications/index.cjs +0 -4821
- package/dist/applications/index.cjs.map +0 -1
- package/dist/applications/index.d.cts +0 -130
- package/dist/applications/index.d.ts +0 -130
- package/dist/applications/index.js +0 -4782
- package/dist/applications/index.js.map +0 -1
- package/dist/function-agent/main.cjs +0 -1838
- package/dist/function-agent/main.cjs.map +0 -1
- package/dist/function-agent/main.d.cts +0 -3
- package/dist/function-agent/main.d.ts +0 -3
- package/dist/function-agent/main.js +0 -1825
- package/dist/function-agent/main.js.map +0 -1
- package/dist/function-executor/main.cjs +0 -4944
- package/dist/function-executor/main.cjs.map +0 -1
- package/dist/function-executor/main.d.cts +0 -4
- package/dist/function-executor/main.d.ts +0 -4
- package/dist/function-executor/main.js +0 -4902
- package/dist/function-executor/main.js.map +0 -1
- package/dist/index.cjs +0 -10184
- package/dist/index.cjs.map +0 -1
- package/dist/index.d.cts +0 -2431
- package/dist/index.d.ts +0 -2431
- package/dist/index.js +0 -10108
- package/dist/index.js.map +0 -1
- package/dist/native-worker.cjs +0 -278
- package/dist/native-worker.cjs.map +0 -1
- package/dist/native-worker.d.cts +0 -2
- package/dist/native-worker.d.ts +0 -2
- package/dist/native-worker.js +0 -276
- package/dist/native-worker.js.map +0 -1
- package/dist/remote-CNJ9TmcQ.d.cts +0 -283
- package/dist/remote-dblFxKug.d.ts +0 -283
- package/dist/sandbox-image-ChzWDeZy.d.cts +0 -357
- package/dist/sandbox-image-ChzWDeZy.d.ts +0 -357
- package/dist/sandbox-image.cjs +0 -1992
- package/dist/sandbox-image.cjs.map +0 -1
- package/dist/sandbox-image.d.cts +0 -1
- package/dist/sandbox-image.d.ts +0 -1
- package/dist/sandbox-image.js +0 -1987
- package/dist/sandbox-image.js.map +0 -1
- package/lib/libc.cjs +0 -61
- package/lib/libc.d.cts +0 -1
- package/lib/runtime.cjs +0 -155
- package/runtime/function-executor/manifest.json +0 -59
- package/runtime/function-executor/package/bin/function-executor.js +0 -8
- package/runtime/function-executor/package/dist/function-executor/main.js +0 -4902
- package/runtime/function-executor/package/dist/function-executor/main.js.map +0 -1
- package/runtime/function-executor/package/dist/native-worker.cjs +0 -278
- package/runtime/function-executor/package/dist/native-worker.cjs.map +0 -1
- package/runtime/function-executor/package/npm-shrinkwrap.json +0 -475
- package/runtime/function-executor/package/package.json +0 -22
- package/runtime/function-executor/package/proto/README.md +0 -18
- package/runtime/function-executor/package/proto/tensorlake/function_executor/proto/function_executor.proto +0 -613
- package/runtime/function-executor/package/proto/tensorlake/function_executor/proto/status.proto +0 -42
- package/runtime/typescript-function-runner/manifest.json +0 -44
- package/runtime/typescript-function-runner/package/bin/tensorlake-typescript-function-runner.js +0 -8
- package/runtime/typescript-function-runner/package/dist/function-agent/main.js +0 -1825
- package/runtime/typescript-function-runner/package/dist/function-agent/main.js.map +0 -1
- package/runtime/typescript-function-runner/package/dist/native-worker.cjs +0 -278
- package/runtime/typescript-function-runner/package/dist/native-worker.cjs.map +0 -1
- package/runtime/typescript-function-runner/package/npm-shrinkwrap.json +0 -580
- package/runtime/typescript-function-runner/package/package.json +0 -25
package/dist/sandbox-image.js
DELETED
|
@@ -1,1987 +0,0 @@
|
|
|
1
|
-
var __create = Object.create;
|
|
2
|
-
var __defProp = Object.defineProperty;
|
|
3
|
-
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
-
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
-
var __getProtoOf = Object.getPrototypeOf;
|
|
6
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
-
var __esm = (fn, res) => function __init() {
|
|
8
|
-
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
9
|
-
};
|
|
10
|
-
var __commonJS = (cb, mod) => function __require() {
|
|
11
|
-
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
|
|
12
|
-
};
|
|
13
|
-
var __export = (target, all) => {
|
|
14
|
-
for (var name in all)
|
|
15
|
-
__defProp(target, name, { get: all[name], enumerable: true });
|
|
16
|
-
};
|
|
17
|
-
var __copyProps = (to, from, except, desc) => {
|
|
18
|
-
if (from && typeof from === "object" || typeof from === "function") {
|
|
19
|
-
for (let key of __getOwnPropNames(from))
|
|
20
|
-
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
21
|
-
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
22
|
-
}
|
|
23
|
-
return to;
|
|
24
|
-
};
|
|
25
|
-
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
26
|
-
// If the importer is in node compatibility mode or this is not an ESM
|
|
27
|
-
// file that has been converted to a CommonJS file using a Babel-
|
|
28
|
-
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
29
|
-
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
30
|
-
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
31
|
-
mod
|
|
32
|
-
));
|
|
33
|
-
|
|
34
|
-
// node_modules/tsup/assets/esm_shims.js
|
|
35
|
-
import path from "path";
|
|
36
|
-
import { fileURLToPath } from "url";
|
|
37
|
-
var init_esm_shims = __esm({
|
|
38
|
-
"node_modules/tsup/assets/esm_shims.js"() {
|
|
39
|
-
"use strict";
|
|
40
|
-
}
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
// src/defaults.ts
|
|
44
|
-
var SDK_VERSION, API_URL, API_KEY, NAMESPACE, SANDBOX_PROXY_URL, DEFAULT_HTTP_TIMEOUT_MS, MAX_RETRIES, RETRY_BACKOFF_MS;
|
|
45
|
-
var init_defaults = __esm({
|
|
46
|
-
"src/defaults.ts"() {
|
|
47
|
-
"use strict";
|
|
48
|
-
init_esm_shims();
|
|
49
|
-
SDK_VERSION = "0.5.143";
|
|
50
|
-
API_URL = process.env.TENSORLAKE_API_URL ?? "https://api.tensorlake.ai";
|
|
51
|
-
API_KEY = process.env.TENSORLAKE_API_KEY ?? void 0;
|
|
52
|
-
NAMESPACE = process.env.INDEXIFY_NAMESPACE ?? "default";
|
|
53
|
-
SANDBOX_PROXY_URL = process.env.TENSORLAKE_SANDBOX_PROXY_URL ?? "https://sandbox.tensorlake.ai";
|
|
54
|
-
DEFAULT_HTTP_TIMEOUT_MS = 3e5;
|
|
55
|
-
MAX_RETRIES = 3;
|
|
56
|
-
RETRY_BACKOFF_MS = 500;
|
|
57
|
-
}
|
|
58
|
-
});
|
|
59
|
-
|
|
60
|
-
// src/models.ts
|
|
61
|
-
function snakeToCamel(str) {
|
|
62
|
-
return str.replace(/_([a-z])/g, (_, ch) => ch.toUpperCase());
|
|
63
|
-
}
|
|
64
|
-
function parseTimestamp(v) {
|
|
65
|
-
if (v == null) return void 0;
|
|
66
|
-
if (v instanceof Date) return v;
|
|
67
|
-
if (typeof v === "string") {
|
|
68
|
-
const parsed = Date.parse(v);
|
|
69
|
-
return Number.isNaN(parsed) ? void 0 : new Date(parsed);
|
|
70
|
-
}
|
|
71
|
-
const ts = Number(v);
|
|
72
|
-
if (isNaN(ts)) return void 0;
|
|
73
|
-
if (ts > 1e15) return new Date(ts / 1e3);
|
|
74
|
-
if (ts > 1e12) return new Date(ts);
|
|
75
|
-
return new Date(ts * 1e3);
|
|
76
|
-
}
|
|
77
|
-
function fromSnakeKeys(obj, idField) {
|
|
78
|
-
if (Array.isArray(obj))
|
|
79
|
-
return obj.map((item) => fromSnakeKeys(item, idField));
|
|
80
|
-
if (obj !== null && typeof obj === "object" && !(obj instanceof Date)) {
|
|
81
|
-
const result = {};
|
|
82
|
-
for (const [k, v] of Object.entries(obj)) {
|
|
83
|
-
let key;
|
|
84
|
-
if (k === "id" && idField) {
|
|
85
|
-
key = idField;
|
|
86
|
-
} else {
|
|
87
|
-
key = snakeToCamel(k);
|
|
88
|
-
}
|
|
89
|
-
if (key.endsWith("At") || key === "timestamp" || key === "startedAt" || key === "endedAt") {
|
|
90
|
-
result[key] = parseTimestamp(v);
|
|
91
|
-
} else if (typeof v === "object" && v !== null && !Array.isArray(v)) {
|
|
92
|
-
result[key] = fromSnakeKeys(v);
|
|
93
|
-
} else if (Array.isArray(v)) {
|
|
94
|
-
result[key] = v.map((item) => fromSnakeKeys(item));
|
|
95
|
-
} else {
|
|
96
|
-
result[key] = v === null ? void 0 : v;
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
return result;
|
|
100
|
-
}
|
|
101
|
-
return obj;
|
|
102
|
-
}
|
|
103
|
-
var init_models = __esm({
|
|
104
|
-
"src/models.ts"() {
|
|
105
|
-
"use strict";
|
|
106
|
-
init_esm_shims();
|
|
107
|
-
}
|
|
108
|
-
});
|
|
109
|
-
|
|
110
|
-
// src/errors.ts
|
|
111
|
-
function formatErrorDetails(errorDetails) {
|
|
112
|
-
if (errorDetails == null) return void 0;
|
|
113
|
-
if (typeof errorDetails === "string") {
|
|
114
|
-
const detail = errorDetails.trim();
|
|
115
|
-
return detail || void 0;
|
|
116
|
-
}
|
|
117
|
-
if (Array.isArray(errorDetails)) {
|
|
118
|
-
const parts = errorDetails.map((item) => formatErrorDetails(item)).filter((item) => Boolean(item));
|
|
119
|
-
return parts.length > 0 ? parts.join("; ") : JSON.stringify(errorDetails);
|
|
120
|
-
}
|
|
121
|
-
if (typeof errorDetails === "object") {
|
|
122
|
-
for (const key of ["message", "detail", "error", "reason"]) {
|
|
123
|
-
const value = errorDetails[key];
|
|
124
|
-
if (typeof value === "string" && value.trim()) {
|
|
125
|
-
return value.trim();
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
return JSON.stringify(errorDetails);
|
|
129
|
-
}
|
|
130
|
-
return String(errorDetails);
|
|
131
|
-
}
|
|
132
|
-
var SandboxException, SandboxError, SandboxResizeError, SandboxConnectionError, SandboxNotFoundError, PoolNotFoundError, PoolInUseError, RemoteAPIError;
|
|
133
|
-
var init_errors = __esm({
|
|
134
|
-
"src/errors.ts"() {
|
|
135
|
-
"use strict";
|
|
136
|
-
init_esm_shims();
|
|
137
|
-
SandboxException = class extends Error {
|
|
138
|
-
constructor(message) {
|
|
139
|
-
super(message);
|
|
140
|
-
this.name = "SandboxException";
|
|
141
|
-
}
|
|
142
|
-
};
|
|
143
|
-
SandboxError = class extends SandboxException {
|
|
144
|
-
reason;
|
|
145
|
-
sandboxId;
|
|
146
|
-
constructor(message, options) {
|
|
147
|
-
super(message);
|
|
148
|
-
this.name = "SandboxError";
|
|
149
|
-
if (options?.reason !== void 0) this.reason = options.reason;
|
|
150
|
-
if (options?.sandboxId !== void 0) this.sandboxId = options.sandboxId;
|
|
151
|
-
}
|
|
152
|
-
};
|
|
153
|
-
SandboxResizeError = class extends SandboxError {
|
|
154
|
-
generation;
|
|
155
|
-
info;
|
|
156
|
-
constructor(payload) {
|
|
157
|
-
const resources = payload.info?.resources;
|
|
158
|
-
const allocation = resources ? `${resources.cpus} CPUs, ${resources.memoryMb} MiB memory, ${resources.diskMb} MiB disk` : "unavailable";
|
|
159
|
-
super(
|
|
160
|
-
`Sandbox ${payload.sandboxId} resize generation ${payload.generation}: ${payload.message}; last confirmed allocation: ${allocation}`,
|
|
161
|
-
{ reason: payload.reason, sandboxId: payload.sandboxId }
|
|
162
|
-
);
|
|
163
|
-
this.name = "SandboxResizeError";
|
|
164
|
-
this.generation = payload.generation;
|
|
165
|
-
this.info = payload.info ?? void 0;
|
|
166
|
-
}
|
|
167
|
-
/** Last confirmed allocation, if an observation was available. */
|
|
168
|
-
get confirmedResources() {
|
|
169
|
-
return this.info?.resources;
|
|
170
|
-
}
|
|
171
|
-
};
|
|
172
|
-
SandboxConnectionError = class extends SandboxError {
|
|
173
|
-
constructor(message, options) {
|
|
174
|
-
super(`Connection error: ${message}`);
|
|
175
|
-
this.name = "SandboxConnectionError";
|
|
176
|
-
if (options?.cause !== void 0) this.cause = options.cause;
|
|
177
|
-
}
|
|
178
|
-
};
|
|
179
|
-
SandboxNotFoundError = class extends SandboxError {
|
|
180
|
-
constructor(sandboxId) {
|
|
181
|
-
super(`Sandbox not found: ${sandboxId}`, { sandboxId });
|
|
182
|
-
this.name = "SandboxNotFoundError";
|
|
183
|
-
}
|
|
184
|
-
};
|
|
185
|
-
PoolNotFoundError = class extends SandboxError {
|
|
186
|
-
poolId;
|
|
187
|
-
constructor(poolId) {
|
|
188
|
-
super(`Sandbox pool not found: ${poolId}`);
|
|
189
|
-
this.name = "PoolNotFoundError";
|
|
190
|
-
this.poolId = poolId;
|
|
191
|
-
}
|
|
192
|
-
};
|
|
193
|
-
PoolInUseError = class extends SandboxError {
|
|
194
|
-
poolId;
|
|
195
|
-
constructor(poolId, message) {
|
|
196
|
-
const base = `Cannot delete pool ${poolId}: pool is in use`;
|
|
197
|
-
super(message ? `${base} - ${message}` : base);
|
|
198
|
-
this.name = "PoolInUseError";
|
|
199
|
-
this.poolId = poolId;
|
|
200
|
-
}
|
|
201
|
-
};
|
|
202
|
-
RemoteAPIError = class extends SandboxError {
|
|
203
|
-
statusCode;
|
|
204
|
-
/** Original response body, retained for compatibility and diagnostics. */
|
|
205
|
-
responseMessage;
|
|
206
|
-
errorDetails;
|
|
207
|
-
constructor(statusCode, message) {
|
|
208
|
-
let failure;
|
|
209
|
-
try {
|
|
210
|
-
const payload = JSON.parse(message);
|
|
211
|
-
if (payload && typeof payload === "object" && !Array.isArray(payload)) {
|
|
212
|
-
const record = payload;
|
|
213
|
-
if (typeof record.sandbox_id === "string" && record.sandbox_id.trim() && (record.status === "failed" || record.status === "terminated"))
|
|
214
|
-
failure = record;
|
|
215
|
-
}
|
|
216
|
-
} catch {
|
|
217
|
-
}
|
|
218
|
-
const sandboxId = failure?.sandbox_id;
|
|
219
|
-
const rawReason = failure?.reason ?? failure?.termination_reason;
|
|
220
|
-
const reason = typeof rawReason === "string" ? rawReason : void 0;
|
|
221
|
-
const errorDetails = failure?.error_details;
|
|
222
|
-
let displayMessage = message;
|
|
223
|
-
if (failure) {
|
|
224
|
-
displayMessage = `Sandbox ${sandboxId} ${failure.status}`;
|
|
225
|
-
if (reason) displayMessage += ` (${reason})`;
|
|
226
|
-
const detail = formatErrorDetails(errorDetails);
|
|
227
|
-
if (detail) displayMessage += `: ${detail}`;
|
|
228
|
-
if (!reason && !detail) displayMessage = message;
|
|
229
|
-
}
|
|
230
|
-
super(`API error (status ${statusCode}): ${displayMessage}`, {
|
|
231
|
-
reason,
|
|
232
|
-
sandboxId
|
|
233
|
-
});
|
|
234
|
-
this.errorDetails = errorDetails;
|
|
235
|
-
this.name = "RemoteAPIError";
|
|
236
|
-
this.statusCode = statusCode;
|
|
237
|
-
this.responseMessage = message;
|
|
238
|
-
}
|
|
239
|
-
};
|
|
240
|
-
}
|
|
241
|
-
});
|
|
242
|
-
|
|
243
|
-
// src/native-worker-protocol.ts
|
|
244
|
-
var cancelNativeCall, closeNativeHandle;
|
|
245
|
-
var init_native_worker_protocol = __esm({
|
|
246
|
-
"src/native-worker-protocol.ts"() {
|
|
247
|
-
"use strict";
|
|
248
|
-
init_esm_shims();
|
|
249
|
-
cancelNativeCall = /* @__PURE__ */ Symbol.for("tensorlake.native.cancel.v1");
|
|
250
|
-
closeNativeHandle = /* @__PURE__ */ Symbol.for("tensorlake.native.close.v1");
|
|
251
|
-
}
|
|
252
|
-
});
|
|
253
|
-
|
|
254
|
-
// src/url.ts
|
|
255
|
-
function trimTrailingSlashes(url) {
|
|
256
|
-
return url.endsWith("/") ? url.slice(0, -1) : url;
|
|
257
|
-
}
|
|
258
|
-
function resolveProxyTarget(proxyUrl, sandboxId) {
|
|
259
|
-
try {
|
|
260
|
-
const parsed = new URL(proxyUrl);
|
|
261
|
-
const host = parsed.hostname;
|
|
262
|
-
if (host === "localhost" || host === "127.0.0.1") {
|
|
263
|
-
return {
|
|
264
|
-
baseUrl: trimTrailingSlashes(proxyUrl),
|
|
265
|
-
hostHeader: `${sandboxId}.local`,
|
|
266
|
-
sandboxIdHeader: void 0
|
|
267
|
-
};
|
|
268
|
-
}
|
|
269
|
-
const port = parsed.port ? `:${parsed.port}` : "";
|
|
270
|
-
return {
|
|
271
|
-
baseUrl: `${parsed.protocol}//${host}${port}`,
|
|
272
|
-
hostHeader: void 0,
|
|
273
|
-
sandboxIdHeader: sandboxId
|
|
274
|
-
};
|
|
275
|
-
} catch {
|
|
276
|
-
return {
|
|
277
|
-
baseUrl: `${trimTrailingSlashes(proxyUrl)}/${sandboxId}`,
|
|
278
|
-
hostHeader: void 0,
|
|
279
|
-
sandboxIdHeader: void 0
|
|
280
|
-
};
|
|
281
|
-
}
|
|
282
|
-
}
|
|
283
|
-
var init_url = __esm({
|
|
284
|
-
"src/url.ts"() {
|
|
285
|
-
"use strict";
|
|
286
|
-
init_esm_shims();
|
|
287
|
-
init_defaults();
|
|
288
|
-
}
|
|
289
|
-
});
|
|
290
|
-
|
|
291
|
-
// src/native-worker-client.ts
|
|
292
|
-
import { createRequire } from "module";
|
|
293
|
-
import { Worker } from "worker_threads";
|
|
294
|
-
function createWorkerBinding(runtime) {
|
|
295
|
-
return {
|
|
296
|
-
NativeCloudClient: class {
|
|
297
|
-
constructor(...args) {
|
|
298
|
-
return runtime.handle("NativeCloudClient", args);
|
|
299
|
-
}
|
|
300
|
-
},
|
|
301
|
-
NativeSandboxClient: class {
|
|
302
|
-
constructor(...args) {
|
|
303
|
-
return runtime.handle("NativeSandboxClient", args);
|
|
304
|
-
}
|
|
305
|
-
},
|
|
306
|
-
NativeSandboxProxyClient: class {
|
|
307
|
-
constructor(...args) {
|
|
308
|
-
return runtime.handle("NativeSandboxProxyClient", args);
|
|
309
|
-
}
|
|
310
|
-
},
|
|
311
|
-
NativeRepositoryClient: class {
|
|
312
|
-
constructor(...args) {
|
|
313
|
-
return runtime.handle("NativeRepositoryClient", args);
|
|
314
|
-
}
|
|
315
|
-
},
|
|
316
|
-
validateManagedName: (name) => runtime.call(void 0, "validateManagedName", [name])
|
|
317
|
-
};
|
|
318
|
-
}
|
|
319
|
-
function workerBinding() {
|
|
320
|
-
return createWorkerBinding(
|
|
321
|
-
runtimes[runtimeKey] ??= new NativeWorkerClient()
|
|
322
|
-
);
|
|
323
|
-
}
|
|
324
|
-
function releaseNativeHandle(handle) {
|
|
325
|
-
handle?.[closeNativeHandle]?.();
|
|
326
|
-
}
|
|
327
|
-
var NativeWorkerClient, runtimeKey, runtimes;
|
|
328
|
-
var init_native_worker_client = __esm({
|
|
329
|
-
"src/native-worker-client.ts"() {
|
|
330
|
-
"use strict";
|
|
331
|
-
init_esm_shims();
|
|
332
|
-
init_native_worker_protocol();
|
|
333
|
-
init_url();
|
|
334
|
-
NativeWorkerClient = class {
|
|
335
|
-
constructor(workerPath = () => createRequire(import.meta.url).resolve(
|
|
336
|
-
"tensorlake/internal/native-worker"
|
|
337
|
-
)) {
|
|
338
|
-
this.workerPath = workerPath;
|
|
339
|
-
}
|
|
340
|
-
worker;
|
|
341
|
-
nextId = 1;
|
|
342
|
-
registered = /* @__PURE__ */ new Set();
|
|
343
|
-
pending = /* @__PURE__ */ new Map();
|
|
344
|
-
finalizers = new FinalizationRegistry(
|
|
345
|
-
(id) => this.release(id)
|
|
346
|
-
);
|
|
347
|
-
handle(kind, args, parent) {
|
|
348
|
-
const handle = { id: this.nextId++, kind, args, parent };
|
|
349
|
-
this.finalizers.register(handle, handle.id);
|
|
350
|
-
let closed = false;
|
|
351
|
-
return new Proxy(
|
|
352
|
-
{},
|
|
353
|
-
{
|
|
354
|
-
get: (_target, method) => {
|
|
355
|
-
if (method === "then") return void 0;
|
|
356
|
-
if (method === closeNativeHandle)
|
|
357
|
-
return () => {
|
|
358
|
-
closed = true;
|
|
359
|
-
this.release(handle.id);
|
|
360
|
-
};
|
|
361
|
-
if (method === "connectProxy")
|
|
362
|
-
return (...proxyArgs) => {
|
|
363
|
-
if (closed) throw new Error("Tensorlake native client is closed");
|
|
364
|
-
return this.handle("NativeSandboxProxyClient", proxyArgs, handle);
|
|
365
|
-
};
|
|
366
|
-
if (method === "baseUrl")
|
|
367
|
-
return () => resolveProxyTarget(String(args[0]), String(args[1])).baseUrl;
|
|
368
|
-
if (typeof method !== "string") return void 0;
|
|
369
|
-
return (...callArgs) => {
|
|
370
|
-
if (closed)
|
|
371
|
-
return Promise.reject(
|
|
372
|
-
new Error("Tensorlake native client is closed")
|
|
373
|
-
);
|
|
374
|
-
const emit = typeof callArgs.at(-1) === "function" ? callArgs.pop() : void 0;
|
|
375
|
-
return this.call(handle, method, callArgs, emit);
|
|
376
|
-
};
|
|
377
|
-
}
|
|
378
|
-
}
|
|
379
|
-
);
|
|
380
|
-
}
|
|
381
|
-
call(handle, method, args, emit) {
|
|
382
|
-
const id = this.nextId++;
|
|
383
|
-
let worker;
|
|
384
|
-
const promise = new Promise((resolve, reject) => {
|
|
385
|
-
try {
|
|
386
|
-
worker = this.getWorker();
|
|
387
|
-
this.pending.set(id, { resolve, reject, emit, handle });
|
|
388
|
-
worker.ref();
|
|
389
|
-
if (handle) this.register(handle, worker);
|
|
390
|
-
this.send(worker, {
|
|
391
|
-
type: "call",
|
|
392
|
-
id,
|
|
393
|
-
handleId: handle?.id,
|
|
394
|
-
method,
|
|
395
|
-
args,
|
|
396
|
-
stream: !!emit
|
|
397
|
-
});
|
|
398
|
-
} catch (error) {
|
|
399
|
-
this.pending.delete(id);
|
|
400
|
-
this.unrefIfIdle();
|
|
401
|
-
reject(error);
|
|
402
|
-
}
|
|
403
|
-
});
|
|
404
|
-
promise[cancelNativeCall] = () => {
|
|
405
|
-
const pending = this.pending.get(id);
|
|
406
|
-
if (pending && worker) {
|
|
407
|
-
pending.emit = void 0;
|
|
408
|
-
this.send(worker, { type: "cancel", id });
|
|
409
|
-
}
|
|
410
|
-
};
|
|
411
|
-
return promise;
|
|
412
|
-
}
|
|
413
|
-
getWorker() {
|
|
414
|
-
if (this.worker) return this.worker;
|
|
415
|
-
const worker = new Worker(this.workerPath(), {
|
|
416
|
-
// The bundled worker needs no application loaders or telemetry preloads.
|
|
417
|
-
// NODE_OPTIONS is parsed independently of execArgv by Node.
|
|
418
|
-
execArgv: [],
|
|
419
|
-
env: { ...process.env, NODE_OPTIONS: "" },
|
|
420
|
-
name: "tensorlake-native"
|
|
421
|
-
});
|
|
422
|
-
this.worker = worker;
|
|
423
|
-
worker.on("message", (message) => {
|
|
424
|
-
const pending = this.pending.get(message.id);
|
|
425
|
-
if (!pending || this.worker !== worker) return;
|
|
426
|
-
if (message.type === "event") {
|
|
427
|
-
Promise.resolve().then(() => pending.emit?.(message.value)).then(
|
|
428
|
-
() => {
|
|
429
|
-
if (this.worker === worker)
|
|
430
|
-
this.send(worker, { type: "ack", id: message.id });
|
|
431
|
-
},
|
|
432
|
-
(error) => {
|
|
433
|
-
this.send(worker, { type: "cancel", id: message.id });
|
|
434
|
-
pending.reject(error);
|
|
435
|
-
}
|
|
436
|
-
);
|
|
437
|
-
return;
|
|
438
|
-
}
|
|
439
|
-
this.pending.delete(message.id);
|
|
440
|
-
if (message.type === "error") {
|
|
441
|
-
const error = new Error(message.error.message);
|
|
442
|
-
error.name = message.error.name;
|
|
443
|
-
error.stack = message.error.stack ?? error.stack;
|
|
444
|
-
pending.reject(error);
|
|
445
|
-
} else {
|
|
446
|
-
pending.resolve(message.value);
|
|
447
|
-
}
|
|
448
|
-
this.unrefIfIdle();
|
|
449
|
-
});
|
|
450
|
-
const fail = (error) => {
|
|
451
|
-
if (this.worker !== worker) return;
|
|
452
|
-
this.worker = void 0;
|
|
453
|
-
this.registered.clear();
|
|
454
|
-
for (const pending of this.pending.values()) pending.reject(error);
|
|
455
|
-
this.pending.clear();
|
|
456
|
-
void worker.terminate();
|
|
457
|
-
};
|
|
458
|
-
worker.on("error", fail);
|
|
459
|
-
worker.on("messageerror", fail);
|
|
460
|
-
worker.on(
|
|
461
|
-
"exit",
|
|
462
|
-
(code) => fail(
|
|
463
|
-
new Error(
|
|
464
|
-
`Tensorlake native worker exited (${code}); in-flight operations were not retried`
|
|
465
|
-
)
|
|
466
|
-
)
|
|
467
|
-
);
|
|
468
|
-
worker.unref();
|
|
469
|
-
return worker;
|
|
470
|
-
}
|
|
471
|
-
register(handle, worker) {
|
|
472
|
-
if (this.registered.has(handle.id)) return;
|
|
473
|
-
if (handle.parent) this.register(handle.parent, worker);
|
|
474
|
-
this.send(worker, {
|
|
475
|
-
type: "create",
|
|
476
|
-
handle: { id: handle.id, kind: handle.kind, args: handle.args },
|
|
477
|
-
parentId: handle.parent?.id
|
|
478
|
-
});
|
|
479
|
-
this.registered.add(handle.id);
|
|
480
|
-
}
|
|
481
|
-
release(handleId) {
|
|
482
|
-
if (this.worker && this.registered.delete(handleId))
|
|
483
|
-
this.send(this.worker, { type: "release", handleId });
|
|
484
|
-
}
|
|
485
|
-
send(worker, message) {
|
|
486
|
-
worker.postMessage(message);
|
|
487
|
-
}
|
|
488
|
-
unrefIfIdle() {
|
|
489
|
-
if (this.pending.size === 0) this.worker?.unref();
|
|
490
|
-
}
|
|
491
|
-
};
|
|
492
|
-
runtimeKey = /* @__PURE__ */ Symbol.for(
|
|
493
|
-
`tensorlake.native.worker.${false ? "source" : "0.5.143"}.v1`
|
|
494
|
-
);
|
|
495
|
-
runtimes = globalThis;
|
|
496
|
-
}
|
|
497
|
-
});
|
|
498
|
-
|
|
499
|
-
// src/native-sandbox.ts
|
|
500
|
-
function loadNativeSandboxBinding() {
|
|
501
|
-
return cachedBinding ??= workerBinding();
|
|
502
|
-
}
|
|
503
|
-
function parseNativeError(error) {
|
|
504
|
-
const message = error instanceof Error ? error.message : typeof error === "string" ? error : "";
|
|
505
|
-
if (!message) return null;
|
|
506
|
-
try {
|
|
507
|
-
const parsed = JSON.parse(message);
|
|
508
|
-
if (parsed && typeof parsed.category === "string") {
|
|
509
|
-
return {
|
|
510
|
-
category: parsed.category,
|
|
511
|
-
status: typeof parsed.status === "number" ? parsed.status : null,
|
|
512
|
-
message: typeof parsed.message === "string" ? parsed.message : message
|
|
513
|
-
};
|
|
514
|
-
}
|
|
515
|
-
} catch {
|
|
516
|
-
}
|
|
517
|
-
return null;
|
|
518
|
-
}
|
|
519
|
-
function translateNativeError(error, context) {
|
|
520
|
-
const payload = parseNativeError(error);
|
|
521
|
-
if (!payload) {
|
|
522
|
-
if (error instanceof Error) return error;
|
|
523
|
-
return new SandboxError(String(error));
|
|
524
|
-
}
|
|
525
|
-
const { category, status, message } = payload;
|
|
526
|
-
if (category === "resize") {
|
|
527
|
-
return new SandboxResizeError(
|
|
528
|
-
fromSnakeKeys(JSON.parse(message), "sandboxId")
|
|
529
|
-
);
|
|
530
|
-
}
|
|
531
|
-
if (category === "connection") {
|
|
532
|
-
return new SandboxConnectionError(message, { cause: error });
|
|
533
|
-
}
|
|
534
|
-
if (status === 404) {
|
|
535
|
-
if (context?.notFoundKind === "pool" && context.poolId) {
|
|
536
|
-
return new PoolNotFoundError(context.poolId);
|
|
537
|
-
}
|
|
538
|
-
if (context?.notFoundKind === "sandbox" && context.sandboxId) {
|
|
539
|
-
return new SandboxNotFoundError(context.sandboxId);
|
|
540
|
-
}
|
|
541
|
-
return new RemoteAPIError(404, message);
|
|
542
|
-
}
|
|
543
|
-
if (status === 409 && context?.poolId) {
|
|
544
|
-
return new PoolInUseError(context.poolId, message);
|
|
545
|
-
}
|
|
546
|
-
if (typeof status === "number") {
|
|
547
|
-
return new RemoteAPIError(status, message);
|
|
548
|
-
}
|
|
549
|
-
return new SandboxError(message);
|
|
550
|
-
}
|
|
551
|
-
async function callNative(fn, context) {
|
|
552
|
-
try {
|
|
553
|
-
return await fn();
|
|
554
|
-
} catch (error) {
|
|
555
|
-
throw translateNativeError(error, context);
|
|
556
|
-
}
|
|
557
|
-
}
|
|
558
|
-
async function* nativeEventStream(start, context, signal) {
|
|
559
|
-
if (signal?.aborted) return;
|
|
560
|
-
const queue = [];
|
|
561
|
-
let wake;
|
|
562
|
-
let finished = false;
|
|
563
|
-
let stopped = false;
|
|
564
|
-
let failure;
|
|
565
|
-
const notify = () => {
|
|
566
|
-
const resolve = wake;
|
|
567
|
-
wake = void 0;
|
|
568
|
-
resolve?.();
|
|
569
|
-
};
|
|
570
|
-
const emit = (value) => {
|
|
571
|
-
if (stopped) return Promise.resolve();
|
|
572
|
-
return new Promise((consumed) => {
|
|
573
|
-
queue.push({ value, consumed });
|
|
574
|
-
notify();
|
|
575
|
-
});
|
|
576
|
-
};
|
|
577
|
-
let call;
|
|
578
|
-
const onAbort = () => {
|
|
579
|
-
stopped = true;
|
|
580
|
-
call?.[cancelNativeCall]?.();
|
|
581
|
-
notify();
|
|
582
|
-
};
|
|
583
|
-
signal?.addEventListener("abort", onAbort, { once: true });
|
|
584
|
-
try {
|
|
585
|
-
call = start(emit);
|
|
586
|
-
void call.catch((error) => {
|
|
587
|
-
failure = error;
|
|
588
|
-
}).finally(() => {
|
|
589
|
-
finished = true;
|
|
590
|
-
notify();
|
|
591
|
-
});
|
|
592
|
-
while (!stopped) {
|
|
593
|
-
const event = queue.shift();
|
|
594
|
-
if (event) {
|
|
595
|
-
try {
|
|
596
|
-
yield JSON.parse(event.value);
|
|
597
|
-
} finally {
|
|
598
|
-
event.consumed();
|
|
599
|
-
}
|
|
600
|
-
} else if (finished) {
|
|
601
|
-
break;
|
|
602
|
-
} else {
|
|
603
|
-
await new Promise((resolve) => {
|
|
604
|
-
wake = resolve;
|
|
605
|
-
});
|
|
606
|
-
}
|
|
607
|
-
}
|
|
608
|
-
if (!stopped && failure !== void 0) throw translateNativeError(failure, context);
|
|
609
|
-
} finally {
|
|
610
|
-
stopped = true;
|
|
611
|
-
signal?.removeEventListener("abort", onAbort);
|
|
612
|
-
call?.[cancelNativeCall]?.();
|
|
613
|
-
for (const event of queue) event.consumed();
|
|
614
|
-
}
|
|
615
|
-
}
|
|
616
|
-
var cachedBinding;
|
|
617
|
-
var init_native_sandbox = __esm({
|
|
618
|
-
"src/native-sandbox.ts"() {
|
|
619
|
-
"use strict";
|
|
620
|
-
init_esm_shims();
|
|
621
|
-
init_models();
|
|
622
|
-
init_errors();
|
|
623
|
-
init_native_worker_client();
|
|
624
|
-
init_native_worker_protocol();
|
|
625
|
-
}
|
|
626
|
-
});
|
|
627
|
-
|
|
628
|
-
// src/native-cloud.ts
|
|
629
|
-
async function serializeRequest(method, path4, options) {
|
|
630
|
-
const headers = { ...options?.headers };
|
|
631
|
-
let body = options?.body;
|
|
632
|
-
if (options?.json !== void 0) {
|
|
633
|
-
body = JSON.stringify(options.json);
|
|
634
|
-
if (!Object.keys(headers).some((key) => key.toLowerCase() === "content-type")) {
|
|
635
|
-
headers["Content-Type"] = "application/json";
|
|
636
|
-
}
|
|
637
|
-
}
|
|
638
|
-
const request = {
|
|
639
|
-
method,
|
|
640
|
-
path: path4,
|
|
641
|
-
headersJson: JSON.stringify(headers),
|
|
642
|
-
statusOnlyCodes: [...options?.statusOnlyCodes ?? []]
|
|
643
|
-
};
|
|
644
|
-
if (body instanceof FormData) {
|
|
645
|
-
request.parts = [];
|
|
646
|
-
for (const [name, value] of body.entries()) {
|
|
647
|
-
request.parts.push(typeof value === "string" ? { name, data: Buffer.from(value) } : { name, data: Buffer.from(await value.arrayBuffer()), filename: value.name, contentType: value.type || "application/octet-stream" });
|
|
648
|
-
}
|
|
649
|
-
} else if (body !== void 0) {
|
|
650
|
-
if (body instanceof Blob) request.body = Buffer.from(await body.arrayBuffer());
|
|
651
|
-
else if (typeof body === "string") request.body = Buffer.from(body);
|
|
652
|
-
else if (body instanceof ArrayBuffer) request.body = Buffer.from(new Uint8Array(body));
|
|
653
|
-
else request.body = Buffer.from(body);
|
|
654
|
-
}
|
|
655
|
-
return request;
|
|
656
|
-
}
|
|
657
|
-
var NativeCloudTransport;
|
|
658
|
-
var init_native_cloud = __esm({
|
|
659
|
-
"src/native-cloud.ts"() {
|
|
660
|
-
"use strict";
|
|
661
|
-
init_esm_shims();
|
|
662
|
-
init_native_sandbox();
|
|
663
|
-
init_native_worker_client();
|
|
664
|
-
NativeCloudTransport = class {
|
|
665
|
-
constructor(options) {
|
|
666
|
-
this.options = options;
|
|
667
|
-
if (!Number.isSafeInteger(options.maxRetries) || options.maxRetries < 0 || options.maxRetries > 4294967295) {
|
|
668
|
-
throw new RangeError("maxRetries must be a non-negative 32-bit integer");
|
|
669
|
-
}
|
|
670
|
-
if (!Number.isFinite(options.retryBackoffMs) || options.retryBackoffMs < 0) {
|
|
671
|
-
throw new RangeError("retryBackoffMs must be a non-negative finite number");
|
|
672
|
-
}
|
|
673
|
-
}
|
|
674
|
-
native;
|
|
675
|
-
closed = false;
|
|
676
|
-
client() {
|
|
677
|
-
if (this.closed) throw new Error("Tensorlake native client is closed");
|
|
678
|
-
if (this.native) return this.native;
|
|
679
|
-
const ctor = loadNativeSandboxBinding().NativeCloudClient;
|
|
680
|
-
if (!ctor) throw new Error("Native binding does not export NativeCloudClient; rebuild with 'npm run build:native'");
|
|
681
|
-
return this.native = new ctor(JSON.stringify(this.options));
|
|
682
|
-
}
|
|
683
|
-
close() {
|
|
684
|
-
this.closed = true;
|
|
685
|
-
releaseNativeHandle(this.native ?? null);
|
|
686
|
-
this.native = void 0;
|
|
687
|
-
}
|
|
688
|
-
async requestResponse(method, path4, options) {
|
|
689
|
-
const request = await serializeRequest(method, path4, options);
|
|
690
|
-
const raw = await callNative(() => this.client().request(request));
|
|
691
|
-
const response = new Response(
|
|
692
|
-
[204, 205, 304].includes(raw.status) ? null : Uint8Array.from(raw.data).buffer,
|
|
693
|
-
{ status: raw.status, headers: JSON.parse(raw.headersJson) }
|
|
694
|
-
);
|
|
695
|
-
return Object.assign(response, { traceId: raw.traceId });
|
|
696
|
-
}
|
|
697
|
-
async requestJson(method, path4) {
|
|
698
|
-
const response = await this.requestResponse(method, path4);
|
|
699
|
-
const text = await response.text();
|
|
700
|
-
const value = text ? JSON.parse(text) : null;
|
|
701
|
-
return Object.assign(value ?? {}, { traceId: response.traceId });
|
|
702
|
-
}
|
|
703
|
-
async *stream(method, path4, signal) {
|
|
704
|
-
if (signal?.aborted) return;
|
|
705
|
-
const request = await serializeRequest(method, path4, { headers: { Accept: "text/event-stream" } });
|
|
706
|
-
yield* nativeEventStream((emit) => this.client().stream(request, emit), void 0, signal);
|
|
707
|
-
}
|
|
708
|
-
};
|
|
709
|
-
}
|
|
710
|
-
});
|
|
711
|
-
|
|
712
|
-
// src/cloud-client.ts
|
|
713
|
-
import { nanoid } from "nanoid";
|
|
714
|
-
function secretFromMetadata(metadata) {
|
|
715
|
-
return {
|
|
716
|
-
id: metadata.id,
|
|
717
|
-
name: metadata.name,
|
|
718
|
-
createdAt: new Date(metadata.created_at_ms)
|
|
719
|
-
};
|
|
720
|
-
}
|
|
721
|
-
function applicationAllowsUnauthenticatedRequests(manifest) {
|
|
722
|
-
return Array.isArray(manifest.allow) && manifest.allow.includes(UNAUTHENTICATED_REQUESTS);
|
|
723
|
-
}
|
|
724
|
-
function publicEndpointIdFromManifest(manifest) {
|
|
725
|
-
for (const key of ["public_endpoint_id", "publicEndpointId"]) {
|
|
726
|
-
const value = manifest[key];
|
|
727
|
-
if (typeof value === "string" && value.length > 0) {
|
|
728
|
-
return value;
|
|
729
|
-
}
|
|
730
|
-
}
|
|
731
|
-
return void 0;
|
|
732
|
-
}
|
|
733
|
-
function generatePublicEndpointId() {
|
|
734
|
-
return `endpoint_${nanoid()}`;
|
|
735
|
-
}
|
|
736
|
-
function createApplicationBuildForm(request, imageContexts) {
|
|
737
|
-
const contextsByPartName = /* @__PURE__ */ new Map();
|
|
738
|
-
for (const context of imageContexts) {
|
|
739
|
-
if (contextsByPartName.has(context.contextTarPartName)) {
|
|
740
|
-
throw new Error(
|
|
741
|
-
`duplicate image context part name '${context.contextTarPartName}'`
|
|
742
|
-
);
|
|
743
|
-
}
|
|
744
|
-
contextsByPartName.set(context.contextTarPartName, context);
|
|
745
|
-
}
|
|
746
|
-
const form = new FormData();
|
|
747
|
-
form.append(
|
|
748
|
-
"app_version",
|
|
749
|
-
new Blob([JSON.stringify(request)], { type: "application/json" }),
|
|
750
|
-
"app_version"
|
|
751
|
-
);
|
|
752
|
-
for (const image of request.images) {
|
|
753
|
-
const context = contextsByPartName.get(image.contextTarPartName);
|
|
754
|
-
if (!context) {
|
|
755
|
-
throw new Error(
|
|
756
|
-
`missing image context for part '${image.contextTarPartName}'`
|
|
757
|
-
);
|
|
758
|
-
}
|
|
759
|
-
form.append(
|
|
760
|
-
image.contextTarPartName,
|
|
761
|
-
new Blob([toBlobPart(context.contextTarGz)]),
|
|
762
|
-
`${image.contextTarPartName}.tar.gz`
|
|
763
|
-
);
|
|
764
|
-
}
|
|
765
|
-
for (const context of imageContexts) {
|
|
766
|
-
if (!request.images.some((image) => image.contextTarPartName === context.contextTarPartName)) {
|
|
767
|
-
throw new Error(
|
|
768
|
-
`unexpected image context for part '${context.contextTarPartName}'`
|
|
769
|
-
);
|
|
770
|
-
}
|
|
771
|
-
}
|
|
772
|
-
return form;
|
|
773
|
-
}
|
|
774
|
-
function trimTrailingSlashes2(value) {
|
|
775
|
-
return value.endsWith("/") ? value.slice(0, -1) : value;
|
|
776
|
-
}
|
|
777
|
-
function nextRequestPath(next) {
|
|
778
|
-
const schemeIndex = next.indexOf("://");
|
|
779
|
-
if (schemeIndex !== -1) {
|
|
780
|
-
const afterScheme = next.slice(schemeIndex + 3);
|
|
781
|
-
const slashIndex = afterScheme.indexOf("/");
|
|
782
|
-
return slashIndex === -1 ? "/" : afterScheme.slice(slashIndex);
|
|
783
|
-
}
|
|
784
|
-
return next.startsWith("/") ? next : `/${next}`;
|
|
785
|
-
}
|
|
786
|
-
function toBlobPart(data) {
|
|
787
|
-
if (typeof data === "string" || data instanceof Blob) {
|
|
788
|
-
return data;
|
|
789
|
-
}
|
|
790
|
-
if (data instanceof Uint8Array) {
|
|
791
|
-
return Uint8Array.from(data).buffer;
|
|
792
|
-
}
|
|
793
|
-
return data;
|
|
794
|
-
}
|
|
795
|
-
function toRequestBody(data) {
|
|
796
|
-
return toBlobPart(data);
|
|
797
|
-
}
|
|
798
|
-
async function parseJsonResponse(response) {
|
|
799
|
-
const text = await response.text();
|
|
800
|
-
if (!text) {
|
|
801
|
-
return void 0;
|
|
802
|
-
}
|
|
803
|
-
return JSON.parse(text);
|
|
804
|
-
}
|
|
805
|
-
var CloudClient, UNAUTHENTICATED_REQUESTS;
|
|
806
|
-
var init_cloud_client = __esm({
|
|
807
|
-
"src/cloud-client.ts"() {
|
|
808
|
-
"use strict";
|
|
809
|
-
init_esm_shims();
|
|
810
|
-
init_defaults();
|
|
811
|
-
init_native_cloud();
|
|
812
|
-
init_models();
|
|
813
|
-
CloudClient = class _CloudClient {
|
|
814
|
-
transport;
|
|
815
|
-
organizationId;
|
|
816
|
-
projectId;
|
|
817
|
-
namespace;
|
|
818
|
-
constructor(options) {
|
|
819
|
-
this.organizationId = options?.organizationId;
|
|
820
|
-
this.projectId = options?.projectId;
|
|
821
|
-
this.namespace = options?.namespace ?? NAMESPACE;
|
|
822
|
-
this.transport = new NativeCloudTransport({
|
|
823
|
-
baseUrl: options?.apiUrl ?? API_URL,
|
|
824
|
-
apiKey: options?.apiKey ?? API_KEY,
|
|
825
|
-
organizationId: this.organizationId,
|
|
826
|
-
projectId: this.projectId,
|
|
827
|
-
maxRetries: options?.maxRetries ?? MAX_RETRIES,
|
|
828
|
-
retryBackoffMs: options?.retryBackoffMs ?? RETRY_BACKOFF_MS,
|
|
829
|
-
timeoutMs: DEFAULT_HTTP_TIMEOUT_MS,
|
|
830
|
-
userAgent: `tensorlake-typescript-sdk/${SDK_VERSION}`
|
|
831
|
-
});
|
|
832
|
-
}
|
|
833
|
-
static forCloud(options) {
|
|
834
|
-
return new _CloudClient(options);
|
|
835
|
-
}
|
|
836
|
-
close() {
|
|
837
|
-
this.transport.close();
|
|
838
|
-
}
|
|
839
|
-
async upsertApplication(manifest, codeZip, upgradeRunningRequests = false) {
|
|
840
|
-
const applicationManifest = { ...manifest };
|
|
841
|
-
let publicEndpointId = publicEndpointIdFromManifest(applicationManifest);
|
|
842
|
-
if (applicationAllowsUnauthenticatedRequests(applicationManifest) && publicEndpointId === void 0) {
|
|
843
|
-
const applicationName = applicationManifest.name;
|
|
844
|
-
if (typeof applicationName === "string" && applicationName.length > 0) {
|
|
845
|
-
publicEndpointId = await this.existingApplicationPublicEndpointId(applicationName);
|
|
846
|
-
}
|
|
847
|
-
publicEndpointId ??= generatePublicEndpointId();
|
|
848
|
-
}
|
|
849
|
-
if (publicEndpointId !== void 0) {
|
|
850
|
-
applicationManifest.public_endpoint_id = publicEndpointId;
|
|
851
|
-
delete applicationManifest.publicEndpointId;
|
|
852
|
-
}
|
|
853
|
-
const form = new FormData();
|
|
854
|
-
form.append(
|
|
855
|
-
"code",
|
|
856
|
-
new Blob([toBlobPart(codeZip)], { type: "application/zip" }),
|
|
857
|
-
"code.zip"
|
|
858
|
-
);
|
|
859
|
-
form.append("code_content_type", "application/zip");
|
|
860
|
-
form.append("application", JSON.stringify(applicationManifest));
|
|
861
|
-
form.append(
|
|
862
|
-
"upgrade_requests_to_latest_code",
|
|
863
|
-
String(upgradeRunningRequests)
|
|
864
|
-
);
|
|
865
|
-
await this.transport.requestResponse("POST", this.namespacePath("applications"), {
|
|
866
|
-
body: form
|
|
867
|
-
});
|
|
868
|
-
}
|
|
869
|
-
async deleteApplication(applicationName) {
|
|
870
|
-
await this.transport.requestResponse(
|
|
871
|
-
"DELETE",
|
|
872
|
-
this.namespacePath(`applications/${encodeURIComponent(applicationName)}`)
|
|
873
|
-
);
|
|
874
|
-
}
|
|
875
|
-
async deleteSandboxImage(imageName) {
|
|
876
|
-
await this.transport.requestResponse(
|
|
877
|
-
"DELETE",
|
|
878
|
-
this.namespacePath(`sandbox-images/${encodeURIComponent(imageName)}`)
|
|
879
|
-
);
|
|
880
|
-
}
|
|
881
|
-
/**
|
|
882
|
-
* Look up a registered sandbox image (template) by its registered name.
|
|
883
|
-
*
|
|
884
|
-
* Returns the template, or `null` when no image with that name exists.
|
|
885
|
-
* API-key clients may omit organization/project IDs and use the
|
|
886
|
-
* token-scoped Platform API route directly. Explicit scope remains
|
|
887
|
-
* available for PAT callers.
|
|
888
|
-
*/
|
|
889
|
-
async findSandboxImageByName(imageName, options) {
|
|
890
|
-
const base = this.platformProjectPath(
|
|
891
|
-
"sandbox-templates",
|
|
892
|
-
options?.organizationId,
|
|
893
|
-
options?.projectId
|
|
894
|
-
);
|
|
895
|
-
const response = await this.transport.requestResponse(
|
|
896
|
-
"GET",
|
|
897
|
-
`${base}/by-name/${encodeURIComponent(imageName)}`,
|
|
898
|
-
{ statusOnlyCodes: /* @__PURE__ */ new Set([404]) }
|
|
899
|
-
);
|
|
900
|
-
if (response.status === 404) {
|
|
901
|
-
return null;
|
|
902
|
-
}
|
|
903
|
-
const raw = await parseJsonResponse(response);
|
|
904
|
-
return fromSnakeKeys(raw);
|
|
905
|
-
}
|
|
906
|
-
/**
|
|
907
|
-
* List all registered sandbox images (templates), following pagination to
|
|
908
|
-
* the end. API-key clients may omit organization/project IDs and use the
|
|
909
|
-
* token-scoped Platform API route directly.
|
|
910
|
-
*/
|
|
911
|
-
async listSandboxImages(options) {
|
|
912
|
-
const base = this.platformProjectPath(
|
|
913
|
-
"sandbox-templates",
|
|
914
|
-
options?.organizationId,
|
|
915
|
-
options?.projectId
|
|
916
|
-
);
|
|
917
|
-
let path4 = `${base}?pageSize=100`;
|
|
918
|
-
const templates = [];
|
|
919
|
-
while (path4 !== null) {
|
|
920
|
-
const page = await this.transport.requestJson(
|
|
921
|
-
"GET",
|
|
922
|
-
path4
|
|
923
|
-
);
|
|
924
|
-
for (const item of page.items ?? []) {
|
|
925
|
-
templates.push(fromSnakeKeys(item));
|
|
926
|
-
}
|
|
927
|
-
const next = page.pagination?.next;
|
|
928
|
-
path4 = next ? nextRequestPath(next) : null;
|
|
929
|
-
}
|
|
930
|
-
return templates;
|
|
931
|
-
}
|
|
932
|
-
async applications() {
|
|
933
|
-
const raw = await this.transport.requestJson(
|
|
934
|
-
"GET",
|
|
935
|
-
this.namespacePath("applications")
|
|
936
|
-
);
|
|
937
|
-
return (raw.applications ?? []).map(
|
|
938
|
-
(application) => fromSnakeKeys(application)
|
|
939
|
-
);
|
|
940
|
-
}
|
|
941
|
-
async applicationManifest(applicationName) {
|
|
942
|
-
const raw = await this.transport.requestJson(
|
|
943
|
-
"GET",
|
|
944
|
-
this.namespacePath(`applications/${encodeURIComponent(applicationName)}`)
|
|
945
|
-
);
|
|
946
|
-
return fromSnakeKeys(raw);
|
|
947
|
-
}
|
|
948
|
-
async runRequest(applicationName, inputs = []) {
|
|
949
|
-
const path4 = this.namespacePath(
|
|
950
|
-
`applications/${encodeURIComponent(applicationName)}`
|
|
951
|
-
);
|
|
952
|
-
const response = inputs.length === 0 ? await this.transport.requestResponse("POST", path4, {
|
|
953
|
-
body: new Uint8Array(),
|
|
954
|
-
headers: { Accept: "application/json" }
|
|
955
|
-
}) : inputs.length === 1 && inputs[0].name === "0" ? await this.transport.requestResponse("POST", path4, {
|
|
956
|
-
body: toRequestBody(inputs[0].data),
|
|
957
|
-
headers: {
|
|
958
|
-
Accept: "application/json",
|
|
959
|
-
"Content-Type": inputs[0].contentType
|
|
960
|
-
}
|
|
961
|
-
}) : await this.runMultipartRequest(path4, inputs);
|
|
962
|
-
const body = await parseJsonResponse(response);
|
|
963
|
-
const requestId = body?.request_id;
|
|
964
|
-
if (!requestId) {
|
|
965
|
-
throw new Error("missing request_id in run request response body");
|
|
966
|
-
}
|
|
967
|
-
return requestId;
|
|
968
|
-
}
|
|
969
|
-
async waitOnRequestCompletion(applicationName, requestId) {
|
|
970
|
-
const stream = this.transport.stream(
|
|
971
|
-
"GET",
|
|
972
|
-
this.namespacePath(
|
|
973
|
-
`applications/${encodeURIComponent(applicationName)}/requests/${encodeURIComponent(requestId)}/progress`
|
|
974
|
-
)
|
|
975
|
-
);
|
|
976
|
-
for await (const event of stream) {
|
|
977
|
-
if (Object.prototype.hasOwnProperty.call(event, "RequestFinished")) {
|
|
978
|
-
return;
|
|
979
|
-
}
|
|
980
|
-
}
|
|
981
|
-
throw new Error("progress stream ended before request completion");
|
|
982
|
-
}
|
|
983
|
-
async requestMetadata(applicationName, requestId) {
|
|
984
|
-
const raw = await this.transport.requestJson(
|
|
985
|
-
"GET",
|
|
986
|
-
this.namespacePath(
|
|
987
|
-
`applications/${encodeURIComponent(applicationName)}/requests/${encodeURIComponent(requestId)}`
|
|
988
|
-
)
|
|
989
|
-
);
|
|
990
|
-
return fromSnakeKeys(raw);
|
|
991
|
-
}
|
|
992
|
-
async requestOutput(applicationName, requestId) {
|
|
993
|
-
const response = await this.transport.requestResponse(
|
|
994
|
-
"GET",
|
|
995
|
-
this.namespacePath(
|
|
996
|
-
`applications/${encodeURIComponent(applicationName)}/requests/${encodeURIComponent(requestId)}/output`
|
|
997
|
-
)
|
|
998
|
-
);
|
|
999
|
-
const serializedValue = new Uint8Array(await response.arrayBuffer());
|
|
1000
|
-
const contentType = response.headers.get("content-type") ?? "";
|
|
1001
|
-
return {
|
|
1002
|
-
serializedValue,
|
|
1003
|
-
contentType
|
|
1004
|
-
};
|
|
1005
|
-
}
|
|
1006
|
-
async listSecrets(options) {
|
|
1007
|
-
const base = this.secretCollectionPath(
|
|
1008
|
-
options?.organizationId,
|
|
1009
|
-
options?.projectId
|
|
1010
|
-
);
|
|
1011
|
-
const raw = await this.transport.requestJson("GET", base);
|
|
1012
|
-
const pageSize = Math.max(0, options?.pageSize ?? 100);
|
|
1013
|
-
return Object.assign(
|
|
1014
|
-
{
|
|
1015
|
-
items: raw.slice(0, pageSize).map(secretFromMetadata),
|
|
1016
|
-
pagination: { total: raw.length }
|
|
1017
|
-
},
|
|
1018
|
-
{ traceId: raw.traceId }
|
|
1019
|
-
);
|
|
1020
|
-
}
|
|
1021
|
-
async getSecret(secretId, options) {
|
|
1022
|
-
const base = this.secretCollectionPath(
|
|
1023
|
-
options?.organizationId,
|
|
1024
|
-
options?.projectId
|
|
1025
|
-
);
|
|
1026
|
-
const raw = await this.transport.requestJson(
|
|
1027
|
-
"GET",
|
|
1028
|
-
`${base}/${encodeURIComponent(secretId)}`
|
|
1029
|
-
);
|
|
1030
|
-
return Object.assign(secretFromMetadata(raw), { traceId: raw.traceId });
|
|
1031
|
-
}
|
|
1032
|
-
async upsertSecrets(secrets, options) {
|
|
1033
|
-
const base = this.secretCollectionPath(
|
|
1034
|
-
options?.organizationId,
|
|
1035
|
-
options?.projectId
|
|
1036
|
-
);
|
|
1037
|
-
if (Array.isArray(secrets)) {
|
|
1038
|
-
const results = [];
|
|
1039
|
-
for (const secret of secrets) {
|
|
1040
|
-
results.push(await this.upsertSecret(base, secret));
|
|
1041
|
-
}
|
|
1042
|
-
return results;
|
|
1043
|
-
}
|
|
1044
|
-
return this.upsertSecret(base, secrets);
|
|
1045
|
-
}
|
|
1046
|
-
async deleteSecret(secretId, options) {
|
|
1047
|
-
const base = this.secretCollectionPath(
|
|
1048
|
-
options?.organizationId,
|
|
1049
|
-
options?.projectId
|
|
1050
|
-
);
|
|
1051
|
-
await this.transport.requestResponse(
|
|
1052
|
-
"DELETE",
|
|
1053
|
-
`${base}/${encodeURIComponent(secretId)}`
|
|
1054
|
-
);
|
|
1055
|
-
}
|
|
1056
|
-
async upsertSecret(base, secret) {
|
|
1057
|
-
let response = await this.transport.requestResponse("POST", base, {
|
|
1058
|
-
json: secret,
|
|
1059
|
-
headers: { "Idempotency-Key": nanoid() },
|
|
1060
|
-
statusOnlyCodes: /* @__PURE__ */ new Set([409])
|
|
1061
|
-
});
|
|
1062
|
-
if (response.status === 409) {
|
|
1063
|
-
const prefix = base.slice(0, -"/secrets".length);
|
|
1064
|
-
const existing = await this.transport.requestJson(
|
|
1065
|
-
"GET",
|
|
1066
|
-
`${prefix}/secret-names/${encodeURIComponent(secret.name)}`
|
|
1067
|
-
);
|
|
1068
|
-
response = await this.transport.requestResponse(
|
|
1069
|
-
"POST",
|
|
1070
|
-
`${base}/${encodeURIComponent(existing.id)}/versions`,
|
|
1071
|
-
{
|
|
1072
|
-
json: { value: secret.value },
|
|
1073
|
-
headers: { "Idempotency-Key": nanoid() }
|
|
1074
|
-
}
|
|
1075
|
-
);
|
|
1076
|
-
}
|
|
1077
|
-
const metadata = await parseJsonResponse(response);
|
|
1078
|
-
return Object.assign(secretFromMetadata(metadata), {
|
|
1079
|
-
traceId: response.traceId
|
|
1080
|
-
});
|
|
1081
|
-
}
|
|
1082
|
-
async startImageBuild(buildServicePath, request) {
|
|
1083
|
-
const form = new FormData();
|
|
1084
|
-
form.append("graph_name", request.applicationName);
|
|
1085
|
-
form.append("graph_version", request.applicationVersion);
|
|
1086
|
-
form.append("graph_function_name", request.functionName);
|
|
1087
|
-
form.append("image_name", request.imageName);
|
|
1088
|
-
form.append("image_id", request.imageId);
|
|
1089
|
-
form.append(
|
|
1090
|
-
"context",
|
|
1091
|
-
new Blob([toBlobPart(request.buildContext)]),
|
|
1092
|
-
"context.tar.gz"
|
|
1093
|
-
);
|
|
1094
|
-
const response = await this.transport.requestResponse(
|
|
1095
|
-
"PUT",
|
|
1096
|
-
`${trimTrailingSlashes2(buildServicePath)}/builds`,
|
|
1097
|
-
{ body: form }
|
|
1098
|
-
);
|
|
1099
|
-
const raw = await parseJsonResponse(response);
|
|
1100
|
-
return fromSnakeKeys(raw);
|
|
1101
|
-
}
|
|
1102
|
-
async createApplicationBuild(buildServicePath, request, imageContexts) {
|
|
1103
|
-
const form = createApplicationBuildForm(request, imageContexts);
|
|
1104
|
-
const response = await this.transport.requestResponse(
|
|
1105
|
-
"POST",
|
|
1106
|
-
trimTrailingSlashes2(buildServicePath),
|
|
1107
|
-
{ body: form }
|
|
1108
|
-
);
|
|
1109
|
-
const raw = await parseJsonResponse(response);
|
|
1110
|
-
return fromSnakeKeys(raw);
|
|
1111
|
-
}
|
|
1112
|
-
async applicationBuildInfo(buildServicePath, applicationBuildId) {
|
|
1113
|
-
const raw = await this.transport.requestJson(
|
|
1114
|
-
"GET",
|
|
1115
|
-
`${trimTrailingSlashes2(buildServicePath)}/${encodeURIComponent(applicationBuildId)}`
|
|
1116
|
-
);
|
|
1117
|
-
return fromSnakeKeys(raw);
|
|
1118
|
-
}
|
|
1119
|
-
async cancelApplicationBuild(buildServicePath, applicationBuildId) {
|
|
1120
|
-
const raw = await this.transport.requestJson(
|
|
1121
|
-
"POST",
|
|
1122
|
-
`${trimTrailingSlashes2(buildServicePath)}/${encodeURIComponent(applicationBuildId)}/cancel`
|
|
1123
|
-
);
|
|
1124
|
-
return fromSnakeKeys(raw);
|
|
1125
|
-
}
|
|
1126
|
-
async buildInfo(buildServicePath, buildId) {
|
|
1127
|
-
const raw = await this.transport.requestJson(
|
|
1128
|
-
"GET",
|
|
1129
|
-
`${trimTrailingSlashes2(buildServicePath)}/builds/${encodeURIComponent(buildId)}`
|
|
1130
|
-
);
|
|
1131
|
-
return fromSnakeKeys(raw);
|
|
1132
|
-
}
|
|
1133
|
-
async cancelBuild(buildServicePath, buildId) {
|
|
1134
|
-
await this.transport.requestResponse(
|
|
1135
|
-
"POST",
|
|
1136
|
-
`${trimTrailingSlashes2(buildServicePath)}/builds/${encodeURIComponent(buildId)}/cancel`
|
|
1137
|
-
);
|
|
1138
|
-
}
|
|
1139
|
-
async *streamBuildLogs(buildServicePath, buildId, signal) {
|
|
1140
|
-
const stream = this.transport.stream(
|
|
1141
|
-
"GET",
|
|
1142
|
-
`${trimTrailingSlashes2(buildServicePath)}/builds/${encodeURIComponent(buildId)}/logs`,
|
|
1143
|
-
signal
|
|
1144
|
-
);
|
|
1145
|
-
for await (const event of stream) {
|
|
1146
|
-
yield fromSnakeKeys(event);
|
|
1147
|
-
}
|
|
1148
|
-
}
|
|
1149
|
-
async runMultipartRequest(path4, inputs) {
|
|
1150
|
-
const form = new FormData();
|
|
1151
|
-
for (const input of inputs) {
|
|
1152
|
-
form.append(
|
|
1153
|
-
input.name,
|
|
1154
|
-
new Blob([toBlobPart(input.data)], { type: input.contentType }),
|
|
1155
|
-
input.name
|
|
1156
|
-
);
|
|
1157
|
-
}
|
|
1158
|
-
return this.transport.requestResponse("POST", path4, {
|
|
1159
|
-
body: form,
|
|
1160
|
-
headers: { Accept: "application/json" }
|
|
1161
|
-
});
|
|
1162
|
-
}
|
|
1163
|
-
namespacePath(subpath) {
|
|
1164
|
-
return `/v1/namespaces/${encodeURIComponent(this.namespace)}/${subpath.replace(/^\/+/, "")}`;
|
|
1165
|
-
}
|
|
1166
|
-
async existingApplicationPublicEndpointId(applicationName) {
|
|
1167
|
-
const response = await this.transport.requestResponse(
|
|
1168
|
-
"GET",
|
|
1169
|
-
this.namespacePath(`applications/${encodeURIComponent(applicationName)}`),
|
|
1170
|
-
{ statusOnlyCodes: /* @__PURE__ */ new Set([404]) }
|
|
1171
|
-
);
|
|
1172
|
-
if (response.status === 404) {
|
|
1173
|
-
return void 0;
|
|
1174
|
-
}
|
|
1175
|
-
const application = await parseJsonResponse(response);
|
|
1176
|
-
return publicEndpointIdFromManifest(application);
|
|
1177
|
-
}
|
|
1178
|
-
platformProjectPath(resource, organizationId, projectId) {
|
|
1179
|
-
const resolvedOrganizationId = organizationId ?? this.organizationId;
|
|
1180
|
-
const resolvedProjectId = projectId ?? this.projectId;
|
|
1181
|
-
if (!resolvedOrganizationId && !resolvedProjectId) {
|
|
1182
|
-
return `/platform/v1/${resource}`;
|
|
1183
|
-
}
|
|
1184
|
-
if (!resolvedOrganizationId || !resolvedProjectId) {
|
|
1185
|
-
throw new Error(
|
|
1186
|
-
"organizationId and projectId must be provided together"
|
|
1187
|
-
);
|
|
1188
|
-
}
|
|
1189
|
-
return `/platform/v1/organizations/${encodeURIComponent(resolvedOrganizationId)}/projects/${encodeURIComponent(resolvedProjectId)}/${resource}`;
|
|
1190
|
-
}
|
|
1191
|
-
secretCollectionPath(organizationId, projectId) {
|
|
1192
|
-
const resolvedOrganizationId = organizationId ?? this.organizationId;
|
|
1193
|
-
const resolvedProjectId = projectId ?? this.projectId;
|
|
1194
|
-
if (!resolvedOrganizationId && !resolvedProjectId) {
|
|
1195
|
-
return this.namespacePath("secrets");
|
|
1196
|
-
}
|
|
1197
|
-
if (!resolvedOrganizationId || !resolvedProjectId) {
|
|
1198
|
-
throw new Error("organizationId and projectId must be provided together");
|
|
1199
|
-
}
|
|
1200
|
-
return this.namespacePath("secrets");
|
|
1201
|
-
}
|
|
1202
|
-
};
|
|
1203
|
-
UNAUTHENTICATED_REQUESTS = "unauthenticated_requests";
|
|
1204
|
-
}
|
|
1205
|
-
});
|
|
1206
|
-
|
|
1207
|
-
// src/image.ts
|
|
1208
|
-
import { randomUUID } from "crypto";
|
|
1209
|
-
function cloneOperation(op) {
|
|
1210
|
-
return {
|
|
1211
|
-
type: op.type,
|
|
1212
|
-
args: [...op.args],
|
|
1213
|
-
options: { ...op.options }
|
|
1214
|
-
};
|
|
1215
|
-
}
|
|
1216
|
-
function renderOptions(options) {
|
|
1217
|
-
const entries = Object.entries(options);
|
|
1218
|
-
if (entries.length === 0) {
|
|
1219
|
-
return "";
|
|
1220
|
-
}
|
|
1221
|
-
return ` ${entries.map(([key, value]) => `--${key}=${value}`).join(" ")}`;
|
|
1222
|
-
}
|
|
1223
|
-
function renderBuildOp(op) {
|
|
1224
|
-
const options = renderOptions(op.options);
|
|
1225
|
-
if (op.type === ImageBuildOperationType.ENV) {
|
|
1226
|
-
return `ENV${options} ${op.args[0]}=${JSON.stringify(op.args[1])}`;
|
|
1227
|
-
}
|
|
1228
|
-
return `${op.type}${options} ${op.args.join(" ")}`;
|
|
1229
|
-
}
|
|
1230
|
-
function dockerfileContent(image) {
|
|
1231
|
-
const lines = image.baseImage == null ? [] : [`FROM ${image.baseImage}`];
|
|
1232
|
-
lines.push(...image.buildOperations.map((op) => renderBuildOp(op)));
|
|
1233
|
-
return lines.join("\n");
|
|
1234
|
-
}
|
|
1235
|
-
var DEFAULT_IMAGE_NAME, ImageBuildOperationType, Image;
|
|
1236
|
-
var init_image = __esm({
|
|
1237
|
-
"src/image.ts"() {
|
|
1238
|
-
"use strict";
|
|
1239
|
-
init_esm_shims();
|
|
1240
|
-
DEFAULT_IMAGE_NAME = "default";
|
|
1241
|
-
ImageBuildOperationType = {
|
|
1242
|
-
ADD: "ADD",
|
|
1243
|
-
COPY: "COPY",
|
|
1244
|
-
ENV: "ENV",
|
|
1245
|
-
RUN: "RUN",
|
|
1246
|
-
WORKDIR: "WORKDIR"
|
|
1247
|
-
};
|
|
1248
|
-
Image = class {
|
|
1249
|
-
_id;
|
|
1250
|
-
_name;
|
|
1251
|
-
_tag;
|
|
1252
|
-
_baseImage;
|
|
1253
|
-
_buildOperations;
|
|
1254
|
-
constructor(nameOrOptions = {}, tag = "latest", baseImage = null) {
|
|
1255
|
-
this._id = randomUUID();
|
|
1256
|
-
this._buildOperations = [];
|
|
1257
|
-
if (typeof nameOrOptions === "string") {
|
|
1258
|
-
this._name = nameOrOptions;
|
|
1259
|
-
this._tag = tag;
|
|
1260
|
-
this._baseImage = baseImage;
|
|
1261
|
-
return;
|
|
1262
|
-
}
|
|
1263
|
-
this._name = nameOrOptions.name ?? DEFAULT_IMAGE_NAME;
|
|
1264
|
-
this._tag = nameOrOptions.tag ?? "latest";
|
|
1265
|
-
this._baseImage = nameOrOptions.baseImage ?? null;
|
|
1266
|
-
}
|
|
1267
|
-
get name() {
|
|
1268
|
-
return this._name;
|
|
1269
|
-
}
|
|
1270
|
-
get tag() {
|
|
1271
|
-
return this._tag;
|
|
1272
|
-
}
|
|
1273
|
-
get baseImage() {
|
|
1274
|
-
return this._baseImage;
|
|
1275
|
-
}
|
|
1276
|
-
get buildOperations() {
|
|
1277
|
-
return this._buildOperations.map(cloneOperation);
|
|
1278
|
-
}
|
|
1279
|
-
add(src, dest, options = void 0) {
|
|
1280
|
-
return this._addOperation({
|
|
1281
|
-
type: ImageBuildOperationType.ADD,
|
|
1282
|
-
args: [src, dest],
|
|
1283
|
-
options: options == null ? {} : { ...options }
|
|
1284
|
-
});
|
|
1285
|
-
}
|
|
1286
|
-
copy(src, dest, options = void 0) {
|
|
1287
|
-
return this._addOperation({
|
|
1288
|
-
type: ImageBuildOperationType.COPY,
|
|
1289
|
-
args: [src, dest],
|
|
1290
|
-
options: options == null ? {} : { ...options }
|
|
1291
|
-
});
|
|
1292
|
-
}
|
|
1293
|
-
env(key, value) {
|
|
1294
|
-
return this._addOperation({
|
|
1295
|
-
type: ImageBuildOperationType.ENV,
|
|
1296
|
-
args: [key, value],
|
|
1297
|
-
options: {}
|
|
1298
|
-
});
|
|
1299
|
-
}
|
|
1300
|
-
run(commands, options = void 0) {
|
|
1301
|
-
return this._addOperation({
|
|
1302
|
-
type: ImageBuildOperationType.RUN,
|
|
1303
|
-
args: Array.isArray(commands) ? [...commands] : [commands],
|
|
1304
|
-
options: options == null ? {} : { ...options }
|
|
1305
|
-
});
|
|
1306
|
-
}
|
|
1307
|
-
workdir(directory) {
|
|
1308
|
-
return this._addOperation({
|
|
1309
|
-
type: ImageBuildOperationType.WORKDIR,
|
|
1310
|
-
args: [directory],
|
|
1311
|
-
options: {}
|
|
1312
|
-
});
|
|
1313
|
-
}
|
|
1314
|
-
/**
|
|
1315
|
-
* Build this image as a sandbox template and register it.
|
|
1316
|
-
*
|
|
1317
|
-
* Materializes the image in a build sandbox, snapshots the filesystem,
|
|
1318
|
-
* and registers the snapshot as a named sandbox template.
|
|
1319
|
-
*/
|
|
1320
|
-
async build(options = {}) {
|
|
1321
|
-
const { createSandboxImage: createSandboxImage2 } = await Promise.resolve().then(() => (init_sandbox_image(), sandbox_image_exports));
|
|
1322
|
-
return createSandboxImage2(this, options);
|
|
1323
|
-
}
|
|
1324
|
-
_addOperation(op) {
|
|
1325
|
-
this._buildOperations.push(op);
|
|
1326
|
-
return this;
|
|
1327
|
-
}
|
|
1328
|
-
};
|
|
1329
|
-
}
|
|
1330
|
-
});
|
|
1331
|
-
|
|
1332
|
-
// lib/libc.cjs
|
|
1333
|
-
var require_libc = __commonJS({
|
|
1334
|
-
"lib/libc.cjs"(exports, module) {
|
|
1335
|
-
"use strict";
|
|
1336
|
-
init_esm_shims();
|
|
1337
|
-
function detectLinuxLibc2(fs2, executable = process.execPath) {
|
|
1338
|
-
const override = process.env.TENSORLAKE_NODE_LIBC;
|
|
1339
|
-
if (override != null) {
|
|
1340
|
-
if (override === "gnu" || override === "musl") return override;
|
|
1341
|
-
throw new Error("TENSORLAKE_NODE_LIBC must be 'gnu' or 'musl'.");
|
|
1342
|
-
}
|
|
1343
|
-
let fd;
|
|
1344
|
-
try {
|
|
1345
|
-
let read2 = function(size, offset) {
|
|
1346
|
-
if (!Number.isSafeInteger(offset) || offset < 0) {
|
|
1347
|
-
throw new Error("Invalid ELF offset");
|
|
1348
|
-
}
|
|
1349
|
-
const buffer = Buffer.alloc(size);
|
|
1350
|
-
let count2 = 0;
|
|
1351
|
-
while (count2 < size) {
|
|
1352
|
-
const bytes = fs2.readSync(fd, buffer, count2, size - count2, offset + count2);
|
|
1353
|
-
if (bytes === 0) throw new Error("Truncated ELF executable");
|
|
1354
|
-
count2 += bytes;
|
|
1355
|
-
}
|
|
1356
|
-
return buffer;
|
|
1357
|
-
};
|
|
1358
|
-
var read = read2;
|
|
1359
|
-
fd = fs2.openSync(executable, "r");
|
|
1360
|
-
const header = read2(64, 0);
|
|
1361
|
-
if (header.readUInt32BE(0) !== 2135247942 || header[4] !== 2 || header[5] !== 1) {
|
|
1362
|
-
throw new Error("Expected a little-endian ELF64 executable");
|
|
1363
|
-
}
|
|
1364
|
-
const entrySize = header.readUInt16LE(54);
|
|
1365
|
-
const count = header.readUInt16LE(56);
|
|
1366
|
-
if (entrySize !== 56 || count === 0 || count > 128) {
|
|
1367
|
-
throw new Error("Unsupported ELF program headers");
|
|
1368
|
-
}
|
|
1369
|
-
const entries = read2(entrySize * count, Number(header.readBigUInt64LE(32)));
|
|
1370
|
-
for (let i = 0; i < count; i++) {
|
|
1371
|
-
const offset = i * entrySize;
|
|
1372
|
-
if (entries.readUInt32LE(offset) !== 3) continue;
|
|
1373
|
-
const size = Number(entries.readBigUInt64LE(offset + 32));
|
|
1374
|
-
if (size < 2 || size > 4096) throw new Error("Invalid ELF interpreter size");
|
|
1375
|
-
const interpreter = read2(size, Number(entries.readBigUInt64LE(offset + 8)));
|
|
1376
|
-
if (interpreter[size - 1] !== 0) throw new Error("Unterminated ELF interpreter");
|
|
1377
|
-
const name = interpreter.subarray(0, -1).toString("utf8").split("/").at(-1);
|
|
1378
|
-
if (name.startsWith("ld-musl-")) return "musl";
|
|
1379
|
-
if (name.startsWith("ld-linux-")) return "gnu";
|
|
1380
|
-
throw new Error("Unrecognized ELF interpreter");
|
|
1381
|
-
}
|
|
1382
|
-
throw new Error("No ELF interpreter (statically linked executable)");
|
|
1383
|
-
} catch (cause) {
|
|
1384
|
-
throw new Error(
|
|
1385
|
-
"Unable to detect Linux libc from the Node executable. Set TENSORLAKE_NODE_LIBC to 'gnu' or 'musl' for a nonstandard runtime.",
|
|
1386
|
-
{ cause }
|
|
1387
|
-
);
|
|
1388
|
-
} finally {
|
|
1389
|
-
if (fd != null) fs2.closeSync(fd);
|
|
1390
|
-
}
|
|
1391
|
-
}
|
|
1392
|
-
module.exports = { detectLinuxLibc: detectLinuxLibc2 };
|
|
1393
|
-
}
|
|
1394
|
-
});
|
|
1395
|
-
|
|
1396
|
-
// src/native-binding.ts
|
|
1397
|
-
import * as fs from "fs";
|
|
1398
|
-
import { createRequire as createRequire2 } from "module";
|
|
1399
|
-
import path2 from "path";
|
|
1400
|
-
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
1401
|
-
function packageRoot() {
|
|
1402
|
-
const parent = fileURLToPath2(new URL("../", import.meta.url));
|
|
1403
|
-
if (fs.existsSync(path2.join(parent, "package.json"))) return parent;
|
|
1404
|
-
const grandparent = fileURLToPath2(new URL("../../", import.meta.url));
|
|
1405
|
-
if (fs.existsSync(path2.join(grandparent, "package.json"))) return grandparent;
|
|
1406
|
-
return parent;
|
|
1407
|
-
}
|
|
1408
|
-
function linuxLibcFamily(options) {
|
|
1409
|
-
if (options.libc != null) return options.libc;
|
|
1410
|
-
if (options.report != null) {
|
|
1411
|
-
return options.report.header?.glibcVersionRuntime ? "gnu" : "musl";
|
|
1412
|
-
}
|
|
1413
|
-
if (cachedLinuxLibc != null) return cachedLinuxLibc;
|
|
1414
|
-
cachedLinuxLibc = (0, import_libc.detectLinuxLibc)(fs);
|
|
1415
|
-
return cachedLinuxLibc;
|
|
1416
|
-
}
|
|
1417
|
-
function nativeTargetId(platform = process.platform, arch = process.arch, options = {}) {
|
|
1418
|
-
const target = `${platform}-${arch}`;
|
|
1419
|
-
if (platform !== "linux") return target;
|
|
1420
|
-
if (options.libc == null && options.report == null && platform !== process.platform) {
|
|
1421
|
-
return target;
|
|
1422
|
-
}
|
|
1423
|
-
return linuxLibcFamily(options) === "musl" ? `${target}-musl` : target;
|
|
1424
|
-
}
|
|
1425
|
-
function nativeBindingPath(options = {}) {
|
|
1426
|
-
const platform = options.platform ?? process.platform;
|
|
1427
|
-
const arch = options.arch ?? process.arch;
|
|
1428
|
-
return path2.join(
|
|
1429
|
-
options.packageRoot ?? packageRoot(),
|
|
1430
|
-
"dist",
|
|
1431
|
-
"native",
|
|
1432
|
-
nativeTargetId(platform, arch, options),
|
|
1433
|
-
"tensorlake-node.node"
|
|
1434
|
-
);
|
|
1435
|
-
}
|
|
1436
|
-
function nativePackageName(platform = process.platform, arch = process.arch, options = {}) {
|
|
1437
|
-
return NATIVE_PACKAGES[nativeTargetId(platform, arch, options)];
|
|
1438
|
-
}
|
|
1439
|
-
function loadNative() {
|
|
1440
|
-
const target = nativeTargetId();
|
|
1441
|
-
const bindingPath = nativeBindingPath();
|
|
1442
|
-
const require2 = createRequire2(import.meta.url);
|
|
1443
|
-
if (fs.existsSync(bindingPath)) return require2(bindingPath);
|
|
1444
|
-
const packageName = nativePackageName();
|
|
1445
|
-
if (!packageName) {
|
|
1446
|
-
throw new Error(
|
|
1447
|
-
`Tensorlake does not provide a native binding for ${target}.`
|
|
1448
|
-
);
|
|
1449
|
-
}
|
|
1450
|
-
let packageEntry;
|
|
1451
|
-
try {
|
|
1452
|
-
packageEntry = require2.resolve(packageName);
|
|
1453
|
-
} catch (cause) {
|
|
1454
|
-
throw new Error(
|
|
1455
|
-
`Missing native binding package ${packageName} for ${target}. Reinstall tensorlake without omitting optional dependencies, and install dependencies on the machine where they will run.`,
|
|
1456
|
-
{ cause }
|
|
1457
|
-
);
|
|
1458
|
-
}
|
|
1459
|
-
return require2(packageEntry);
|
|
1460
|
-
}
|
|
1461
|
-
var import_libc, NATIVE_PACKAGES, cachedLinuxLibc;
|
|
1462
|
-
var init_native_binding = __esm({
|
|
1463
|
-
"src/native-binding.ts"() {
|
|
1464
|
-
"use strict";
|
|
1465
|
-
init_esm_shims();
|
|
1466
|
-
import_libc = __toESM(require_libc(), 1);
|
|
1467
|
-
NATIVE_PACKAGES = {
|
|
1468
|
-
"darwin-arm64": "tensorlake-native-darwin-arm64",
|
|
1469
|
-
"linux-arm64": "tensorlake-native-linux-arm64-gnu",
|
|
1470
|
-
"linux-arm64-musl": "tensorlake-native-linux-arm64-musl",
|
|
1471
|
-
"linux-x64": "tensorlake-native-linux-x64-gnu",
|
|
1472
|
-
"linux-x64-musl": "tensorlake-native-linux-x64-musl",
|
|
1473
|
-
"win32-x64": "tensorlake-native-win32-x64"
|
|
1474
|
-
};
|
|
1475
|
-
}
|
|
1476
|
-
});
|
|
1477
|
-
|
|
1478
|
-
// src/sandbox-image.ts
|
|
1479
|
-
var sandbox_image_exports = {};
|
|
1480
|
-
__export(sandbox_image_exports, {
|
|
1481
|
-
__setNativeBindingForTest: () => __setNativeBindingForTest,
|
|
1482
|
-
buildContextFromEnv: () => buildContextFromEnv,
|
|
1483
|
-
createSandboxImage: () => createSandboxImage,
|
|
1484
|
-
deleteSandboxImage: () => deleteSandboxImage,
|
|
1485
|
-
findSandboxImageByName: () => findSandboxImageByName,
|
|
1486
|
-
importSandboxImage: () => importSandboxImage,
|
|
1487
|
-
listSandboxImages: () => listSandboxImages,
|
|
1488
|
-
runCreateSandboxImageCli: () => runCreateSandboxImageCli,
|
|
1489
|
-
runImportSandboxImageCli: () => runImportSandboxImageCli
|
|
1490
|
-
});
|
|
1491
|
-
import path3 from "path";
|
|
1492
|
-
import os from "os";
|
|
1493
|
-
import { existsSync as existsSync2, mkdtempSync, rmSync } from "fs";
|
|
1494
|
-
import { parseArgs } from "util";
|
|
1495
|
-
function loadNativeBinding() {
|
|
1496
|
-
if (cachedNativeBinding) return cachedNativeBinding;
|
|
1497
|
-
if (cachedNativeBindingError) throw cachedNativeBindingError;
|
|
1498
|
-
try {
|
|
1499
|
-
cachedNativeBinding = loadNative();
|
|
1500
|
-
return cachedNativeBinding;
|
|
1501
|
-
} catch (error) {
|
|
1502
|
-
cachedNativeBindingError = error instanceof Error ? error : new Error(String(error));
|
|
1503
|
-
throw cachedNativeBindingError;
|
|
1504
|
-
}
|
|
1505
|
-
}
|
|
1506
|
-
function __setNativeBindingForTest(binding) {
|
|
1507
|
-
cachedNativeBinding = binding;
|
|
1508
|
-
cachedNativeBindingError = void 0;
|
|
1509
|
-
}
|
|
1510
|
-
function nonEmpty(value) {
|
|
1511
|
-
return value && value.length > 0 ? value : void 0;
|
|
1512
|
-
}
|
|
1513
|
-
function buildContextFromEnv() {
|
|
1514
|
-
const debugRaw = (process.env.TENSORLAKE_DEBUG ?? "").toLowerCase();
|
|
1515
|
-
const debug = ["1", "true", "yes", "on"].includes(debugRaw);
|
|
1516
|
-
return {
|
|
1517
|
-
apiUrl: nonEmpty(process.env.TENSORLAKE_API_URL) ?? "https://api.tensorlake.ai",
|
|
1518
|
-
apiKey: nonEmpty(process.env.TENSORLAKE_API_KEY),
|
|
1519
|
-
personalAccessToken: nonEmpty(process.env.TENSORLAKE_PAT),
|
|
1520
|
-
namespace: nonEmpty(process.env.INDEXIFY_NAMESPACE) ?? "default",
|
|
1521
|
-
organizationId: nonEmpty(process.env.TENSORLAKE_ORGANIZATION_ID),
|
|
1522
|
-
projectId: nonEmpty(process.env.TENSORLAKE_PROJECT_ID),
|
|
1523
|
-
debug
|
|
1524
|
-
};
|
|
1525
|
-
}
|
|
1526
|
-
function defaultRegisteredName(dockerfilePath) {
|
|
1527
|
-
const parsed = path3.parse(dockerfilePath);
|
|
1528
|
-
if (parsed.name.toLowerCase() === "dockerfile") {
|
|
1529
|
-
const parentName = path3.basename(path3.dirname(dockerfilePath)).trim();
|
|
1530
|
-
return parentName || "sandbox-image";
|
|
1531
|
-
}
|
|
1532
|
-
return parsed.name || "sandbox-image";
|
|
1533
|
-
}
|
|
1534
|
-
function defaultRegisteredNameFromImage(imageReference) {
|
|
1535
|
-
const withoutDigest = imageReference.split("@", 1)[0] ?? imageReference;
|
|
1536
|
-
const lastSegment = withoutDigest.split("/").pop() ?? withoutDigest;
|
|
1537
|
-
const colonIndex = lastSegment.lastIndexOf(":");
|
|
1538
|
-
const name = colonIndex > 0 && colonIndex < lastSegment.length - 1 ? lastSegment.slice(0, colonIndex) : lastSegment;
|
|
1539
|
-
return name || "imported-image";
|
|
1540
|
-
}
|
|
1541
|
-
function noopEmit(_event) {
|
|
1542
|
-
}
|
|
1543
|
-
function stderrEmit(event) {
|
|
1544
|
-
const message = typeof event.message === "string" ? event.message : "";
|
|
1545
|
-
const type = typeof event.type === "string" ? event.type : "";
|
|
1546
|
-
if (type === "build_log") {
|
|
1547
|
-
const stream = typeof event.stream === "string" ? event.stream : "stdout";
|
|
1548
|
-
process.stderr.write(`[${stream}] ${message}
|
|
1549
|
-
`);
|
|
1550
|
-
} else if (message) {
|
|
1551
|
-
process.stderr.write(`[${type}] ${message}
|
|
1552
|
-
`);
|
|
1553
|
-
}
|
|
1554
|
-
}
|
|
1555
|
-
function ndjsonStdoutEmit(event) {
|
|
1556
|
-
process.stdout.write(`${JSON.stringify(event)}
|
|
1557
|
-
`);
|
|
1558
|
-
}
|
|
1559
|
-
function eventToEmitDict(event) {
|
|
1560
|
-
const out = {
|
|
1561
|
-
type: event.eventType,
|
|
1562
|
-
message: event.message
|
|
1563
|
-
};
|
|
1564
|
-
if (event.stream != null) out.stream = event.stream;
|
|
1565
|
-
return out;
|
|
1566
|
-
}
|
|
1567
|
-
function runOpMountsContext(op) {
|
|
1568
|
-
if (op.type !== ImageBuildOperationType.RUN) {
|
|
1569
|
-
return false;
|
|
1570
|
-
}
|
|
1571
|
-
const mount = op.options.mount;
|
|
1572
|
-
if (mount == null || mount === "") {
|
|
1573
|
-
return false;
|
|
1574
|
-
}
|
|
1575
|
-
const fields = {};
|
|
1576
|
-
for (const token of mount.split(",")) {
|
|
1577
|
-
const eq = token.indexOf("=");
|
|
1578
|
-
const key = (eq === -1 ? token : token.slice(0, eq)).trim();
|
|
1579
|
-
const value = eq === -1 ? "" : token.slice(eq + 1).trim();
|
|
1580
|
-
fields[key] = value;
|
|
1581
|
-
}
|
|
1582
|
-
if ((fields.type ?? "bind") !== "bind") {
|
|
1583
|
-
return false;
|
|
1584
|
-
}
|
|
1585
|
-
return !("from" in fields);
|
|
1586
|
-
}
|
|
1587
|
-
function opReferencesHostFiles(op) {
|
|
1588
|
-
if (op.type === ImageBuildOperationType.RUN) {
|
|
1589
|
-
return runOpMountsContext(op);
|
|
1590
|
-
}
|
|
1591
|
-
if (op.type !== ImageBuildOperationType.COPY && op.type !== ImageBuildOperationType.ADD) {
|
|
1592
|
-
return false;
|
|
1593
|
-
}
|
|
1594
|
-
if (op.options.from != null) {
|
|
1595
|
-
return false;
|
|
1596
|
-
}
|
|
1597
|
-
if (op.type === ImageBuildOperationType.ADD && (op.args[0].startsWith("http://") || op.args[0].startsWith("https://"))) {
|
|
1598
|
-
return false;
|
|
1599
|
-
}
|
|
1600
|
-
return true;
|
|
1601
|
-
}
|
|
1602
|
-
function imageRequiresContext(image) {
|
|
1603
|
-
return image.buildOperations.some(opReferencesHostFiles);
|
|
1604
|
-
}
|
|
1605
|
-
async function createSandboxImage(source, options = {}, deps = {}) {
|
|
1606
|
-
const emit = deps.emit ?? (options.verbose ? stderrEmit : noopEmit);
|
|
1607
|
-
const context = buildContextFromEnv();
|
|
1608
|
-
let dockerfilePath;
|
|
1609
|
-
let dockerfileText;
|
|
1610
|
-
let nativeContextDir;
|
|
1611
|
-
let effectiveName;
|
|
1612
|
-
let tempContextDir;
|
|
1613
|
-
if (source instanceof Image) {
|
|
1614
|
-
if (!source.baseImage) {
|
|
1615
|
-
throw new Error("Image must have a baseImage to build");
|
|
1616
|
-
}
|
|
1617
|
-
let resolvedContext;
|
|
1618
|
-
if (options.contextDir != null) {
|
|
1619
|
-
resolvedContext = path3.resolve(options.contextDir);
|
|
1620
|
-
} else if (imageRequiresContext(source)) {
|
|
1621
|
-
throw new Error(
|
|
1622
|
-
"This image reads files from the host (via COPY/ADD or a RUN bind mount), so it needs a build context. Pass `contextDir` pointing at the directory that contains those sources; they resolve relative to it, like `docker build <contextDir>`."
|
|
1623
|
-
);
|
|
1624
|
-
} else {
|
|
1625
|
-
tempContextDir = mkdtempSync(path3.join(os.tmpdir(), "tl-build-context-"));
|
|
1626
|
-
resolvedContext = tempContextDir;
|
|
1627
|
-
}
|
|
1628
|
-
dockerfilePath = path3.join(resolvedContext, "Dockerfile");
|
|
1629
|
-
let text = dockerfileContent(source);
|
|
1630
|
-
if (!text.endsWith("\n")) text += "\n";
|
|
1631
|
-
dockerfileText = text;
|
|
1632
|
-
nativeContextDir = resolvedContext;
|
|
1633
|
-
effectiveName = options.registeredName ?? source.name;
|
|
1634
|
-
} else if (typeof source === "string") {
|
|
1635
|
-
const resolvedPath = path3.resolve(source);
|
|
1636
|
-
if (!existsSync2(resolvedPath)) {
|
|
1637
|
-
throw new Error(`Dockerfile not found: ${source}`);
|
|
1638
|
-
}
|
|
1639
|
-
dockerfilePath = resolvedPath;
|
|
1640
|
-
dockerfileText = void 0;
|
|
1641
|
-
nativeContextDir = void 0;
|
|
1642
|
-
effectiveName = options.registeredName ?? defaultRegisteredName(resolvedPath);
|
|
1643
|
-
} else {
|
|
1644
|
-
throw new TypeError(
|
|
1645
|
-
`source must be an Image or a Dockerfile path, got ${typeof source}`
|
|
1646
|
-
);
|
|
1647
|
-
}
|
|
1648
|
-
try {
|
|
1649
|
-
if (effectiveName === DEFAULT_IMAGE_NAME2) {
|
|
1650
|
-
console.warn(
|
|
1651
|
-
`Building sandbox image with the default name "${DEFAULT_IMAGE_NAME2}". Pass \`registeredName\` or \`Image({ name })\` to avoid collisions with other default-named images in this project.`
|
|
1652
|
-
);
|
|
1653
|
-
}
|
|
1654
|
-
const usePat = deps._allowPat === true && context.apiKey == null;
|
|
1655
|
-
const bearerToken = context.apiKey ?? (usePat ? context.personalAccessToken : void 0);
|
|
1656
|
-
if (!bearerToken) {
|
|
1657
|
-
if (context.personalAccessToken && !deps._allowPat) {
|
|
1658
|
-
throw new Error(
|
|
1659
|
-
"Sandbox image SDKs require TENSORLAKE_API_KEY. Personal access tokens are CLI-only."
|
|
1660
|
-
);
|
|
1661
|
-
}
|
|
1662
|
-
throw new Error(
|
|
1663
|
-
deps._allowPat ? "Missing TENSORLAKE_API_KEY or TENSORLAKE_PAT credentials." : "Missing TENSORLAKE_API_KEY credentials."
|
|
1664
|
-
);
|
|
1665
|
-
}
|
|
1666
|
-
emit({ type: "status", message: `Building image '${effectiveName}'...` });
|
|
1667
|
-
const binding = loadNativeBinding();
|
|
1668
|
-
let emitError;
|
|
1669
|
-
const resultJson = await binding.buildSandboxImage(
|
|
1670
|
-
{
|
|
1671
|
-
apiUrl: context.apiUrl,
|
|
1672
|
-
bearerToken,
|
|
1673
|
-
dockerfilePath,
|
|
1674
|
-
registeredName: effectiveName,
|
|
1675
|
-
diskMb: options.diskMb,
|
|
1676
|
-
builderDiskMb: options.builderDiskMb,
|
|
1677
|
-
cpus: options.cpus,
|
|
1678
|
-
memoryMb: options.memoryMb,
|
|
1679
|
-
isPublic: options.isPublic ?? false,
|
|
1680
|
-
organizationId: usePat ? context.organizationId : void 0,
|
|
1681
|
-
projectId: usePat ? context.projectId : void 0,
|
|
1682
|
-
namespace: context.namespace,
|
|
1683
|
-
useScopeHeaders: usePat,
|
|
1684
|
-
userAgent: void 0,
|
|
1685
|
-
dockerCompat: options.dockerCompat ?? false,
|
|
1686
|
-
dockerfileText,
|
|
1687
|
-
contextDir: nativeContextDir
|
|
1688
|
-
},
|
|
1689
|
-
(event) => {
|
|
1690
|
-
try {
|
|
1691
|
-
emit(eventToEmitDict(event));
|
|
1692
|
-
} catch (error) {
|
|
1693
|
-
emitError ??= error;
|
|
1694
|
-
}
|
|
1695
|
-
}
|
|
1696
|
-
);
|
|
1697
|
-
if (emitError != null) {
|
|
1698
|
-
throw emitError;
|
|
1699
|
-
}
|
|
1700
|
-
let result = {};
|
|
1701
|
-
if (resultJson.trim().length > 0) {
|
|
1702
|
-
result = JSON.parse(resultJson);
|
|
1703
|
-
}
|
|
1704
|
-
emit({
|
|
1705
|
-
type: "image_registered",
|
|
1706
|
-
name: effectiveName,
|
|
1707
|
-
image_id: typeof result.id === "string" && result.id || typeof result.templateId === "string" && result.templateId || ""
|
|
1708
|
-
});
|
|
1709
|
-
emit({ type: "done" });
|
|
1710
|
-
return result;
|
|
1711
|
-
} finally {
|
|
1712
|
-
if (tempContextDir != null) {
|
|
1713
|
-
rmSync(tempContextDir, { recursive: true, force: true });
|
|
1714
|
-
}
|
|
1715
|
-
}
|
|
1716
|
-
}
|
|
1717
|
-
async function importSandboxImage(imageReference, options = {}, deps = {}) {
|
|
1718
|
-
const emit = deps.emit ?? (options.verbose ? stderrEmit : noopEmit);
|
|
1719
|
-
if (typeof imageReference !== "string" || imageReference.trim().length === 0) {
|
|
1720
|
-
throw new Error("image reference to import must not be empty");
|
|
1721
|
-
}
|
|
1722
|
-
const reference = imageReference.trim();
|
|
1723
|
-
const context = buildContextFromEnv();
|
|
1724
|
-
const effectiveName = options.registeredName ?? defaultRegisteredNameFromImage(reference);
|
|
1725
|
-
if (effectiveName === DEFAULT_IMAGE_NAME2) {
|
|
1726
|
-
console.warn(
|
|
1727
|
-
`Importing sandbox image with the default name "${DEFAULT_IMAGE_NAME2}". Pass \`registeredName\` to avoid collisions with other default-named images in this project.`
|
|
1728
|
-
);
|
|
1729
|
-
}
|
|
1730
|
-
const usePat = deps._allowPat === true && context.apiKey == null;
|
|
1731
|
-
const bearerToken = context.apiKey ?? (usePat ? context.personalAccessToken : void 0);
|
|
1732
|
-
if (!bearerToken) {
|
|
1733
|
-
if (context.personalAccessToken && !deps._allowPat) {
|
|
1734
|
-
throw new Error(
|
|
1735
|
-
"Sandbox image SDKs require TENSORLAKE_API_KEY. Personal access tokens are CLI-only."
|
|
1736
|
-
);
|
|
1737
|
-
}
|
|
1738
|
-
throw new Error(
|
|
1739
|
-
deps._allowPat ? "Missing TENSORLAKE_API_KEY or TENSORLAKE_PAT credentials." : "Missing TENSORLAKE_API_KEY credentials."
|
|
1740
|
-
);
|
|
1741
|
-
}
|
|
1742
|
-
emit({
|
|
1743
|
-
type: "status",
|
|
1744
|
-
message: `Importing image '${reference}' as '${effectiveName}'...`
|
|
1745
|
-
});
|
|
1746
|
-
const binding = loadNativeBinding();
|
|
1747
|
-
let emitError;
|
|
1748
|
-
const resultJson = await binding.importSandboxImage(
|
|
1749
|
-
{
|
|
1750
|
-
apiUrl: context.apiUrl,
|
|
1751
|
-
bearerToken,
|
|
1752
|
-
imageReference: reference,
|
|
1753
|
-
registeredName: effectiveName,
|
|
1754
|
-
diskMb: options.diskMb,
|
|
1755
|
-
builderDiskMb: options.builderDiskMb,
|
|
1756
|
-
cpus: options.cpus,
|
|
1757
|
-
memoryMb: options.memoryMb,
|
|
1758
|
-
isPublic: options.isPublic ?? false,
|
|
1759
|
-
organizationId: usePat ? context.organizationId : void 0,
|
|
1760
|
-
projectId: usePat ? context.projectId : void 0,
|
|
1761
|
-
namespace: context.namespace,
|
|
1762
|
-
useScopeHeaders: usePat,
|
|
1763
|
-
userAgent: void 0,
|
|
1764
|
-
dockerCompat: options.dockerCompat ?? false
|
|
1765
|
-
},
|
|
1766
|
-
(event) => {
|
|
1767
|
-
try {
|
|
1768
|
-
emit(eventToEmitDict(event));
|
|
1769
|
-
} catch (error) {
|
|
1770
|
-
emitError ??= error;
|
|
1771
|
-
}
|
|
1772
|
-
}
|
|
1773
|
-
);
|
|
1774
|
-
if (emitError != null) {
|
|
1775
|
-
throw emitError;
|
|
1776
|
-
}
|
|
1777
|
-
let result = {};
|
|
1778
|
-
if (resultJson.trim().length > 0) {
|
|
1779
|
-
result = JSON.parse(resultJson);
|
|
1780
|
-
}
|
|
1781
|
-
emit({
|
|
1782
|
-
type: "image_registered",
|
|
1783
|
-
name: effectiveName,
|
|
1784
|
-
image_id: typeof result.id === "string" && result.id || typeof result.templateId === "string" && result.templateId || ""
|
|
1785
|
-
});
|
|
1786
|
-
emit({ type: "done" });
|
|
1787
|
-
return result;
|
|
1788
|
-
}
|
|
1789
|
-
async function deleteSandboxImage(imageName) {
|
|
1790
|
-
if (typeof imageName !== "string" || imageName.length === 0) {
|
|
1791
|
-
throw new TypeError("imageName must be a non-empty string");
|
|
1792
|
-
}
|
|
1793
|
-
const context = buildContextFromEnv();
|
|
1794
|
-
const bearerToken = context.apiKey;
|
|
1795
|
-
if (!bearerToken) {
|
|
1796
|
-
if (context.personalAccessToken) {
|
|
1797
|
-
throw new Error(
|
|
1798
|
-
"Sandbox image SDKs require TENSORLAKE_API_KEY. Personal access tokens are CLI-only."
|
|
1799
|
-
);
|
|
1800
|
-
}
|
|
1801
|
-
throw new Error("Missing TENSORLAKE_API_KEY credentials.");
|
|
1802
|
-
}
|
|
1803
|
-
const client = new CloudClient({
|
|
1804
|
-
apiUrl: context.apiUrl,
|
|
1805
|
-
apiKey: bearerToken,
|
|
1806
|
-
namespace: context.namespace
|
|
1807
|
-
});
|
|
1808
|
-
try {
|
|
1809
|
-
await client.deleteSandboxImage(imageName);
|
|
1810
|
-
} finally {
|
|
1811
|
-
client.close();
|
|
1812
|
-
}
|
|
1813
|
-
}
|
|
1814
|
-
async function findSandboxImageByName(imageName) {
|
|
1815
|
-
if (typeof imageName !== "string" || imageName.length === 0) {
|
|
1816
|
-
throw new TypeError("imageName must be a non-empty string");
|
|
1817
|
-
}
|
|
1818
|
-
const context = buildContextFromEnv();
|
|
1819
|
-
const bearerToken = context.apiKey;
|
|
1820
|
-
if (!bearerToken) {
|
|
1821
|
-
if (context.personalAccessToken) {
|
|
1822
|
-
throw new Error(
|
|
1823
|
-
"Sandbox image SDKs require TENSORLAKE_API_KEY. Personal access tokens are CLI-only."
|
|
1824
|
-
);
|
|
1825
|
-
}
|
|
1826
|
-
throw new Error("Missing TENSORLAKE_API_KEY credentials.");
|
|
1827
|
-
}
|
|
1828
|
-
const client = new CloudClient({
|
|
1829
|
-
apiUrl: context.apiUrl,
|
|
1830
|
-
apiKey: bearerToken,
|
|
1831
|
-
namespace: context.namespace
|
|
1832
|
-
});
|
|
1833
|
-
try {
|
|
1834
|
-
return await client.findSandboxImageByName(imageName);
|
|
1835
|
-
} finally {
|
|
1836
|
-
client.close();
|
|
1837
|
-
}
|
|
1838
|
-
}
|
|
1839
|
-
async function listSandboxImages() {
|
|
1840
|
-
const context = buildContextFromEnv();
|
|
1841
|
-
const bearerToken = context.apiKey;
|
|
1842
|
-
if (!bearerToken) {
|
|
1843
|
-
if (context.personalAccessToken) {
|
|
1844
|
-
throw new Error(
|
|
1845
|
-
"Sandbox image SDKs require TENSORLAKE_API_KEY. Personal access tokens are CLI-only."
|
|
1846
|
-
);
|
|
1847
|
-
}
|
|
1848
|
-
throw new Error("Missing TENSORLAKE_API_KEY credentials.");
|
|
1849
|
-
}
|
|
1850
|
-
const client = new CloudClient({
|
|
1851
|
-
apiUrl: context.apiUrl,
|
|
1852
|
-
apiKey: bearerToken,
|
|
1853
|
-
namespace: context.namespace
|
|
1854
|
-
});
|
|
1855
|
-
try {
|
|
1856
|
-
return await client.listSandboxImages();
|
|
1857
|
-
} finally {
|
|
1858
|
-
client.close();
|
|
1859
|
-
}
|
|
1860
|
-
}
|
|
1861
|
-
async function runCreateSandboxImageCli(argv = process.argv.slice(2)) {
|
|
1862
|
-
const parsed = parseArgs({
|
|
1863
|
-
args: argv,
|
|
1864
|
-
allowPositionals: true,
|
|
1865
|
-
options: {
|
|
1866
|
-
name: { type: "string", short: "n" },
|
|
1867
|
-
cpus: { type: "string" },
|
|
1868
|
-
memory: { type: "string" },
|
|
1869
|
-
disk_mb: { type: "string" },
|
|
1870
|
-
builder_disk_mb: { type: "string" },
|
|
1871
|
-
docker_compat: { type: "boolean", default: false },
|
|
1872
|
-
public: { type: "boolean", default: false }
|
|
1873
|
-
}
|
|
1874
|
-
});
|
|
1875
|
-
const dockerfilePath = parsed.positionals[0];
|
|
1876
|
-
if (!dockerfilePath) {
|
|
1877
|
-
throw new Error(
|
|
1878
|
-
"Usage: tensorlake-create-sandbox-image <dockerfile_path> [--name NAME] [--cpus N] [--memory MiB] [--disk_mb MiB] [--builder_disk_mb MiB] [--docker_compat] [--public]"
|
|
1879
|
-
);
|
|
1880
|
-
}
|
|
1881
|
-
const cpus = parsed.values.cpus != null ? Number(parsed.values.cpus) : void 0;
|
|
1882
|
-
const memoryMb = parsed.values.memory != null ? Number(parsed.values.memory) : void 0;
|
|
1883
|
-
const diskMb = parsed.values.disk_mb != null ? Number(parsed.values.disk_mb) : void 0;
|
|
1884
|
-
const builderDiskMb = parsed.values.builder_disk_mb != null ? Number(parsed.values.builder_disk_mb) : void 0;
|
|
1885
|
-
if (cpus != null && !Number.isFinite(cpus)) {
|
|
1886
|
-
throw new Error(`Invalid --cpus value: ${parsed.values.cpus}`);
|
|
1887
|
-
}
|
|
1888
|
-
if (memoryMb != null && !Number.isInteger(memoryMb)) {
|
|
1889
|
-
throw new Error(`Invalid --memory value: ${parsed.values.memory}`);
|
|
1890
|
-
}
|
|
1891
|
-
if (diskMb != null && !Number.isInteger(diskMb)) {
|
|
1892
|
-
throw new Error(`Invalid --disk_mb value: ${parsed.values.disk_mb}`);
|
|
1893
|
-
}
|
|
1894
|
-
if (builderDiskMb != null && !Number.isInteger(builderDiskMb)) {
|
|
1895
|
-
throw new Error(
|
|
1896
|
-
`Invalid --builder_disk_mb value: ${parsed.values.builder_disk_mb}`
|
|
1897
|
-
);
|
|
1898
|
-
}
|
|
1899
|
-
await createSandboxImage(
|
|
1900
|
-
dockerfilePath,
|
|
1901
|
-
{
|
|
1902
|
-
registeredName: parsed.values.name,
|
|
1903
|
-
cpus,
|
|
1904
|
-
memoryMb,
|
|
1905
|
-
diskMb,
|
|
1906
|
-
builderDiskMb,
|
|
1907
|
-
dockerCompat: parsed.values.docker_compat,
|
|
1908
|
-
isPublic: parsed.values.public
|
|
1909
|
-
},
|
|
1910
|
-
{ emit: ndjsonStdoutEmit, _allowPat: true }
|
|
1911
|
-
);
|
|
1912
|
-
}
|
|
1913
|
-
async function runImportSandboxImageCli(argv = process.argv.slice(2)) {
|
|
1914
|
-
const parsed = parseArgs({
|
|
1915
|
-
args: argv,
|
|
1916
|
-
allowPositionals: true,
|
|
1917
|
-
options: {
|
|
1918
|
-
name: { type: "string", short: "n" },
|
|
1919
|
-
cpus: { type: "string" },
|
|
1920
|
-
memory: { type: "string" },
|
|
1921
|
-
disk_mb: { type: "string" },
|
|
1922
|
-
builder_disk_mb: { type: "string" },
|
|
1923
|
-
docker_compat: { type: "boolean", default: false },
|
|
1924
|
-
public: { type: "boolean", default: false }
|
|
1925
|
-
}
|
|
1926
|
-
});
|
|
1927
|
-
const imageReference = parsed.positionals[0];
|
|
1928
|
-
if (!imageReference) {
|
|
1929
|
-
throw new Error(
|
|
1930
|
-
"Usage: tensorlake-import-sandbox-image <image_reference> [--name NAME] [--cpus N] [--memory MiB] [--disk_mb MiB] [--builder_disk_mb MiB] [--docker_compat] [--public]"
|
|
1931
|
-
);
|
|
1932
|
-
}
|
|
1933
|
-
const cpus = parsed.values.cpus != null ? Number(parsed.values.cpus) : void 0;
|
|
1934
|
-
const memoryMb = parsed.values.memory != null ? Number(parsed.values.memory) : void 0;
|
|
1935
|
-
const diskMb = parsed.values.disk_mb != null ? Number(parsed.values.disk_mb) : void 0;
|
|
1936
|
-
const builderDiskMb = parsed.values.builder_disk_mb != null ? Number(parsed.values.builder_disk_mb) : void 0;
|
|
1937
|
-
if (cpus != null && !Number.isFinite(cpus)) {
|
|
1938
|
-
throw new Error(`Invalid --cpus value: ${parsed.values.cpus}`);
|
|
1939
|
-
}
|
|
1940
|
-
if (memoryMb != null && !Number.isInteger(memoryMb)) {
|
|
1941
|
-
throw new Error(`Invalid --memory value: ${parsed.values.memory}`);
|
|
1942
|
-
}
|
|
1943
|
-
if (diskMb != null && !Number.isInteger(diskMb)) {
|
|
1944
|
-
throw new Error(`Invalid --disk_mb value: ${parsed.values.disk_mb}`);
|
|
1945
|
-
}
|
|
1946
|
-
if (builderDiskMb != null && !Number.isInteger(builderDiskMb)) {
|
|
1947
|
-
throw new Error(
|
|
1948
|
-
`Invalid --builder_disk_mb value: ${parsed.values.builder_disk_mb}`
|
|
1949
|
-
);
|
|
1950
|
-
}
|
|
1951
|
-
await importSandboxImage(
|
|
1952
|
-
imageReference,
|
|
1953
|
-
{
|
|
1954
|
-
registeredName: parsed.values.name,
|
|
1955
|
-
cpus,
|
|
1956
|
-
memoryMb,
|
|
1957
|
-
diskMb,
|
|
1958
|
-
builderDiskMb,
|
|
1959
|
-
dockerCompat: parsed.values.docker_compat,
|
|
1960
|
-
isPublic: parsed.values.public
|
|
1961
|
-
},
|
|
1962
|
-
{ emit: ndjsonStdoutEmit, _allowPat: true }
|
|
1963
|
-
);
|
|
1964
|
-
}
|
|
1965
|
-
var cachedNativeBinding, cachedNativeBindingError, DEFAULT_IMAGE_NAME2;
|
|
1966
|
-
var init_sandbox_image = __esm({
|
|
1967
|
-
"src/sandbox-image.ts"() {
|
|
1968
|
-
init_esm_shims();
|
|
1969
|
-
init_cloud_client();
|
|
1970
|
-
init_image();
|
|
1971
|
-
init_native_binding();
|
|
1972
|
-
DEFAULT_IMAGE_NAME2 = "default";
|
|
1973
|
-
}
|
|
1974
|
-
});
|
|
1975
|
-
init_sandbox_image();
|
|
1976
|
-
export {
|
|
1977
|
-
__setNativeBindingForTest,
|
|
1978
|
-
buildContextFromEnv,
|
|
1979
|
-
createSandboxImage,
|
|
1980
|
-
deleteSandboxImage,
|
|
1981
|
-
findSandboxImageByName,
|
|
1982
|
-
importSandboxImage,
|
|
1983
|
-
listSandboxImages,
|
|
1984
|
-
runCreateSandboxImageCli,
|
|
1985
|
-
runImportSandboxImageCli
|
|
1986
|
-
};
|
|
1987
|
-
//# sourceMappingURL=sandbox-image.js.map
|