@blaxel/core 0.3.26-preview.310 → 0.3.26-preview.312
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/cjs/.tsbuildinfo +1 -1
- package/dist/cjs/common/settings.js +2 -2
- package/dist/cjs/sandbox/client/sdk.gen.js +17 -8
- package/dist/cjs/sandbox/filesystem/filesystem.js +1 -1
- package/dist/cjs/sandbox/preview.js +104 -1
- package/dist/cjs/types/sandbox/client/sdk.gen.d.ts +17 -8
- package/dist/cjs/types/sandbox/client/types.gen.d.ts +21 -5
- package/dist/cjs/types/sandbox/preview.d.ts +12 -3
- package/dist/cjs/types/sandbox/types.d.ts +7 -0
- package/dist/cjs-browser/.tsbuildinfo +1 -1
- package/dist/cjs-browser/common/settings.js +2 -2
- package/dist/cjs-browser/sandbox/client/sdk.gen.js +17 -8
- package/dist/cjs-browser/sandbox/filesystem/filesystem.js +1 -1
- package/dist/cjs-browser/sandbox/preview.js +104 -1
- package/dist/cjs-browser/types/sandbox/client/sdk.gen.d.ts +17 -8
- package/dist/cjs-browser/types/sandbox/client/types.gen.d.ts +21 -5
- package/dist/cjs-browser/types/sandbox/preview.d.ts +12 -3
- package/dist/cjs-browser/types/sandbox/types.d.ts +7 -0
- package/dist/esm/.tsbuildinfo +1 -1
- package/dist/esm/common/settings.js +2 -2
- package/dist/esm/sandbox/client/sdk.gen.js +17 -8
- package/dist/esm/sandbox/filesystem/filesystem.js +1 -1
- package/dist/esm/sandbox/preview.js +104 -1
- package/dist/esm-browser/.tsbuildinfo +1 -1
- package/dist/esm-browser/common/settings.js +2 -2
- package/dist/esm-browser/sandbox/client/sdk.gen.js +17 -8
- package/dist/esm-browser/sandbox/filesystem/filesystem.js +1 -1
- package/dist/esm-browser/sandbox/preview.js +104 -1
- package/package.json +1 -1
|
@@ -24,8 +24,8 @@ function missingCredentialsMessage() {
|
|
|
24
24
|
return "No Blaxel credentials found. Set the BL_API_KEY and BL_WORKSPACE environment variables, or run `bl login`.";
|
|
25
25
|
}
|
|
26
26
|
// Build info - these placeholders are replaced at build time by build:replace-imports
|
|
27
|
-
const BUILD_VERSION = "0.3.26-preview.
|
|
28
|
-
const BUILD_COMMIT = "
|
|
27
|
+
const BUILD_VERSION = "0.3.26-preview.312";
|
|
28
|
+
const BUILD_COMMIT = "45891cd9862d690bb6532b5758e75084083d511f";
|
|
29
29
|
const BUILD_SENTRY_DSN = "https://fd5e60e1c9820e1eef5ccebb84a07127@o4508714045276160.ingest.us.sentry.io/4510465864564736";
|
|
30
30
|
const BLAXEL_API_VERSION = "2026-09-22";
|
|
31
31
|
// Bun < 1.3.11 never sends connection-level WINDOW_UPDATE: the pooled h2
|
|
@@ -277,7 +277,7 @@ export const postFilesystemMultipartByUploadIdComplete = (options) => {
|
|
|
277
277
|
};
|
|
278
278
|
/**
|
|
279
279
|
* Upload part
|
|
280
|
-
* Upload a single part of a multipart upload
|
|
280
|
+
* Upload a single part of a multipart upload. Re-uploading a part number replaces that part. Wait for the previous request for that part to finish before retrying.
|
|
281
281
|
*/
|
|
282
282
|
export const putFilesystemMultipartByUploadIdPart = (options) => {
|
|
283
283
|
return (options.client ?? _heyApiClient).put({
|
|
@@ -334,7 +334,8 @@ export const postFilesystemMultipartInitiateByPath = (options) => {
|
|
|
334
334
|
};
|
|
335
335
|
/**
|
|
336
336
|
* Fuzzy search for files and directories
|
|
337
|
-
*
|
|
337
|
+
* Ranks the files and directories under a path by how well their relative path fuzzy-matches `query` (fzf algorithm: the query's characters must appear in order, not necessarily next to each other), best match first.
|
|
338
|
+
* Fuzzy search is for "jump to file" lookups from a partial name. The `patterns` parameter is currently ignored by this endpoint; use find for exact glob filtering.
|
|
338
339
|
*/
|
|
339
340
|
export const getFilesystemSearchByPath = (options) => {
|
|
340
341
|
return (options.client ?? _heyApiClient).get({
|
|
@@ -382,7 +383,11 @@ export const getFilesystemByPath = (options) => {
|
|
|
382
383
|
};
|
|
383
384
|
/**
|
|
384
385
|
* Create or update a file or directory
|
|
385
|
-
* Create or update a file or directory
|
|
386
|
+
* Create or update a file or directory.
|
|
387
|
+
*
|
|
388
|
+
* Idempotent: an existing file is overwritten (truncated, not appended to) and an existing directory is kept, so retrying the same request is safe.
|
|
389
|
+
*
|
|
390
|
+
* Send either a JSON body (FileRequest) or `multipart/form-data` for binary files. Multipart fields, in any order: `file` (required, the file content), `permissions` (optional octal mode such as `0755`, applied when the file is created, default `0644`; an existing file keeps its mode), `path` (optional, ignored: the target is always the URL path).
|
|
386
391
|
*/
|
|
387
392
|
export const putFilesystemByPath = (options) => {
|
|
388
393
|
return (options.client ?? _heyApiClient).put({
|
|
@@ -434,7 +439,7 @@ export const getFilesystemTreeByPath = (options) => {
|
|
|
434
439
|
};
|
|
435
440
|
/**
|
|
436
441
|
* Create or update directory tree
|
|
437
|
-
* Create or update multiple files within a directory tree structure
|
|
442
|
+
* Create or update multiple files within a directory tree structure. Idempotent: existing files are overwritten, so retrying the same request is safe.
|
|
438
443
|
*/
|
|
439
444
|
export const putFilesystemTreeByPath = (options) => {
|
|
440
445
|
return (options.client ?? _heyApiClient).put({
|
|
@@ -575,7 +580,10 @@ export const getProcess = (options) => {
|
|
|
575
580
|
};
|
|
576
581
|
/**
|
|
577
582
|
* Execute a command
|
|
578
|
-
* Execute a command and return process information.
|
|
583
|
+
* Execute a command and return process information.
|
|
584
|
+
*
|
|
585
|
+
* Streaming: with `Accept: application/x-ndjson` (or `Accept: text/event-stream`, kept for compatibility) the response is NDJSON (`Content-Type: application/x-ndjson`), not SSE: one JSON object per line, `{"type": "...", "data": "..."}`.
|
|
586
|
+
* `type` is `stdout` or `stderr` (`data` is a raw output chunk, sent as soon as the process writes it, newlines included; if the process finished before any chunk was streamed, its output is sent instead as one event per line, without the newline), `keepalive` (every 5 seconds, no data), `error` (`data` is the message, ends the stream) or `result` (last event, `data` is the ProcessResponse as a JSON string).
|
|
579
587
|
*/
|
|
580
588
|
export const postProcess = (options) => {
|
|
581
589
|
return (options.client ?? _heyApiClient).post({
|
|
@@ -595,7 +603,7 @@ export const postProcess = (options) => {
|
|
|
595
603
|
};
|
|
596
604
|
/**
|
|
597
605
|
* Stop a process
|
|
598
|
-
*
|
|
606
|
+
* Request graceful termination. Poll GET /process/{identifier} until terminal status confirms the managed process has exited.
|
|
599
607
|
*/
|
|
600
608
|
export const deleteProcessByIdentifier = (options) => {
|
|
601
609
|
return (options.client ?? _heyApiClient).delete({
|
|
@@ -627,7 +635,7 @@ export const getProcessByIdentifier = (options) => {
|
|
|
627
635
|
};
|
|
628
636
|
/**
|
|
629
637
|
* Kill a process
|
|
630
|
-
*
|
|
638
|
+
* Request forceful termination. Poll GET /process/{identifier} until terminal status confirms the managed process has exited.
|
|
631
639
|
*/
|
|
632
640
|
export const deleteProcessByIdentifierKill = (options) => {
|
|
633
641
|
return (options.client ?? _heyApiClient).delete({
|
|
@@ -659,7 +667,8 @@ export const getProcessByIdentifierLogs = (options) => {
|
|
|
659
667
|
};
|
|
660
668
|
/**
|
|
661
669
|
* Stream process logs in real time
|
|
662
|
-
* Streams the stdout and stderr output of a process in real time
|
|
670
|
+
* Streams the stdout and stderr output of a process in real time: the output so far, then live output as the process writes it. Closes when the process exits or the client disconnects.
|
|
671
|
+
* Each output line starts with `stdout:` or `stderr:` and keeps its trailing newline. A partial line (e.g. a prompt) is sent as soon as it is written; when the process completes it, the rest follows without a new prefix. `[keepalive]` lines are sent every 30 seconds.
|
|
663
672
|
*/
|
|
664
673
|
export const getProcessByIdentifierLogsStream = (options) => {
|
|
665
674
|
return (options.client ?? _heyApiClient).get({
|
|
@@ -262,7 +262,7 @@ export class SandboxFileSystem extends SandboxAction {
|
|
|
262
262
|
}
|
|
263
263
|
async search(query, path = "/", options) {
|
|
264
264
|
const formattedPath = this.formatPath(path);
|
|
265
|
-
const queryParams = {};
|
|
265
|
+
const queryParams = { query };
|
|
266
266
|
if (options?.maxResults !== undefined) {
|
|
267
267
|
queryParams.maxResults = options.maxResults;
|
|
268
268
|
}
|
|
@@ -1,9 +1,46 @@
|
|
|
1
1
|
import { createSandboxPreview, createSandboxPreviewToken, deleteSandboxPreview, deleteSandboxPreviewToken, getSandboxPreview, listSandboxPreviews, listSandboxPreviewTokens } from "../client/index.js";
|
|
2
|
+
function isShorthand(preview) {
|
|
3
|
+
return !("metadata" in preview || "spec" in preview);
|
|
4
|
+
}
|
|
5
|
+
function normalizePreview(preview) {
|
|
6
|
+
if (!isShorthand(preview))
|
|
7
|
+
return preview;
|
|
8
|
+
if (!Number.isInteger(preview.port) || preview.port < 1 || preview.port > 65535) {
|
|
9
|
+
throw new RangeError("Preview port must be an integer between 1 and 65535");
|
|
10
|
+
}
|
|
11
|
+
if (preview.name !== undefined && (typeof preview.name !== "string" || preview.name.length === 0)) {
|
|
12
|
+
throw new RangeError("Preview name must be a nonempty string");
|
|
13
|
+
}
|
|
14
|
+
if (preview.public !== undefined && typeof preview.public !== "boolean") {
|
|
15
|
+
throw new RangeError("Preview public must be a boolean");
|
|
16
|
+
}
|
|
17
|
+
return {
|
|
18
|
+
metadata: { name: preview.name ?? `preview-${preview.port}` },
|
|
19
|
+
spec: { port: preview.port, public: preview.public ?? false },
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
// Explicit HTTP status takes precedence over a legacy numeric service code.
|
|
23
|
+
function httpStatus(error) {
|
|
24
|
+
if (typeof error !== "object" || error === null)
|
|
25
|
+
return undefined;
|
|
26
|
+
const fields = error;
|
|
27
|
+
const response = fields.response;
|
|
28
|
+
const responseStatus = typeof response === "object" && response !== null && "status" in response
|
|
29
|
+
? response.status : undefined;
|
|
30
|
+
for (const status of [fields.status, fields.statusCode, responseStatus, fields.code]) {
|
|
31
|
+
if (typeof status === "number")
|
|
32
|
+
return status;
|
|
33
|
+
}
|
|
34
|
+
return undefined;
|
|
35
|
+
}
|
|
2
36
|
export class SandboxPreviewToken {
|
|
3
37
|
previewToken;
|
|
4
38
|
constructor(previewToken) {
|
|
5
39
|
this.previewToken = previewToken;
|
|
6
40
|
}
|
|
41
|
+
get name() {
|
|
42
|
+
return this.previewToken.metadata?.name ?? "";
|
|
43
|
+
}
|
|
7
44
|
get value() {
|
|
8
45
|
return this.previewToken.spec.token ?? "";
|
|
9
46
|
}
|
|
@@ -43,6 +80,49 @@ export class SandboxPreviewTokens {
|
|
|
43
80
|
});
|
|
44
81
|
return new SandboxPreviewToken(data);
|
|
45
82
|
}
|
|
83
|
+
/**
|
|
84
|
+
* Reuse the latest token within the requested expiry ceiling, or mint one.
|
|
85
|
+
* minValidity is in milliseconds. Concurrent callers may create separate tokens.
|
|
86
|
+
*/
|
|
87
|
+
async createIfExpired(expiresAt, minValidity = 3_600_000) {
|
|
88
|
+
const now = Date.now();
|
|
89
|
+
if (!Number.isFinite(minValidity) || minValidity < 0) {
|
|
90
|
+
throw new RangeError("minValidity must be finite and non-negative");
|
|
91
|
+
}
|
|
92
|
+
const requestedExpiry = expiresAt ?? new Date(now + 86_400_000);
|
|
93
|
+
const ceiling = requestedExpiry instanceof Date ? requestedExpiry.getTime() : NaN;
|
|
94
|
+
if (!Number.isFinite(ceiling) || ceiling <= now || ceiling < now + minValidity) {
|
|
95
|
+
throw new RangeError("expiresAt must be a valid future date at least minValidity from now");
|
|
96
|
+
}
|
|
97
|
+
if (this.preview.spec?.public === true) {
|
|
98
|
+
throw new Error("Cannot create or reuse a token for a public preview");
|
|
99
|
+
}
|
|
100
|
+
const { data } = await listSandboxPreviewTokens({
|
|
101
|
+
path: {
|
|
102
|
+
sandboxName: this.resourceName,
|
|
103
|
+
previewName: this.previewName,
|
|
104
|
+
},
|
|
105
|
+
throwOnError: true,
|
|
106
|
+
});
|
|
107
|
+
if (!Array.isArray(data))
|
|
108
|
+
throw new Error("Failed to list preview tokens");
|
|
109
|
+
let selected;
|
|
110
|
+
let latestExpiry = -Infinity;
|
|
111
|
+
for (const token of data) {
|
|
112
|
+
const spec = token?.spec;
|
|
113
|
+
if (!spec || typeof spec.token !== "string" || spec.token.length === 0 || spec.expired === true ||
|
|
114
|
+
typeof spec.expiresAt !== "string")
|
|
115
|
+
continue;
|
|
116
|
+
const expiry = Date.parse(spec.expiresAt);
|
|
117
|
+
if (!Number.isFinite(expiry) || expiry <= now || expiry < now + minValidity || expiry > ceiling)
|
|
118
|
+
continue;
|
|
119
|
+
if (expiry > latestExpiry) {
|
|
120
|
+
selected = token;
|
|
121
|
+
latestExpiry = expiry;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
return selected ? new SandboxPreviewToken(selected) : this.create(requestedExpiry);
|
|
125
|
+
}
|
|
46
126
|
async list() {
|
|
47
127
|
const { data } = await listSandboxPreviewTokens({
|
|
48
128
|
path: {
|
|
@@ -75,6 +155,9 @@ export class SandboxPreview {
|
|
|
75
155
|
get name() {
|
|
76
156
|
return this.preview.metadata.name;
|
|
77
157
|
}
|
|
158
|
+
get url() {
|
|
159
|
+
return this.preview.spec?.url ?? "";
|
|
160
|
+
}
|
|
78
161
|
get metadata() {
|
|
79
162
|
return this.preview.metadata;
|
|
80
163
|
}
|
|
@@ -100,6 +183,7 @@ export class SandboxPreviews {
|
|
|
100
183
|
return data.map((preview) => new SandboxPreview(preview));
|
|
101
184
|
}
|
|
102
185
|
async create(preview, force) {
|
|
186
|
+
const normalized = normalizePreview(preview);
|
|
103
187
|
const query = {};
|
|
104
188
|
if (force) {
|
|
105
189
|
query['force'] = 'true';
|
|
@@ -109,12 +193,31 @@ export class SandboxPreviews {
|
|
|
109
193
|
sandboxName: this.sandboxName,
|
|
110
194
|
},
|
|
111
195
|
query,
|
|
112
|
-
body:
|
|
196
|
+
body: normalized,
|
|
113
197
|
throwOnError: true,
|
|
114
198
|
});
|
|
115
199
|
return new SandboxPreview(data);
|
|
116
200
|
}
|
|
201
|
+
/** Existing previews are returned as-is; shorthand's private default applies only on creation. */
|
|
117
202
|
async createIfNotExists(preview, force) {
|
|
203
|
+
if (isShorthand(preview)) {
|
|
204
|
+
const normalized = normalizePreview(preview);
|
|
205
|
+
try {
|
|
206
|
+
return await this.get(normalized.metadata.name);
|
|
207
|
+
}
|
|
208
|
+
catch (error) {
|
|
209
|
+
if (httpStatus(error) !== 404)
|
|
210
|
+
throw error;
|
|
211
|
+
}
|
|
212
|
+
try {
|
|
213
|
+
return await this.create(normalized, force);
|
|
214
|
+
}
|
|
215
|
+
catch (error) {
|
|
216
|
+
if (httpStatus(error) !== 409)
|
|
217
|
+
throw error;
|
|
218
|
+
return this.get(normalized.metadata.name);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
118
221
|
try {
|
|
119
222
|
const previewInstance = await this.get(preview.metadata.name);
|
|
120
223
|
return previewInstance;
|