deploy_code
Deploys JavaScript files to a Codehooks.io project, creating serverless APIs with built-in CORS and optional instant CRUD backends.
Instructions
Deploy JavaScript code to Codehooks.io project.
MINIMAL WORKING EXAMPLE:
import { app } from 'codehooks-js';
app.get('/hello', (req, res) => {
res.json({ message: 'Hello, world!' });
});
// MANDATORY: bind to serverless runtime
export default app.init();INSTANT CRUD BACKEND:
import { app } from 'codehooks-js';
// Creates complete CRUD API for any collection (no schema required)
app.crudlify();
export default app.init();KEY REQUIREMENTS:
Always import from 'codehooks-js'
Always end with
export default app.init();Use app.get(), app.post(), app.put(), app.delete() for routes
For database:
const conn = await Datastore.open(); conn.insertOne(collection, data);Use app.crudlify() to create complete CRUD backend with no schema required
Package.json will be auto-generated if not provided
DOCUMENTATION:
Use 'docs' tool for more information
Online ChatGPT prompt: https://codehooks.io/docs/chatgpt-backend-api-prompt
Online Workflow API: https://codehooks.io/docs/workflow-api
LLM-optimized docs: https://codehooks.io/llms.txt and https://codehooks.io/llms-full.txt
Note: Codehooks.io has CORS built-in by default, so no additional CORS middleware is needed.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| files | Yes | Array of files to deploy | |
| main | No | Application main file (defaults to 'index') | |
| json | No | Output JSON format | |
| projectId | No | Project ID | |
| spaceId | No | Space ID | dev |
Implementation Reference
- src/index.ts:71-80 (schema)Zod validation schema for the deploy_code tool input parameters. Defines: 'files' (array of {path, content}), optional 'main', 'json', 'projectId', 'spaceId'.
const deployCodeSchema = z.object({ files: z.array(z.object({ path: z.string(), content: z.string() })), main: z.string().optional(), json: z.boolean().optional(), projectId: z.string().optional(), spaceId: z.string().optional() }); - src/index.ts:236-262 (registration)Tool registration entry in the tools array. Maps name 'deploy_code' to its description, schema, and inputSchema for tool listing.
{ name: "deploy_code", description: "Deploy JavaScript code to Codehooks.io project. \n\nMINIMAL WORKING EXAMPLE:\n```javascript\nimport { app } from 'codehooks-js';\n\napp.get('/hello', (req, res) => {\n res.json({ message: 'Hello, world!' });\n});\n\n// MANDATORY: bind to serverless runtime\nexport default app.init();\n```\n\nINSTANT CRUD BACKEND:\n```javascript\nimport { app } from 'codehooks-js';\n\n// Creates complete CRUD API for any collection (no schema required)\napp.crudlify();\n\nexport default app.init();\n```\n\nKEY REQUIREMENTS:\n- Always import from 'codehooks-js'\n- Always end with `export default app.init();`\n- Use app.get(), app.post(), app.put(), app.delete() for routes\n- For database: `const conn = await Datastore.open(); conn.insertOne(collection, data);`\n- Use app.crudlify() to create complete CRUD backend with no schema required\n- Package.json will be auto-generated if not provided\n\nDOCUMENTATION:\n- Use 'docs' tool for more information \n- Online ChatGPT prompt: https://codehooks.io/docs/chatgpt-backend-api-prompt\n- Online Workflow API: https://codehooks.io/docs/workflow-api\n- LLM-optimized docs: https://codehooks.io/llms.txt and https://codehooks.io/llms-full.txt\n\nNote: Codehooks.io has CORS built-in by default, so no additional CORS middleware is needed.", schema: deployCodeSchema, inputSchema: { type: "object", properties: { files: { type: "array", items: { type: "object", properties: { path: { type: "string", description: "File path relative to project root (e.g. 'index.js', 'src/utils.js')" }, content: { type: "string", description: "File content" } }, required: ["path", "content"] }, description: "Array of files to deploy" }, main: { type: "string", description: "Application main file (defaults to 'index')" }, json: { type: "boolean", description: "Output JSON format" }, projectId: { type: "string", description: "Project ID" }, spaceId: { type: "string", description: "Space ID", default: "dev" } }, required: ["files"] } }, - src/index.ts:677-834 (handler)Full handler implementation for the deploy_code tool. Writes files to temp directory, runs npm install, executes 'coho deploy' CLI command, and returns deployment result.
case "deploy_code": { const { files, main = "index", json = false, projectId, spaceId } = args as DeployCodeArgs; // Check if package.json is provided, if not create a default one const hasPackageJson = files.some(file => file.path === 'package.json'); let filesToDeploy = [...files]; if (!hasPackageJson) { console.error('No package.json provided, creating default one'); const defaultPackageJson = { name: projectId || config.projectId || "codehooks-project", version: "1.0.0", description: "Codehooks project", type: "module", main: `${main}.js`, scripts: { test: "echo \"Error: no test specified\" && exit 1" }, author: "", license: "ISC", dependencies: { "codehooks-js": "latest" } }; filesToDeploy.push({ path: 'package.json', content: JSON.stringify(defaultPackageJson, null, 2) }); } console.error(`Deploying ${filesToDeploy.length} files`); const tmpDir = await fs.mkdtemp('/tmp/codehooks-deploy-'); console.error('Created temporary directory:', tmpDir); try { // Write all files to the temporary directory with proper formatting for (const file of filesToDeploy) { const filePath = path.join(tmpDir, file.path); // Ensure directory exists await fs.mkdir(path.dirname(filePath), { recursive: true }); console.error(`Writing file: ${filePath}`); if (file.path === 'package.json') { // Create a properly structured package.json const defaultPackage = { name: projectId || config.projectId || "codehooks-project", version: "1.0.0", description: "Codehooks project", main: `${main}.js`, scripts: { test: "echo \"Error: no test specified\" && exit 1" }, author: "", license: "ISC", dependencies: { "codehooks-js": "latest" } }; // Merge with any existing package.json content let packageJson; try { packageJson = JSON.parse(file.content); packageJson = { ...defaultPackage, ...packageJson }; } catch (e) { console.error('Invalid package.json content, using default'); packageJson = defaultPackage; } // Write package.json with proper formatting await fs.writeFile(filePath, JSON.stringify(packageJson, null, 2)); } else { await fs.writeFile(filePath, file.content); } } // Log directory contents console.error('Directory contents before npm install:'); const { stdout: lsOutput } = await execFile('ls', ['-la'], { cwd: tmpDir }); console.error(lsOutput); // Install dependencies try { console.error('Installing dependencies...'); const { stdout: npmStdout, stderr: npmStderr } = await execFile('npm', ['install'], { cwd: tmpDir }); if (npmStderr) console.error('npm install stderr:', npmStderr); console.error('npm install stdout:', npmStdout); // Log directory contents after npm install console.error('Directory contents after npm install:'); const { stdout: lsOutput2 } = await execFile('ls', ['-la'], { cwd: tmpDir }); console.error(lsOutput2); } catch (error: any) { console.error('npm install error:', error); throw new McpError(ErrorCode.InvalidRequest, `Failed to install dependencies: ${error.message}`); } // Change working directory to tmpDir const originalCwd = process.cwd(); try { process.chdir(tmpDir); console.error('Changed working directory to:', tmpDir); // Log file contents before deployment console.error('File contents before deployment:'); for (const file of filesToDeploy) { console.error(`\n=== ${file.path} ===`); const content = await fs.readFile(path.join(tmpDir, file.path), 'utf8'); console.error(content); } // Construct deploy command arguments const deployArgs = [ 'deploy', '--projectname', projectId || config.projectId, '--space', spaceId || config.space, '--main', main, '--admintoken', config.adminToken ]; if (json) deployArgs.push('--json'); console.error('Executing deploy command...'); const { stdout, stderr } = await execFile('coho', deployArgs); console.error('Deploy stdout:', stdout); if (stderr) console.error('Deploy stderr:', stderr); // Only clean up on success await fs.rm(tmpDir, { recursive: true, force: true }); console.error('Cleaned up temporary directory:', tmpDir); return { content: [ { type: "text", text: stdout || stderr || "Deployment successful" } ], isError: false }; } finally { // Restore original working directory process.chdir(originalCwd); console.error('Restored working directory to:', originalCwd); } } catch (error: any) { console.error(`Deployment failed. Temporary directory ${tmpDir} preserved for inspection.`); console.error('Error:', error); throw error; } } - src/index.ts:529-564 (helper)Helper function executeCohoCommand() used by the deploy_code handler (and all other tools) to run 'coho' CLI commands via execFile with admin token injection and timeout.
async function executeCohoCommand(args: string[]): Promise<string> { const safeArgs = ['coho', ...args, '--admintoken', '***']; console.error(`Executing command: ${safeArgs.join(' ')}`); try { const { stdout, stderr } = await execFile('coho', [...args, '--admintoken', config.adminToken], { timeout: 120000 // 2 minutes timeout for CLI operations }); if (stderr) { // Sanitize stderr before logging to avoid token exposure const safeSterr = stderr.replace(new RegExp(config.adminToken, 'g'), '***'); console.error(`Command output to stderr:`, safeSterr); } console.error(`Command successful`); const result = stdout || stderr; // Sanitize result to ensure admin token is not exposed return result ? result.replace(new RegExp(config.adminToken, 'g'), '***') : result; } catch (error: any) { // Comprehensive sanitization of all error properties to avoid admin token exposure const sanitizeText = (text: string): string => text ? text.replace(new RegExp(config.adminToken, 'g'), '***') : text; const sanitizedMessage = sanitizeText(error?.message || 'Unknown error'); const sanitizedCmd = sanitizeText(error?.cmd || ''); const sanitizedStdout = sanitizeText(error?.stdout || ''); const sanitizedStderr = sanitizeText(error?.stderr || ''); // Log sanitized error details console.error(`Command failed: ${sanitizedMessage}`); if (sanitizedCmd) console.error(`Command: ${sanitizedCmd}`); if (sanitizedStdout) console.error(`Stdout: ${sanitizedStdout}`); if (sanitizedStderr) console.error(`Stderr: ${sanitizedStderr}`); // Return sanitized error message const errorDetails = [sanitizedMessage, sanitizedStderr].filter(Boolean).join(' - '); throw new McpError(ErrorCode.InvalidRequest, `Command failed: ${errorDetails}`); } } - src/index.ts:184-184 (registration)TypeScript type inference for DeployCodeArgs, derived from the deployCodeSchema.
type QueryCollectionArgs = z.infer<typeof queryCollectionSchema>;