Initial commit

This commit is contained in:
David Snelling 2025-06-24 11:41:30 -07:00
commit 5a8a6c1ba3
81 changed files with 39269 additions and 0 deletions

View file

@ -0,0 +1,205 @@
#!/usr/bin/env node
/**
* AWS Deployment Script for Brainy Cloud Wrapper
*
* This script helps deploy the Brainy cloud wrapper to AWS Lambda and API Gateway.
* It uses the AWS SDK to create and configure the necessary resources.
*
* Prerequisites:
* - AWS CLI installed and configured with appropriate credentials
* - Node.js 23.11.0 or higher
* - Brainy cloud wrapper built (npm run build)
*/
import { execSync } from 'child_process';
import fs from 'fs';
import path from 'path';
import dotenv from 'dotenv';
// Load environment variables
dotenv.config();
// Configuration
const config = {
region: process.env.AWS_REGION || 'us-east-1',
functionName: process.env.AWS_FUNCTION_NAME || 'brainy-cloud-service',
s3Bucket: process.env.S3_BUCKET_NAME,
s3Key: process.env.S3_ACCESS_KEY_ID,
s3Secret: process.env.S3_SECRET_ACCESS_KEY,
apiGatewayName: process.env.AWS_API_GATEWAY_NAME || 'brainy-api',
stageName: process.env.AWS_STAGE_NAME || 'prod'
};
// Validate configuration
if (!config.s3Bucket && process.env.STORAGE_TYPE === 's3') {
console.error('Error: S3 bucket name is required when using S3 storage');
process.exit(1);
}
// Create deployment package
function createDeploymentPackage() {
console.log('Creating deployment package...');
try {
// Create a temporary directory for the deployment package
if (!fs.existsSync('deploy')) {
fs.mkdirSync('deploy');
}
// Copy necessary files
execSync('cp -r dist deploy/');
execSync('cp package.json deploy/');
execSync('cp .env deploy/');
// Create a zip file
execSync('cd deploy && zip -r ../deployment.zip .');
console.log('Deployment package created successfully');
} catch (error) {
console.error('Error creating deployment package:', error);
process.exit(1);
}
}
// Deploy to AWS Lambda
function deployToLambda() {
console.log('Deploying to AWS Lambda...');
try {
// Check if function exists
try {
execSync(`aws lambda get-function --function-name ${config.functionName} --region ${config.region}`);
// Update existing function
execSync(`aws lambda update-function-code --function-name ${config.functionName} --zip-file fileb://deployment.zip --region ${config.region}`);
console.log(`Lambda function ${config.functionName} updated successfully`);
} catch (error) {
// Create new function
execSync(`aws lambda create-function --function-name ${config.functionName} --runtime nodejs20.x --handler dist/index.handler --zip-file fileb://deployment.zip --role arn:aws:iam::${process.env.AWS_ACCOUNT_ID}:role/lambda-basic-execution --region ${config.region}`);
console.log(`Lambda function ${config.functionName} created successfully`);
}
// Configure environment variables
const envVars = {
Variables: {
NODE_ENV: 'production',
STORAGE_TYPE: process.env.STORAGE_TYPE || 'filesystem',
S3_BUCKET_NAME: config.s3Bucket,
S3_ACCESS_KEY_ID: config.s3Key,
S3_SECRET_ACCESS_KEY: config.s3Secret,
S3_REGION: config.region
}
};
execSync(`aws lambda update-function-configuration --function-name ${config.functionName} --environment '${JSON.stringify(envVars)}' --region ${config.region}`);
console.log('Lambda function environment variables configured');
} catch (error) {
console.error('Error deploying to AWS Lambda:', error);
process.exit(1);
}
}
// Create API Gateway
function createApiGateway() {
console.log('Creating API Gateway...');
try {
// Check if API Gateway exists
let apiId;
try {
const result = execSync(`aws apigateway get-rest-apis --region ${config.region}`).toString();
const apis = JSON.parse(result).items;
const api = apis.find(api => api.name === config.apiGatewayName);
if (api) {
apiId = api.id;
console.log(`Using existing API Gateway: ${apiId}`);
} else {
throw new Error('API Gateway not found');
}
} catch (error) {
// Create new API Gateway
const result = execSync(`aws apigateway create-rest-api --name ${config.apiGatewayName} --region ${config.region}`).toString();
apiId = JSON.parse(result).id;
console.log(`API Gateway created: ${apiId}`);
}
// Get root resource ID
const resourcesResult = execSync(`aws apigateway get-resources --rest-api-id ${apiId} --region ${config.region}`).toString();
const rootResourceId = JSON.parse(resourcesResult).items.find(resource => resource.path === '/').id;
// Create proxy resource
let proxyResourceId;
try {
const proxyResource = JSON.parse(resourcesResult).items.find(resource => resource.path === '/{proxy+}');
if (proxyResource) {
proxyResourceId = proxyResource.id;
} else {
throw new Error('Proxy resource not found');
}
} catch (error) {
const proxyResult = execSync(`aws apigateway create-resource --rest-api-id ${apiId} --parent-id ${rootResourceId} --path-part {proxy+} --region ${config.region}`).toString();
proxyResourceId = JSON.parse(proxyResult).id;
}
// Create ANY method
try {
execSync(`aws apigateway put-method --rest-api-id ${apiId} --resource-id ${proxyResourceId} --http-method ANY --authorization-type NONE --region ${config.region}`);
} catch (error) {
console.log('Method already exists, skipping...');
}
// Create integration
try {
execSync(`aws apigateway put-integration --rest-api-id ${apiId} --resource-id ${proxyResourceId} --http-method ANY --type AWS_PROXY --integration-http-method POST --uri arn:aws:apigateway:${config.region}:lambda:path/2015-03-31/functions/arn:aws:lambda:${config.region}:${process.env.AWS_ACCOUNT_ID}:function:${config.functionName}/invocations --region ${config.region}`);
} catch (error) {
console.log('Integration already exists, skipping...');
}
// Deploy API
execSync(`aws apigateway create-deployment --rest-api-id ${apiId} --stage-name ${config.stageName} --region ${config.region}`);
console.log(`API Gateway deployed: https://${apiId}.execute-api.${config.region}.amazonaws.com/${config.stageName}`);
} catch (error) {
console.error('Error creating API Gateway:', error);
process.exit(1);
}
}
// Clean up
function cleanup() {
console.log('Cleaning up...');
try {
execSync('rm -rf deploy');
execSync('rm -f deployment.zip');
console.log('Cleanup completed');
} catch (error) {
console.error('Error during cleanup:', error);
}
}
// Main function
async function main() {
try {
console.log('Starting AWS deployment...');
createDeploymentPackage();
deployToLambda();
createApiGateway();
cleanup();
console.log('Deployment completed successfully');
} catch (error) {
console.error('Deployment failed:', error);
cleanup();
process.exit(1);
}
}
// Run the script
main();

