@computesdk/fly 1.1.8 → 1.1.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -270,7 +270,7 @@ var fly = (0, import_provider.defineProvider)({
270
270
  runCode: async (_sandbox, _code, _runtime) => {
271
271
  throw new Error("Fly.io runCode method not implemented yet");
272
272
  },
273
- runCommand: async (_sandbox, _command, _args, _options) => {
273
+ runCommand: async (_sandbox, _command, _options) => {
274
274
  throw new Error("Fly.io runCommand method not implemented yet");
275
275
  },
276
276
  getInfo: async (sandbox) => {
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"sourcesContent":["/**\n * Fly.io Provider - Factory-based Implementation\n * FLY_API_TOKEN=\n * FLY_API_HOSTNAME=\"https://api.machines.dev\"\n * FLY_APP_NAME=\n * FLY_ORG=\n * FLY_REGION=\n */\n\nimport { defineProvider } from '@computesdk/provider';\n\nimport type { Runtime, CodeResult, CommandResult, SandboxInfo, CreateSandboxOptions, RunCommandOptions } from '@computesdk/provider';\n\n/**\n * Fly.io sandbox interface\n */\ninterface FlyMachine {\n machineId: string;\n appName: string;\n region: string;\n privateIp?: string;\n}\n\nexport interface FlyConfig {\n /** Fly.io API token - if not provided, will fallback to FLY_API_TOKEN environment variable */\n apiToken?: string;\n /** Fly.io organization slug - defaults to 'personal' */\n org?: string;\n /** Fly.io region - defaults to 'iad' */\n region?: string;\n /** Base API hostname - defaults to public endpoint */\n apiHostname?: string;\n /** App name - if not provided, defaults to 'computesdk' */\n appName?: string;\n}\n\nexport const getAndValidateCredentials = (config: FlyConfig) => {\n const apiToken = config.apiToken || (typeof process !== 'undefined' && process.env?.FLY_API_TOKEN) || '';\n const org = config.org || (typeof process !== 'undefined' && process.env?.FLY_ORG) || 'personal';\n const region = config.region || (typeof process !== 'undefined' && process.env?.FLY_REGION) || 'iad';\n const apiHostname = config.apiHostname || 'https://api.machines.dev';\n const appName = config.appName || (typeof process !== 'undefined' && process.env?.FLY_APP_NAME) || 'compute-sdk';\n\n if (!apiToken) {\n throw new Error(\n 'Missing Fly.io API token. Provide apiToken in config or set FLY_API_TOKEN environment variable.'\n );\n }\n\n return { apiToken, org, region, apiHostname, appName };\n};\n\nconst RUNTIME_IMAGES: Record<string, string> = {\n node: 'node:alpine',\n python: 'python:alpine',\n default: 'docker.io/traefik/whoami'\n};\n\n/**\n * Fetch from Fly.io Machines REST API\n */\nexport const fetchMachinesApi = async (\n apiToken: string,\n apiHostname: string,\n endpoint: string,\n options: RequestInit = {}\n) => {\n const response = await fetch(`${apiHostname}${endpoint}`, {\n ...options,\n headers: {\n 'Content-Type': 'application/json',\n 'Authorization': `Bearer ${apiToken}`,\n ...options.headers\n }\n });\n\n // Handle DELETE which may return empty body\n if (response.status === 200 && options.method === 'DELETE') {\n return { ok: true };\n }\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(`Fly.io API error: ${response.status} ${response.statusText} - ${errorText}`);\n }\n\n const text = await response.text();\n return text ? JSON.parse(text) : {};\n};\n\n/**\n * Ensure the app exists, create it if it doesn't\n */\nconst ensureAppExists = async (\n apiToken: string,\n apiHostname: string,\n appName: string,\n org: string\n): Promise<void> => {\n try {\n // Check if app exists\n await fetchMachinesApi(apiToken, apiHostname, `/v1/apps/${appName}`, {\n method: 'GET'\n });\n } catch (error) {\n if (error instanceof Error && error.message.includes('404')) {\n // App doesn't exist, create it\n await fetchMachinesApi(apiToken, apiHostname, '/v1/apps', {\n method: 'POST',\n body: JSON.stringify({\n app_name: appName,\n org_slug: org\n })\n });\n } else {\n throw error; // Re-throw other errors\n }\n }\n};\n\n/**\n * Wait for a machine to reach a specific state\n */\nconst waitForMachineState = async (\n apiToken: string,\n apiHostname: string,\n appName: string,\n machineId: string,\n targetState: string,\n maxWaitMs: number = 30000\n): Promise<void> => {\n const startTime = Date.now();\n \n while (Date.now() - startTime < maxWaitMs) {\n try {\n const machine = await fetchMachinesApi(apiToken, apiHostname, `/v1/apps/${appName}/machines/${machineId}`);\n if (machine.state === targetState) {\n return;\n }\n await new Promise(resolve => setTimeout(resolve, 1000)); // Wait 1 second\n } catch {\n // If machine not found, consider it stopped/deleted\n return;\n }\n }\n throw new Error(`Machine ${machineId} did not reach state ${targetState} within ${maxWaitMs}ms`);\n};\n\n/**\n * Create a Fly.io provider instance using the factory pattern\n */\nexport const fly = defineProvider<FlyMachine, FlyConfig>({\n name: 'fly',\n methods: {\n sandbox: {\n create: async (config: FlyConfig, options?: CreateSandboxOptions) => {\n const { apiToken, org, region, apiHostname, appName } = getAndValidateCredentials(config);\n\n try {\n // 1. Ensure the app exists (create if needed)\n await ensureAppExists(apiToken, apiHostname, appName, org);\n\n // 2. Determine the image based on runtime\n const image = options?.runtime \n ? (RUNTIME_IMAGES[options.runtime] || RUNTIME_IMAGES.default)\n : RUNTIME_IMAGES.default;\n\n // 3. Create the machine (no app creation here)\n const machineConfig: any = {\n name: `machine-${Date.now()}`, // Unique machine name\n region,\n config: {\n image,\n guest: {\n cpu_kind: 'shared',\n cpus: 1,\n memory_mb: 256\n }\n }\n };\n\n // Add init command for node/python to keep container running\n if (options?.runtime === 'node') {\n machineConfig.config.init = {\n cmd: ['node', '-e', 'require(\"http\").createServer((req,res)=>{res.end(\"ok\")}).listen(80)']\n };\n } else if (options?.runtime === 'python') {\n machineConfig.config.init = {\n cmd: ['python', '-c', 'import http.server;http.server.HTTPServer((\"\",80),http.server.SimpleHTTPRequestHandler).serve_forever()']\n };\n }\n\n const machine = await fetchMachinesApi(apiToken, apiHostname, `/v1/apps/${appName}/machines`, {\n method: 'POST',\n body: JSON.stringify(machineConfig)\n });\n\n const flyMachine: FlyMachine = {\n machineId: machine.id,\n appName,\n region: machine.region,\n privateIp: machine.private_ip\n };\n\n return {\n sandbox: flyMachine,\n sandboxId: `${appName}:${machine.id}`\n };\n } catch (error) {\n throw new Error(\n `Failed to create Fly.io machine: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n },\n\n getById: async (config: FlyConfig, sandboxId: string) => {\n const { apiToken, apiHostname } = getAndValidateCredentials(config);\n const [appName, machineId] = sandboxId.split(':');\n\n if (!appName || !machineId) {\n throw new Error('Invalid sandboxId format. Expected \"appName:machineId\"');\n }\n\n try {\n const machine = await fetchMachinesApi(apiToken, apiHostname, `/v1/apps/${appName}/machines/${machineId}`, {\n method: 'GET'\n });\n\n const flyMachine: FlyMachine = {\n machineId: machine.id,\n appName,\n region: machine.region,\n privateIp: machine.private_ip\n };\n\n return {\n sandbox: flyMachine,\n sandboxId\n };\n } catch (error) {\n if (error instanceof Error && error.message.includes('404')) {\n return null;\n }\n throw new Error(\n `Failed to get Fly.io sandbox: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n },\n\n list: async (config: FlyConfig) => {\n const { apiToken, apiHostname, appName } = getAndValidateCredentials(config);\n\n try {\n // Get machines for the specific app only\n const machines = await fetchMachinesApi(\n apiToken,\n apiHostname,\n `/v1/apps/${appName}/machines`,\n { method: 'GET' }\n );\n\n const machineList = Array.isArray(machines) ? machines : [];\n \n return machineList.map(machine => ({\n sandbox: {\n machineId: machine.id,\n appName,\n region: machine.region,\n privateIp: machine.private_ip\n },\n sandboxId: `${appName}:${machine.id}`\n }));\n } catch (error) {\n throw new Error(\n `Failed to list Fly.io machines: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n },\n\n destroy: async (config: FlyConfig, sandboxId: string) => {\n const { apiToken, apiHostname } = getAndValidateCredentials(config);\n const [appName, machineId] = sandboxId.split(':');\n\n if (!machineId) {\n console.warn('Invalid sandboxId format for destroy');\n return;\n }\n\n try {\n // 1. Check current machine state\n let machine;\n try {\n machine = await fetchMachinesApi(apiToken, apiHostname, `/v1/apps/${appName}/machines/${machineId}`);\n } catch (error) {\n if (error instanceof Error && error.message.includes('404')) {\n // Machine already deleted\n return;\n }\n throw error;\n }\n\n const currentState = machine.state;\n \n // 2. Handle based on current state\n if (currentState === 'created') {\n // Machine is in created state, try to start it first, then stop it\n try {\n await fetchMachinesApi(apiToken, apiHostname, `/v1/apps/${appName}/machines/${machineId}/start`, {\n method: 'POST'\n });\n // Wait a moment for it to start\n await new Promise(resolve => setTimeout(resolve, 2000));\n } catch {\n // If start fails, machine might be in a weird state, try deletion anyway\n }\n }\n \n if (currentState !== 'stopped' && currentState !== 'failed' && currentState !== 'destroyed') {\n\n try {\n await fetchMachinesApi(apiToken, apiHostname, `/v1/apps/${appName}/machines/${machineId}/stop`, {\n method: 'POST',\n body: JSON.stringify({ signal: 'SIGTERM' })\n });\n\n // Give it 5 seconds to stop gracefully before checking state\n await new Promise(resolve => setTimeout(resolve, 5000));\n \n // Wait for machine to actually stop\n await waitForMachineState(apiToken, apiHostname, appName, machineId, 'stopped', 15000);\n } catch (stopError) {\n // Try force stop if graceful stop failed\n try {\n await fetchMachinesApi(apiToken, apiHostname, `/v1/apps/${appName}/machines/${machineId}/stop`, {\n method: 'POST',\n body: JSON.stringify({ signal: 'SIGKILL' })\n });\n \n await new Promise(resolve => setTimeout(resolve, 5000));\n \n await waitForMachineState(apiToken, apiHostname, appName, machineId, 'stopped', 10000);\n\n } catch (forceStopError) {\n // Force stop errors are ignored because the machine may already be stopped or in a terminal state.\n // Log at debug level for troubleshooting.\n console.debug(`Fly.io force stop warning: ${forceStopError instanceof Error ? forceStopError.message : String(forceStopError)}`);\n }\n }\n }\n\n // 5. Delete the machine, with force if necessary\n try {\n await fetchMachinesApi(apiToken, apiHostname, `/v1/apps/${appName}/machines/${machineId}`, {\n method: 'DELETE'\n });\n } catch (deleteError) {\n if (deleteError instanceof Error && deleteError.message.includes('412')) {\n // Try force delete if normal delete fails with precondition\n await fetchMachinesApi(apiToken, apiHostname, `/v1/apps/${appName}/machines/${machineId}?force=true`, {\n method: 'DELETE'\n });\n } else {\n throw deleteError;\n }\n }\n } catch (error) {\n console.warn(`Fly.io destroy warning: ${error instanceof Error ? error.message : String(error)}`);\n }\n },\n\n runCode: async (_sandbox: FlyMachine, _code: string, _runtime?: Runtime) => {\n throw new Error('Fly.io runCode method not implemented yet');\n },\n\n runCommand: async (_sandbox: FlyMachine, _command: string, _args?: string[], _options?: RunCommandOptions) => {\n throw new Error('Fly.io runCommand method not implemented yet');\n },\n\n getInfo: async (sandbox: FlyMachine) => {\n throw new Error('Fly.io getInfo method not implemented yet');\n },\n\n getUrl: async (sandbox: FlyMachine, options: { port: number; protocol?: string }) => {\n throw new Error('Fly.io getUrl method not implemented yet');\n },\n },\n },\n});\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["/**\n * Fly.io Provider - Factory-based Implementation\n * FLY_API_TOKEN=\n * FLY_API_HOSTNAME=\"https://api.machines.dev\"\n * FLY_APP_NAME=\n * FLY_ORG=\n * FLY_REGION=\n */\n\nimport { defineProvider } from '@computesdk/provider';\n\nimport type { Runtime, CodeResult, CommandResult, SandboxInfo, CreateSandboxOptions, RunCommandOptions } from '@computesdk/provider';\n\n/**\n * Fly.io sandbox interface\n */\ninterface FlyMachine {\n machineId: string;\n appName: string;\n region: string;\n privateIp?: string;\n}\n\nexport interface FlyConfig {\n /** Fly.io API token - if not provided, will fallback to FLY_API_TOKEN environment variable */\n apiToken?: string;\n /** Fly.io organization slug - defaults to 'personal' */\n org?: string;\n /** Fly.io region - defaults to 'iad' */\n region?: string;\n /** Base API hostname - defaults to public endpoint */\n apiHostname?: string;\n /** App name - if not provided, defaults to 'computesdk' */\n appName?: string;\n}\n\nexport const getAndValidateCredentials = (config: FlyConfig) => {\n const apiToken = config.apiToken || (typeof process !== 'undefined' && process.env?.FLY_API_TOKEN) || '';\n const org = config.org || (typeof process !== 'undefined' && process.env?.FLY_ORG) || 'personal';\n const region = config.region || (typeof process !== 'undefined' && process.env?.FLY_REGION) || 'iad';\n const apiHostname = config.apiHostname || 'https://api.machines.dev';\n const appName = config.appName || (typeof process !== 'undefined' && process.env?.FLY_APP_NAME) || 'compute-sdk';\n\n if (!apiToken) {\n throw new Error(\n 'Missing Fly.io API token. Provide apiToken in config or set FLY_API_TOKEN environment variable.'\n );\n }\n\n return { apiToken, org, region, apiHostname, appName };\n};\n\nconst RUNTIME_IMAGES: Record<string, string> = {\n node: 'node:alpine',\n python: 'python:alpine',\n default: 'docker.io/traefik/whoami'\n};\n\n/**\n * Fetch from Fly.io Machines REST API\n */\nexport const fetchMachinesApi = async (\n apiToken: string,\n apiHostname: string,\n endpoint: string,\n options: RequestInit = {}\n) => {\n const response = await fetch(`${apiHostname}${endpoint}`, {\n ...options,\n headers: {\n 'Content-Type': 'application/json',\n 'Authorization': `Bearer ${apiToken}`,\n ...options.headers\n }\n });\n\n // Handle DELETE which may return empty body\n if (response.status === 200 && options.method === 'DELETE') {\n return { ok: true };\n }\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(`Fly.io API error: ${response.status} ${response.statusText} - ${errorText}`);\n }\n\n const text = await response.text();\n return text ? JSON.parse(text) : {};\n};\n\n/**\n * Ensure the app exists, create it if it doesn't\n */\nconst ensureAppExists = async (\n apiToken: string,\n apiHostname: string,\n appName: string,\n org: string\n): Promise<void> => {\n try {\n // Check if app exists\n await fetchMachinesApi(apiToken, apiHostname, `/v1/apps/${appName}`, {\n method: 'GET'\n });\n } catch (error) {\n if (error instanceof Error && error.message.includes('404')) {\n // App doesn't exist, create it\n await fetchMachinesApi(apiToken, apiHostname, '/v1/apps', {\n method: 'POST',\n body: JSON.stringify({\n app_name: appName,\n org_slug: org\n })\n });\n } else {\n throw error; // Re-throw other errors\n }\n }\n};\n\n/**\n * Wait for a machine to reach a specific state\n */\nconst waitForMachineState = async (\n apiToken: string,\n apiHostname: string,\n appName: string,\n machineId: string,\n targetState: string,\n maxWaitMs: number = 30000\n): Promise<void> => {\n const startTime = Date.now();\n \n while (Date.now() - startTime < maxWaitMs) {\n try {\n const machine = await fetchMachinesApi(apiToken, apiHostname, `/v1/apps/${appName}/machines/${machineId}`);\n if (machine.state === targetState) {\n return;\n }\n await new Promise(resolve => setTimeout(resolve, 1000)); // Wait 1 second\n } catch {\n // If machine not found, consider it stopped/deleted\n return;\n }\n }\n throw new Error(`Machine ${machineId} did not reach state ${targetState} within ${maxWaitMs}ms`);\n};\n\n/**\n * Create a Fly.io provider instance using the factory pattern\n */\nexport const fly = defineProvider<FlyMachine, FlyConfig>({\n name: 'fly',\n methods: {\n sandbox: {\n create: async (config: FlyConfig, options?: CreateSandboxOptions) => {\n const { apiToken, org, region, apiHostname, appName } = getAndValidateCredentials(config);\n\n try {\n // 1. Ensure the app exists (create if needed)\n await ensureAppExists(apiToken, apiHostname, appName, org);\n\n // 2. Determine the image based on runtime\n const image = options?.runtime \n ? (RUNTIME_IMAGES[options.runtime] || RUNTIME_IMAGES.default)\n : RUNTIME_IMAGES.default;\n\n // 3. Create the machine (no app creation here)\n const machineConfig: any = {\n name: `machine-${Date.now()}`, // Unique machine name\n region,\n config: {\n image,\n guest: {\n cpu_kind: 'shared',\n cpus: 1,\n memory_mb: 256\n }\n }\n };\n\n // Add init command for node/python to keep container running\n if (options?.runtime === 'node') {\n machineConfig.config.init = {\n cmd: ['node', '-e', 'require(\"http\").createServer((req,res)=>{res.end(\"ok\")}).listen(80)']\n };\n } else if (options?.runtime === 'python') {\n machineConfig.config.init = {\n cmd: ['python', '-c', 'import http.server;http.server.HTTPServer((\"\",80),http.server.SimpleHTTPRequestHandler).serve_forever()']\n };\n }\n\n const machine = await fetchMachinesApi(apiToken, apiHostname, `/v1/apps/${appName}/machines`, {\n method: 'POST',\n body: JSON.stringify(machineConfig)\n });\n\n const flyMachine: FlyMachine = {\n machineId: machine.id,\n appName,\n region: machine.region,\n privateIp: machine.private_ip\n };\n\n return {\n sandbox: flyMachine,\n sandboxId: `${appName}:${machine.id}`\n };\n } catch (error) {\n throw new Error(\n `Failed to create Fly.io machine: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n },\n\n getById: async (config: FlyConfig, sandboxId: string) => {\n const { apiToken, apiHostname } = getAndValidateCredentials(config);\n const [appName, machineId] = sandboxId.split(':');\n\n if (!appName || !machineId) {\n throw new Error('Invalid sandboxId format. Expected \"appName:machineId\"');\n }\n\n try {\n const machine = await fetchMachinesApi(apiToken, apiHostname, `/v1/apps/${appName}/machines/${machineId}`, {\n method: 'GET'\n });\n\n const flyMachine: FlyMachine = {\n machineId: machine.id,\n appName,\n region: machine.region,\n privateIp: machine.private_ip\n };\n\n return {\n sandbox: flyMachine,\n sandboxId\n };\n } catch (error) {\n if (error instanceof Error && error.message.includes('404')) {\n return null;\n }\n throw new Error(\n `Failed to get Fly.io sandbox: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n },\n\n list: async (config: FlyConfig) => {\n const { apiToken, apiHostname, appName } = getAndValidateCredentials(config);\n\n try {\n // Get machines for the specific app only\n const machines = await fetchMachinesApi(\n apiToken,\n apiHostname,\n `/v1/apps/${appName}/machines`,\n { method: 'GET' }\n );\n\n const machineList = Array.isArray(machines) ? machines : [];\n \n return machineList.map(machine => ({\n sandbox: {\n machineId: machine.id,\n appName,\n region: machine.region,\n privateIp: machine.private_ip\n },\n sandboxId: `${appName}:${machine.id}`\n }));\n } catch (error) {\n throw new Error(\n `Failed to list Fly.io machines: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n },\n\n destroy: async (config: FlyConfig, sandboxId: string) => {\n const { apiToken, apiHostname } = getAndValidateCredentials(config);\n const [appName, machineId] = sandboxId.split(':');\n\n if (!machineId) {\n console.warn('Invalid sandboxId format for destroy');\n return;\n }\n\n try {\n // 1. Check current machine state\n let machine;\n try {\n machine = await fetchMachinesApi(apiToken, apiHostname, `/v1/apps/${appName}/machines/${machineId}`);\n } catch (error) {\n if (error instanceof Error && error.message.includes('404')) {\n // Machine already deleted\n return;\n }\n throw error;\n }\n\n const currentState = machine.state;\n \n // 2. Handle based on current state\n if (currentState === 'created') {\n // Machine is in created state, try to start it first, then stop it\n try {\n await fetchMachinesApi(apiToken, apiHostname, `/v1/apps/${appName}/machines/${machineId}/start`, {\n method: 'POST'\n });\n // Wait a moment for it to start\n await new Promise(resolve => setTimeout(resolve, 2000));\n } catch {\n // If start fails, machine might be in a weird state, try deletion anyway\n }\n }\n \n if (currentState !== 'stopped' && currentState !== 'failed' && currentState !== 'destroyed') {\n\n try {\n await fetchMachinesApi(apiToken, apiHostname, `/v1/apps/${appName}/machines/${machineId}/stop`, {\n method: 'POST',\n body: JSON.stringify({ signal: 'SIGTERM' })\n });\n\n // Give it 5 seconds to stop gracefully before checking state\n await new Promise(resolve => setTimeout(resolve, 5000));\n \n // Wait for machine to actually stop\n await waitForMachineState(apiToken, apiHostname, appName, machineId, 'stopped', 15000);\n } catch (stopError) {\n // Try force stop if graceful stop failed\n try {\n await fetchMachinesApi(apiToken, apiHostname, `/v1/apps/${appName}/machines/${machineId}/stop`, {\n method: 'POST',\n body: JSON.stringify({ signal: 'SIGKILL' })\n });\n \n await new Promise(resolve => setTimeout(resolve, 5000));\n \n await waitForMachineState(apiToken, apiHostname, appName, machineId, 'stopped', 10000);\n\n } catch (forceStopError) {\n // Force stop errors are ignored because the machine may already be stopped or in a terminal state.\n // Log at debug level for troubleshooting.\n console.debug(`Fly.io force stop warning: ${forceStopError instanceof Error ? forceStopError.message : String(forceStopError)}`);\n }\n }\n }\n\n // 5. Delete the machine, with force if necessary\n try {\n await fetchMachinesApi(apiToken, apiHostname, `/v1/apps/${appName}/machines/${machineId}`, {\n method: 'DELETE'\n });\n } catch (deleteError) {\n if (deleteError instanceof Error && deleteError.message.includes('412')) {\n // Try force delete if normal delete fails with precondition\n await fetchMachinesApi(apiToken, apiHostname, `/v1/apps/${appName}/machines/${machineId}?force=true`, {\n method: 'DELETE'\n });\n } else {\n throw deleteError;\n }\n }\n } catch (error) {\n console.warn(`Fly.io destroy warning: ${error instanceof Error ? error.message : String(error)}`);\n }\n },\n\n runCode: async (_sandbox: FlyMachine, _code: string, _runtime?: Runtime) => {\n throw new Error('Fly.io runCode method not implemented yet');\n },\n\n runCommand: async (_sandbox: FlyMachine, _command: string, _options?: RunCommandOptions) => {\n throw new Error('Fly.io runCommand method not implemented yet');\n },\n\n getInfo: async (sandbox: FlyMachine) => {\n throw new Error('Fly.io getInfo method not implemented yet');\n },\n\n getUrl: async (sandbox: FlyMachine, options: { port: number; protocol?: string }) => {\n throw new Error('Fly.io getUrl method not implemented yet');\n },\n },\n },\n});\n"],"mappings":"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","names":[]}
package/dist/index.mjs CHANGED
@@ -244,7 +244,7 @@ var fly = defineProvider({
244
244
  runCode: async (_sandbox, _code, _runtime) => {
245
245
  throw new Error("Fly.io runCode method not implemented yet");
246
246
  },
247
- runCommand: async (_sandbox, _command, _args, _options) => {
247
+ runCommand: async (_sandbox, _command, _options) => {
248
248
  throw new Error("Fly.io runCommand method not implemented yet");
249
249
  },
250
250
  getInfo: async (sandbox) => {
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"sourcesContent":["/**\n * Fly.io Provider - Factory-based Implementation\n * FLY_API_TOKEN=\n * FLY_API_HOSTNAME=\"https://api.machines.dev\"\n * FLY_APP_NAME=\n * FLY_ORG=\n * FLY_REGION=\n */\n\nimport { defineProvider } from '@computesdk/provider';\n\nimport type { Runtime, CodeResult, CommandResult, SandboxInfo, CreateSandboxOptions, RunCommandOptions } from '@computesdk/provider';\n\n/**\n * Fly.io sandbox interface\n */\ninterface FlyMachine {\n machineId: string;\n appName: string;\n region: string;\n privateIp?: string;\n}\n\nexport interface FlyConfig {\n /** Fly.io API token - if not provided, will fallback to FLY_API_TOKEN environment variable */\n apiToken?: string;\n /** Fly.io organization slug - defaults to 'personal' */\n org?: string;\n /** Fly.io region - defaults to 'iad' */\n region?: string;\n /** Base API hostname - defaults to public endpoint */\n apiHostname?: string;\n /** App name - if not provided, defaults to 'computesdk' */\n appName?: string;\n}\n\nexport const getAndValidateCredentials = (config: FlyConfig) => {\n const apiToken = config.apiToken || (typeof process !== 'undefined' && process.env?.FLY_API_TOKEN) || '';\n const org = config.org || (typeof process !== 'undefined' && process.env?.FLY_ORG) || 'personal';\n const region = config.region || (typeof process !== 'undefined' && process.env?.FLY_REGION) || 'iad';\n const apiHostname = config.apiHostname || 'https://api.machines.dev';\n const appName = config.appName || (typeof process !== 'undefined' && process.env?.FLY_APP_NAME) || 'compute-sdk';\n\n if (!apiToken) {\n throw new Error(\n 'Missing Fly.io API token. Provide apiToken in config or set FLY_API_TOKEN environment variable.'\n );\n }\n\n return { apiToken, org, region, apiHostname, appName };\n};\n\nconst RUNTIME_IMAGES: Record<string, string> = {\n node: 'node:alpine',\n python: 'python:alpine',\n default: 'docker.io/traefik/whoami'\n};\n\n/**\n * Fetch from Fly.io Machines REST API\n */\nexport const fetchMachinesApi = async (\n apiToken: string,\n apiHostname: string,\n endpoint: string,\n options: RequestInit = {}\n) => {\n const response = await fetch(`${apiHostname}${endpoint}`, {\n ...options,\n headers: {\n 'Content-Type': 'application/json',\n 'Authorization': `Bearer ${apiToken}`,\n ...options.headers\n }\n });\n\n // Handle DELETE which may return empty body\n if (response.status === 200 && options.method === 'DELETE') {\n return { ok: true };\n }\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(`Fly.io API error: ${response.status} ${response.statusText} - ${errorText}`);\n }\n\n const text = await response.text();\n return text ? JSON.parse(text) : {};\n};\n\n/**\n * Ensure the app exists, create it if it doesn't\n */\nconst ensureAppExists = async (\n apiToken: string,\n apiHostname: string,\n appName: string,\n org: string\n): Promise<void> => {\n try {\n // Check if app exists\n await fetchMachinesApi(apiToken, apiHostname, `/v1/apps/${appName}`, {\n method: 'GET'\n });\n } catch (error) {\n if (error instanceof Error && error.message.includes('404')) {\n // App doesn't exist, create it\n await fetchMachinesApi(apiToken, apiHostname, '/v1/apps', {\n method: 'POST',\n body: JSON.stringify({\n app_name: appName,\n org_slug: org\n })\n });\n } else {\n throw error; // Re-throw other errors\n }\n }\n};\n\n/**\n * Wait for a machine to reach a specific state\n */\nconst waitForMachineState = async (\n apiToken: string,\n apiHostname: string,\n appName: string,\n machineId: string,\n targetState: string,\n maxWaitMs: number = 30000\n): Promise<void> => {\n const startTime = Date.now();\n \n while (Date.now() - startTime < maxWaitMs) {\n try {\n const machine = await fetchMachinesApi(apiToken, apiHostname, `/v1/apps/${appName}/machines/${machineId}`);\n if (machine.state === targetState) {\n return;\n }\n await new Promise(resolve => setTimeout(resolve, 1000)); // Wait 1 second\n } catch {\n // If machine not found, consider it stopped/deleted\n return;\n }\n }\n throw new Error(`Machine ${machineId} did not reach state ${targetState} within ${maxWaitMs}ms`);\n};\n\n/**\n * Create a Fly.io provider instance using the factory pattern\n */\nexport const fly = defineProvider<FlyMachine, FlyConfig>({\n name: 'fly',\n methods: {\n sandbox: {\n create: async (config: FlyConfig, options?: CreateSandboxOptions) => {\n const { apiToken, org, region, apiHostname, appName } = getAndValidateCredentials(config);\n\n try {\n // 1. Ensure the app exists (create if needed)\n await ensureAppExists(apiToken, apiHostname, appName, org);\n\n // 2. Determine the image based on runtime\n const image = options?.runtime \n ? (RUNTIME_IMAGES[options.runtime] || RUNTIME_IMAGES.default)\n : RUNTIME_IMAGES.default;\n\n // 3. Create the machine (no app creation here)\n const machineConfig: any = {\n name: `machine-${Date.now()}`, // Unique machine name\n region,\n config: {\n image,\n guest: {\n cpu_kind: 'shared',\n cpus: 1,\n memory_mb: 256\n }\n }\n };\n\n // Add init command for node/python to keep container running\n if (options?.runtime === 'node') {\n machineConfig.config.init = {\n cmd: ['node', '-e', 'require(\"http\").createServer((req,res)=>{res.end(\"ok\")}).listen(80)']\n };\n } else if (options?.runtime === 'python') {\n machineConfig.config.init = {\n cmd: ['python', '-c', 'import http.server;http.server.HTTPServer((\"\",80),http.server.SimpleHTTPRequestHandler).serve_forever()']\n };\n }\n\n const machine = await fetchMachinesApi(apiToken, apiHostname, `/v1/apps/${appName}/machines`, {\n method: 'POST',\n body: JSON.stringify(machineConfig)\n });\n\n const flyMachine: FlyMachine = {\n machineId: machine.id,\n appName,\n region: machine.region,\n privateIp: machine.private_ip\n };\n\n return {\n sandbox: flyMachine,\n sandboxId: `${appName}:${machine.id}`\n };\n } catch (error) {\n throw new Error(\n `Failed to create Fly.io machine: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n },\n\n getById: async (config: FlyConfig, sandboxId: string) => {\n const { apiToken, apiHostname } = getAndValidateCredentials(config);\n const [appName, machineId] = sandboxId.split(':');\n\n if (!appName || !machineId) {\n throw new Error('Invalid sandboxId format. Expected \"appName:machineId\"');\n }\n\n try {\n const machine = await fetchMachinesApi(apiToken, apiHostname, `/v1/apps/${appName}/machines/${machineId}`, {\n method: 'GET'\n });\n\n const flyMachine: FlyMachine = {\n machineId: machine.id,\n appName,\n region: machine.region,\n privateIp: machine.private_ip\n };\n\n return {\n sandbox: flyMachine,\n sandboxId\n };\n } catch (error) {\n if (error instanceof Error && error.message.includes('404')) {\n return null;\n }\n throw new Error(\n `Failed to get Fly.io sandbox: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n },\n\n list: async (config: FlyConfig) => {\n const { apiToken, apiHostname, appName } = getAndValidateCredentials(config);\n\n try {\n // Get machines for the specific app only\n const machines = await fetchMachinesApi(\n apiToken,\n apiHostname,\n `/v1/apps/${appName}/machines`,\n { method: 'GET' }\n );\n\n const machineList = Array.isArray(machines) ? machines : [];\n \n return machineList.map(machine => ({\n sandbox: {\n machineId: machine.id,\n appName,\n region: machine.region,\n privateIp: machine.private_ip\n },\n sandboxId: `${appName}:${machine.id}`\n }));\n } catch (error) {\n throw new Error(\n `Failed to list Fly.io machines: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n },\n\n destroy: async (config: FlyConfig, sandboxId: string) => {\n const { apiToken, apiHostname } = getAndValidateCredentials(config);\n const [appName, machineId] = sandboxId.split(':');\n\n if (!machineId) {\n console.warn('Invalid sandboxId format for destroy');\n return;\n }\n\n try {\n // 1. Check current machine state\n let machine;\n try {\n machine = await fetchMachinesApi(apiToken, apiHostname, `/v1/apps/${appName}/machines/${machineId}`);\n } catch (error) {\n if (error instanceof Error && error.message.includes('404')) {\n // Machine already deleted\n return;\n }\n throw error;\n }\n\n const currentState = machine.state;\n \n // 2. Handle based on current state\n if (currentState === 'created') {\n // Machine is in created state, try to start it first, then stop it\n try {\n await fetchMachinesApi(apiToken, apiHostname, `/v1/apps/${appName}/machines/${machineId}/start`, {\n method: 'POST'\n });\n // Wait a moment for it to start\n await new Promise(resolve => setTimeout(resolve, 2000));\n } catch {\n // If start fails, machine might be in a weird state, try deletion anyway\n }\n }\n \n if (currentState !== 'stopped' && currentState !== 'failed' && currentState !== 'destroyed') {\n\n try {\n await fetchMachinesApi(apiToken, apiHostname, `/v1/apps/${appName}/machines/${machineId}/stop`, {\n method: 'POST',\n body: JSON.stringify({ signal: 'SIGTERM' })\n });\n\n // Give it 5 seconds to stop gracefully before checking state\n await new Promise(resolve => setTimeout(resolve, 5000));\n \n // Wait for machine to actually stop\n await waitForMachineState(apiToken, apiHostname, appName, machineId, 'stopped', 15000);\n } catch (stopError) {\n // Try force stop if graceful stop failed\n try {\n await fetchMachinesApi(apiToken, apiHostname, `/v1/apps/${appName}/machines/${machineId}/stop`, {\n method: 'POST',\n body: JSON.stringify({ signal: 'SIGKILL' })\n });\n \n await new Promise(resolve => setTimeout(resolve, 5000));\n \n await waitForMachineState(apiToken, apiHostname, appName, machineId, 'stopped', 10000);\n\n } catch (forceStopError) {\n // Force stop errors are ignored because the machine may already be stopped or in a terminal state.\n // Log at debug level for troubleshooting.\n console.debug(`Fly.io force stop warning: ${forceStopError instanceof Error ? forceStopError.message : String(forceStopError)}`);\n }\n }\n }\n\n // 5. Delete the machine, with force if necessary\n try {\n await fetchMachinesApi(apiToken, apiHostname, `/v1/apps/${appName}/machines/${machineId}`, {\n method: 'DELETE'\n });\n } catch (deleteError) {\n if (deleteError instanceof Error && deleteError.message.includes('412')) {\n // Try force delete if normal delete fails with precondition\n await fetchMachinesApi(apiToken, apiHostname, `/v1/apps/${appName}/machines/${machineId}?force=true`, {\n method: 'DELETE'\n });\n } else {\n throw deleteError;\n }\n }\n } catch (error) {\n console.warn(`Fly.io destroy warning: ${error instanceof Error ? error.message : String(error)}`);\n }\n },\n\n runCode: async (_sandbox: FlyMachine, _code: string, _runtime?: Runtime) => {\n throw new Error('Fly.io runCode method not implemented yet');\n },\n\n runCommand: async (_sandbox: FlyMachine, _command: string, _args?: string[], _options?: RunCommandOptions) => {\n throw new Error('Fly.io runCommand method not implemented yet');\n },\n\n getInfo: async (sandbox: FlyMachine) => {\n throw new Error('Fly.io getInfo method not implemented yet');\n },\n\n getUrl: async (sandbox: FlyMachine, options: { port: number; protocol?: string }) => {\n throw new Error('Fly.io getUrl method not implemented yet');\n },\n },\n },\n});\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["/**\n * Fly.io Provider - Factory-based Implementation\n * FLY_API_TOKEN=\n * FLY_API_HOSTNAME=\"https://api.machines.dev\"\n * FLY_APP_NAME=\n * FLY_ORG=\n * FLY_REGION=\n */\n\nimport { defineProvider } from '@computesdk/provider';\n\nimport type { Runtime, CodeResult, CommandResult, SandboxInfo, CreateSandboxOptions, RunCommandOptions } from '@computesdk/provider';\n\n/**\n * Fly.io sandbox interface\n */\ninterface FlyMachine {\n machineId: string;\n appName: string;\n region: string;\n privateIp?: string;\n}\n\nexport interface FlyConfig {\n /** Fly.io API token - if not provided, will fallback to FLY_API_TOKEN environment variable */\n apiToken?: string;\n /** Fly.io organization slug - defaults to 'personal' */\n org?: string;\n /** Fly.io region - defaults to 'iad' */\n region?: string;\n /** Base API hostname - defaults to public endpoint */\n apiHostname?: string;\n /** App name - if not provided, defaults to 'computesdk' */\n appName?: string;\n}\n\nexport const getAndValidateCredentials = (config: FlyConfig) => {\n const apiToken = config.apiToken || (typeof process !== 'undefined' && process.env?.FLY_API_TOKEN) || '';\n const org = config.org || (typeof process !== 'undefined' && process.env?.FLY_ORG) || 'personal';\n const region = config.region || (typeof process !== 'undefined' && process.env?.FLY_REGION) || 'iad';\n const apiHostname = config.apiHostname || 'https://api.machines.dev';\n const appName = config.appName || (typeof process !== 'undefined' && process.env?.FLY_APP_NAME) || 'compute-sdk';\n\n if (!apiToken) {\n throw new Error(\n 'Missing Fly.io API token. Provide apiToken in config or set FLY_API_TOKEN environment variable.'\n );\n }\n\n return { apiToken, org, region, apiHostname, appName };\n};\n\nconst RUNTIME_IMAGES: Record<string, string> = {\n node: 'node:alpine',\n python: 'python:alpine',\n default: 'docker.io/traefik/whoami'\n};\n\n/**\n * Fetch from Fly.io Machines REST API\n */\nexport const fetchMachinesApi = async (\n apiToken: string,\n apiHostname: string,\n endpoint: string,\n options: RequestInit = {}\n) => {\n const response = await fetch(`${apiHostname}${endpoint}`, {\n ...options,\n headers: {\n 'Content-Type': 'application/json',\n 'Authorization': `Bearer ${apiToken}`,\n ...options.headers\n }\n });\n\n // Handle DELETE which may return empty body\n if (response.status === 200 && options.method === 'DELETE') {\n return { ok: true };\n }\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(`Fly.io API error: ${response.status} ${response.statusText} - ${errorText}`);\n }\n\n const text = await response.text();\n return text ? JSON.parse(text) : {};\n};\n\n/**\n * Ensure the app exists, create it if it doesn't\n */\nconst ensureAppExists = async (\n apiToken: string,\n apiHostname: string,\n appName: string,\n org: string\n): Promise<void> => {\n try {\n // Check if app exists\n await fetchMachinesApi(apiToken, apiHostname, `/v1/apps/${appName}`, {\n method: 'GET'\n });\n } catch (error) {\n if (error instanceof Error && error.message.includes('404')) {\n // App doesn't exist, create it\n await fetchMachinesApi(apiToken, apiHostname, '/v1/apps', {\n method: 'POST',\n body: JSON.stringify({\n app_name: appName,\n org_slug: org\n })\n });\n } else {\n throw error; // Re-throw other errors\n }\n }\n};\n\n/**\n * Wait for a machine to reach a specific state\n */\nconst waitForMachineState = async (\n apiToken: string,\n apiHostname: string,\n appName: string,\n machineId: string,\n targetState: string,\n maxWaitMs: number = 30000\n): Promise<void> => {\n const startTime = Date.now();\n \n while (Date.now() - startTime < maxWaitMs) {\n try {\n const machine = await fetchMachinesApi(apiToken, apiHostname, `/v1/apps/${appName}/machines/${machineId}`);\n if (machine.state === targetState) {\n return;\n }\n await new Promise(resolve => setTimeout(resolve, 1000)); // Wait 1 second\n } catch {\n // If machine not found, consider it stopped/deleted\n return;\n }\n }\n throw new Error(`Machine ${machineId} did not reach state ${targetState} within ${maxWaitMs}ms`);\n};\n\n/**\n * Create a Fly.io provider instance using the factory pattern\n */\nexport const fly = defineProvider<FlyMachine, FlyConfig>({\n name: 'fly',\n methods: {\n sandbox: {\n create: async (config: FlyConfig, options?: CreateSandboxOptions) => {\n const { apiToken, org, region, apiHostname, appName } = getAndValidateCredentials(config);\n\n try {\n // 1. Ensure the app exists (create if needed)\n await ensureAppExists(apiToken, apiHostname, appName, org);\n\n // 2. Determine the image based on runtime\n const image = options?.runtime \n ? (RUNTIME_IMAGES[options.runtime] || RUNTIME_IMAGES.default)\n : RUNTIME_IMAGES.default;\n\n // 3. Create the machine (no app creation here)\n const machineConfig: any = {\n name: `machine-${Date.now()}`, // Unique machine name\n region,\n config: {\n image,\n guest: {\n cpu_kind: 'shared',\n cpus: 1,\n memory_mb: 256\n }\n }\n };\n\n // Add init command for node/python to keep container running\n if (options?.runtime === 'node') {\n machineConfig.config.init = {\n cmd: ['node', '-e', 'require(\"http\").createServer((req,res)=>{res.end(\"ok\")}).listen(80)']\n };\n } else if (options?.runtime === 'python') {\n machineConfig.config.init = {\n cmd: ['python', '-c', 'import http.server;http.server.HTTPServer((\"\",80),http.server.SimpleHTTPRequestHandler).serve_forever()']\n };\n }\n\n const machine = await fetchMachinesApi(apiToken, apiHostname, `/v1/apps/${appName}/machines`, {\n method: 'POST',\n body: JSON.stringify(machineConfig)\n });\n\n const flyMachine: FlyMachine = {\n machineId: machine.id,\n appName,\n region: machine.region,\n privateIp: machine.private_ip\n };\n\n return {\n sandbox: flyMachine,\n sandboxId: `${appName}:${machine.id}`\n };\n } catch (error) {\n throw new Error(\n `Failed to create Fly.io machine: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n },\n\n getById: async (config: FlyConfig, sandboxId: string) => {\n const { apiToken, apiHostname } = getAndValidateCredentials(config);\n const [appName, machineId] = sandboxId.split(':');\n\n if (!appName || !machineId) {\n throw new Error('Invalid sandboxId format. Expected \"appName:machineId\"');\n }\n\n try {\n const machine = await fetchMachinesApi(apiToken, apiHostname, `/v1/apps/${appName}/machines/${machineId}`, {\n method: 'GET'\n });\n\n const flyMachine: FlyMachine = {\n machineId: machine.id,\n appName,\n region: machine.region,\n privateIp: machine.private_ip\n };\n\n return {\n sandbox: flyMachine,\n sandboxId\n };\n } catch (error) {\n if (error instanceof Error && error.message.includes('404')) {\n return null;\n }\n throw new Error(\n `Failed to get Fly.io sandbox: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n },\n\n list: async (config: FlyConfig) => {\n const { apiToken, apiHostname, appName } = getAndValidateCredentials(config);\n\n try {\n // Get machines for the specific app only\n const machines = await fetchMachinesApi(\n apiToken,\n apiHostname,\n `/v1/apps/${appName}/machines`,\n { method: 'GET' }\n );\n\n const machineList = Array.isArray(machines) ? machines : [];\n \n return machineList.map(machine => ({\n sandbox: {\n machineId: machine.id,\n appName,\n region: machine.region,\n privateIp: machine.private_ip\n },\n sandboxId: `${appName}:${machine.id}`\n }));\n } catch (error) {\n throw new Error(\n `Failed to list Fly.io machines: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n },\n\n destroy: async (config: FlyConfig, sandboxId: string) => {\n const { apiToken, apiHostname } = getAndValidateCredentials(config);\n const [appName, machineId] = sandboxId.split(':');\n\n if (!machineId) {\n console.warn('Invalid sandboxId format for destroy');\n return;\n }\n\n try {\n // 1. Check current machine state\n let machine;\n try {\n machine = await fetchMachinesApi(apiToken, apiHostname, `/v1/apps/${appName}/machines/${machineId}`);\n } catch (error) {\n if (error instanceof Error && error.message.includes('404')) {\n // Machine already deleted\n return;\n }\n throw error;\n }\n\n const currentState = machine.state;\n \n // 2. Handle based on current state\n if (currentState === 'created') {\n // Machine is in created state, try to start it first, then stop it\n try {\n await fetchMachinesApi(apiToken, apiHostname, `/v1/apps/${appName}/machines/${machineId}/start`, {\n method: 'POST'\n });\n // Wait a moment for it to start\n await new Promise(resolve => setTimeout(resolve, 2000));\n } catch {\n // If start fails, machine might be in a weird state, try deletion anyway\n }\n }\n \n if (currentState !== 'stopped' && currentState !== 'failed' && currentState !== 'destroyed') {\n\n try {\n await fetchMachinesApi(apiToken, apiHostname, `/v1/apps/${appName}/machines/${machineId}/stop`, {\n method: 'POST',\n body: JSON.stringify({ signal: 'SIGTERM' })\n });\n\n // Give it 5 seconds to stop gracefully before checking state\n await new Promise(resolve => setTimeout(resolve, 5000));\n \n // Wait for machine to actually stop\n await waitForMachineState(apiToken, apiHostname, appName, machineId, 'stopped', 15000);\n } catch (stopError) {\n // Try force stop if graceful stop failed\n try {\n await fetchMachinesApi(apiToken, apiHostname, `/v1/apps/${appName}/machines/${machineId}/stop`, {\n method: 'POST',\n body: JSON.stringify({ signal: 'SIGKILL' })\n });\n \n await new Promise(resolve => setTimeout(resolve, 5000));\n \n await waitForMachineState(apiToken, apiHostname, appName, machineId, 'stopped', 10000);\n\n } catch (forceStopError) {\n // Force stop errors are ignored because the machine may already be stopped or in a terminal state.\n // Log at debug level for troubleshooting.\n console.debug(`Fly.io force stop warning: ${forceStopError instanceof Error ? forceStopError.message : String(forceStopError)}`);\n }\n }\n }\n\n // 5. Delete the machine, with force if necessary\n try {\n await fetchMachinesApi(apiToken, apiHostname, `/v1/apps/${appName}/machines/${machineId}`, {\n method: 'DELETE'\n });\n } catch (deleteError) {\n if (deleteError instanceof Error && deleteError.message.includes('412')) {\n // Try force delete if normal delete fails with precondition\n await fetchMachinesApi(apiToken, apiHostname, `/v1/apps/${appName}/machines/${machineId}?force=true`, {\n method: 'DELETE'\n });\n } else {\n throw deleteError;\n }\n }\n } catch (error) {\n console.warn(`Fly.io destroy warning: ${error instanceof Error ? error.message : String(error)}`);\n }\n },\n\n runCode: async (_sandbox: FlyMachine, _code: string, _runtime?: Runtime) => {\n throw new Error('Fly.io runCode method not implemented yet');\n },\n\n runCommand: async (_sandbox: FlyMachine, _command: string, _options?: RunCommandOptions) => {\n throw new Error('Fly.io runCommand method not implemented yet');\n },\n\n getInfo: async (sandbox: FlyMachine) => {\n throw new Error('Fly.io getInfo method not implemented yet');\n },\n\n getUrl: async (sandbox: FlyMachine, options: { port: number; protocol?: string }) => {\n throw new Error('Fly.io getUrl method not implemented yet');\n },\n },\n },\n});\n"],"mappings":"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","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@computesdk/fly",
3
- "version": "1.1.8",
3
+ "version": "1.1.10",
4
4
  "description": "Fly.io provider for ComputeSDK - globally distributed sandboxes using Fly Machines",
5
5
  "author": "ComputeSDK Team",
6
6
  "license": "MIT",
@@ -18,8 +18,8 @@
18
18
  "dist"
19
19
  ],
20
20
  "dependencies": {
21
- "@computesdk/provider": "1.0.2",
22
- "computesdk": "1.10.2"
21
+ "@computesdk/provider": "1.0.4",
22
+ "computesdk": "1.10.3"
23
23
  },
24
24
  "keywords": [
25
25
  "computesdk",
@@ -50,7 +50,7 @@
50
50
  "tsup": "^8.0.0",
51
51
  "typescript": "^5.0.0",
52
52
  "vitest": "^1.0.0",
53
- "@computesdk/test-utils": "1.5.0"
53
+ "@computesdk/test-utils": "1.5.1"
54
54
  },
55
55
  "scripts": {
56
56
  "build": "tsup",