@computesdk/blaxel 1.3.7 → 1.3.9
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 +70 -45
- package/dist/index.js +12 -8
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +13 -9
- package/dist/index.mjs.map +1 -1
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -8,60 +8,52 @@ Blaxel provider for ComputeSDK - Execute code in secure Blaxel cloud sandboxes.
|
|
|
8
8
|
npm install @computesdk/blaxel
|
|
9
9
|
```
|
|
10
10
|
|
|
11
|
-
##
|
|
11
|
+
## Quick Start
|
|
12
12
|
|
|
13
|
-
###
|
|
13
|
+
### Gateway Mode (Recommended)
|
|
14
14
|
|
|
15
|
-
|
|
16
|
-
import { createCompute } from 'computesdk';
|
|
17
|
-
import { blaxel } from '@computesdk/blaxel';
|
|
15
|
+
Use the gateway for zero-config auto-detection:
|
|
18
16
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
provider: blaxel({ apiKey: process.env.BL_API_KEY })
|
|
22
|
-
compute.setConfig({
|
|
23
|
-
provider: blaxel({
|
|
24
|
-
apiKey: process.env.BLAXEL_API_KEY,
|
|
25
|
-
workspace: process.env.BLAXEL_WORKSPACE
|
|
26
|
-
})
|
|
27
|
-
});
|
|
17
|
+
```typescript
|
|
18
|
+
import { compute } from 'computesdk';
|
|
28
19
|
|
|
29
|
-
//
|
|
20
|
+
// Auto-detects Blaxel from BL_WORKSPACE/BL_API_KEY environment variables
|
|
30
21
|
const sandbox = await compute.sandbox.create();
|
|
31
22
|
|
|
32
23
|
// Execute code
|
|
33
24
|
const result = await sandbox.runCode('console.log("Hello from Blaxel!")');
|
|
34
25
|
console.log(result.stdout); // "Hello from Blaxel!"
|
|
35
26
|
|
|
36
|
-
// Clean up
|
|
37
27
|
await sandbox.destroy();
|
|
38
28
|
```
|
|
39
29
|
|
|
40
|
-
### Direct
|
|
30
|
+
### Direct Mode
|
|
31
|
+
|
|
32
|
+
For direct SDK usage without the gateway:
|
|
41
33
|
|
|
42
34
|
```typescript
|
|
43
35
|
import { blaxel } from '@computesdk/blaxel';
|
|
44
36
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
apiKey: 'your-api-key',
|
|
37
|
+
const compute = blaxel({
|
|
38
|
+
workspace: process.env.BL_WORKSPACE,
|
|
39
|
+
apiKey: process.env.BL_API_KEY,
|
|
49
40
|
image: 'blaxel/prod-py-app:latest', // Python image
|
|
50
41
|
memory: 8192, // 8GB RAM
|
|
51
42
|
ports: [3000, 8080] // Exposed ports
|
|
52
43
|
});
|
|
53
44
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
timeout: 3600000, // 1 hour timeout
|
|
60
|
-
envs: {
|
|
61
|
-
DEBUG: 'true'
|
|
62
|
-
}
|
|
45
|
+
const sandbox = await compute.sandbox.create({
|
|
46
|
+
runtime: 'python', // Runtime specified at creation time
|
|
47
|
+
timeout: 3600000, // 1 hour timeout
|
|
48
|
+
envs: {
|
|
49
|
+
DEBUG: 'true'
|
|
63
50
|
}
|
|
64
51
|
});
|
|
52
|
+
|
|
53
|
+
const result = await sandbox.runCode('print("Hello from Blaxel!")');
|
|
54
|
+
console.log(result.stdout);
|
|
55
|
+
|
|
56
|
+
await sandbox.destroy();
|
|
65
57
|
```
|
|
66
58
|
|
|
67
59
|
## Configuration
|
|
@@ -380,7 +372,15 @@ The provider automatically detects the runtime based on code patterns:
|
|
|
380
372
|
## Error Handling
|
|
381
373
|
|
|
382
374
|
```typescript
|
|
375
|
+
import { blaxel } from '@computesdk/blaxel';
|
|
376
|
+
|
|
383
377
|
try {
|
|
378
|
+
const compute = blaxel({
|
|
379
|
+
workspace: process.env.BL_WORKSPACE,
|
|
380
|
+
apiKey: process.env.BL_API_KEY
|
|
381
|
+
});
|
|
382
|
+
const sandbox = await compute.sandbox.create();
|
|
383
|
+
|
|
384
384
|
const result = await sandbox.runCode('invalid code');
|
|
385
385
|
} catch (error) {
|
|
386
386
|
if (error.message.includes('Syntax error')) {
|
|
@@ -398,27 +398,19 @@ try {
|
|
|
398
398
|
- `1` - General error or runtime error
|
|
399
399
|
- `127` - Command not found
|
|
400
400
|
|
|
401
|
-
##
|
|
401
|
+
## Examples
|
|
402
402
|
|
|
403
|
-
|
|
403
|
+
### Data Processing
|
|
404
404
|
|
|
405
405
|
```typescript
|
|
406
|
-
import { handleComputeRequest } from 'computesdk';
|
|
407
406
|
import { blaxel } from '@computesdk/blaxel';
|
|
408
407
|
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
}
|
|
415
|
-
```
|
|
416
|
-
|
|
417
|
-
## Examples
|
|
418
|
-
|
|
419
|
-
### Data Processing
|
|
408
|
+
const compute = blaxel({
|
|
409
|
+
workspace: process.env.BL_WORKSPACE,
|
|
410
|
+
apiKey: process.env.BL_API_KEY
|
|
411
|
+
});
|
|
412
|
+
const sandbox = await compute.sandbox.create();
|
|
420
413
|
|
|
421
|
-
```typescript
|
|
422
414
|
const result = await sandbox.runCode(`
|
|
423
415
|
import json
|
|
424
416
|
|
|
@@ -435,11 +427,21 @@ print(json.dumps(result))
|
|
|
435
427
|
|
|
436
428
|
const output = JSON.parse(result.stdout);
|
|
437
429
|
console.log(output); // { sum: 15, average: 3, max: 5 }
|
|
430
|
+
|
|
431
|
+
await sandbox.destroy();
|
|
438
432
|
```
|
|
439
433
|
|
|
440
434
|
### File Processing
|
|
441
435
|
|
|
442
436
|
```typescript
|
|
437
|
+
import { blaxel } from '@computesdk/blaxel';
|
|
438
|
+
|
|
439
|
+
const compute = blaxel({
|
|
440
|
+
workspace: process.env.BL_WORKSPACE,
|
|
441
|
+
apiKey: process.env.BL_API_KEY
|
|
442
|
+
});
|
|
443
|
+
const sandbox = await compute.sandbox.create();
|
|
444
|
+
|
|
443
445
|
// Create data file
|
|
444
446
|
await sandbox.filesystem.writeFile('/tmp/data.json',
|
|
445
447
|
JSON.stringify({ users: ['Alice', 'Bob', 'Charlie'] })
|
|
@@ -465,11 +467,21 @@ with open('/tmp/result.json', 'w') as f:
|
|
|
465
467
|
// Read result
|
|
466
468
|
const resultData = await sandbox.filesystem.readFile('/tmp/result.json');
|
|
467
469
|
console.log(JSON.parse(resultData));
|
|
470
|
+
|
|
471
|
+
await sandbox.destroy();
|
|
468
472
|
```
|
|
469
473
|
|
|
470
474
|
### Web Scraping Example
|
|
471
475
|
|
|
472
476
|
```typescript
|
|
477
|
+
import { blaxel } from '@computesdk/blaxel';
|
|
478
|
+
|
|
479
|
+
const compute = blaxel({
|
|
480
|
+
workspace: process.env.BL_WORKSPACE,
|
|
481
|
+
apiKey: process.env.BL_API_KEY
|
|
482
|
+
});
|
|
483
|
+
const sandbox = await compute.sandbox.create();
|
|
484
|
+
|
|
473
485
|
// Install dependencies
|
|
474
486
|
await sandbox.runCommand('pip', ['install', 'requests', 'beautifulsoup4']);
|
|
475
487
|
|
|
@@ -497,11 +509,22 @@ print(json.dumps(result))
|
|
|
497
509
|
`);
|
|
498
510
|
|
|
499
511
|
console.log(JSON.parse(result.stdout));
|
|
512
|
+
|
|
513
|
+
await sandbox.destroy();
|
|
500
514
|
```
|
|
501
515
|
|
|
502
516
|
### API Development
|
|
503
517
|
|
|
504
518
|
```typescript
|
|
519
|
+
import { blaxel } from '@computesdk/blaxel';
|
|
520
|
+
|
|
521
|
+
const compute = blaxel({
|
|
522
|
+
workspace: process.env.BL_WORKSPACE,
|
|
523
|
+
apiKey: process.env.BL_API_KEY,
|
|
524
|
+
ports: [3000]
|
|
525
|
+
});
|
|
526
|
+
const sandbox = await compute.sandbox.create();
|
|
527
|
+
|
|
505
528
|
// Create a simple API server
|
|
506
529
|
await sandbox.filesystem.writeFile('/tmp/server.js', `
|
|
507
530
|
const http = require('http');
|
|
@@ -536,6 +559,8 @@ const privateUrl = await sandbox.getUrl({
|
|
|
536
559
|
}
|
|
537
560
|
});
|
|
538
561
|
console.log(`Private API: ${privateUrl}`);
|
|
562
|
+
|
|
563
|
+
await sandbox.destroy();
|
|
539
564
|
```
|
|
540
565
|
|
|
541
566
|
## Authentication Methods
|
package/dist/index.js
CHANGED
|
@@ -160,16 +160,20 @@ ${stderr}`.trim() : stdout;
|
|
|
160
160
|
};
|
|
161
161
|
}
|
|
162
162
|
},
|
|
163
|
-
runCommand: async (sandbox, command,
|
|
163
|
+
runCommand: async (sandbox, command, options) => {
|
|
164
164
|
const startTime = Date.now();
|
|
165
165
|
try {
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
166
|
+
let fullCommand = command;
|
|
167
|
+
if (options?.env && Object.keys(options.env).length > 0) {
|
|
168
|
+
const envPrefix = Object.entries(options.env).map(([k, v]) => `${k}="${(0, import_provider.escapeShellArg)(v)}"`).join(" ");
|
|
169
|
+
fullCommand = `${envPrefix} ${fullCommand}`;
|
|
170
|
+
}
|
|
171
|
+
if (options?.cwd) {
|
|
172
|
+
fullCommand = `cd "${(0, import_provider.escapeShellArg)(options.cwd)}" && ${fullCommand}`;
|
|
173
|
+
}
|
|
174
|
+
if (options?.background) {
|
|
175
|
+
fullCommand = `nohup ${fullCommand} > /dev/null 2>&1 &`;
|
|
176
|
+
}
|
|
173
177
|
const { stdout, stderr, exitCode } = await executeWithStreaming(sandbox, fullCommand);
|
|
174
178
|
return {
|
|
175
179
|
stdout,
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["/**\n * Blaxel Provider - Factory-based Implementation\n * \n * Full-featured provider with filesystem support using the factory pattern.\n */\n\nimport { SandboxInstance, settings } from '@blaxel/core';\nimport { defineProvider } from '@computesdk/provider';\n\nimport type { Runtime, CodeResult, CommandResult, SandboxInfo, CreateSandboxOptions, FileEntry } from '@computesdk/provider';\n\n/**\n * Blaxel-specific configuration options\n */\nexport interface BlaxelConfig {\n\t/** Blaxel workspace ID - if not provided, will fallback to BL_WORKSPACE environment variable */\n\tworkspace?: string;\n\t/** Blaxel API key - if not provided, will fallback to BL_API_KEY environment variable */\n\tapiKey?: string;\n\t/** Default image for sandboxes */\n\timage?: string;\n\t/** Default region for sandbox deployment */\n\tregion?: string;\n\t/** Default memory allocation in MB */\n\tmemory?: number | 4096;\n\t/** Default ports for sandbox */\n\tports?: number[] | [3000];\n}\n\n/**\n * Create a Blaxel provider instance using the factory pattern\n */\nexport const blaxel = defineProvider<SandboxInstance, BlaxelConfig>({\n\tname: 'blaxel',\n\tmethods: {\n\t\tsandbox: {\n\t\t\t// Collection operations (map to compute.sandbox.*)\n\t\t\tcreate: async (config: BlaxelConfig, options?: CreateSandboxOptions) => {\n\t\t\t\tawait handleBlaxelAuth(config);\n\n\t\t\t\t// Determine the image to use\n\t\t\t\tlet image = config.image || 'blaxel/prod-base:latest'; // Default to prod-base\n\n\t\t\t\t// Override with runtime-specific image if runtime is specified and no explicit image\n\t\t\t\tif (!config.image && options?.runtime) {\n\t\t\t\t\tswitch (options.runtime) {\n\t\t\t\t\t\tcase 'python':\n\t\t\t\t\t\t\timage = 'blaxel/prod-py-app:latest';\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase 'node':\n\t\t\t\t\t\t\timage = 'blaxel/prod-ts-app:latest';\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tdefault:\n\t\t\t\t\t\t\timage = 'blaxel/prod-base:latest';\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tconst memory = config.memory;\n\t\t\t\tconst region = config.region;\n\t\t\t\tconst envs = options?.envs;\n\t\t\t\tconst ttl = options?.timeout ? `${Math.ceil(options.timeout / 1000)}s` : undefined;\n\n\t\t\t\ttry {\n\t\t\t\t\tlet sandbox: SandboxInstance;\n\n\t\t\t\t\t// Create new Blaxel sandbox\n\t\t\t\t\tsandbox = await SandboxInstance.createIfNotExists({\n\t\t\t\t\t\tname: options?.sandboxId || `blaxel-${Date.now()}`,\n\t\t\t\t\t\timage,\n\t\t\t\t\t\tmemory,\n\t\t\t\t\t\tenvs: Object.entries(envs || {}).map(([name, value]) => ({ name, value })),\n\t\t\t\t\t\tmetadata: {\n\t\t\t\t\t\t\tlabels: {\n\t\t\t\t\t\t\t\t...options?.metadata?.labels,\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t},\n\t\t\t\t\t\tttl,\n\t\t\t\t\t\tports: config.ports?.map(port => ({ target: port, protocol: 'HTTP' })),\n\t\t\t\t\t\t...(region && { region })\n\t\t\t\t\t});\n\n\t\t\t\t\treturn {\n\t\t\t\t\t\tsandbox,\n\t\t\t\t\t\tsandboxId: sandbox.metadata?.name || 'blaxel-unknown'\n\t\t\t\t\t};\n\t\t\t\t} catch (error) {\n\t\t\t\t\tif (error instanceof Error) {\n\t\t\t\t\t\tif (error.message.includes('unauthorized') || error.message.includes('API key')) {\n\t\t\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t\t\t`Blaxel authentication failed. Please check your BLAXEL_API_KEY environment variable.`\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (error.message.includes('quota') || error.message.includes('limit')) {\n\t\t\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t\t\t`Blaxel quota exceeded. Please check your usage limits.`\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t`Failed to create Blaxel sandbox: ${error instanceof Error ? error.message : String(error)}`\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t},\n\n\t\t\tgetById: async (config: BlaxelConfig, sandboxId: string) => {\n\t\t\t\tawait handleBlaxelAuth(config);\n\n\t\t\t\ttry {\n\t\t\t\t\tconst sandbox = await SandboxInstance.get(sandboxId);\n\n\t\t\t\t\tif (!sandbox) {\n\t\t\t\t\t\treturn null;\n\t\t\t\t\t}\n\n\t\t\t\t\treturn {\n\t\t\t\t\t\tsandbox,\n\t\t\t\t\t\tsandboxId\n\t\t\t\t\t};\n\t\t\t\t} catch (error) {\n\t\t\t\t\t// Sandbox doesn't exist or can't be accessed\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\t\t\t},\n\n\t\t\tlist: async (config: BlaxelConfig) => {\n\t\t\t\tawait handleBlaxelAuth(config);\n\n\t\t\t\tconst sandboxList = await SandboxInstance.list();\n\t\t\t\treturn sandboxList.map(sandbox => ({\n\t\t\t\t\tsandbox,\n\t\t\t\t\tsandboxId: sandbox.metadata?.name || 'blaxel-unknown'\n\t\t\t\t}));\n\t\t\t},\n\n\t\t\tdestroy: async (config: BlaxelConfig, sandboxId: string) => {\n\t\t\t\tawait handleBlaxelAuth(config);\n\n\t\t\t\ttry {\n\t\t\t\t\tawait SandboxInstance.delete(sandboxId);\n\t\t\t\t} catch (error) {\n\t\t\t\t\t// Sandbox might already be destroyed or doesn't exist\n\t\t\t\t\t// This is acceptable for destroy operations\n\t\t\t\t}\n\t\t\t},\n\n\t\t\t// Instance operations (map to individual Sandbox methods)\n\t\t\trunCode: async (sandbox: SandboxInstance, code: string, runtime?: Runtime): Promise<CodeResult> => {\n\t\t\t\tconst startTime = Date.now();\n\n\t\t\t\ttry {\n\t\t\t\t\t// Determine runtime: \n\t\t\t\t\t// 1. Use explicitly passed runtime if provided\n\t\t\t\t\t// 2. Check sandbox's actual runtime based on its image\n\t\t\t\t\t// 3. Fall back to auto-detection from code content\n\t\t\t\t\tlet effectiveRuntime = runtime;\n\n\t\t\t\t\tif (!effectiveRuntime) {\n\t\t\t\t\t\t// Check sandbox's image to determine its runtime\n\t\t\t\t\t\tconst sandboxImage = sandbox.spec?.runtime?.image || '';\n\t\t\t\t\t\tif (sandboxImage.includes('py')) {\n\t\t\t\t\t\t\teffectiveRuntime = 'python';\n\t\t\t\t\t\t} else if (sandboxImage.includes('ts') || sandboxImage.includes('node') || sandboxImage.includes('base')) {\n\t\t\t\t\t\t\t// prod-base, prod-ts-app are both Node/TypeScript environments\n\t\t\t\t\t\t\teffectiveRuntime = 'node';\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t// Fall back to auto-detection with improved patterns for unknown images\n\t\t\t\t\t\t\teffectiveRuntime = (\n\t\t\t\t\t\t\t\t// Strong Python indicators\n\t\t\t\t\t\t\t\tcode.includes('print(') ||\n\t\t\t\t\t\t\t\t\tcode.includes('import ') ||\n\t\t\t\t\t\t\t\t\tcode.includes('from ') ||\n\t\t\t\t\t\t\t\t\tcode.includes('def ') ||\n\t\t\t\t\t\t\t\t\tcode.includes('class ') ||\n\t\t\t\t\t\t\t\t\tcode.includes('raise ') ||\n\t\t\t\t\t\t\t\t\tcode.includes('except ') ||\n\t\t\t\t\t\t\t\t\tcode.includes('elif ') ||\n\t\t\t\t\t\t\t\t\tcode.includes('lambda ') ||\n\t\t\t\t\t\t\t\t\tcode.includes('True') ||\n\t\t\t\t\t\t\t\t\tcode.includes('False') ||\n\t\t\t\t\t\t\t\t\tcode.includes('None') ||\n\t\t\t\t\t\t\t\t\tcode.includes('sys.') ||\n\t\t\t\t\t\t\t\t\tcode.includes('json.') ||\n\t\t\t\t\t\t\t\t\tcode.includes('__') ||\n\t\t\t\t\t\t\t\t\tcode.includes('f\"') ||\n\t\t\t\t\t\t\t\t\tcode.includes(\"f'\") ||\n\t\t\t\t\t\t\t\t\tcode.includes('\"\"\"') ||\n\t\t\t\t\t\t\t\t\tcode.includes(\"'''\")\n\t\t\t\t\t\t\t\t\t? 'python'\n\t\t\t\t\t\t\t\t\t// Default to Node.js for all other cases (including ambiguous)\n\t\t\t\t\t\t\t\t\t: 'node'\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t// Execute code using Blaxel's process execution\n\t\t\t\t\t// Escape the code properly for shell execution\n\t\t\t\t\tconst escapedCode = code.replace(/\\\\/g, '\\\\\\\\').replace(/\"/g, '\\\\\"').replace(/\\$/g, '\\\\$').replace(/`/g, '\\\\`');\n\n\t\t\t\t\tconst command = effectiveRuntime === 'python'\n\t\t\t\t\t\t? `python3 -c \"${escapedCode}\"`\n\t\t\t\t\t\t: `node -e \"${escapedCode}\"`;\n\n\t\t\t\t\tconst { stdout, stderr, exitCode } = await executeWithStreaming(sandbox, command);\n\n\t\t\t\t\t// Check for syntax errors and throw them\n\t\t\t\t\tif (exitCode !== 0 && stderr) {\n\t\t\t\t\t\t// Check for common syntax error patterns\n\t\t\t\t\t\tif (stderr.includes('SyntaxError') ||\n\t\t\t\t\t\t\tstderr.includes('invalid syntax') ||\n\t\t\t\t\t\t\tstderr.includes('Unexpected token') ||\n\t\t\t\t\t\t\tstderr.includes('Unexpected identifier')) {\n\t\t\t\t\t\t\tthrow new Error(`Syntax error: ${stderr.trim()}`);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t// Combine stdout and stderr into output\n\t\t\t\t\tconst output = stderr ? `${stdout}\\n${stderr}`.trim() : stdout;\n\n\t\t\t\t\treturn {\n\t\t\t\t\t\toutput,\n\t\t\t\t\t\texitCode,\n\t\t\t\t\t\tlanguage: effectiveRuntime\n\t\t\t\t\t};\n\t\t\t\t} catch (error) {\n\t\t\t\t\t// Re-throw syntax errors\n\t\t\t\t\tif (error instanceof Error && error.message.includes('Syntax error')) {\n\t\t\t\t\t\tthrow error;\n\t\t\t\t\t}\n\n\t\t\t\t\t// For runtime errors, return a result instead of throwing\n\t\t\t\t\treturn {\n\t\t\t\t\t\toutput: error instanceof Error ? error.message : String(error),\n\t\t\t\t\t\texitCode: 1,\n\t\t\t\t\t\tlanguage: runtime || 'node'\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t},\n\n\t\t\trunCommand: async (sandbox: SandboxInstance, command: string, args: string[] = []): Promise<CommandResult> => {\n\t\t\t\tconst startTime = Date.now();\n\n\t\t\t\ttry {\n\t\t\t\t\t// Construct full command with arguments, properly quoting each arg\n\t\t\t\t\tconst quotedArgs = args.map((arg: string) => {\n\t\t\t\t\t\tif (arg.includes(' ') || arg.includes('\"') || arg.includes(\"'\") || arg.includes('$') || arg.includes('`')) {\n\t\t\t\t\t\t\treturn `\"${arg.replace(/\"/g, '\\\\\"')}\"`;\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn arg;\n\t\t\t\t\t});\n\t\t\t\t\tconst fullCommand = quotedArgs.length > 0 ? `${command} ${quotedArgs.join(' ')}` : command;\n\n\t\t\t\t\tconst { stdout, stderr, exitCode } = await executeWithStreaming(sandbox, fullCommand);\n\n\t\t\t\t\treturn {\n\t\t\t\t\t\tstdout,\n\t\t\t\t\t\tstderr,\n\t\t\t\t\t\texitCode,\n\t\t\t\t\t\tdurationMs: Date.now() - startTime\n\t\t\t\t\t};\n\t\t\t\t} catch (error) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tstdout: '',\n\t\t\t\t\t\tstderr: error instanceof Error ? error.message : String(error),\n\t\t\t\t\t\texitCode: 127,\n\t\t\t\t\t\tdurationMs: Date.now() - startTime\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t},\n\n\t\t\tgetInfo: async (sandbox: SandboxInstance): Promise<SandboxInfo> => {\n\t\t\t\treturn {\n\t\t\t\t\tid: sandbox.metadata?.name || 'blaxel-unknown',\n\t\t\t\t\tprovider: 'blaxel',\n\t\t\t\t\truntime: sandbox.spec?.runtime?.image?.includes('py') ? 'python' : 'node',\n\t\t\t\t\tstatus: convertSandboxStatus(sandbox.status),\n\t\t\t\t\tcreatedAt: sandbox.metadata?.createdAt ? new Date(sandbox.metadata.createdAt) : new Date(),\n\t\t\t\t\ttimeout: parseTTLToMilliseconds(sandbox.spec?.runtime?.ttl),\n\t\t\t\t\tmetadata: {\n\t\t\t\t\t\t...sandbox.metadata?.labels\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t\t},\n\n\t\t\tgetUrl: async (sandbox: SandboxInstance, options: {\n\t\t\t\tport: number;\n\t\t\t\tttl?: number;\n\t\t\t\tprefixUrl?: string;\n\t\t\t\theaders?: {\n\t\t\t\t\tresponse?: Record<string, string>;\n\t\t\t\t\trequest?: Record<string, string>;\n\t\t\t\t};\n\t\t\t\tcustomDomain?: string;\n\t\t\t\tauthentication?: {\n\t\t\t\t\tpublic?: boolean;\n\t\t\t\t\ttokenExpiryMinutes?: number;\n\t\t\t\t};\n\t\t\t}): Promise<string> => {\n\t\t\t\ttry {\n\t\t\t\t\t// If public is not set, default to true\n\t\t\t\t\tconst isPublic = options.authentication?.public !== undefined ? options.authentication.public : true;\n\n\t\t\t\t\t// Default CORS headers for broad compatibility\n\t\t\t\t\tconst defaultHeaders = {\n\t\t\t\t\t\t\"Access-Control-Allow-Origin\": \"*\",\n\t\t\t\t\t\t\"Access-Control-Allow-Methods\": \"GET, POST, PUT, DELETE, OPTIONS, PATCH\",\n\t\t\t\t\t\t\"Access-Control-Allow-Headers\": \"Content-Type, Authorization, X-Requested-With, X-Blaxel-Preview-Token, X-Blaxel-Authorization\",\n\t\t\t\t\t\t\"Access-Control-Allow-Credentials\": \"true\",\n\t\t\t\t\t\t\"Access-Control-Expose-Headers\": \"Content-Length, X-Request-Id\",\n\t\t\t\t\t\t\"Access-Control-Max-Age\": \"86400\",\n\t\t\t\t\t\t\"Vary\": \"Origin\"\n\t\t\t\t\t};\n\n\t\t\t\t\t// Use custom headers if provided, otherwise use defaults\n\t\t\t\t\tconst responseHeaders = options.headers?.response || defaultHeaders;\n\n\t\t\t\t\t// Create or get existing preview URL using Blaxel's preview API\n\t\t\t\t\tconst preview = await sandbox.previews.createIfNotExists({\n\t\t\t\t\t\tmetadata: {\n\t\t\t\t\t\t\tname: `preview-port-${options.port}-${isPublic ? 'public' : 'private'}`\n\t\t\t\t\t\t},\n\t\t\t\t\t\tspec: {\n\t\t\t\t\t\t\tport: options.port,\n\t\t\t\t\t\t\tpublic: isPublic,\n\t\t\t\t\t\t\tresponseHeaders,\n\t\t\t\t\t\t\trequestHeaders: options.headers?.request || defaultHeaders,\n\t\t\t\t\t\t\tcustomDomain: options.customDomain,\n\t\t\t\t\t\t\tprefixUrl: options.prefixUrl,\n\t\t\t\t\t\t\tttl: options.ttl ? `${Math.ceil(options.ttl / 1000)}s` : undefined\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\n\t\t\t\t\t// Get the preview URL\n\t\t\t\t\tconst url = preview.spec?.url;\n\t\t\t\t\tif (!url) {\n\t\t\t\t\t\tthrow new Error(`Failed to get preview URL for port ${options.port}`);\n\t\t\t\t\t}\n\n\t\t\t\t\t// For private previews, create an access token and append it to the URL\n\t\t\t\t\tif (!isPublic) {\n\t\t\t\t\t\t// Create token with specified expiry (default 60 minutes)\n\t\t\t\t\t\tconst expiryMinutes = options.authentication?.tokenExpiryMinutes || 60;\n\t\t\t\t\t\tconst expiresAt = new Date(Date.now() + expiryMinutes * 60 * 1000);\n\t\t\t\t\t\tconst token = await preview.tokens.create(expiresAt);\n\n\t\t\t\t\t\t// Return URL with token as query parameter\n\t\t\t\t\t\tconst separator = url.includes('?') ? '&' : '?';\n\t\t\t\t\t\treturn `${url}${separator}bl_preview_token=${token.value}`;\n\t\t\t\t\t}\n\n\t\t\t\t\t// For public previews, just return the URL\n\t\t\t\t\treturn url;\n\t\t\t\t} catch (error) {\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t`Failed to get Blaxel preview URL for port ${options.port}: ${error instanceof Error ? error.message : String(error)}`\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t},\n\n\t\t\t// Optional filesystem methods - implement using Blaxel's filesystem API\n\t\t\tfilesystem: {\n\t\t\t\treadFile: async (sandbox: SandboxInstance, path: string): Promise<string> => {\n\t\t\t\t\tconst result = await sandbox.fs.read(path);\n\t\t\t\t\treturn result || '';\n\t\t\t\t},\n\n\t\t\t\twriteFile: async (sandbox: SandboxInstance, path: string, content: string): Promise<void> => {\n\t\t\t\t\tawait sandbox.fs.write(path, content);\n\t\t\t\t},\n\n\t\t\t\tmkdir: async (sandbox: SandboxInstance, path: string): Promise<void> => {\n\t\t\t\t\tawait sandbox.fs.mkdir(path);\n\t\t\t\t},\n\n\t\t\t\treaddir: async (sandbox: SandboxInstance, path: string): Promise<FileEntry[]> => {\n\t\t\t\t\tconst result = await sandbox.fs.ls(path);\n\t\t\t\t\tconst files = result.files || [];\n\t\t\t\t\tconst directories = result.subdirectories || [];\n\t\t\t\t\tlet entries = [];\n\t\t\t\t\tfor (const file of files) {\n\t\t\t\t\t\tentries.push({\n\t\t\t\t\t\t\tname: file.name,\n\t\t\t\t\t\t\ttype: 'file' as const,\n\t\t\t\t\t\t\tsize: file.size || 0,\n\t\t\t\t\t\t\tmodified: new Date(file.lastModified || Date.now())\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t\tfor (const directory of directories) {\n\t\t\t\t\t\tentries.push({\n\t\t\t\t\t\t\tname: directory.name,\n\t\t\t\t\t\t\ttype: 'directory' as const,\n\t\t\t\t\t\t\tsize: 0,\n\t\t\t\t\t\t\tmodified: new Date()\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t\treturn entries;\n\t\t\t\t},\n\n\t\t\t\texists: async (sandbox: SandboxInstance, path: string): Promise<boolean> => {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tawait sandbox.fs.read(path);\n\t\t\t\t\t\treturn true; // It's a file and exists\n\t\t\t\t\t} catch {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tawait sandbox.fs.ls(path);\n\t\t\t\t\t\t\treturn true; // It's a directory and exists\n\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\treturn false; // Path doesn't exist\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t},\n\n\t\t\t\tremove: async (sandbox: SandboxInstance, path: string): Promise<void> => {\n\t\t\t\t\tawait sandbox.fs.rm(path);\n\t\t\t\t}\n\t\t\t},\n\n\t\t\t// Provider-specific typed getInstance method\n\t\t\tgetInstance: (sandbox: SandboxInstance): SandboxInstance => {\n\t\t\t\treturn sandbox;\n\t\t\t},\n\t\t}\n\t}\n});\n\nasync function handleBlaxelAuth(config: BlaxelConfig) {\n\t// Check if auth is already set in the SDK\n\ttry {\n\t\tawait settings.authenticate();\n\t} catch (error) {\n\t\t// If not, set the auth from the config\n\t\tif (config.workspace || process.env.BLAXEL_WORKSPACE && typeof process !== 'undefined') {\n\t\t\tprocess.env.BL_WORKSPACE = config.workspace || process.env.BLAXEL_WORKSPACE;\n\t\t}\n\t\tif (config.apiKey || process.env.BLAXEL_API_KEY && typeof process !== 'undefined') {\n\t\t\tprocess.env.BL_API_KEY = config.apiKey || process.env.BLAXEL_API_KEY;\n\t\t}\n\t\ttry {\n\t\t\tawait settings.authenticate();\n\t\t} catch (error) {\n\t\t\tthrow new Error('Blaxel authentication failed. Please check the following documents for more information: https://docs.blaxel.ai/Security/Access-tokens#using-api-keys');\n\t\t}\n\t}\n}\n\n/**\n * Parse TTL value from Blaxel's format to milliseconds\n * Supports formats like \"30m\", \"24h\", \"7d\" or plain numbers (seconds)\n */\nfunction parseTTLToMilliseconds(ttl: string | number | undefined): number {\n\tif (!ttl) return 300000; // Default to 5 minutes\n\n\t// If it's already a number, treat it as seconds and convert to milliseconds\n\tif (typeof ttl === 'number') {\n\t\treturn ttl * 1000;\n\t}\n\n\t// Parse string formats like \"30m\", \"24h\", \"7d\"\n\tconst match = ttl.match(/^(\\d+)([smhd])?$/);\n\tif (!match) return 300000; // Default if format is invalid\n\n\tconst value = parseInt(match[1], 10);\n\tconst unit = match[2] || 's'; // Default to seconds if no unit\n\n\tswitch (unit) {\n\t\tcase 's': return value * 1000; // seconds to ms\n\t\tcase 'm': return value * 60 * 1000; // minutes to ms\n\t\tcase 'h': return value * 60 * 60 * 1000; // hours to ms\n\t\tcase 'd': return value * 24 * 60 * 60 * 1000; // days to ms\n\t\tdefault: return 300000; // Default fallback\n\t}\n}\n\nfunction convertSandboxStatus(status: string | undefined): 'running' | 'stopped' | 'error' {\n\tswitch (status?.toLowerCase()) {\n\t\tcase 'deployed': return 'running';\n\t\tcase 'deleting': return 'stopped';\n\t\tcase 'failed': return 'error';\n\t\tdefault: return 'running';\n\t}\n}\n\n/**\n * Execute a command in the sandbox and capture stdout/stderr\n * Handles the common pattern of executing, streaming logs, and waiting for completion\n */\nasync function executeWithStreaming(\n\tsandbox: SandboxInstance,\n\tcommand: string\n): Promise<{ stdout: string; stderr: string; exitCode: number }> {\n\t// Execute the command\n\tconst result = await sandbox.process.exec({ command });\n\n\t// Wait for process completion\n\tawait sandbox.process.wait(result.name);\n\n\t// Get final process result for exit code\n\tconst processResult = await sandbox.process.get(result.name);\n\n\treturn {\n\t\tstdout: processResult.logs,\n\t\tstderr: processResult.logs,\n\t\texitCode: processResult.exitCode || 0\n\t};\n}\n\n// Export the Blaxel SandboxInstance type for explicit typing\nexport type { SandboxInstance as BlaxelSandbox } from '@blaxel/core';\n\n"],"mappings":"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","names":["error"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["/**\n * Blaxel Provider - Factory-based Implementation\n * \n * Full-featured provider with filesystem support using the factory pattern.\n */\n\nimport { SandboxInstance, settings } from '@blaxel/core';\nimport { defineProvider, escapeShellArg } from '@computesdk/provider';\n\nimport type { Runtime, CodeResult, CommandResult, SandboxInfo, CreateSandboxOptions, FileEntry, RunCommandOptions } from '@computesdk/provider';\n\n/**\n * Blaxel-specific configuration options\n */\nexport interface BlaxelConfig {\n\t/** Blaxel workspace ID - if not provided, will fallback to BL_WORKSPACE environment variable */\n\tworkspace?: string;\n\t/** Blaxel API key - if not provided, will fallback to BL_API_KEY environment variable */\n\tapiKey?: string;\n\t/** Default image for sandboxes */\n\timage?: string;\n\t/** Default region for sandbox deployment */\n\tregion?: string;\n\t/** Default memory allocation in MB */\n\tmemory?: number | 4096;\n\t/** Default ports for sandbox */\n\tports?: number[] | [3000];\n}\n\n/**\n * Create a Blaxel provider instance using the factory pattern\n */\nexport const blaxel = defineProvider<SandboxInstance, BlaxelConfig>({\n\tname: 'blaxel',\n\tmethods: {\n\t\tsandbox: {\n\t\t\t// Collection operations (map to compute.sandbox.*)\n\t\t\tcreate: async (config: BlaxelConfig, options?: CreateSandboxOptions) => {\n\t\t\t\tawait handleBlaxelAuth(config);\n\n\t\t\t\t// Determine the image to use\n\t\t\t\tlet image = config.image || 'blaxel/prod-base:latest'; // Default to prod-base\n\n\t\t\t\t// Override with runtime-specific image if runtime is specified and no explicit image\n\t\t\t\tif (!config.image && options?.runtime) {\n\t\t\t\t\tswitch (options.runtime) {\n\t\t\t\t\t\tcase 'python':\n\t\t\t\t\t\t\timage = 'blaxel/prod-py-app:latest';\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase 'node':\n\t\t\t\t\t\t\timage = 'blaxel/prod-ts-app:latest';\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tdefault:\n\t\t\t\t\t\t\timage = 'blaxel/prod-base:latest';\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tconst memory = config.memory;\n\t\t\t\tconst region = config.region;\n\t\t\t\tconst envs = options?.envs;\n\t\t\t\tconst ttl = options?.timeout ? `${Math.ceil(options.timeout / 1000)}s` : undefined;\n\n\t\t\t\ttry {\n\t\t\t\t\tlet sandbox: SandboxInstance;\n\n\t\t\t\t\t// Create new Blaxel sandbox\n\t\t\t\t\tsandbox = await SandboxInstance.createIfNotExists({\n\t\t\t\t\t\tname: options?.sandboxId || `blaxel-${Date.now()}`,\n\t\t\t\t\t\timage,\n\t\t\t\t\t\tmemory,\n\t\t\t\t\t\tenvs: Object.entries(envs || {}).map(([name, value]) => ({ name, value })),\n\t\t\t\t\t\tmetadata: {\n\t\t\t\t\t\t\tlabels: {\n\t\t\t\t\t\t\t\t...options?.metadata?.labels,\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t},\n\t\t\t\t\t\tttl,\n\t\t\t\t\t\tports: config.ports?.map(port => ({ target: port, protocol: 'HTTP' })),\n\t\t\t\t\t\t...(region && { region })\n\t\t\t\t\t});\n\n\t\t\t\t\treturn {\n\t\t\t\t\t\tsandbox,\n\t\t\t\t\t\tsandboxId: sandbox.metadata?.name || 'blaxel-unknown'\n\t\t\t\t\t};\n\t\t\t\t} catch (error) {\n\t\t\t\t\tif (error instanceof Error) {\n\t\t\t\t\t\tif (error.message.includes('unauthorized') || error.message.includes('API key')) {\n\t\t\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t\t\t`Blaxel authentication failed. Please check your BLAXEL_API_KEY environment variable.`\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (error.message.includes('quota') || error.message.includes('limit')) {\n\t\t\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t\t\t`Blaxel quota exceeded. Please check your usage limits.`\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t`Failed to create Blaxel sandbox: ${error instanceof Error ? error.message : String(error)}`\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t},\n\n\t\t\tgetById: async (config: BlaxelConfig, sandboxId: string) => {\n\t\t\t\tawait handleBlaxelAuth(config);\n\n\t\t\t\ttry {\n\t\t\t\t\tconst sandbox = await SandboxInstance.get(sandboxId);\n\n\t\t\t\t\tif (!sandbox) {\n\t\t\t\t\t\treturn null;\n\t\t\t\t\t}\n\n\t\t\t\t\treturn {\n\t\t\t\t\t\tsandbox,\n\t\t\t\t\t\tsandboxId\n\t\t\t\t\t};\n\t\t\t\t} catch (error) {\n\t\t\t\t\t// Sandbox doesn't exist or can't be accessed\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\t\t\t},\n\n\t\t\tlist: async (config: BlaxelConfig) => {\n\t\t\t\tawait handleBlaxelAuth(config);\n\n\t\t\t\tconst sandboxList = await SandboxInstance.list();\n\t\t\t\treturn sandboxList.map(sandbox => ({\n\t\t\t\t\tsandbox,\n\t\t\t\t\tsandboxId: sandbox.metadata?.name || 'blaxel-unknown'\n\t\t\t\t}));\n\t\t\t},\n\n\t\t\tdestroy: async (config: BlaxelConfig, sandboxId: string) => {\n\t\t\t\tawait handleBlaxelAuth(config);\n\n\t\t\t\ttry {\n\t\t\t\t\tawait SandboxInstance.delete(sandboxId);\n\t\t\t\t} catch (error) {\n\t\t\t\t\t// Sandbox might already be destroyed or doesn't exist\n\t\t\t\t\t// This is acceptable for destroy operations\n\t\t\t\t}\n\t\t\t},\n\n\t\t\t// Instance operations (map to individual Sandbox methods)\n\t\t\trunCode: async (sandbox: SandboxInstance, code: string, runtime?: Runtime): Promise<CodeResult> => {\n\t\t\t\tconst startTime = Date.now();\n\n\t\t\t\ttry {\n\t\t\t\t\t// Determine runtime: \n\t\t\t\t\t// 1. Use explicitly passed runtime if provided\n\t\t\t\t\t// 2. Check sandbox's actual runtime based on its image\n\t\t\t\t\t// 3. Fall back to auto-detection from code content\n\t\t\t\t\tlet effectiveRuntime = runtime;\n\n\t\t\t\t\tif (!effectiveRuntime) {\n\t\t\t\t\t\t// Check sandbox's image to determine its runtime\n\t\t\t\t\t\tconst sandboxImage = sandbox.spec?.runtime?.image || '';\n\t\t\t\t\t\tif (sandboxImage.includes('py')) {\n\t\t\t\t\t\t\teffectiveRuntime = 'python';\n\t\t\t\t\t\t} else if (sandboxImage.includes('ts') || sandboxImage.includes('node') || sandboxImage.includes('base')) {\n\t\t\t\t\t\t\t// prod-base, prod-ts-app are both Node/TypeScript environments\n\t\t\t\t\t\t\teffectiveRuntime = 'node';\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t// Fall back to auto-detection with improved patterns for unknown images\n\t\t\t\t\t\t\teffectiveRuntime = (\n\t\t\t\t\t\t\t\t// Strong Python indicators\n\t\t\t\t\t\t\t\tcode.includes('print(') ||\n\t\t\t\t\t\t\t\t\tcode.includes('import ') ||\n\t\t\t\t\t\t\t\t\tcode.includes('from ') ||\n\t\t\t\t\t\t\t\t\tcode.includes('def ') ||\n\t\t\t\t\t\t\t\t\tcode.includes('class ') ||\n\t\t\t\t\t\t\t\t\tcode.includes('raise ') ||\n\t\t\t\t\t\t\t\t\tcode.includes('except ') ||\n\t\t\t\t\t\t\t\t\tcode.includes('elif ') ||\n\t\t\t\t\t\t\t\t\tcode.includes('lambda ') ||\n\t\t\t\t\t\t\t\t\tcode.includes('True') ||\n\t\t\t\t\t\t\t\t\tcode.includes('False') ||\n\t\t\t\t\t\t\t\t\tcode.includes('None') ||\n\t\t\t\t\t\t\t\t\tcode.includes('sys.') ||\n\t\t\t\t\t\t\t\t\tcode.includes('json.') ||\n\t\t\t\t\t\t\t\t\tcode.includes('__') ||\n\t\t\t\t\t\t\t\t\tcode.includes('f\"') ||\n\t\t\t\t\t\t\t\t\tcode.includes(\"f'\") ||\n\t\t\t\t\t\t\t\t\tcode.includes('\"\"\"') ||\n\t\t\t\t\t\t\t\t\tcode.includes(\"'''\")\n\t\t\t\t\t\t\t\t\t? 'python'\n\t\t\t\t\t\t\t\t\t// Default to Node.js for all other cases (including ambiguous)\n\t\t\t\t\t\t\t\t\t: 'node'\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t// Execute code using Blaxel's process execution\n\t\t\t\t\t// Escape the code properly for shell execution\n\t\t\t\t\tconst escapedCode = code.replace(/\\\\/g, '\\\\\\\\').replace(/\"/g, '\\\\\"').replace(/\\$/g, '\\\\$').replace(/`/g, '\\\\`');\n\n\t\t\t\t\tconst command = effectiveRuntime === 'python'\n\t\t\t\t\t\t? `python3 -c \"${escapedCode}\"`\n\t\t\t\t\t\t: `node -e \"${escapedCode}\"`;\n\n\t\t\t\t\tconst { stdout, stderr, exitCode } = await executeWithStreaming(sandbox, command);\n\n\t\t\t\t\t// Check for syntax errors and throw them\n\t\t\t\t\tif (exitCode !== 0 && stderr) {\n\t\t\t\t\t\t// Check for common syntax error patterns\n\t\t\t\t\t\tif (stderr.includes('SyntaxError') ||\n\t\t\t\t\t\t\tstderr.includes('invalid syntax') ||\n\t\t\t\t\t\t\tstderr.includes('Unexpected token') ||\n\t\t\t\t\t\t\tstderr.includes('Unexpected identifier')) {\n\t\t\t\t\t\t\tthrow new Error(`Syntax error: ${stderr.trim()}`);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t// Combine stdout and stderr into output\n\t\t\t\t\tconst output = stderr ? `${stdout}\\n${stderr}`.trim() : stdout;\n\n\t\t\t\t\treturn {\n\t\t\t\t\t\toutput,\n\t\t\t\t\t\texitCode,\n\t\t\t\t\t\tlanguage: effectiveRuntime\n\t\t\t\t\t};\n\t\t\t\t} catch (error) {\n\t\t\t\t\t// Re-throw syntax errors\n\t\t\t\t\tif (error instanceof Error && error.message.includes('Syntax error')) {\n\t\t\t\t\t\tthrow error;\n\t\t\t\t\t}\n\n\t\t\t\t\t// For runtime errors, return a result instead of throwing\n\t\t\t\t\treturn {\n\t\t\t\t\t\toutput: error instanceof Error ? error.message : String(error),\n\t\t\t\t\t\texitCode: 1,\n\t\t\t\t\t\tlanguage: runtime || 'node'\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t},\n\n\t\trunCommand: async (sandbox: SandboxInstance, command: string, options?: RunCommandOptions): Promise<CommandResult> => {\n\t\t\tconst startTime = Date.now();\n\n\t\t\ttry {\n\t\t\t\t// Build command with options\n\t\t\t\tlet fullCommand = command;\n\t\t\t\t\n\t\t\t\t// Handle environment variables\n\t\t\t\tif (options?.env && Object.keys(options.env).length > 0) {\n\t\t\t\t\tconst envPrefix = Object.entries(options.env)\n\t\t\t\t\t\t.map(([k, v]) => `${k}=\"${escapeShellArg(v)}\"`)\n\t\t\t\t\t\t.join(' ');\n\t\t\t\t\tfullCommand = `${envPrefix} ${fullCommand}`;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t// Handle working directory\n\t\t\t\tif (options?.cwd) {\n\t\t\t\t\tfullCommand = `cd \"${escapeShellArg(options.cwd)}\" && ${fullCommand}`;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t// Handle background execution\n\t\t\t\tif (options?.background) {\n\t\t\t\t\tfullCommand = `nohup ${fullCommand} > /dev/null 2>&1 &`;\n\t\t\t\t}\n\n\t\t\t\tconst { stdout, stderr, exitCode } = await executeWithStreaming(sandbox, fullCommand);\n\n\t\t\t\treturn {\n\t\t\t\t\tstdout,\n\t\t\t\t\tstderr,\n\t\t\t\t\texitCode,\n\t\t\t\t\tdurationMs: Date.now() - startTime\n\t\t\t\t};\n\t\t\t} catch (error) {\n\t\t\t\treturn {\n\t\t\t\t\tstdout: '',\n\t\t\t\t\tstderr: error instanceof Error ? error.message : String(error),\n\t\t\t\t\texitCode: 127,\n\t\t\t\t\tdurationMs: Date.now() - startTime\n\t\t\t\t};\n\t\t\t}\n\t\t},\n\n\t\t\tgetInfo: async (sandbox: SandboxInstance): Promise<SandboxInfo> => {\n\t\t\t\treturn {\n\t\t\t\t\tid: sandbox.metadata?.name || 'blaxel-unknown',\n\t\t\t\t\tprovider: 'blaxel',\n\t\t\t\t\truntime: sandbox.spec?.runtime?.image?.includes('py') ? 'python' : 'node',\n\t\t\t\t\tstatus: convertSandboxStatus(sandbox.status),\n\t\t\t\t\tcreatedAt: sandbox.metadata?.createdAt ? new Date(sandbox.metadata.createdAt) : new Date(),\n\t\t\t\t\ttimeout: parseTTLToMilliseconds(sandbox.spec?.runtime?.ttl),\n\t\t\t\t\tmetadata: {\n\t\t\t\t\t\t...sandbox.metadata?.labels\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t\t},\n\n\t\t\tgetUrl: async (sandbox: SandboxInstance, options: {\n\t\t\t\tport: number;\n\t\t\t\tttl?: number;\n\t\t\t\tprefixUrl?: string;\n\t\t\t\theaders?: {\n\t\t\t\t\tresponse?: Record<string, string>;\n\t\t\t\t\trequest?: Record<string, string>;\n\t\t\t\t};\n\t\t\t\tcustomDomain?: string;\n\t\t\t\tauthentication?: {\n\t\t\t\t\tpublic?: boolean;\n\t\t\t\t\ttokenExpiryMinutes?: number;\n\t\t\t\t};\n\t\t\t}): Promise<string> => {\n\t\t\t\ttry {\n\t\t\t\t\t// If public is not set, default to true\n\t\t\t\t\tconst isPublic = options.authentication?.public !== undefined ? options.authentication.public : true;\n\n\t\t\t\t\t// Default CORS headers for broad compatibility\n\t\t\t\t\tconst defaultHeaders = {\n\t\t\t\t\t\t\"Access-Control-Allow-Origin\": \"*\",\n\t\t\t\t\t\t\"Access-Control-Allow-Methods\": \"GET, POST, PUT, DELETE, OPTIONS, PATCH\",\n\t\t\t\t\t\t\"Access-Control-Allow-Headers\": \"Content-Type, Authorization, X-Requested-With, X-Blaxel-Preview-Token, X-Blaxel-Authorization\",\n\t\t\t\t\t\t\"Access-Control-Allow-Credentials\": \"true\",\n\t\t\t\t\t\t\"Access-Control-Expose-Headers\": \"Content-Length, X-Request-Id\",\n\t\t\t\t\t\t\"Access-Control-Max-Age\": \"86400\",\n\t\t\t\t\t\t\"Vary\": \"Origin\"\n\t\t\t\t\t};\n\n\t\t\t\t\t// Use custom headers if provided, otherwise use defaults\n\t\t\t\t\tconst responseHeaders = options.headers?.response || defaultHeaders;\n\n\t\t\t\t\t// Create or get existing preview URL using Blaxel's preview API\n\t\t\t\t\tconst preview = await sandbox.previews.createIfNotExists({\n\t\t\t\t\t\tmetadata: {\n\t\t\t\t\t\t\tname: `preview-port-${options.port}-${isPublic ? 'public' : 'private'}`\n\t\t\t\t\t\t},\n\t\t\t\t\t\tspec: {\n\t\t\t\t\t\t\tport: options.port,\n\t\t\t\t\t\t\tpublic: isPublic,\n\t\t\t\t\t\t\tresponseHeaders,\n\t\t\t\t\t\t\trequestHeaders: options.headers?.request || defaultHeaders,\n\t\t\t\t\t\t\tcustomDomain: options.customDomain,\n\t\t\t\t\t\t\tprefixUrl: options.prefixUrl,\n\t\t\t\t\t\t\tttl: options.ttl ? `${Math.ceil(options.ttl / 1000)}s` : undefined\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\n\t\t\t\t\t// Get the preview URL\n\t\t\t\t\tconst url = preview.spec?.url;\n\t\t\t\t\tif (!url) {\n\t\t\t\t\t\tthrow new Error(`Failed to get preview URL for port ${options.port}`);\n\t\t\t\t\t}\n\n\t\t\t\t\t// For private previews, create an access token and append it to the URL\n\t\t\t\t\tif (!isPublic) {\n\t\t\t\t\t\t// Create token with specified expiry (default 60 minutes)\n\t\t\t\t\t\tconst expiryMinutes = options.authentication?.tokenExpiryMinutes || 60;\n\t\t\t\t\t\tconst expiresAt = new Date(Date.now() + expiryMinutes * 60 * 1000);\n\t\t\t\t\t\tconst token = await preview.tokens.create(expiresAt);\n\n\t\t\t\t\t\t// Return URL with token as query parameter\n\t\t\t\t\t\tconst separator = url.includes('?') ? '&' : '?';\n\t\t\t\t\t\treturn `${url}${separator}bl_preview_token=${token.value}`;\n\t\t\t\t\t}\n\n\t\t\t\t\t// For public previews, just return the URL\n\t\t\t\t\treturn url;\n\t\t\t\t} catch (error) {\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t`Failed to get Blaxel preview URL for port ${options.port}: ${error instanceof Error ? error.message : String(error)}`\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t},\n\n\t\t\t// Optional filesystem methods - implement using Blaxel's filesystem API\n\t\t\tfilesystem: {\n\t\t\t\treadFile: async (sandbox: SandboxInstance, path: string): Promise<string> => {\n\t\t\t\t\tconst result = await sandbox.fs.read(path);\n\t\t\t\t\treturn result || '';\n\t\t\t\t},\n\n\t\t\t\twriteFile: async (sandbox: SandboxInstance, path: string, content: string): Promise<void> => {\n\t\t\t\t\tawait sandbox.fs.write(path, content);\n\t\t\t\t},\n\n\t\t\t\tmkdir: async (sandbox: SandboxInstance, path: string): Promise<void> => {\n\t\t\t\t\tawait sandbox.fs.mkdir(path);\n\t\t\t\t},\n\n\t\t\t\treaddir: async (sandbox: SandboxInstance, path: string): Promise<FileEntry[]> => {\n\t\t\t\t\tconst result = await sandbox.fs.ls(path);\n\t\t\t\t\tconst files = result.files || [];\n\t\t\t\t\tconst directories = result.subdirectories || [];\n\t\t\t\t\tlet entries = [];\n\t\t\t\t\tfor (const file of files) {\n\t\t\t\t\t\tentries.push({\n\t\t\t\t\t\t\tname: file.name,\n\t\t\t\t\t\t\ttype: 'file' as const,\n\t\t\t\t\t\t\tsize: file.size || 0,\n\t\t\t\t\t\t\tmodified: new Date(file.lastModified || Date.now())\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t\tfor (const directory of directories) {\n\t\t\t\t\t\tentries.push({\n\t\t\t\t\t\t\tname: directory.name,\n\t\t\t\t\t\t\ttype: 'directory' as const,\n\t\t\t\t\t\t\tsize: 0,\n\t\t\t\t\t\t\tmodified: new Date()\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t\treturn entries;\n\t\t\t\t},\n\n\t\t\t\texists: async (sandbox: SandboxInstance, path: string): Promise<boolean> => {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tawait sandbox.fs.read(path);\n\t\t\t\t\t\treturn true; // It's a file and exists\n\t\t\t\t\t} catch {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tawait sandbox.fs.ls(path);\n\t\t\t\t\t\t\treturn true; // It's a directory and exists\n\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\treturn false; // Path doesn't exist\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t},\n\n\t\t\t\tremove: async (sandbox: SandboxInstance, path: string): Promise<void> => {\n\t\t\t\t\tawait sandbox.fs.rm(path);\n\t\t\t\t}\n\t\t\t},\n\n\t\t\t// Provider-specific typed getInstance method\n\t\t\tgetInstance: (sandbox: SandboxInstance): SandboxInstance => {\n\t\t\t\treturn sandbox;\n\t\t\t},\n\t\t}\n\t}\n});\n\nasync function handleBlaxelAuth(config: BlaxelConfig) {\n\t// Check if auth is already set in the SDK\n\ttry {\n\t\tawait settings.authenticate();\n\t} catch (error) {\n\t\t// If not, set the auth from the config\n\t\tif (config.workspace || process.env.BLAXEL_WORKSPACE && typeof process !== 'undefined') {\n\t\t\tprocess.env.BL_WORKSPACE = config.workspace || process.env.BLAXEL_WORKSPACE;\n\t\t}\n\t\tif (config.apiKey || process.env.BLAXEL_API_KEY && typeof process !== 'undefined') {\n\t\t\tprocess.env.BL_API_KEY = config.apiKey || process.env.BLAXEL_API_KEY;\n\t\t}\n\t\ttry {\n\t\t\tawait settings.authenticate();\n\t\t} catch (error) {\n\t\t\tthrow new Error('Blaxel authentication failed. Please check the following documents for more information: https://docs.blaxel.ai/Security/Access-tokens#using-api-keys');\n\t\t}\n\t}\n}\n\n/**\n * Parse TTL value from Blaxel's format to milliseconds\n * Supports formats like \"30m\", \"24h\", \"7d\" or plain numbers (seconds)\n */\nfunction parseTTLToMilliseconds(ttl: string | number | undefined): number {\n\tif (!ttl) return 300000; // Default to 5 minutes\n\n\t// If it's already a number, treat it as seconds and convert to milliseconds\n\tif (typeof ttl === 'number') {\n\t\treturn ttl * 1000;\n\t}\n\n\t// Parse string formats like \"30m\", \"24h\", \"7d\"\n\tconst match = ttl.match(/^(\\d+)([smhd])?$/);\n\tif (!match) return 300000; // Default if format is invalid\n\n\tconst value = parseInt(match[1], 10);\n\tconst unit = match[2] || 's'; // Default to seconds if no unit\n\n\tswitch (unit) {\n\t\tcase 's': return value * 1000; // seconds to ms\n\t\tcase 'm': return value * 60 * 1000; // minutes to ms\n\t\tcase 'h': return value * 60 * 60 * 1000; // hours to ms\n\t\tcase 'd': return value * 24 * 60 * 60 * 1000; // days to ms\n\t\tdefault: return 300000; // Default fallback\n\t}\n}\n\nfunction convertSandboxStatus(status: string | undefined): 'running' | 'stopped' | 'error' {\n\tswitch (status?.toLowerCase()) {\n\t\tcase 'deployed': return 'running';\n\t\tcase 'deleting': return 'stopped';\n\t\tcase 'failed': return 'error';\n\t\tdefault: return 'running';\n\t}\n}\n\n/**\n * Execute a command in the sandbox and capture stdout/stderr\n * Handles the common pattern of executing, streaming logs, and waiting for completion\n */\nasync function executeWithStreaming(\n\tsandbox: SandboxInstance,\n\tcommand: string\n): Promise<{ stdout: string; stderr: string; exitCode: number }> {\n\t// Execute the command\n\tconst result = await sandbox.process.exec({ command });\n\n\t// Wait for process completion\n\tawait sandbox.process.wait(result.name);\n\n\t// Get final process result for exit code\n\tconst processResult = await sandbox.process.get(result.name);\n\n\treturn {\n\t\tstdout: processResult.logs,\n\t\tstderr: processResult.logs,\n\t\texitCode: processResult.exitCode || 0\n\t};\n}\n\n// Export the Blaxel SandboxInstance type for explicit typing\nexport type { SandboxInstance as BlaxelSandbox } from '@blaxel/core';\n\n"],"mappings":"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","names":["error"]}
|
package/dist/index.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// src/index.ts
|
|
2
2
|
import { SandboxInstance, settings } from "@blaxel/core";
|
|
3
|
-
import { defineProvider } from "@computesdk/provider";
|
|
3
|
+
import { defineProvider, escapeShellArg } from "@computesdk/provider";
|
|
4
4
|
var blaxel = defineProvider({
|
|
5
5
|
name: "blaxel",
|
|
6
6
|
methods: {
|
|
@@ -136,16 +136,20 @@ ${stderr}`.trim() : stdout;
|
|
|
136
136
|
};
|
|
137
137
|
}
|
|
138
138
|
},
|
|
139
|
-
runCommand: async (sandbox, command,
|
|
139
|
+
runCommand: async (sandbox, command, options) => {
|
|
140
140
|
const startTime = Date.now();
|
|
141
141
|
try {
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
142
|
+
let fullCommand = command;
|
|
143
|
+
if (options?.env && Object.keys(options.env).length > 0) {
|
|
144
|
+
const envPrefix = Object.entries(options.env).map(([k, v]) => `${k}="${escapeShellArg(v)}"`).join(" ");
|
|
145
|
+
fullCommand = `${envPrefix} ${fullCommand}`;
|
|
146
|
+
}
|
|
147
|
+
if (options?.cwd) {
|
|
148
|
+
fullCommand = `cd "${escapeShellArg(options.cwd)}" && ${fullCommand}`;
|
|
149
|
+
}
|
|
150
|
+
if (options?.background) {
|
|
151
|
+
fullCommand = `nohup ${fullCommand} > /dev/null 2>&1 &`;
|
|
152
|
+
}
|
|
149
153
|
const { stdout, stderr, exitCode } = await executeWithStreaming(sandbox, fullCommand);
|
|
150
154
|
return {
|
|
151
155
|
stdout,
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["/**\n * Blaxel Provider - Factory-based Implementation\n * \n * Full-featured provider with filesystem support using the factory pattern.\n */\n\nimport { SandboxInstance, settings } from '@blaxel/core';\nimport { defineProvider } from '@computesdk/provider';\n\nimport type { Runtime, CodeResult, CommandResult, SandboxInfo, CreateSandboxOptions, FileEntry } from '@computesdk/provider';\n\n/**\n * Blaxel-specific configuration options\n */\nexport interface BlaxelConfig {\n\t/** Blaxel workspace ID - if not provided, will fallback to BL_WORKSPACE environment variable */\n\tworkspace?: string;\n\t/** Blaxel API key - if not provided, will fallback to BL_API_KEY environment variable */\n\tapiKey?: string;\n\t/** Default image for sandboxes */\n\timage?: string;\n\t/** Default region for sandbox deployment */\n\tregion?: string;\n\t/** Default memory allocation in MB */\n\tmemory?: number | 4096;\n\t/** Default ports for sandbox */\n\tports?: number[] | [3000];\n}\n\n/**\n * Create a Blaxel provider instance using the factory pattern\n */\nexport const blaxel = defineProvider<SandboxInstance, BlaxelConfig>({\n\tname: 'blaxel',\n\tmethods: {\n\t\tsandbox: {\n\t\t\t// Collection operations (map to compute.sandbox.*)\n\t\t\tcreate: async (config: BlaxelConfig, options?: CreateSandboxOptions) => {\n\t\t\t\tawait handleBlaxelAuth(config);\n\n\t\t\t\t// Determine the image to use\n\t\t\t\tlet image = config.image || 'blaxel/prod-base:latest'; // Default to prod-base\n\n\t\t\t\t// Override with runtime-specific image if runtime is specified and no explicit image\n\t\t\t\tif (!config.image && options?.runtime) {\n\t\t\t\t\tswitch (options.runtime) {\n\t\t\t\t\t\tcase 'python':\n\t\t\t\t\t\t\timage = 'blaxel/prod-py-app:latest';\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase 'node':\n\t\t\t\t\t\t\timage = 'blaxel/prod-ts-app:latest';\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tdefault:\n\t\t\t\t\t\t\timage = 'blaxel/prod-base:latest';\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tconst memory = config.memory;\n\t\t\t\tconst region = config.region;\n\t\t\t\tconst envs = options?.envs;\n\t\t\t\tconst ttl = options?.timeout ? `${Math.ceil(options.timeout / 1000)}s` : undefined;\n\n\t\t\t\ttry {\n\t\t\t\t\tlet sandbox: SandboxInstance;\n\n\t\t\t\t\t// Create new Blaxel sandbox\n\t\t\t\t\tsandbox = await SandboxInstance.createIfNotExists({\n\t\t\t\t\t\tname: options?.sandboxId || `blaxel-${Date.now()}`,\n\t\t\t\t\t\timage,\n\t\t\t\t\t\tmemory,\n\t\t\t\t\t\tenvs: Object.entries(envs || {}).map(([name, value]) => ({ name, value })),\n\t\t\t\t\t\tmetadata: {\n\t\t\t\t\t\t\tlabels: {\n\t\t\t\t\t\t\t\t...options?.metadata?.labels,\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t},\n\t\t\t\t\t\tttl,\n\t\t\t\t\t\tports: config.ports?.map(port => ({ target: port, protocol: 'HTTP' })),\n\t\t\t\t\t\t...(region && { region })\n\t\t\t\t\t});\n\n\t\t\t\t\treturn {\n\t\t\t\t\t\tsandbox,\n\t\t\t\t\t\tsandboxId: sandbox.metadata?.name || 'blaxel-unknown'\n\t\t\t\t\t};\n\t\t\t\t} catch (error) {\n\t\t\t\t\tif (error instanceof Error) {\n\t\t\t\t\t\tif (error.message.includes('unauthorized') || error.message.includes('API key')) {\n\t\t\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t\t\t`Blaxel authentication failed. Please check your BLAXEL_API_KEY environment variable.`\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (error.message.includes('quota') || error.message.includes('limit')) {\n\t\t\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t\t\t`Blaxel quota exceeded. Please check your usage limits.`\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t`Failed to create Blaxel sandbox: ${error instanceof Error ? error.message : String(error)}`\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t},\n\n\t\t\tgetById: async (config: BlaxelConfig, sandboxId: string) => {\n\t\t\t\tawait handleBlaxelAuth(config);\n\n\t\t\t\ttry {\n\t\t\t\t\tconst sandbox = await SandboxInstance.get(sandboxId);\n\n\t\t\t\t\tif (!sandbox) {\n\t\t\t\t\t\treturn null;\n\t\t\t\t\t}\n\n\t\t\t\t\treturn {\n\t\t\t\t\t\tsandbox,\n\t\t\t\t\t\tsandboxId\n\t\t\t\t\t};\n\t\t\t\t} catch (error) {\n\t\t\t\t\t// Sandbox doesn't exist or can't be accessed\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\t\t\t},\n\n\t\t\tlist: async (config: BlaxelConfig) => {\n\t\t\t\tawait handleBlaxelAuth(config);\n\n\t\t\t\tconst sandboxList = await SandboxInstance.list();\n\t\t\t\treturn sandboxList.map(sandbox => ({\n\t\t\t\t\tsandbox,\n\t\t\t\t\tsandboxId: sandbox.metadata?.name || 'blaxel-unknown'\n\t\t\t\t}));\n\t\t\t},\n\n\t\t\tdestroy: async (config: BlaxelConfig, sandboxId: string) => {\n\t\t\t\tawait handleBlaxelAuth(config);\n\n\t\t\t\ttry {\n\t\t\t\t\tawait SandboxInstance.delete(sandboxId);\n\t\t\t\t} catch (error) {\n\t\t\t\t\t// Sandbox might already be destroyed or doesn't exist\n\t\t\t\t\t// This is acceptable for destroy operations\n\t\t\t\t}\n\t\t\t},\n\n\t\t\t// Instance operations (map to individual Sandbox methods)\n\t\t\trunCode: async (sandbox: SandboxInstance, code: string, runtime?: Runtime): Promise<CodeResult> => {\n\t\t\t\tconst startTime = Date.now();\n\n\t\t\t\ttry {\n\t\t\t\t\t// Determine runtime: \n\t\t\t\t\t// 1. Use explicitly passed runtime if provided\n\t\t\t\t\t// 2. Check sandbox's actual runtime based on its image\n\t\t\t\t\t// 3. Fall back to auto-detection from code content\n\t\t\t\t\tlet effectiveRuntime = runtime;\n\n\t\t\t\t\tif (!effectiveRuntime) {\n\t\t\t\t\t\t// Check sandbox's image to determine its runtime\n\t\t\t\t\t\tconst sandboxImage = sandbox.spec?.runtime?.image || '';\n\t\t\t\t\t\tif (sandboxImage.includes('py')) {\n\t\t\t\t\t\t\teffectiveRuntime = 'python';\n\t\t\t\t\t\t} else if (sandboxImage.includes('ts') || sandboxImage.includes('node') || sandboxImage.includes('base')) {\n\t\t\t\t\t\t\t// prod-base, prod-ts-app are both Node/TypeScript environments\n\t\t\t\t\t\t\teffectiveRuntime = 'node';\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t// Fall back to auto-detection with improved patterns for unknown images\n\t\t\t\t\t\t\teffectiveRuntime = (\n\t\t\t\t\t\t\t\t// Strong Python indicators\n\t\t\t\t\t\t\t\tcode.includes('print(') ||\n\t\t\t\t\t\t\t\t\tcode.includes('import ') ||\n\t\t\t\t\t\t\t\t\tcode.includes('from ') ||\n\t\t\t\t\t\t\t\t\tcode.includes('def ') ||\n\t\t\t\t\t\t\t\t\tcode.includes('class ') ||\n\t\t\t\t\t\t\t\t\tcode.includes('raise ') ||\n\t\t\t\t\t\t\t\t\tcode.includes('except ') ||\n\t\t\t\t\t\t\t\t\tcode.includes('elif ') ||\n\t\t\t\t\t\t\t\t\tcode.includes('lambda ') ||\n\t\t\t\t\t\t\t\t\tcode.includes('True') ||\n\t\t\t\t\t\t\t\t\tcode.includes('False') ||\n\t\t\t\t\t\t\t\t\tcode.includes('None') ||\n\t\t\t\t\t\t\t\t\tcode.includes('sys.') ||\n\t\t\t\t\t\t\t\t\tcode.includes('json.') ||\n\t\t\t\t\t\t\t\t\tcode.includes('__') ||\n\t\t\t\t\t\t\t\t\tcode.includes('f\"') ||\n\t\t\t\t\t\t\t\t\tcode.includes(\"f'\") ||\n\t\t\t\t\t\t\t\t\tcode.includes('\"\"\"') ||\n\t\t\t\t\t\t\t\t\tcode.includes(\"'''\")\n\t\t\t\t\t\t\t\t\t? 'python'\n\t\t\t\t\t\t\t\t\t// Default to Node.js for all other cases (including ambiguous)\n\t\t\t\t\t\t\t\t\t: 'node'\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t// Execute code using Blaxel's process execution\n\t\t\t\t\t// Escape the code properly for shell execution\n\t\t\t\t\tconst escapedCode = code.replace(/\\\\/g, '\\\\\\\\').replace(/\"/g, '\\\\\"').replace(/\\$/g, '\\\\$').replace(/`/g, '\\\\`');\n\n\t\t\t\t\tconst command = effectiveRuntime === 'python'\n\t\t\t\t\t\t? `python3 -c \"${escapedCode}\"`\n\t\t\t\t\t\t: `node -e \"${escapedCode}\"`;\n\n\t\t\t\t\tconst { stdout, stderr, exitCode } = await executeWithStreaming(sandbox, command);\n\n\t\t\t\t\t// Check for syntax errors and throw them\n\t\t\t\t\tif (exitCode !== 0 && stderr) {\n\t\t\t\t\t\t// Check for common syntax error patterns\n\t\t\t\t\t\tif (stderr.includes('SyntaxError') ||\n\t\t\t\t\t\t\tstderr.includes('invalid syntax') ||\n\t\t\t\t\t\t\tstderr.includes('Unexpected token') ||\n\t\t\t\t\t\t\tstderr.includes('Unexpected identifier')) {\n\t\t\t\t\t\t\tthrow new Error(`Syntax error: ${stderr.trim()}`);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t// Combine stdout and stderr into output\n\t\t\t\t\tconst output = stderr ? `${stdout}\\n${stderr}`.trim() : stdout;\n\n\t\t\t\t\treturn {\n\t\t\t\t\t\toutput,\n\t\t\t\t\t\texitCode,\n\t\t\t\t\t\tlanguage: effectiveRuntime\n\t\t\t\t\t};\n\t\t\t\t} catch (error) {\n\t\t\t\t\t// Re-throw syntax errors\n\t\t\t\t\tif (error instanceof Error && error.message.includes('Syntax error')) {\n\t\t\t\t\t\tthrow error;\n\t\t\t\t\t}\n\n\t\t\t\t\t// For runtime errors, return a result instead of throwing\n\t\t\t\t\treturn {\n\t\t\t\t\t\toutput: error instanceof Error ? error.message : String(error),\n\t\t\t\t\t\texitCode: 1,\n\t\t\t\t\t\tlanguage: runtime || 'node'\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t},\n\n\t\t\trunCommand: async (sandbox: SandboxInstance, command: string, args: string[] = []): Promise<CommandResult> => {\n\t\t\t\tconst startTime = Date.now();\n\n\t\t\t\ttry {\n\t\t\t\t\t// Construct full command with arguments, properly quoting each arg\n\t\t\t\t\tconst quotedArgs = args.map((arg: string) => {\n\t\t\t\t\t\tif (arg.includes(' ') || arg.includes('\"') || arg.includes(\"'\") || arg.includes('$') || arg.includes('`')) {\n\t\t\t\t\t\t\treturn `\"${arg.replace(/\"/g, '\\\\\"')}\"`;\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn arg;\n\t\t\t\t\t});\n\t\t\t\t\tconst fullCommand = quotedArgs.length > 0 ? `${command} ${quotedArgs.join(' ')}` : command;\n\n\t\t\t\t\tconst { stdout, stderr, exitCode } = await executeWithStreaming(sandbox, fullCommand);\n\n\t\t\t\t\treturn {\n\t\t\t\t\t\tstdout,\n\t\t\t\t\t\tstderr,\n\t\t\t\t\t\texitCode,\n\t\t\t\t\t\tdurationMs: Date.now() - startTime\n\t\t\t\t\t};\n\t\t\t\t} catch (error) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tstdout: '',\n\t\t\t\t\t\tstderr: error instanceof Error ? error.message : String(error),\n\t\t\t\t\t\texitCode: 127,\n\t\t\t\t\t\tdurationMs: Date.now() - startTime\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t},\n\n\t\t\tgetInfo: async (sandbox: SandboxInstance): Promise<SandboxInfo> => {\n\t\t\t\treturn {\n\t\t\t\t\tid: sandbox.metadata?.name || 'blaxel-unknown',\n\t\t\t\t\tprovider: 'blaxel',\n\t\t\t\t\truntime: sandbox.spec?.runtime?.image?.includes('py') ? 'python' : 'node',\n\t\t\t\t\tstatus: convertSandboxStatus(sandbox.status),\n\t\t\t\t\tcreatedAt: sandbox.metadata?.createdAt ? new Date(sandbox.metadata.createdAt) : new Date(),\n\t\t\t\t\ttimeout: parseTTLToMilliseconds(sandbox.spec?.runtime?.ttl),\n\t\t\t\t\tmetadata: {\n\t\t\t\t\t\t...sandbox.metadata?.labels\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t\t},\n\n\t\t\tgetUrl: async (sandbox: SandboxInstance, options: {\n\t\t\t\tport: number;\n\t\t\t\tttl?: number;\n\t\t\t\tprefixUrl?: string;\n\t\t\t\theaders?: {\n\t\t\t\t\tresponse?: Record<string, string>;\n\t\t\t\t\trequest?: Record<string, string>;\n\t\t\t\t};\n\t\t\t\tcustomDomain?: string;\n\t\t\t\tauthentication?: {\n\t\t\t\t\tpublic?: boolean;\n\t\t\t\t\ttokenExpiryMinutes?: number;\n\t\t\t\t};\n\t\t\t}): Promise<string> => {\n\t\t\t\ttry {\n\t\t\t\t\t// If public is not set, default to true\n\t\t\t\t\tconst isPublic = options.authentication?.public !== undefined ? options.authentication.public : true;\n\n\t\t\t\t\t// Default CORS headers for broad compatibility\n\t\t\t\t\tconst defaultHeaders = {\n\t\t\t\t\t\t\"Access-Control-Allow-Origin\": \"*\",\n\t\t\t\t\t\t\"Access-Control-Allow-Methods\": \"GET, POST, PUT, DELETE, OPTIONS, PATCH\",\n\t\t\t\t\t\t\"Access-Control-Allow-Headers\": \"Content-Type, Authorization, X-Requested-With, X-Blaxel-Preview-Token, X-Blaxel-Authorization\",\n\t\t\t\t\t\t\"Access-Control-Allow-Credentials\": \"true\",\n\t\t\t\t\t\t\"Access-Control-Expose-Headers\": \"Content-Length, X-Request-Id\",\n\t\t\t\t\t\t\"Access-Control-Max-Age\": \"86400\",\n\t\t\t\t\t\t\"Vary\": \"Origin\"\n\t\t\t\t\t};\n\n\t\t\t\t\t// Use custom headers if provided, otherwise use defaults\n\t\t\t\t\tconst responseHeaders = options.headers?.response || defaultHeaders;\n\n\t\t\t\t\t// Create or get existing preview URL using Blaxel's preview API\n\t\t\t\t\tconst preview = await sandbox.previews.createIfNotExists({\n\t\t\t\t\t\tmetadata: {\n\t\t\t\t\t\t\tname: `preview-port-${options.port}-${isPublic ? 'public' : 'private'}`\n\t\t\t\t\t\t},\n\t\t\t\t\t\tspec: {\n\t\t\t\t\t\t\tport: options.port,\n\t\t\t\t\t\t\tpublic: isPublic,\n\t\t\t\t\t\t\tresponseHeaders,\n\t\t\t\t\t\t\trequestHeaders: options.headers?.request || defaultHeaders,\n\t\t\t\t\t\t\tcustomDomain: options.customDomain,\n\t\t\t\t\t\t\tprefixUrl: options.prefixUrl,\n\t\t\t\t\t\t\tttl: options.ttl ? `${Math.ceil(options.ttl / 1000)}s` : undefined\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\n\t\t\t\t\t// Get the preview URL\n\t\t\t\t\tconst url = preview.spec?.url;\n\t\t\t\t\tif (!url) {\n\t\t\t\t\t\tthrow new Error(`Failed to get preview URL for port ${options.port}`);\n\t\t\t\t\t}\n\n\t\t\t\t\t// For private previews, create an access token and append it to the URL\n\t\t\t\t\tif (!isPublic) {\n\t\t\t\t\t\t// Create token with specified expiry (default 60 minutes)\n\t\t\t\t\t\tconst expiryMinutes = options.authentication?.tokenExpiryMinutes || 60;\n\t\t\t\t\t\tconst expiresAt = new Date(Date.now() + expiryMinutes * 60 * 1000);\n\t\t\t\t\t\tconst token = await preview.tokens.create(expiresAt);\n\n\t\t\t\t\t\t// Return URL with token as query parameter\n\t\t\t\t\t\tconst separator = url.includes('?') ? '&' : '?';\n\t\t\t\t\t\treturn `${url}${separator}bl_preview_token=${token.value}`;\n\t\t\t\t\t}\n\n\t\t\t\t\t// For public previews, just return the URL\n\t\t\t\t\treturn url;\n\t\t\t\t} catch (error) {\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t`Failed to get Blaxel preview URL for port ${options.port}: ${error instanceof Error ? error.message : String(error)}`\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t},\n\n\t\t\t// Optional filesystem methods - implement using Blaxel's filesystem API\n\t\t\tfilesystem: {\n\t\t\t\treadFile: async (sandbox: SandboxInstance, path: string): Promise<string> => {\n\t\t\t\t\tconst result = await sandbox.fs.read(path);\n\t\t\t\t\treturn result || '';\n\t\t\t\t},\n\n\t\t\t\twriteFile: async (sandbox: SandboxInstance, path: string, content: string): Promise<void> => {\n\t\t\t\t\tawait sandbox.fs.write(path, content);\n\t\t\t\t},\n\n\t\t\t\tmkdir: async (sandbox: SandboxInstance, path: string): Promise<void> => {\n\t\t\t\t\tawait sandbox.fs.mkdir(path);\n\t\t\t\t},\n\n\t\t\t\treaddir: async (sandbox: SandboxInstance, path: string): Promise<FileEntry[]> => {\n\t\t\t\t\tconst result = await sandbox.fs.ls(path);\n\t\t\t\t\tconst files = result.files || [];\n\t\t\t\t\tconst directories = result.subdirectories || [];\n\t\t\t\t\tlet entries = [];\n\t\t\t\t\tfor (const file of files) {\n\t\t\t\t\t\tentries.push({\n\t\t\t\t\t\t\tname: file.name,\n\t\t\t\t\t\t\ttype: 'file' as const,\n\t\t\t\t\t\t\tsize: file.size || 0,\n\t\t\t\t\t\t\tmodified: new Date(file.lastModified || Date.now())\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t\tfor (const directory of directories) {\n\t\t\t\t\t\tentries.push({\n\t\t\t\t\t\t\tname: directory.name,\n\t\t\t\t\t\t\ttype: 'directory' as const,\n\t\t\t\t\t\t\tsize: 0,\n\t\t\t\t\t\t\tmodified: new Date()\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t\treturn entries;\n\t\t\t\t},\n\n\t\t\t\texists: async (sandbox: SandboxInstance, path: string): Promise<boolean> => {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tawait sandbox.fs.read(path);\n\t\t\t\t\t\treturn true; // It's a file and exists\n\t\t\t\t\t} catch {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tawait sandbox.fs.ls(path);\n\t\t\t\t\t\t\treturn true; // It's a directory and exists\n\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\treturn false; // Path doesn't exist\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t},\n\n\t\t\t\tremove: async (sandbox: SandboxInstance, path: string): Promise<void> => {\n\t\t\t\t\tawait sandbox.fs.rm(path);\n\t\t\t\t}\n\t\t\t},\n\n\t\t\t// Provider-specific typed getInstance method\n\t\t\tgetInstance: (sandbox: SandboxInstance): SandboxInstance => {\n\t\t\t\treturn sandbox;\n\t\t\t},\n\t\t}\n\t}\n});\n\nasync function handleBlaxelAuth(config: BlaxelConfig) {\n\t// Check if auth is already set in the SDK\n\ttry {\n\t\tawait settings.authenticate();\n\t} catch (error) {\n\t\t// If not, set the auth from the config\n\t\tif (config.workspace || process.env.BLAXEL_WORKSPACE && typeof process !== 'undefined') {\n\t\t\tprocess.env.BL_WORKSPACE = config.workspace || process.env.BLAXEL_WORKSPACE;\n\t\t}\n\t\tif (config.apiKey || process.env.BLAXEL_API_KEY && typeof process !== 'undefined') {\n\t\t\tprocess.env.BL_API_KEY = config.apiKey || process.env.BLAXEL_API_KEY;\n\t\t}\n\t\ttry {\n\t\t\tawait settings.authenticate();\n\t\t} catch (error) {\n\t\t\tthrow new Error('Blaxel authentication failed. Please check the following documents for more information: https://docs.blaxel.ai/Security/Access-tokens#using-api-keys');\n\t\t}\n\t}\n}\n\n/**\n * Parse TTL value from Blaxel's format to milliseconds\n * Supports formats like \"30m\", \"24h\", \"7d\" or plain numbers (seconds)\n */\nfunction parseTTLToMilliseconds(ttl: string | number | undefined): number {\n\tif (!ttl) return 300000; // Default to 5 minutes\n\n\t// If it's already a number, treat it as seconds and convert to milliseconds\n\tif (typeof ttl === 'number') {\n\t\treturn ttl * 1000;\n\t}\n\n\t// Parse string formats like \"30m\", \"24h\", \"7d\"\n\tconst match = ttl.match(/^(\\d+)([smhd])?$/);\n\tif (!match) return 300000; // Default if format is invalid\n\n\tconst value = parseInt(match[1], 10);\n\tconst unit = match[2] || 's'; // Default to seconds if no unit\n\n\tswitch (unit) {\n\t\tcase 's': return value * 1000; // seconds to ms\n\t\tcase 'm': return value * 60 * 1000; // minutes to ms\n\t\tcase 'h': return value * 60 * 60 * 1000; // hours to ms\n\t\tcase 'd': return value * 24 * 60 * 60 * 1000; // days to ms\n\t\tdefault: return 300000; // Default fallback\n\t}\n}\n\nfunction convertSandboxStatus(status: string | undefined): 'running' | 'stopped' | 'error' {\n\tswitch (status?.toLowerCase()) {\n\t\tcase 'deployed': return 'running';\n\t\tcase 'deleting': return 'stopped';\n\t\tcase 'failed': return 'error';\n\t\tdefault: return 'running';\n\t}\n}\n\n/**\n * Execute a command in the sandbox and capture stdout/stderr\n * Handles the common pattern of executing, streaming logs, and waiting for completion\n */\nasync function executeWithStreaming(\n\tsandbox: SandboxInstance,\n\tcommand: string\n): Promise<{ stdout: string; stderr: string; exitCode: number }> {\n\t// Execute the command\n\tconst result = await sandbox.process.exec({ command });\n\n\t// Wait for process completion\n\tawait sandbox.process.wait(result.name);\n\n\t// Get final process result for exit code\n\tconst processResult = await sandbox.process.get(result.name);\n\n\treturn {\n\t\tstdout: processResult.logs,\n\t\tstderr: processResult.logs,\n\t\texitCode: processResult.exitCode || 0\n\t};\n}\n\n// Export the Blaxel SandboxInstance type for explicit typing\nexport type { SandboxInstance as BlaxelSandbox } from '@blaxel/core';\n\n"],"mappings":"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","names":["error"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["/**\n * Blaxel Provider - Factory-based Implementation\n * \n * Full-featured provider with filesystem support using the factory pattern.\n */\n\nimport { SandboxInstance, settings } from '@blaxel/core';\nimport { defineProvider, escapeShellArg } from '@computesdk/provider';\n\nimport type { Runtime, CodeResult, CommandResult, SandboxInfo, CreateSandboxOptions, FileEntry, RunCommandOptions } from '@computesdk/provider';\n\n/**\n * Blaxel-specific configuration options\n */\nexport interface BlaxelConfig {\n\t/** Blaxel workspace ID - if not provided, will fallback to BL_WORKSPACE environment variable */\n\tworkspace?: string;\n\t/** Blaxel API key - if not provided, will fallback to BL_API_KEY environment variable */\n\tapiKey?: string;\n\t/** Default image for sandboxes */\n\timage?: string;\n\t/** Default region for sandbox deployment */\n\tregion?: string;\n\t/** Default memory allocation in MB */\n\tmemory?: number | 4096;\n\t/** Default ports for sandbox */\n\tports?: number[] | [3000];\n}\n\n/**\n * Create a Blaxel provider instance using the factory pattern\n */\nexport const blaxel = defineProvider<SandboxInstance, BlaxelConfig>({\n\tname: 'blaxel',\n\tmethods: {\n\t\tsandbox: {\n\t\t\t// Collection operations (map to compute.sandbox.*)\n\t\t\tcreate: async (config: BlaxelConfig, options?: CreateSandboxOptions) => {\n\t\t\t\tawait handleBlaxelAuth(config);\n\n\t\t\t\t// Determine the image to use\n\t\t\t\tlet image = config.image || 'blaxel/prod-base:latest'; // Default to prod-base\n\n\t\t\t\t// Override with runtime-specific image if runtime is specified and no explicit image\n\t\t\t\tif (!config.image && options?.runtime) {\n\t\t\t\t\tswitch (options.runtime) {\n\t\t\t\t\t\tcase 'python':\n\t\t\t\t\t\t\timage = 'blaxel/prod-py-app:latest';\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase 'node':\n\t\t\t\t\t\t\timage = 'blaxel/prod-ts-app:latest';\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tdefault:\n\t\t\t\t\t\t\timage = 'blaxel/prod-base:latest';\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tconst memory = config.memory;\n\t\t\t\tconst region = config.region;\n\t\t\t\tconst envs = options?.envs;\n\t\t\t\tconst ttl = options?.timeout ? `${Math.ceil(options.timeout / 1000)}s` : undefined;\n\n\t\t\t\ttry {\n\t\t\t\t\tlet sandbox: SandboxInstance;\n\n\t\t\t\t\t// Create new Blaxel sandbox\n\t\t\t\t\tsandbox = await SandboxInstance.createIfNotExists({\n\t\t\t\t\t\tname: options?.sandboxId || `blaxel-${Date.now()}`,\n\t\t\t\t\t\timage,\n\t\t\t\t\t\tmemory,\n\t\t\t\t\t\tenvs: Object.entries(envs || {}).map(([name, value]) => ({ name, value })),\n\t\t\t\t\t\tmetadata: {\n\t\t\t\t\t\t\tlabels: {\n\t\t\t\t\t\t\t\t...options?.metadata?.labels,\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t},\n\t\t\t\t\t\tttl,\n\t\t\t\t\t\tports: config.ports?.map(port => ({ target: port, protocol: 'HTTP' })),\n\t\t\t\t\t\t...(region && { region })\n\t\t\t\t\t});\n\n\t\t\t\t\treturn {\n\t\t\t\t\t\tsandbox,\n\t\t\t\t\t\tsandboxId: sandbox.metadata?.name || 'blaxel-unknown'\n\t\t\t\t\t};\n\t\t\t\t} catch (error) {\n\t\t\t\t\tif (error instanceof Error) {\n\t\t\t\t\t\tif (error.message.includes('unauthorized') || error.message.includes('API key')) {\n\t\t\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t\t\t`Blaxel authentication failed. Please check your BLAXEL_API_KEY environment variable.`\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (error.message.includes('quota') || error.message.includes('limit')) {\n\t\t\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t\t\t`Blaxel quota exceeded. Please check your usage limits.`\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t`Failed to create Blaxel sandbox: ${error instanceof Error ? error.message : String(error)}`\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t},\n\n\t\t\tgetById: async (config: BlaxelConfig, sandboxId: string) => {\n\t\t\t\tawait handleBlaxelAuth(config);\n\n\t\t\t\ttry {\n\t\t\t\t\tconst sandbox = await SandboxInstance.get(sandboxId);\n\n\t\t\t\t\tif (!sandbox) {\n\t\t\t\t\t\treturn null;\n\t\t\t\t\t}\n\n\t\t\t\t\treturn {\n\t\t\t\t\t\tsandbox,\n\t\t\t\t\t\tsandboxId\n\t\t\t\t\t};\n\t\t\t\t} catch (error) {\n\t\t\t\t\t// Sandbox doesn't exist or can't be accessed\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\t\t\t},\n\n\t\t\tlist: async (config: BlaxelConfig) => {\n\t\t\t\tawait handleBlaxelAuth(config);\n\n\t\t\t\tconst sandboxList = await SandboxInstance.list();\n\t\t\t\treturn sandboxList.map(sandbox => ({\n\t\t\t\t\tsandbox,\n\t\t\t\t\tsandboxId: sandbox.metadata?.name || 'blaxel-unknown'\n\t\t\t\t}));\n\t\t\t},\n\n\t\t\tdestroy: async (config: BlaxelConfig, sandboxId: string) => {\n\t\t\t\tawait handleBlaxelAuth(config);\n\n\t\t\t\ttry {\n\t\t\t\t\tawait SandboxInstance.delete(sandboxId);\n\t\t\t\t} catch (error) {\n\t\t\t\t\t// Sandbox might already be destroyed or doesn't exist\n\t\t\t\t\t// This is acceptable for destroy operations\n\t\t\t\t}\n\t\t\t},\n\n\t\t\t// Instance operations (map to individual Sandbox methods)\n\t\t\trunCode: async (sandbox: SandboxInstance, code: string, runtime?: Runtime): Promise<CodeResult> => {\n\t\t\t\tconst startTime = Date.now();\n\n\t\t\t\ttry {\n\t\t\t\t\t// Determine runtime: \n\t\t\t\t\t// 1. Use explicitly passed runtime if provided\n\t\t\t\t\t// 2. Check sandbox's actual runtime based on its image\n\t\t\t\t\t// 3. Fall back to auto-detection from code content\n\t\t\t\t\tlet effectiveRuntime = runtime;\n\n\t\t\t\t\tif (!effectiveRuntime) {\n\t\t\t\t\t\t// Check sandbox's image to determine its runtime\n\t\t\t\t\t\tconst sandboxImage = sandbox.spec?.runtime?.image || '';\n\t\t\t\t\t\tif (sandboxImage.includes('py')) {\n\t\t\t\t\t\t\teffectiveRuntime = 'python';\n\t\t\t\t\t\t} else if (sandboxImage.includes('ts') || sandboxImage.includes('node') || sandboxImage.includes('base')) {\n\t\t\t\t\t\t\t// prod-base, prod-ts-app are both Node/TypeScript environments\n\t\t\t\t\t\t\teffectiveRuntime = 'node';\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t// Fall back to auto-detection with improved patterns for unknown images\n\t\t\t\t\t\t\teffectiveRuntime = (\n\t\t\t\t\t\t\t\t// Strong Python indicators\n\t\t\t\t\t\t\t\tcode.includes('print(') ||\n\t\t\t\t\t\t\t\t\tcode.includes('import ') ||\n\t\t\t\t\t\t\t\t\tcode.includes('from ') ||\n\t\t\t\t\t\t\t\t\tcode.includes('def ') ||\n\t\t\t\t\t\t\t\t\tcode.includes('class ') ||\n\t\t\t\t\t\t\t\t\tcode.includes('raise ') ||\n\t\t\t\t\t\t\t\t\tcode.includes('except ') ||\n\t\t\t\t\t\t\t\t\tcode.includes('elif ') ||\n\t\t\t\t\t\t\t\t\tcode.includes('lambda ') ||\n\t\t\t\t\t\t\t\t\tcode.includes('True') ||\n\t\t\t\t\t\t\t\t\tcode.includes('False') ||\n\t\t\t\t\t\t\t\t\tcode.includes('None') ||\n\t\t\t\t\t\t\t\t\tcode.includes('sys.') ||\n\t\t\t\t\t\t\t\t\tcode.includes('json.') ||\n\t\t\t\t\t\t\t\t\tcode.includes('__') ||\n\t\t\t\t\t\t\t\t\tcode.includes('f\"') ||\n\t\t\t\t\t\t\t\t\tcode.includes(\"f'\") ||\n\t\t\t\t\t\t\t\t\tcode.includes('\"\"\"') ||\n\t\t\t\t\t\t\t\t\tcode.includes(\"'''\")\n\t\t\t\t\t\t\t\t\t? 'python'\n\t\t\t\t\t\t\t\t\t// Default to Node.js for all other cases (including ambiguous)\n\t\t\t\t\t\t\t\t\t: 'node'\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t// Execute code using Blaxel's process execution\n\t\t\t\t\t// Escape the code properly for shell execution\n\t\t\t\t\tconst escapedCode = code.replace(/\\\\/g, '\\\\\\\\').replace(/\"/g, '\\\\\"').replace(/\\$/g, '\\\\$').replace(/`/g, '\\\\`');\n\n\t\t\t\t\tconst command = effectiveRuntime === 'python'\n\t\t\t\t\t\t? `python3 -c \"${escapedCode}\"`\n\t\t\t\t\t\t: `node -e \"${escapedCode}\"`;\n\n\t\t\t\t\tconst { stdout, stderr, exitCode } = await executeWithStreaming(sandbox, command);\n\n\t\t\t\t\t// Check for syntax errors and throw them\n\t\t\t\t\tif (exitCode !== 0 && stderr) {\n\t\t\t\t\t\t// Check for common syntax error patterns\n\t\t\t\t\t\tif (stderr.includes('SyntaxError') ||\n\t\t\t\t\t\t\tstderr.includes('invalid syntax') ||\n\t\t\t\t\t\t\tstderr.includes('Unexpected token') ||\n\t\t\t\t\t\t\tstderr.includes('Unexpected identifier')) {\n\t\t\t\t\t\t\tthrow new Error(`Syntax error: ${stderr.trim()}`);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t// Combine stdout and stderr into output\n\t\t\t\t\tconst output = stderr ? `${stdout}\\n${stderr}`.trim() : stdout;\n\n\t\t\t\t\treturn {\n\t\t\t\t\t\toutput,\n\t\t\t\t\t\texitCode,\n\t\t\t\t\t\tlanguage: effectiveRuntime\n\t\t\t\t\t};\n\t\t\t\t} catch (error) {\n\t\t\t\t\t// Re-throw syntax errors\n\t\t\t\t\tif (error instanceof Error && error.message.includes('Syntax error')) {\n\t\t\t\t\t\tthrow error;\n\t\t\t\t\t}\n\n\t\t\t\t\t// For runtime errors, return a result instead of throwing\n\t\t\t\t\treturn {\n\t\t\t\t\t\toutput: error instanceof Error ? error.message : String(error),\n\t\t\t\t\t\texitCode: 1,\n\t\t\t\t\t\tlanguage: runtime || 'node'\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t},\n\n\t\trunCommand: async (sandbox: SandboxInstance, command: string, options?: RunCommandOptions): Promise<CommandResult> => {\n\t\t\tconst startTime = Date.now();\n\n\t\t\ttry {\n\t\t\t\t// Build command with options\n\t\t\t\tlet fullCommand = command;\n\t\t\t\t\n\t\t\t\t// Handle environment variables\n\t\t\t\tif (options?.env && Object.keys(options.env).length > 0) {\n\t\t\t\t\tconst envPrefix = Object.entries(options.env)\n\t\t\t\t\t\t.map(([k, v]) => `${k}=\"${escapeShellArg(v)}\"`)\n\t\t\t\t\t\t.join(' ');\n\t\t\t\t\tfullCommand = `${envPrefix} ${fullCommand}`;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t// Handle working directory\n\t\t\t\tif (options?.cwd) {\n\t\t\t\t\tfullCommand = `cd \"${escapeShellArg(options.cwd)}\" && ${fullCommand}`;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t// Handle background execution\n\t\t\t\tif (options?.background) {\n\t\t\t\t\tfullCommand = `nohup ${fullCommand} > /dev/null 2>&1 &`;\n\t\t\t\t}\n\n\t\t\t\tconst { stdout, stderr, exitCode } = await executeWithStreaming(sandbox, fullCommand);\n\n\t\t\t\treturn {\n\t\t\t\t\tstdout,\n\t\t\t\t\tstderr,\n\t\t\t\t\texitCode,\n\t\t\t\t\tdurationMs: Date.now() - startTime\n\t\t\t\t};\n\t\t\t} catch (error) {\n\t\t\t\treturn {\n\t\t\t\t\tstdout: '',\n\t\t\t\t\tstderr: error instanceof Error ? error.message : String(error),\n\t\t\t\t\texitCode: 127,\n\t\t\t\t\tdurationMs: Date.now() - startTime\n\t\t\t\t};\n\t\t\t}\n\t\t},\n\n\t\t\tgetInfo: async (sandbox: SandboxInstance): Promise<SandboxInfo> => {\n\t\t\t\treturn {\n\t\t\t\t\tid: sandbox.metadata?.name || 'blaxel-unknown',\n\t\t\t\t\tprovider: 'blaxel',\n\t\t\t\t\truntime: sandbox.spec?.runtime?.image?.includes('py') ? 'python' : 'node',\n\t\t\t\t\tstatus: convertSandboxStatus(sandbox.status),\n\t\t\t\t\tcreatedAt: sandbox.metadata?.createdAt ? new Date(sandbox.metadata.createdAt) : new Date(),\n\t\t\t\t\ttimeout: parseTTLToMilliseconds(sandbox.spec?.runtime?.ttl),\n\t\t\t\t\tmetadata: {\n\t\t\t\t\t\t...sandbox.metadata?.labels\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t\t},\n\n\t\t\tgetUrl: async (sandbox: SandboxInstance, options: {\n\t\t\t\tport: number;\n\t\t\t\tttl?: number;\n\t\t\t\tprefixUrl?: string;\n\t\t\t\theaders?: {\n\t\t\t\t\tresponse?: Record<string, string>;\n\t\t\t\t\trequest?: Record<string, string>;\n\t\t\t\t};\n\t\t\t\tcustomDomain?: string;\n\t\t\t\tauthentication?: {\n\t\t\t\t\tpublic?: boolean;\n\t\t\t\t\ttokenExpiryMinutes?: number;\n\t\t\t\t};\n\t\t\t}): Promise<string> => {\n\t\t\t\ttry {\n\t\t\t\t\t// If public is not set, default to true\n\t\t\t\t\tconst isPublic = options.authentication?.public !== undefined ? options.authentication.public : true;\n\n\t\t\t\t\t// Default CORS headers for broad compatibility\n\t\t\t\t\tconst defaultHeaders = {\n\t\t\t\t\t\t\"Access-Control-Allow-Origin\": \"*\",\n\t\t\t\t\t\t\"Access-Control-Allow-Methods\": \"GET, POST, PUT, DELETE, OPTIONS, PATCH\",\n\t\t\t\t\t\t\"Access-Control-Allow-Headers\": \"Content-Type, Authorization, X-Requested-With, X-Blaxel-Preview-Token, X-Blaxel-Authorization\",\n\t\t\t\t\t\t\"Access-Control-Allow-Credentials\": \"true\",\n\t\t\t\t\t\t\"Access-Control-Expose-Headers\": \"Content-Length, X-Request-Id\",\n\t\t\t\t\t\t\"Access-Control-Max-Age\": \"86400\",\n\t\t\t\t\t\t\"Vary\": \"Origin\"\n\t\t\t\t\t};\n\n\t\t\t\t\t// Use custom headers if provided, otherwise use defaults\n\t\t\t\t\tconst responseHeaders = options.headers?.response || defaultHeaders;\n\n\t\t\t\t\t// Create or get existing preview URL using Blaxel's preview API\n\t\t\t\t\tconst preview = await sandbox.previews.createIfNotExists({\n\t\t\t\t\t\tmetadata: {\n\t\t\t\t\t\t\tname: `preview-port-${options.port}-${isPublic ? 'public' : 'private'}`\n\t\t\t\t\t\t},\n\t\t\t\t\t\tspec: {\n\t\t\t\t\t\t\tport: options.port,\n\t\t\t\t\t\t\tpublic: isPublic,\n\t\t\t\t\t\t\tresponseHeaders,\n\t\t\t\t\t\t\trequestHeaders: options.headers?.request || defaultHeaders,\n\t\t\t\t\t\t\tcustomDomain: options.customDomain,\n\t\t\t\t\t\t\tprefixUrl: options.prefixUrl,\n\t\t\t\t\t\t\tttl: options.ttl ? `${Math.ceil(options.ttl / 1000)}s` : undefined\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\n\t\t\t\t\t// Get the preview URL\n\t\t\t\t\tconst url = preview.spec?.url;\n\t\t\t\t\tif (!url) {\n\t\t\t\t\t\tthrow new Error(`Failed to get preview URL for port ${options.port}`);\n\t\t\t\t\t}\n\n\t\t\t\t\t// For private previews, create an access token and append it to the URL\n\t\t\t\t\tif (!isPublic) {\n\t\t\t\t\t\t// Create token with specified expiry (default 60 minutes)\n\t\t\t\t\t\tconst expiryMinutes = options.authentication?.tokenExpiryMinutes || 60;\n\t\t\t\t\t\tconst expiresAt = new Date(Date.now() + expiryMinutes * 60 * 1000);\n\t\t\t\t\t\tconst token = await preview.tokens.create(expiresAt);\n\n\t\t\t\t\t\t// Return URL with token as query parameter\n\t\t\t\t\t\tconst separator = url.includes('?') ? '&' : '?';\n\t\t\t\t\t\treturn `${url}${separator}bl_preview_token=${token.value}`;\n\t\t\t\t\t}\n\n\t\t\t\t\t// For public previews, just return the URL\n\t\t\t\t\treturn url;\n\t\t\t\t} catch (error) {\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t`Failed to get Blaxel preview URL for port ${options.port}: ${error instanceof Error ? error.message : String(error)}`\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t},\n\n\t\t\t// Optional filesystem methods - implement using Blaxel's filesystem API\n\t\t\tfilesystem: {\n\t\t\t\treadFile: async (sandbox: SandboxInstance, path: string): Promise<string> => {\n\t\t\t\t\tconst result = await sandbox.fs.read(path);\n\t\t\t\t\treturn result || '';\n\t\t\t\t},\n\n\t\t\t\twriteFile: async (sandbox: SandboxInstance, path: string, content: string): Promise<void> => {\n\t\t\t\t\tawait sandbox.fs.write(path, content);\n\t\t\t\t},\n\n\t\t\t\tmkdir: async (sandbox: SandboxInstance, path: string): Promise<void> => {\n\t\t\t\t\tawait sandbox.fs.mkdir(path);\n\t\t\t\t},\n\n\t\t\t\treaddir: async (sandbox: SandboxInstance, path: string): Promise<FileEntry[]> => {\n\t\t\t\t\tconst result = await sandbox.fs.ls(path);\n\t\t\t\t\tconst files = result.files || [];\n\t\t\t\t\tconst directories = result.subdirectories || [];\n\t\t\t\t\tlet entries = [];\n\t\t\t\t\tfor (const file of files) {\n\t\t\t\t\t\tentries.push({\n\t\t\t\t\t\t\tname: file.name,\n\t\t\t\t\t\t\ttype: 'file' as const,\n\t\t\t\t\t\t\tsize: file.size || 0,\n\t\t\t\t\t\t\tmodified: new Date(file.lastModified || Date.now())\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t\tfor (const directory of directories) {\n\t\t\t\t\t\tentries.push({\n\t\t\t\t\t\t\tname: directory.name,\n\t\t\t\t\t\t\ttype: 'directory' as const,\n\t\t\t\t\t\t\tsize: 0,\n\t\t\t\t\t\t\tmodified: new Date()\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t\treturn entries;\n\t\t\t\t},\n\n\t\t\t\texists: async (sandbox: SandboxInstance, path: string): Promise<boolean> => {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tawait sandbox.fs.read(path);\n\t\t\t\t\t\treturn true; // It's a file and exists\n\t\t\t\t\t} catch {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tawait sandbox.fs.ls(path);\n\t\t\t\t\t\t\treturn true; // It's a directory and exists\n\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\treturn false; // Path doesn't exist\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t},\n\n\t\t\t\tremove: async (sandbox: SandboxInstance, path: string): Promise<void> => {\n\t\t\t\t\tawait sandbox.fs.rm(path);\n\t\t\t\t}\n\t\t\t},\n\n\t\t\t// Provider-specific typed getInstance method\n\t\t\tgetInstance: (sandbox: SandboxInstance): SandboxInstance => {\n\t\t\t\treturn sandbox;\n\t\t\t},\n\t\t}\n\t}\n});\n\nasync function handleBlaxelAuth(config: BlaxelConfig) {\n\t// Check if auth is already set in the SDK\n\ttry {\n\t\tawait settings.authenticate();\n\t} catch (error) {\n\t\t// If not, set the auth from the config\n\t\tif (config.workspace || process.env.BLAXEL_WORKSPACE && typeof process !== 'undefined') {\n\t\t\tprocess.env.BL_WORKSPACE = config.workspace || process.env.BLAXEL_WORKSPACE;\n\t\t}\n\t\tif (config.apiKey || process.env.BLAXEL_API_KEY && typeof process !== 'undefined') {\n\t\t\tprocess.env.BL_API_KEY = config.apiKey || process.env.BLAXEL_API_KEY;\n\t\t}\n\t\ttry {\n\t\t\tawait settings.authenticate();\n\t\t} catch (error) {\n\t\t\tthrow new Error('Blaxel authentication failed. Please check the following documents for more information: https://docs.blaxel.ai/Security/Access-tokens#using-api-keys');\n\t\t}\n\t}\n}\n\n/**\n * Parse TTL value from Blaxel's format to milliseconds\n * Supports formats like \"30m\", \"24h\", \"7d\" or plain numbers (seconds)\n */\nfunction parseTTLToMilliseconds(ttl: string | number | undefined): number {\n\tif (!ttl) return 300000; // Default to 5 minutes\n\n\t// If it's already a number, treat it as seconds and convert to milliseconds\n\tif (typeof ttl === 'number') {\n\t\treturn ttl * 1000;\n\t}\n\n\t// Parse string formats like \"30m\", \"24h\", \"7d\"\n\tconst match = ttl.match(/^(\\d+)([smhd])?$/);\n\tif (!match) return 300000; // Default if format is invalid\n\n\tconst value = parseInt(match[1], 10);\n\tconst unit = match[2] || 's'; // Default to seconds if no unit\n\n\tswitch (unit) {\n\t\tcase 's': return value * 1000; // seconds to ms\n\t\tcase 'm': return value * 60 * 1000; // minutes to ms\n\t\tcase 'h': return value * 60 * 60 * 1000; // hours to ms\n\t\tcase 'd': return value * 24 * 60 * 60 * 1000; // days to ms\n\t\tdefault: return 300000; // Default fallback\n\t}\n}\n\nfunction convertSandboxStatus(status: string | undefined): 'running' | 'stopped' | 'error' {\n\tswitch (status?.toLowerCase()) {\n\t\tcase 'deployed': return 'running';\n\t\tcase 'deleting': return 'stopped';\n\t\tcase 'failed': return 'error';\n\t\tdefault: return 'running';\n\t}\n}\n\n/**\n * Execute a command in the sandbox and capture stdout/stderr\n * Handles the common pattern of executing, streaming logs, and waiting for completion\n */\nasync function executeWithStreaming(\n\tsandbox: SandboxInstance,\n\tcommand: string\n): Promise<{ stdout: string; stderr: string; exitCode: number }> {\n\t// Execute the command\n\tconst result = await sandbox.process.exec({ command });\n\n\t// Wait for process completion\n\tawait sandbox.process.wait(result.name);\n\n\t// Get final process result for exit code\n\tconst processResult = await sandbox.process.get(result.name);\n\n\treturn {\n\t\tstdout: processResult.logs,\n\t\tstderr: processResult.logs,\n\t\texitCode: processResult.exitCode || 0\n\t};\n}\n\n// Export the Blaxel SandboxInstance type for explicit typing\nexport type { SandboxInstance as BlaxelSandbox } from '@blaxel/core';\n\n"],"mappings":"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","names":["error"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@computesdk/blaxel",
|
|
3
|
-
"version": "1.3.
|
|
3
|
+
"version": "1.3.9",
|
|
4
4
|
"description": "Blaxel provider for ComputeSDK - lightweight cloud sandboxes for code execution",
|
|
5
5
|
"author": "ComputeSDK",
|
|
6
6
|
"license": "MIT",
|
|
@@ -19,8 +19,8 @@
|
|
|
19
19
|
],
|
|
20
20
|
"dependencies": {
|
|
21
21
|
"@blaxel/core": "^0.2.42",
|
|
22
|
-
"@computesdk/provider": "1.0.
|
|
23
|
-
"computesdk": "1.10.
|
|
22
|
+
"@computesdk/provider": "1.0.3",
|
|
23
|
+
"computesdk": "1.10.2"
|
|
24
24
|
},
|
|
25
25
|
"keywords": [
|
|
26
26
|
"computesdk",
|
|
@@ -49,7 +49,7 @@
|
|
|
49
49
|
"tsup": "^8.0.0",
|
|
50
50
|
"typescript": "^5.0.0",
|
|
51
51
|
"vitest": "^1.0.0",
|
|
52
|
-
"@computesdk/test-utils": "1.5.
|
|
52
|
+
"@computesdk/test-utils": "1.5.1"
|
|
53
53
|
},
|
|
54
54
|
"scripts": {
|
|
55
55
|
"build": "tsup",
|