View file

@ -0,0 +1,245 @@
#!/usr/bin/env node
/**
* Cloudflare Deployment Script for Brainy Cloud Wrapper
*
* This script helps deploy the Brainy cloud wrapper to Cloudflare Workers.
* It uses the Wrangler CLI to create and configure the necessary resources.
*
* Prerequisites:
* - Wrangler CLI installed and configured with appropriate credentials
* - Node.js 23.11.0 or higher
* - Brainy cloud wrapper built (npm run build)
*/
import { execSync } from 'child_process';
import fs from 'fs';
import path from 'path';
import dotenv from 'dotenv';
// Load environment variables
dotenv.config();
// Configuration
const config = {
workerName: process.env.CF_WORKER_NAME || 'brainy-cloud-service',
accountId: process.env.CF_ACCOUNT_ID,
kvNamespace: process.env.CF_KV_NAMESPACE || 'BRAINY_STORAGE',
r2Bucket: process.env.CF_R2_BUCKET || 'brainy-storage'
};
// Validate configuration
if (!config.accountId) {
console.error('Error: CF_ACCOUNT_ID environment variable is required');
process.exit(1);
}
// Create wrangler.toml configuration
function createWranglerConfig() {
console.log('Creating wrangler.toml configuration...');
const wranglerContent = `
name = "${config.workerName}"
main = "dist/worker.js"
compatibility_date = "2023-12-01"
node_compat = true
account_id = "${config.accountId}"
[build]
command = "npm run build"
[vars]
NODE_ENV = "production"
STORAGE_TYPE = "${process.env.STORAGE_TYPE || 'memory'}"
USE_SIMPLE_EMBEDDING = "${process.env.USE_SIMPLE_EMBEDDING || 'false'}"
# KV Namespace for storage
[[kv_namespaces]]
binding = "BRAINY_KV"
id = "${process.env.CF_KV_NAMESPACE_ID || 'create_kv_namespace_and_add_id_here'}"
# R2 Bucket for storage (if using R2)
[[r2_buckets]]
binding = "BRAINY_R2"
bucket_name = "${config.r2Bucket}"
`;
try {
fs.writeFileSync('wrangler.toml', wranglerContent);
console.log('wrangler.toml created successfully');
} catch (error) {
console.error('Error creating wrangler.toml:', error);
process.exit(1);
}
}
// Create Cloudflare Worker adapter
function createWorkerAdapter() {
console.log('Creating Cloudflare Worker adapter...');
const workerContent = `
import { createServer } from '@cloudflare/workers-adapter';
import app from './index.js';
// Create a fetch handler for the worker
export default {
async fetch(request, env, ctx) {
// Add environment variables to process.env
process.env = {
...process.env,
...env.vars,
CF_KV_NAMESPACE: env.BRAINY_KV,
CF_R2_BUCKET: env.BRAINY_R2
};
// Create a server adapter
const server = createServer(app);
// Handle the request
return server.fetch(request, env, ctx);
}
};
`;
try {
// Create dist directory if it doesn't exist
if (!fs.existsSync('dist')) {
fs.mkdirSync('dist');
}
fs.writeFileSync('dist/worker.js', workerContent);
console.log('Worker adapter created successfully');
} catch (error) {
console.error('Error creating worker adapter:', error);
process.exit(1);
}
}
// Update package.json to include Cloudflare Workers dependencies
function updatePackageJson() {
console.log('Updating package.json...');
try {
const packageJson = JSON.parse(fs.readFileSync('package.json', 'utf8'));
// Add Cloudflare Workers dependencies
packageJson.dependencies = {
...packageJson.dependencies,
'@cloudflare/workers-adapter': '^1.1.0',
'@cloudflare/kv-asset-handler': '^0.3.0'
};
// Add Cloudflare Workers scripts
packageJson.scripts = {
...packageJson.scripts,
'deploy:cloudflare': 'wrangler deploy'
};
fs.writeFileSync('package.json', JSON.stringify(packageJson, null, 2));
console.log('package.json updated successfully');
// Install new dependencies
execSync('npm install --legacy-peer-deps');
} catch (error) {
console.error('Error updating package.json:', error);
process.exit(1);
}
}
// Create KV namespace if it doesn't exist
function createKVNamespace() {
console.log('Creating KV namespace...');
try {
// Check if KV namespace ID is provided
if (process.env.CF_KV_NAMESPACE_ID) {
console.log(`Using existing KV namespace: ${process.env.CF_KV_NAMESPACE_ID}`);
return;
}
// Create KV namespace
const result = execSync(`wrangler kv:namespace create "${config.kvNamespace}"`).toString();
const match = result.match(/id = "([^"]+)"/);
if (match && match[1]) {
const namespaceId = match[1];
console.log(`KV namespace created with ID: ${namespaceId}`);
// Update wrangler.toml with the new namespace ID
let wranglerContent = fs.readFileSync('wrangler.toml', 'utf8');
wranglerContent = wranglerContent.replace(/id = "create_kv_namespace_and_add_id_here"/, `id = "${namespaceId}"`);
fs.writeFileSync('wrangler.toml', wranglerContent);
} else {
console.error('Failed to extract KV namespace ID from wrangler output');
}
} catch (error) {
console.error('Error creating KV namespace:', error);
console.log('You may need to create the KV namespace manually and update wrangler.toml');
}
}
// Create R2 bucket if it doesn't exist
function createR2Bucket() {
console.log('Creating R2 bucket...');
try {
// Only create R2 bucket if using R2 storage
if (process.env.STORAGE_TYPE !== 'r2') {
console.log('Skipping R2 bucket creation (not using R2 storage)');
return;
}
// Create R2 bucket
execSync(`wrangler r2 bucket create ${config.r2Bucket}`);
console.log(`R2 bucket created: ${config.r2Bucket}`);
} catch (error) {
console.error('Error creating R2 bucket:', error);
console.log('You may need to create the R2 bucket manually');
}
}
// Deploy to Cloudflare Workers
function deployToCloudflare() {
console.log('Deploying to Cloudflare Workers...');
try {
execSync('wrangler deploy', { stdio: 'inherit' });
console.log('Deployed to Cloudflare Workers successfully');
} catch (error) {
console.error('Error deploying to Cloudflare Workers:', error);
process.exit(1);
}
}
// Clean up
function cleanup() {
console.log('Cleaning up...');
// No cleanup needed for now
console.log('Cleanup completed');
}
// Main function
async function main() {
try {
console.log('Starting Cloudflare deployment...');
createWranglerConfig();
createWorkerAdapter();
updatePackageJson();
createKVNamespace();
createR2Bucket();
deployToCloudflare();
cleanup();
console.log('Deployment completed successfully');
} catch (error) {
console.error('Deployment failed:', error);
cleanup();
process.exit(1);
}
}
// Run the script
main();

