buildfunctions 0.0.3 → 0.0.5
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 +87 -1
- package/dist/client.d.ts +34 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +198 -0
- package/dist/client.js.map +1 -0
- package/dist/function/cpu-function.d.ts +19 -0
- package/dist/function/cpu-function.d.ts.map +1 -0
- package/dist/function/cpu-function.js +103 -0
- package/dist/function/cpu-function.js.map +1 -0
- package/dist/function/gpu-function.d.ts +13 -0
- package/dist/function/gpu-function.d.ts.map +1 -0
- package/dist/function/gpu-function.js +202 -0
- package/dist/function/gpu-function.js.map +1 -0
- package/dist/function/index.d.ts +8 -0
- package/dist/function/index.d.ts.map +1 -0
- package/dist/function/index.js +6 -0
- package/dist/function/index.js.map +1 -0
- package/dist/index.d.ts +45 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +55 -0
- package/dist/index.js.map +1 -0
- package/dist/sandbox/cpu-sandbox.d.ts +18 -0
- package/dist/sandbox/cpu-sandbox.d.ts.map +1 -0
- package/dist/sandbox/cpu-sandbox.js +293 -0
- package/dist/sandbox/cpu-sandbox.js.map +1 -0
- package/dist/sandbox/gpu-sandbox.d.ts +15 -0
- package/dist/sandbox/gpu-sandbox.d.ts.map +1 -0
- package/dist/sandbox/gpu-sandbox.js +359 -0
- package/dist/sandbox/gpu-sandbox.js.map +1 -0
- package/dist/sandbox/index.d.ts +6 -0
- package/dist/sandbox/index.d.ts.map +1 -0
- package/dist/sandbox/index.js +6 -0
- package/dist/sandbox/index.js.map +1 -0
- package/dist/types/index.d.ts +153 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +5 -0
- package/dist/types/index.js.map +1 -0
- package/dist/utils/errors.d.ts +27 -0
- package/dist/utils/errors.d.ts.map +1 -0
- package/dist/utils/errors.js +79 -0
- package/dist/utils/errors.js.map +1 -0
- package/dist/utils/framework.d.ts +6 -0
- package/dist/utils/framework.d.ts.map +1 -0
- package/dist/utils/framework.js +17 -0
- package/dist/utils/framework.js.map +1 -0
- package/dist/utils/http.d.ts +24 -0
- package/dist/utils/http.d.ts.map +1 -0
- package/dist/utils/http.js +75 -0
- package/dist/utils/http.js.map +1 -0
- package/dist/utils/index.d.ts +8 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +8 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/memory.d.ts +6 -0
- package/dist/utils/memory.d.ts.map +1 -0
- package/dist/utils/memory.js +21 -0
- package/dist/utils/memory.js.map +1 -0
- package/dist/utils/uploader.d.ts +41 -0
- package/dist/utils/uploader.d.ts.map +1 -0
- package/dist/utils/uploader.js +157 -0
- package/dist/utils/uploader.js.map +1 -0
- package/package.json +27 -17
- package/dist/cli.d.ts +0 -3
- package/dist/cli.d.ts.map +0 -1
- package/dist/cli.js +0 -18
- package/dist/cli.js.map +0 -1
- package/dist/test.d.ts +0 -10
- package/dist/test.d.ts.map +0 -1
- package/dist/test.js +0 -7
- package/dist/test.js.map +0 -1
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GPU Function - Deploy GPU-accelerated serverless functions to Buildfunctions
|
|
3
|
+
*/
|
|
4
|
+
import https from 'https';
|
|
5
|
+
import { ValidationError } from '../utils/errors.js';
|
|
6
|
+
import { parseMemory } from '../utils/memory.js';
|
|
7
|
+
import { detectFramework } from '../utils/framework.js';
|
|
8
|
+
const DEFAULT_GPU_BUILD_URL = 'https://prod-gpu-build.buildfunctions.link';
|
|
9
|
+
function getFileExtension(language) {
|
|
10
|
+
const extensions = {
|
|
11
|
+
javascript: '.js',
|
|
12
|
+
typescript: '.ts',
|
|
13
|
+
python: '.py',
|
|
14
|
+
go: '.go',
|
|
15
|
+
shell: '.sh',
|
|
16
|
+
};
|
|
17
|
+
return extensions[language] ?? '.js';
|
|
18
|
+
}
|
|
19
|
+
function getDefaultRuntime(language) {
|
|
20
|
+
// JavaScript requires explicit runtime (node.js or deno)
|
|
21
|
+
if (language === 'javascript') {
|
|
22
|
+
throw new ValidationError('JavaScript requires explicit runtime: "nodejs" or "deno"');
|
|
23
|
+
}
|
|
24
|
+
// All other languages have single runtime = language name
|
|
25
|
+
return language;
|
|
26
|
+
}
|
|
27
|
+
function validateOptions(options) {
|
|
28
|
+
if (!options.name || typeof options.name !== 'string') {
|
|
29
|
+
throw new ValidationError('Function name is required');
|
|
30
|
+
}
|
|
31
|
+
if (!/^[a-z0-9-]+$/.test(options.name.toLowerCase())) {
|
|
32
|
+
throw new ValidationError('Function name can only contain lowercase letters, numbers, and hyphens');
|
|
33
|
+
}
|
|
34
|
+
if (!options.code || typeof options.code !== 'string') {
|
|
35
|
+
throw new ValidationError('Function code is required');
|
|
36
|
+
}
|
|
37
|
+
if (!options.language) {
|
|
38
|
+
throw new ValidationError('Language is required');
|
|
39
|
+
}
|
|
40
|
+
// GPU Functions only support Python currently
|
|
41
|
+
if (options.language !== 'python') {
|
|
42
|
+
throw new ValidationError('GPU Functions currently only support Python. Additional languages coming soon.');
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
function buildRequestBody(options) {
|
|
46
|
+
const { name, language, code, config, envVariables, dependencies, cronSchedule, framework, } = options;
|
|
47
|
+
// Auto-infer runtime from language (server handles runtimeVersion)
|
|
48
|
+
const runtime = options.runtime ?? getDefaultRuntime(language);
|
|
49
|
+
// Default GPU to T4G
|
|
50
|
+
const gpu = options.gpu ?? 'T4G';
|
|
51
|
+
const fileExt = getFileExtension(language);
|
|
52
|
+
const functionName = name.toLowerCase();
|
|
53
|
+
return {
|
|
54
|
+
name: functionName,
|
|
55
|
+
language,
|
|
56
|
+
runtime,
|
|
57
|
+
sourceWith: code, // source with env vars
|
|
58
|
+
sourceWithout: code,
|
|
59
|
+
fileExt,
|
|
60
|
+
processorType: 'GPU',
|
|
61
|
+
gpu,
|
|
62
|
+
memoryAllocated: config?.memory ? parseMemory(config.memory) : 4096,
|
|
63
|
+
timeout: config?.timeout ?? 180,
|
|
64
|
+
cpuCores: config?.cpuCores ?? 2,
|
|
65
|
+
envVariables: envVariables ? JSON.stringify(Object.entries(envVariables).map(([key, value]) => ({ key, value }))) : '[]',
|
|
66
|
+
requirements: dependencies ?? '',
|
|
67
|
+
cronExpression: cronSchedule ?? '',
|
|
68
|
+
totalVariables: envVariables ? Object.keys(envVariables).length : 0,
|
|
69
|
+
selectedFramework: framework ?? detectFramework(dependencies),
|
|
70
|
+
// GPU Function requires these fields
|
|
71
|
+
useEmptyFolder: true,
|
|
72
|
+
selectedFunction: {
|
|
73
|
+
name: functionName,
|
|
74
|
+
sourceWith: code,
|
|
75
|
+
runtime,
|
|
76
|
+
language,
|
|
77
|
+
sizeInBytes: new TextEncoder().encode(code).length,
|
|
78
|
+
},
|
|
79
|
+
selectedModel: {
|
|
80
|
+
currentModelName: null,
|
|
81
|
+
isCreatingNewModel: true,
|
|
82
|
+
gpufProjectTitleState: 'test', // todo: need to update
|
|
83
|
+
useEmptyFolder: true,
|
|
84
|
+
},
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
function createGPUFunctionBuilder(options, _apiKey, gpuBuildUrl, userId, username, computeTier) {
|
|
88
|
+
validateOptions(options);
|
|
89
|
+
const resolvedGpuBuildUrl = gpuBuildUrl ?? DEFAULT_GPU_BUILD_URL;
|
|
90
|
+
const deploy = async () => {
|
|
91
|
+
// Compute runtime for use in resolved function
|
|
92
|
+
const resolvedRuntime = options.runtime ?? getDefaultRuntime(options.language);
|
|
93
|
+
const body = {
|
|
94
|
+
...buildRequestBody(options),
|
|
95
|
+
userId,
|
|
96
|
+
username,
|
|
97
|
+
computeTier,
|
|
98
|
+
runCommand: null,
|
|
99
|
+
};
|
|
100
|
+
const buildUrl = `${resolvedGpuBuildUrl}/build`;
|
|
101
|
+
const postData = JSON.stringify(body);
|
|
102
|
+
const url = new URL(buildUrl);
|
|
103
|
+
return new Promise((resolve, reject) => {
|
|
104
|
+
const req = https.request({
|
|
105
|
+
hostname: url.hostname,
|
|
106
|
+
port: url.port || 443,
|
|
107
|
+
path: url.pathname,
|
|
108
|
+
method: 'POST',
|
|
109
|
+
headers: {
|
|
110
|
+
'Content-Type': 'application/json',
|
|
111
|
+
'Content-Length': Buffer.byteLength(postData),
|
|
112
|
+
'Connection': 'keep-alive',
|
|
113
|
+
},
|
|
114
|
+
timeout: 30 * 60 * 1000, // 30 minutes total timeout
|
|
115
|
+
}, (res) => {
|
|
116
|
+
let responseText = '';
|
|
117
|
+
res.on('data', (chunk) => {
|
|
118
|
+
responseText += chunk.toString();
|
|
119
|
+
});
|
|
120
|
+
res.on('end', () => {
|
|
121
|
+
// Parse the response
|
|
122
|
+
let data;
|
|
123
|
+
try {
|
|
124
|
+
data = JSON.parse(responseText);
|
|
125
|
+
}
|
|
126
|
+
catch {
|
|
127
|
+
data = { success: res.statusCode === 201 };
|
|
128
|
+
}
|
|
129
|
+
// Storage server returns 201 on success
|
|
130
|
+
if (res.statusCode !== 201 && res.statusCode !== 200) {
|
|
131
|
+
resolve(null);
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
const siteId = data.data?.siteId || data.siteId || data.id;
|
|
135
|
+
const funcName = options.name.toLowerCase();
|
|
136
|
+
const endpoint = data.endpoint || `https://${funcName}.buildfunctions.app`;
|
|
137
|
+
resolve({
|
|
138
|
+
id: siteId,
|
|
139
|
+
name: funcName,
|
|
140
|
+
subdomain: funcName,
|
|
141
|
+
endpoint,
|
|
142
|
+
lambdaUrl: data.data?.sslCertificateEndpoint || '',
|
|
143
|
+
language: options.language,
|
|
144
|
+
runtime: resolvedRuntime,
|
|
145
|
+
lambdaMemoryAllocated: options.config?.memory ? parseMemory(options.config.memory) : 4096,
|
|
146
|
+
timeoutSeconds: options.config?.timeout ?? 180,
|
|
147
|
+
isGPUF: true,
|
|
148
|
+
framework: options.framework,
|
|
149
|
+
createdAt: new Date().toISOString(),
|
|
150
|
+
updatedAt: new Date().toISOString(),
|
|
151
|
+
delete: async () => {
|
|
152
|
+
await fetch(`${resolvedGpuBuildUrl}/delete`, {
|
|
153
|
+
method: 'POST',
|
|
154
|
+
headers: { 'Content-Type': 'application/json' },
|
|
155
|
+
body: JSON.stringify({ siteId, userId, username }),
|
|
156
|
+
});
|
|
157
|
+
},
|
|
158
|
+
});
|
|
159
|
+
});
|
|
160
|
+
res.on('error', (error) => {
|
|
161
|
+
reject(error);
|
|
162
|
+
});
|
|
163
|
+
});
|
|
164
|
+
// Set socket timeout separately (for connection establishment)
|
|
165
|
+
req.on('socket', (socket) => {
|
|
166
|
+
socket.setTimeout(30 * 60 * 1000); // 30 minutes
|
|
167
|
+
socket.on('timeout', () => {
|
|
168
|
+
req.destroy(new Error('Socket timeout'));
|
|
169
|
+
});
|
|
170
|
+
});
|
|
171
|
+
req.on('timeout', () => {
|
|
172
|
+
req.destroy(new Error('Request timeout'));
|
|
173
|
+
});
|
|
174
|
+
req.on('error', (error) => {
|
|
175
|
+
reject(error);
|
|
176
|
+
});
|
|
177
|
+
// Send the request body
|
|
178
|
+
req.write(postData);
|
|
179
|
+
req.end();
|
|
180
|
+
});
|
|
181
|
+
};
|
|
182
|
+
return { deploy };
|
|
183
|
+
}
|
|
184
|
+
let globalApiKey = null;
|
|
185
|
+
let globalGpuBuildUrl;
|
|
186
|
+
let globalUserId;
|
|
187
|
+
let globalUsername;
|
|
188
|
+
let globalComputeTier;
|
|
189
|
+
export function setGpuApiKey(apiKey, gpuBuildUrl, userId, username, computeTier) {
|
|
190
|
+
globalApiKey = apiKey;
|
|
191
|
+
globalGpuBuildUrl = gpuBuildUrl;
|
|
192
|
+
globalUserId = userId;
|
|
193
|
+
globalUsername = username;
|
|
194
|
+
globalComputeTier = computeTier;
|
|
195
|
+
}
|
|
196
|
+
export function GPUFunction(options) {
|
|
197
|
+
if (!globalApiKey) {
|
|
198
|
+
throw new ValidationError('API key not set. Initialize Buildfunctions client first.');
|
|
199
|
+
}
|
|
200
|
+
return createGPUFunctionBuilder(options, globalApiKey, globalGpuBuildUrl, globalUserId, globalUsername, globalComputeTier);
|
|
201
|
+
}
|
|
202
|
+
//# sourceMappingURL=gpu-function.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gpu-function.js","sourceRoot":"","sources":["../../src/function/gpu-function.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Function exports
|
|
3
|
+
*/
|
|
4
|
+
export { CPUFunction, setApiKey } from './cpu-function.js';
|
|
5
|
+
export type { CPUFunctionBuilder } from './cpu-function.js';
|
|
6
|
+
export { GPUFunction, setGpuApiKey } from './gpu-function.js';
|
|
7
|
+
export type { GPUFunctionBuilder } from './gpu-function.js';
|
|
8
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/function/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAC3D,YAAY,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAC5D,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAC9D,YAAY,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/function/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAE3D,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Buildfunctions SDK
|
|
3
|
+
*
|
|
4
|
+
* A TypeScript SDK for Buildfunctions - the serverless platform for AI agents.
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* ```typescript
|
|
8
|
+
* import { Buildfunctions, CPUSandbox, GPUSandbox, GPUFunction } from 'buildfunctions';
|
|
9
|
+
*
|
|
10
|
+
* // Initialize the client (authenticates with the API)
|
|
11
|
+
* const buildfunctions = await Buildfunctions({
|
|
12
|
+
* apiKey: process.env.BUILDFUNCTIONS_API_KEY
|
|
13
|
+
* });
|
|
14
|
+
*
|
|
15
|
+
* // Access authenticated user info
|
|
16
|
+
* console.log(buildfunctions.user);
|
|
17
|
+
* console.log(buildfunctions.authenticatedAt);
|
|
18
|
+
*
|
|
19
|
+
* // Create a CPU sandbox
|
|
20
|
+
* const sandbox = await CPUSandbox.create({
|
|
21
|
+
* name: 'my-sandbox',
|
|
22
|
+
* language: 'python',
|
|
23
|
+
* memory: '512MB'
|
|
24
|
+
* });
|
|
25
|
+
*
|
|
26
|
+
* // Run code
|
|
27
|
+
* const result = await sandbox.run('print("Hello from Buildfunctions!")');
|
|
28
|
+
* console.log(result.stdout);
|
|
29
|
+
*
|
|
30
|
+
* // Clean up
|
|
31
|
+
* await sandbox.delete();
|
|
32
|
+
* ```
|
|
33
|
+
*/
|
|
34
|
+
export { CPUFunction } from './function/cpu-function.js';
|
|
35
|
+
export type { CPUFunctionBuilder } from './function/cpu-function.js';
|
|
36
|
+
export { GPUFunction } from './function/gpu-function.js';
|
|
37
|
+
export type { GPUFunctionBuilder } from './function/gpu-function.js';
|
|
38
|
+
export { CPUSandbox } from './sandbox/cpu-sandbox.js';
|
|
39
|
+
export { GPUSandbox } from './sandbox/gpu-sandbox.js';
|
|
40
|
+
export type { BuildfunctionsConfig, AuthenticatedUser, AuthResponse, Language, Runtime, GPUType, Framework, Memory, FunctionConfig, CPUFunctionOptions, GPUFunctionOptions, CreateFunctionOptions, DeployedFunction, CPUSandboxConfig, GPUSandboxConfig, RunResult, UploadOptions, SandboxInstance, CPUSandboxInstance, GPUSandboxInstance, FindUniqueOptions, ListOptions, ErrorCode, } from './types/index.js';
|
|
41
|
+
export { BuildfunctionsError, AuthenticationError, NotFoundError, ValidationError, CapacityError, } from './utils/errors.js';
|
|
42
|
+
export { Buildfunctions, createClient } from './client.js';
|
|
43
|
+
export type { BuildfunctionsClient, FunctionsManager } from './client.js';
|
|
44
|
+
export declare function init(apiKey: string, baseUrl?: string, gpuBuildUrl?: string, userId?: string, username?: string, computeTier?: string): void;
|
|
45
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AAGH,OAAO,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAC;AACzD,YAAY,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AACrE,OAAO,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAC;AACzD,YAAY,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AAGrE,OAAO,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AACtD,OAAO,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAGtD,YAAY,EACV,oBAAoB,EACpB,iBAAiB,EACjB,YAAY,EACZ,QAAQ,EACR,OAAO,EACP,OAAO,EACP,SAAS,EACT,MAAM,EACN,cAAc,EACd,kBAAkB,EAClB,kBAAkB,EAClB,qBAAqB,EACrB,gBAAgB,EAChB,gBAAgB,EAChB,gBAAgB,EAChB,SAAS,EACT,aAAa,EACb,eAAe,EACf,kBAAkB,EAClB,kBAAkB,EAClB,iBAAiB,EACjB,WAAW,EACX,SAAS,GACV,MAAM,kBAAkB,CAAC;AAG1B,OAAO,EACL,mBAAmB,EACnB,mBAAmB,EACnB,aAAa,EACb,eAAe,EACf,aAAa,GACd,MAAM,mBAAmB,CAAC;AAG3B,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3D,YAAY,EAAE,oBAAoB,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAQ1E,wBAAgB,IAAI,CAClB,MAAM,EAAE,MAAM,EACd,OAAO,CAAC,EAAE,MAAM,EAChB,WAAW,CAAC,EAAE,MAAM,EACpB,MAAM,CAAC,EAAE,MAAM,EACf,QAAQ,CAAC,EAAE,MAAM,EACjB,WAAW,CAAC,EAAE,MAAM,GACnB,IAAI,CAKN"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Buildfunctions SDK
|
|
3
|
+
*
|
|
4
|
+
* A TypeScript SDK for Buildfunctions - the serverless platform for AI agents.
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* ```typescript
|
|
8
|
+
* import { Buildfunctions, CPUSandbox, GPUSandbox, GPUFunction } from 'buildfunctions';
|
|
9
|
+
*
|
|
10
|
+
* // Initialize the client (authenticates with the API)
|
|
11
|
+
* const buildfunctions = await Buildfunctions({
|
|
12
|
+
* apiKey: process.env.BUILDFUNCTIONS_API_KEY
|
|
13
|
+
* });
|
|
14
|
+
*
|
|
15
|
+
* // Access authenticated user info
|
|
16
|
+
* console.log(buildfunctions.user);
|
|
17
|
+
* console.log(buildfunctions.authenticatedAt);
|
|
18
|
+
*
|
|
19
|
+
* // Create a CPU sandbox
|
|
20
|
+
* const sandbox = await CPUSandbox.create({
|
|
21
|
+
* name: 'my-sandbox',
|
|
22
|
+
* language: 'python',
|
|
23
|
+
* memory: '512MB'
|
|
24
|
+
* });
|
|
25
|
+
*
|
|
26
|
+
* // Run code
|
|
27
|
+
* const result = await sandbox.run('print("Hello from Buildfunctions!")');
|
|
28
|
+
* console.log(result.stdout);
|
|
29
|
+
*
|
|
30
|
+
* // Clean up
|
|
31
|
+
* await sandbox.delete();
|
|
32
|
+
* ```
|
|
33
|
+
*/
|
|
34
|
+
// Re-export functions
|
|
35
|
+
export { CPUFunction } from './function/cpu-function.js';
|
|
36
|
+
export { GPUFunction } from './function/gpu-function.js';
|
|
37
|
+
// Re-export sandboxes
|
|
38
|
+
export { CPUSandbox } from './sandbox/cpu-sandbox.js';
|
|
39
|
+
export { GPUSandbox } from './sandbox/gpu-sandbox.js';
|
|
40
|
+
// Re-export errors
|
|
41
|
+
export { BuildfunctionsError, AuthenticationError, NotFoundError, ValidationError, CapacityError, } from './utils/errors.js';
|
|
42
|
+
// Re-export client
|
|
43
|
+
export { Buildfunctions, createClient } from './client.js';
|
|
44
|
+
// Import internal setters for initialization
|
|
45
|
+
import { setApiKey } from './function/cpu-function.js';
|
|
46
|
+
import { setGpuApiKey } from './function/gpu-function.js';
|
|
47
|
+
import { setCpuSandboxApiKey } from './sandbox/cpu-sandbox.js';
|
|
48
|
+
import { setGpuSandboxApiKey } from './sandbox/gpu-sandbox.js';
|
|
49
|
+
export function init(apiKey, baseUrl, gpuBuildUrl, userId, username, computeTier) {
|
|
50
|
+
setApiKey(apiKey, baseUrl);
|
|
51
|
+
setGpuApiKey(apiKey, gpuBuildUrl, userId, username, computeTier);
|
|
52
|
+
setCpuSandboxApiKey(apiKey, baseUrl);
|
|
53
|
+
setGpuSandboxApiKey(apiKey, gpuBuildUrl, userId, username, computeTier, baseUrl);
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AAEH,sBAAsB;AACtB,OAAO,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAC;AAEzD,OAAO,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAC;AAGzD,sBAAsB;AACtB,OAAO,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AACtD,OAAO,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AA6BtD,mBAAmB;AACnB,OAAO,EACL,mBAAmB,EACnB,mBAAmB,EACnB,aAAa,EACb,eAAe,EACf,aAAa,GACd,MAAM,mBAAmB,CAAC;AAE3B,mBAAmB;AACnB,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAG3D,6CAA6C;AAC7C,OAAO,EAAE,SAAS,EAAE,MAAM,4BAA4B,CAAC;AACvD,OAAO,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAC1D,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAC/D,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAE/D,MAAM,UAAU,IAAI,CAClB,MAAc,EACd,OAAgB,EAChB,WAAoB,EACpB,MAAe,EACf,QAAiB,EACjB,WAAoB;IAEpB,SAAS,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC3B,YAAY,CAAC,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,QAAQ,EAAE,WAAW,CAAC,CAAC;IACjE,mBAAmB,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACrC,mBAAmB,CAAC,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,QAAQ,EAAE,WAAW,EAAE,OAAO,CAAC,CAAC;AACnF,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CPU Sandbox - Hardware-isolated execution environment for untrusted AI actions
|
|
3
|
+
*/
|
|
4
|
+
import type { CPUSandboxConfig, CPUSandboxInstance } from '../types/index.js';
|
|
5
|
+
/**
|
|
6
|
+
* Set the API key for sandbox operations
|
|
7
|
+
*/
|
|
8
|
+
export declare function setCpuSandboxApiKey(apiKey: string, baseUrl?: string): void;
|
|
9
|
+
/**
|
|
10
|
+
* CPU Sandbox factory
|
|
11
|
+
*/
|
|
12
|
+
export declare const CPUSandbox: {
|
|
13
|
+
/**
|
|
14
|
+
* Create a new CPU sandbox
|
|
15
|
+
*/
|
|
16
|
+
create: (config: CPUSandboxConfig) => Promise<CPUSandboxInstance>;
|
|
17
|
+
};
|
|
18
|
+
//# sourceMappingURL=cpu-sandbox.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cpu-sandbox.d.ts","sourceRoot":"","sources":["../../src/sandbox/cpu-sandbox.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAE,kBAAkB,EAA4B,MAAM,mBAAmB,CAAC;AA0GxG;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAG1E;AAsJD;;GAEG;AACH,eAAO,MAAM,UAAU;IACrB;;OAEG;qBACoB,gBAAgB,KAAG,OAAO,CAAC,kBAAkB,CAAC;CAuEtE,CAAC"}
|
|
@@ -0,0 +1,293 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CPU Sandbox - Hardware-isolated execution environment for untrusted AI actions
|
|
3
|
+
*/
|
|
4
|
+
import { ValidationError, BuildfunctionsError } from '../utils/errors.js';
|
|
5
|
+
import { parseMemory } from '../utils/memory.js';
|
|
6
|
+
import { readFile } from 'fs/promises';
|
|
7
|
+
import { existsSync } from 'fs';
|
|
8
|
+
import dns from 'dns';
|
|
9
|
+
import https from 'https';
|
|
10
|
+
const DEFAULT_BASE_URL = 'https://www.buildfunctions.com';
|
|
11
|
+
// AWS Route53 authoritative nameservers for buildfunctions.app
|
|
12
|
+
// These have the DNS records IMMEDIATELY - no propagation delay
|
|
13
|
+
const awsNameservers = [
|
|
14
|
+
'205.251.193.143', // ns-399.awsdns-49.com
|
|
15
|
+
'205.251.198.254', // ns-1278.awsdns-31.org
|
|
16
|
+
'205.251.195.249', // ns-1017.awsdns-63.net
|
|
17
|
+
'205.251.198.95', // ns-1631.awsdns-11.co.uk
|
|
18
|
+
];
|
|
19
|
+
// DNS resolver using AWS Route53 authoritative nameservers
|
|
20
|
+
const awsResolver = new dns.Resolver();
|
|
21
|
+
awsResolver.setServers(awsNameservers);
|
|
22
|
+
/**
|
|
23
|
+
* Resolve hostname using AWS Route53 authoritative nameservers
|
|
24
|
+
*/
|
|
25
|
+
function resolveWithAWS(hostname) {
|
|
26
|
+
return new Promise((resolve, reject) => {
|
|
27
|
+
awsResolver.resolve4(hostname, (err, addresses) => {
|
|
28
|
+
if (err || !addresses || addresses.length === 0) {
|
|
29
|
+
reject(err || new Error('No addresses'));
|
|
30
|
+
}
|
|
31
|
+
else {
|
|
32
|
+
resolve(addresses[0]);
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* HTTPS GET using resolved IP (bypasses system DNS entirely)
|
|
39
|
+
*/
|
|
40
|
+
function httpsGetWithIP(ip, hostname, path) {
|
|
41
|
+
return new Promise((resolve, reject) => {
|
|
42
|
+
const req = https.request({
|
|
43
|
+
hostname: ip,
|
|
44
|
+
port: 443,
|
|
45
|
+
path: path,
|
|
46
|
+
method: 'GET',
|
|
47
|
+
headers: { 'Host': hostname },
|
|
48
|
+
servername: hostname, // SNI for TLS
|
|
49
|
+
timeout: 10000,
|
|
50
|
+
}, (res) => {
|
|
51
|
+
let body = '';
|
|
52
|
+
res.on('data', chunk => body += chunk);
|
|
53
|
+
res.on('end', () => resolve({ status: res.statusCode || 0, body }));
|
|
54
|
+
});
|
|
55
|
+
req.on('error', reject);
|
|
56
|
+
req.on('timeout', () => { req.destroy(); reject(new Error('timeout')); });
|
|
57
|
+
req.end();
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Wait for endpoint using AWS Route53 authoritative DNS
|
|
62
|
+
*/
|
|
63
|
+
async function waitForEndpoint(endpoint, maxAttempts = 60, delayMs = 500) {
|
|
64
|
+
const url = new URL(endpoint);
|
|
65
|
+
const hostname = url.hostname;
|
|
66
|
+
const path = url.pathname + url.search || '/';
|
|
67
|
+
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
68
|
+
try {
|
|
69
|
+
// Step 1: Resolve via AWS Route53 authoritative nameservers (immediate, no propagation)
|
|
70
|
+
const ip = await resolveWithAWS(hostname);
|
|
71
|
+
// Step 2: Connect directly to IP with proper Host/SNI headers
|
|
72
|
+
const res = await httpsGetWithIP(ip, hostname, path);
|
|
73
|
+
if (res.status >= 200 && res.status < 500)
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
catch (err) {
|
|
77
|
+
const error = err;
|
|
78
|
+
if (attempt === 1 || attempt % 10 === 0) {
|
|
79
|
+
console.log(` Waiting for endpoint... (attempt ${attempt}/${maxAttempts}) ${error.code || error.message}`);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
await new Promise(r => setTimeout(r, delayMs));
|
|
83
|
+
}
|
|
84
|
+
throw new BuildfunctionsError(`Endpoint not ready after ${maxAttempts} attempts`, 'NETWORK_ERROR');
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Fetch endpoint using AWS Route53 authoritative DNS
|
|
88
|
+
*/
|
|
89
|
+
async function fetchWithAuthDNS(endpoint) {
|
|
90
|
+
const url = new URL(endpoint);
|
|
91
|
+
const hostname = url.hostname;
|
|
92
|
+
const path = url.pathname + url.search || '/';
|
|
93
|
+
const ip = await resolveWithAWS(hostname);
|
|
94
|
+
return httpsGetWithIP(ip, hostname, path);
|
|
95
|
+
}
|
|
96
|
+
// Global configuration
|
|
97
|
+
let globalApiKey = null;
|
|
98
|
+
let globalBaseUrl;
|
|
99
|
+
/**
|
|
100
|
+
* Set the API key for sandbox operations
|
|
101
|
+
*/
|
|
102
|
+
export function setCpuSandboxApiKey(apiKey, baseUrl) {
|
|
103
|
+
globalApiKey = apiKey;
|
|
104
|
+
globalBaseUrl = baseUrl;
|
|
105
|
+
}
|
|
106
|
+
function validateConfig(config) {
|
|
107
|
+
if (!config.name || typeof config.name !== 'string') {
|
|
108
|
+
throw new ValidationError('Sandbox name is required');
|
|
109
|
+
}
|
|
110
|
+
if (!config.language || typeof config.language !== 'string') {
|
|
111
|
+
throw new ValidationError('Language is required');
|
|
112
|
+
}
|
|
113
|
+
// JavaScript requires explicit runtime (node or deno)
|
|
114
|
+
if (config.language === 'javascript' && !config.runtime) {
|
|
115
|
+
throw new ValidationError('JavaScript requires explicit runtime: "node" or "deno"');
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Create a CPU sandbox instance
|
|
120
|
+
*/
|
|
121
|
+
function createCPUSandboxInstance(id, name, runtime, endpoint, apiKey, baseUrl) {
|
|
122
|
+
let deleted = false;
|
|
123
|
+
const run = async () => {
|
|
124
|
+
if (deleted) {
|
|
125
|
+
throw new BuildfunctionsError('Sandbox has been deleted', 'INVALID_REQUEST');
|
|
126
|
+
}
|
|
127
|
+
// Wait for endpoint to be ready
|
|
128
|
+
await waitForEndpoint(endpoint);
|
|
129
|
+
// Call the sandbox endpoint using authoritative DNS
|
|
130
|
+
const response = await fetchWithAuthDNS(endpoint);
|
|
131
|
+
const responseText = response.body;
|
|
132
|
+
if (!responseText) {
|
|
133
|
+
throw new BuildfunctionsError('Empty response from sandbox', 'UNKNOWN_ERROR', response.status);
|
|
134
|
+
}
|
|
135
|
+
let data;
|
|
136
|
+
try {
|
|
137
|
+
data = JSON.parse(responseText);
|
|
138
|
+
}
|
|
139
|
+
catch {
|
|
140
|
+
// Response is plain text
|
|
141
|
+
return {
|
|
142
|
+
stdout: responseText,
|
|
143
|
+
stderr: '',
|
|
144
|
+
text: responseText,
|
|
145
|
+
results: null,
|
|
146
|
+
exit_code: 0,
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
if (response.status < 200 || response.status >= 300) {
|
|
150
|
+
const errorData = data;
|
|
151
|
+
throw new BuildfunctionsError(`Execution failed: ${errorData.error || 'Unknown error'}`, 'UNKNOWN_ERROR', response.status);
|
|
152
|
+
}
|
|
153
|
+
// Response is already the unwrapped result from the handler
|
|
154
|
+
return {
|
|
155
|
+
stdout: responseText,
|
|
156
|
+
stderr: '',
|
|
157
|
+
text: responseText,
|
|
158
|
+
results: data,
|
|
159
|
+
exit_code: 0,
|
|
160
|
+
};
|
|
161
|
+
};
|
|
162
|
+
const upload = async (options) => {
|
|
163
|
+
if (deleted) {
|
|
164
|
+
throw new BuildfunctionsError('Sandbox has been deleted', 'INVALID_REQUEST');
|
|
165
|
+
}
|
|
166
|
+
// Normalize options to support both snake_case and camelCase
|
|
167
|
+
const localPath = options.local_path ?? options.localPath;
|
|
168
|
+
const filePath = options.file_path ?? options.filePath;
|
|
169
|
+
if (!localPath || !filePath) {
|
|
170
|
+
throw new ValidationError('Both local_path and file_path are required');
|
|
171
|
+
}
|
|
172
|
+
// Read file content
|
|
173
|
+
if (!existsSync(localPath)) {
|
|
174
|
+
throw new ValidationError(`Local file not found: ${localPath}`);
|
|
175
|
+
}
|
|
176
|
+
const content = await readFile(localPath, 'utf-8');
|
|
177
|
+
const response = await fetch(`${baseUrl}/api/sdk/sandbox/upload`, {
|
|
178
|
+
method: 'POST',
|
|
179
|
+
headers: {
|
|
180
|
+
'Content-Type': 'application/json',
|
|
181
|
+
Authorization: `Bearer ${apiKey}`,
|
|
182
|
+
},
|
|
183
|
+
body: JSON.stringify({
|
|
184
|
+
sandboxId: id,
|
|
185
|
+
filePath,
|
|
186
|
+
content,
|
|
187
|
+
type: 'cpu',
|
|
188
|
+
}),
|
|
189
|
+
});
|
|
190
|
+
if (!response.ok) {
|
|
191
|
+
throw new BuildfunctionsError('Upload failed', 'UNKNOWN_ERROR', response.status);
|
|
192
|
+
}
|
|
193
|
+
};
|
|
194
|
+
const deleteFn = async () => {
|
|
195
|
+
if (deleted) {
|
|
196
|
+
return;
|
|
197
|
+
}
|
|
198
|
+
const response = await fetch(`${baseUrl}/api/sdk/sandbox/delete`, {
|
|
199
|
+
method: 'DELETE',
|
|
200
|
+
headers: {
|
|
201
|
+
'Content-Type': 'application/json',
|
|
202
|
+
Authorization: `Bearer ${apiKey}`,
|
|
203
|
+
},
|
|
204
|
+
body: JSON.stringify({
|
|
205
|
+
sandboxId: id,
|
|
206
|
+
type: 'cpu',
|
|
207
|
+
}),
|
|
208
|
+
});
|
|
209
|
+
if (!response.ok) {
|
|
210
|
+
throw new BuildfunctionsError('Delete failed', 'UNKNOWN_ERROR', response.status);
|
|
211
|
+
}
|
|
212
|
+
deleted = true;
|
|
213
|
+
};
|
|
214
|
+
return {
|
|
215
|
+
id,
|
|
216
|
+
name,
|
|
217
|
+
runtime,
|
|
218
|
+
endpoint,
|
|
219
|
+
type: 'cpu',
|
|
220
|
+
run,
|
|
221
|
+
upload,
|
|
222
|
+
delete: deleteFn,
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
/**
|
|
226
|
+
* CPU Sandbox factory
|
|
227
|
+
*/
|
|
228
|
+
export const CPUSandbox = {
|
|
229
|
+
/**
|
|
230
|
+
* Create a new CPU sandbox
|
|
231
|
+
*/
|
|
232
|
+
create: async (config) => {
|
|
233
|
+
if (!globalApiKey) {
|
|
234
|
+
throw new ValidationError('API key not set. Initialize Buildfunctions client first.');
|
|
235
|
+
}
|
|
236
|
+
validateConfig(config);
|
|
237
|
+
const baseUrl = globalBaseUrl ?? DEFAULT_BASE_URL;
|
|
238
|
+
// CPU sandbox endpoint
|
|
239
|
+
const url = `${baseUrl}/api/sdk/sandbox/create`;
|
|
240
|
+
// Match CPU function body exactly (from client.ts create function)
|
|
241
|
+
const name = config.name.toLowerCase();
|
|
242
|
+
const fileExt = config.language === 'python' ? '.py' : config.language === 'javascript' ? '.js' : '.py';
|
|
243
|
+
const requestBody = {
|
|
244
|
+
// Required by sandbox/create endpoint
|
|
245
|
+
type: 'cpu',
|
|
246
|
+
// Same fields as CPU function
|
|
247
|
+
name,
|
|
248
|
+
fileExt,
|
|
249
|
+
code: config.code ?? '',
|
|
250
|
+
sourceWith: config.code ?? '',
|
|
251
|
+
sourceWithout: config.code ?? '',
|
|
252
|
+
language: config.language,
|
|
253
|
+
runtime: config.runtime ?? config.language,
|
|
254
|
+
memoryAllocated: config.memory ? parseMemory(config.memory) : 128,
|
|
255
|
+
timeout: config.timeout ?? 10,
|
|
256
|
+
envVariables: JSON.stringify(config.envVariables ?? []),
|
|
257
|
+
requirements: config.requirements ?? '',
|
|
258
|
+
cronExpression: '',
|
|
259
|
+
subdomain: name,
|
|
260
|
+
totalVariables: (config.envVariables ?? []).length,
|
|
261
|
+
functionCount: 0,
|
|
262
|
+
};
|
|
263
|
+
const controller = new AbortController();
|
|
264
|
+
const timeoutId = setTimeout(() => controller.abort(), 5 * 60 * 1000); // 5 minute timeout
|
|
265
|
+
const response = await fetch(url, {
|
|
266
|
+
method: 'POST',
|
|
267
|
+
headers: {
|
|
268
|
+
'Content-Type': 'application/json',
|
|
269
|
+
Authorization: `Bearer ${globalApiKey}`,
|
|
270
|
+
},
|
|
271
|
+
body: JSON.stringify(requestBody),
|
|
272
|
+
signal: controller.signal,
|
|
273
|
+
});
|
|
274
|
+
clearTimeout(timeoutId);
|
|
275
|
+
const responseText = await response.text();
|
|
276
|
+
if (!response.ok) {
|
|
277
|
+
throw new BuildfunctionsError(`Failed to create sandbox: ${responseText}`, 'UNKNOWN_ERROR', response.status);
|
|
278
|
+
}
|
|
279
|
+
let data;
|
|
280
|
+
try {
|
|
281
|
+
data = JSON.parse(responseText);
|
|
282
|
+
}
|
|
283
|
+
catch {
|
|
284
|
+
throw new BuildfunctionsError(`Invalid JSON response: ${responseText}`, 'UNKNOWN_ERROR', response.status);
|
|
285
|
+
}
|
|
286
|
+
// Response has siteId and endpoint
|
|
287
|
+
const sandboxId = data.siteId;
|
|
288
|
+
const sandboxEndpoint = data.endpoint || `https://${name}.buildfunctions.app`;
|
|
289
|
+
const sandboxRuntime = config.runtime ?? config.language;
|
|
290
|
+
return createCPUSandboxInstance(sandboxId, name, sandboxRuntime, sandboxEndpoint, globalApiKey, baseUrl);
|
|
291
|
+
},
|
|
292
|
+
};
|
|
293
|
+
//# sourceMappingURL=cpu-sandbox.js.map
|