View file

@ -0,0 +1,196 @@
#!/usr/bin/env node
/**
* Google Cloud Platform Deployment Script for Brainy Cloud Wrapper
*
* This script helps deploy the Brainy cloud wrapper to Google Cloud Run.
* It uses the Google Cloud SDK to create and configure the necessary resources.
*
* Prerequisites:
* - Google Cloud SDK installed and configured with appropriate credentials
* - Node.js 23.11.0 or higher
* - Brainy cloud wrapper built (npm run build)
* - Docker installed (for building container images)
*/
import { execSync } from 'child_process';
import fs from 'fs';
import path from 'path';
import dotenv from 'dotenv';
// Load environment variables
dotenv.config();
// Configuration
const config = {
projectId: process.env.GCP_PROJECT_ID,
region: process.env.GCP_REGION || 'us-central1',
serviceName: process.env.GCP_SERVICE_NAME || 'brainy-cloud-service',
imageName: process.env.GCP_IMAGE_NAME || 'brainy-cloud-service',
memory: process.env.GCP_MEMORY || '512Mi',
cpu: process.env.GCP_CPU || '1',
maxInstances: process.env.GCP_MAX_INSTANCES || '10',
minInstances: process.env.GCP_MIN_INSTANCES || '0'
};
// Validate configuration
if (!config.projectId) {
console.error('Error: GCP_PROJECT_ID environment variable is required');
process.exit(1);
}
// Create Dockerfile
function createDockerfile() {
console.log('Creating Dockerfile...');
const dockerfileContent = `
FROM node:23-slim
WORKDIR /app
# Copy package.json and package-lock.json
COPY package*.json ./
# Install dependencies
RUN npm install --production --legacy-peer-deps
# Copy built application
COPY dist/ ./dist/
# Copy environment variables
COPY .env ./
# Expose port
EXPOSE 8080
# Start the application
CMD ["node", "dist/index.js"]
`;
try {
fs.writeFileSync('Dockerfile', dockerfileContent);
console.log('Dockerfile created successfully');
} catch (error) {
console.error('Error creating Dockerfile:', error);
process.exit(1);
}
}
// Build and push Docker image
function buildAndPushImage() {
console.log('Building and pushing Docker image...');
try {
// Set Google Cloud project
execSync(`gcloud config set project ${config.projectId}`);
// Build the Docker image
execSync(`docker build -t gcr.io/${config.projectId}/${config.imageName} .`);
// Configure Docker to use gcloud as a credential helper
execSync('gcloud auth configure-docker');
// Push the image to Google Container Registry
execSync(`docker push gcr.io/${config.projectId}/${config.imageName}`);
console.log('Docker image built and pushed successfully');
} catch (error) {
console.error('Error building and pushing Docker image:', error);
process.exit(1);
}
}
// Deploy to Google Cloud Run
function deployToCloudRun() {
console.log('Deploying to Google Cloud Run...');
try {
// Create environment variables string
const envVars = [
`NODE_ENV=production`,
`PORT=8080`,
`STORAGE_TYPE=${process.env.STORAGE_TYPE || 'filesystem'}`
];
// Add S3 environment variables if using S3 storage
if (process.env.STORAGE_TYPE === 's3') {
envVars.push(`S3_BUCKET_NAME=${process.env.S3_BUCKET_NAME}`);
envVars.push(`S3_ACCESS_KEY_ID=${process.env.S3_ACCESS_KEY_ID}`);
envVars.push(`S3_SECRET_ACCESS_KEY=${process.env.S3_SECRET_ACCESS_KEY}`);
envVars.push(`S3_REGION=${process.env.S3_REGION || 'us-east-1'}`);
if (process.env.S3_ENDPOINT) {
envVars.push(`S3_ENDPOINT=${process.env.S3_ENDPOINT}`);
}
}
// Add embedding and HNSW configuration if provided
if (process.env.USE_SIMPLE_EMBEDDING) {
envVars.push(`USE_SIMPLE_EMBEDDING=${process.env.USE_SIMPLE_EMBEDDING}`);
}
if (process.env.HNSW_M) {
envVars.push(`HNSW_M=${process.env.HNSW_M}`);
envVars.push(`HNSW_EF_CONSTRUCTION=${process.env.HNSW_EF_CONSTRUCTION || '200'}`);
envVars.push(`HNSW_EF_SEARCH=${process.env.HNSW_EF_SEARCH || '50'}`);
}
// Deploy to Cloud Run
const envVarsString = envVars.map(env => `--set-env-vars="${env}"`).join(' ');
execSync(`gcloud run deploy ${config.serviceName} \
--image=gcr.io/${config.projectId}/${config.imageName} \
--platform=managed \
--region=${config.region} \
--memory=${config.memory} \
--cpu=${config.cpu} \
--max-instances=${config.maxInstances} \
--min-instances=${config.minInstances} \
--allow-unauthenticated \
${envVarsString}`);
console.log('Deployed to Google Cloud Run successfully');
// Get the service URL
const serviceUrl = execSync(`gcloud run services describe ${config.serviceName} --region=${config.region} --format="value(status.url)"`).toString().trim();
console.log(`Service URL: ${serviceUrl}`);
} catch (error) {
console.error('Error deploying to Google Cloud Run:', error);
process.exit(1);
}
}
// Clean up
function cleanup() {
console.log('Cleaning up...');
try {
// Remove Dockerfile
fs.unlinkSync('Dockerfile');
console.log('Cleanup completed');
} catch (error) {
console.error('Error during cleanup:', error);
}
}
// Main function
async function main() {
try {
console.log('Starting Google Cloud Platform deployment...');
createDockerfile();
buildAndPushImage();
deployToCloudRun();
cleanup();
console.log('Deployment completed successfully');
} catch (error) {
console.error('Deployment failed:', error);
cleanup();
process.exit(1);
}
}
// Run the script
main();