DevOps Pipeline Generator
Run ID: 69bca5d277c0421c0bf499bf2026-03-29Infrastructure
PantheraHive BOS
BOS Dashboard

DevOps Pipeline Generation: GitHub Actions for Node.js on AWS

This output provides a comprehensive CI/CD pipeline configuration for your "Test Project Name" using GitHub Actions, tailored for a Node.js application and deployment to AWS. The pipeline incorporates standard stages including linting, testing, building (Docker image), pushing to Amazon Elastic Container Registry (ECR), and deploying to Amazon Elastic Container Service (ECS).


1. Generated GitHub Actions Workflow Configuration

Below is the complete YAML configuration for your GitHub Actions workflow. You should save this file as .github/workflows/main.yml in your project repository.

text • 4,024 chars
---

### 2. Explanation of Pipeline Stages

The generated pipeline is structured into logical stages (jobs) to ensure code quality, build integrity, and reliable deployment.

*   **`lint`**:
    *   **Purpose**: Enforces code style and catches potential errors early.
    *   **Actions**: Checks out the repository, sets up Node.js, installs project dependencies, and runs the `npm run lint` command (you must have a `lint` script defined in your `package.json`).
*   **`test`**:
    *   **Purpose**: Verifies the application's functionality and prevents regressions.
    *   **Actions**: Runs after `lint` completes successfully. It checks out the repository, sets up Node.js, installs dependencies, and executes the `npm test` command (you must have a `test` script defined in your `package.json`).
*   **`build_and_push_docker`**:
    *   **Purpose**: Creates a Docker image of your Node.js application and pushes it to Amazon ECR.
    *   **Actions**: Runs only on pushes to the `main` branch after `test` has passed.
        *   Configures AWS credentials using GitHub Secrets.
        *   Logs into ECR.
        *   Builds a Docker image using the `Dockerfile` in your repository root.
        *   Tags the image with the Git SHA and `latest`.
        *   Pushes both tagged images to your specified ECR repository.
    *   **Output**: Exports the full ECR image URI for use in the deployment stage.
*   **`deploy_to_aws`**:
    *   **Purpose**: Deploys the newly built Docker image to your AWS ECS cluster.
    *   **Actions**: Runs only on pushes to the `main` branch after `build_and_push_docker` has completed.
        *   Configures AWS credentials.
        *   Downloads your existing ECS task definition (`.aws/task-definition.json`) and updates the image URI for the specified container with the newly pushed ECR image.
        *   Deploys the updated task definition to the specified ECS service and cluster, waiting for the service to stabilize.

---

### 3. AWS Setup Requirements

Before running this pipeline, you need to configure the following in your AWS account and GitHub repository:

1.  **AWS IAM User/Role**:
    *   Create an IAM user or role with programmatic access.
    *   Attach policies that grant necessary permissions:
        *   **ECR**: `AmazonEC2ContainerRegistryPowerUser` (or more restrictive permissions for `ecr:GetAuthorizationToken`, `ecr:BatchCheckLayerAvailability`, `ecr:InitiateLayerUpload`, `ecr:UploadLayerPart`, `ecr:CompleteLayerUpload`, `ecr:PutImage`).
        *   **ECS**: `AmazonECS_FullAccess` (or more restrictive permissions for `ecs:DescribeServices`, `ecs:UpdateService`, `ecs:RegisterTaskDefinition`, `ecs:DescribeTaskDefinition`).
        *   **S3 (optional)**: If your `task-definition.json` is stored in S3, you'll need `s3:GetObject` permission.
    *   Record the `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY`.

2.  **GitHub Repository Secrets**:
    *   In your GitHub repository, navigate to `Settings > Secrets and variables > Actions > New repository secret`.
    *   Add the following secrets:
        *   `AWS_ACCESS_KEY_ID`: Your AWS IAM access key ID.
        *   `AWS_SECRET_ACCESS_KEY`: Your AWS IAM secret access key.

3.  **AWS ECR Repository**:
    *   Create an ECR repository with the name specified in `ECR_REPOSITORY` (e.g., `test-project-name`).

4.  **AWS ECS Cluster, Service, and Task Definition**:
    *   Set up an ECS cluster (e.g., `test-project-cluster`).
    *   Create an ECS service (e.g., `test-project-service`) within that cluster.
    *   Define an ECS task definition (e.g., `test-project-task-definition`).
    *   **Crucially**: You need a `task-definition.json` file in your repository (as specified in the `deploy_to_aws` job: `.aws/task-definition.json`). This file should contain a placeholder for the image, which the `aws-actions/amazon-ecs-render-task-definition` action will update.
        *   Example `task-definition.json` (ensure `containerDefinitions[0].name` matches `CONTAINER_NAME` env var):
        
Sandboxed live preview

4. Next Steps and Recommendations

  1. Customize Environment Variables: Update the env section at the top of the YAML file with your specific NODE_VERSION, AWS_REGION, ECR_REPOSITORY, ECS_CLUSTER, ECS_SERVICE, ECS_TASK_DEFINITION, and CONTAINER_NAME.
  2. Create Dockerfile: If you don't have one, create a Dockerfile in your repository root.
  3. Create .aws/task-definition.json: Ensure this file exists and is correctly configured for your ECS setup.
  4. Configure package.json Scripts: Verify npm run lint and npm test commands are correctly defined and work locally.
  5. Set up GitHub Secrets: Add AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY to your GitHub repository secrets.
  6. Push to main: Once configured, push your changes to the main branch to trigger the pipeline.
  7. Review GitHub Actions Runs: Monitor the workflow runs in the "Actions" tab of your GitHub repository to ensure all stages execute successfully.
  8. Error Handling & Notifications: Consider adding steps for failure notifications (e.g., Slack, email) using GitHub Actions integrations.
  9. Multiple Environments: For more complex setups, you would typically extend this to have separate deploy jobs for staging, production, etc., triggered by different branches or manual approvals, each with their own AWS credentials and environment variables.
  10. Security Best Practices: For production environments, consider using OIDC (OpenID Connect) with GitHub Actions instead of long-lived AWS IAM user keys for enhanced security. This allows GitHub Actions to assume an IAM role directly.
  11. Testing Frameworks: Ensure your npm test command correctly invokes your chosen testing framework (e.g., Jest, Mocha).
  12. Linting Tools: Ensure npm run lint correctly invokes your chosen linter (e.g., ESLint).
Step 2: projectmanager

The "DevOps Pipeline Generator" workflow has successfully generated a comprehensive CI/CD pipeline configuration for your Node.js project, tailored for GitHub Actions and deployment to AWS ECS. This output provides the complete YAML configuration, along with necessary supporting files and detailed instructions to get your pipeline up and running.


🚀 Workflow Execution Summary

Project Name: Test Project Name

CI Platform: GitHub Actions

Language: Node.js

Deployment Target: AWS (specifically AWS ECR for Docker images and AWS ECS for container orchestration)

Pipeline Stages: Linting, Testing, Docker Build & Push, ECS Deployment

This pipeline ensures that every code change undergoes automated quality checks, is packaged into a Docker image, pushed to Amazon Elastic Container Registry (ECR), and then deployed to Amazon Elastic Container Service (ECS).


📝 Generated GitHub Actions Workflow Configuration

Below is the complete GitHub Actions workflow configuration. Save this content as .github/workflows/main.yml in the root of your project repository.


name: Test Project Name CI/CD

on:
  push:
    branches:
      - main
  pull_request:
    branches:
      - main
  workflow_dispatch: # Allows manual triggering of the workflow

env:
  AWS_REGION: us-east-1 # Default AWS region for your resources
  ECR_REPOSITORY: test-project-name # Name of your Amazon ECR repository
  ECS_CLUSTER: test-project-name-cluster # Name of your Amazon ECS cluster
  ECS_SERVICE: test-project-name-service # Name of your Amazon ECS service
  ECS_TASK_DEFINITION_PATH: .aws/task-definition.json # Path to your base ECS task definition file
  CONTAINER_NAME: test-project-name-container # Name of the container defined in your task definition

jobs:
  lint-and-test:
    name: Lint and Test
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '20' # Specify your Node.js version
          cache: 'npm' # Cache npm dependencies

      - name: Install dependencies
        run: npm ci

      - name: Run Lint
        run: npm run lint # Assumes a 'lint' script in package.json (e.g., using ESLint)

      - name: Run Tests
        run: npm test # Assumes a 'test' script in package.json (e.g., using Jest)

  build-and-push-docker:
    name: Build and Push Docker Image
    runs-on: ubuntu-latest
    needs: lint-and-test # This job depends on lint-and-test succeeding
    outputs:
      # Output the path to the rendered task definition for the next job
      rendered_task_definition_path: rendered-task-definition.json
    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Configure AWS Credentials
        uses: aws-actions/configure-aws-credentials@v4
        with:
          aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
          aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          aws-region: ${{ env.AWS_REGION }}

      - name: Login to Amazon ECR
        id: login-ecr
        uses: aws-actions/amazon-ecr-login@v2

      - name: Build and Push Docker Image
        env:
          ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }}
          IMAGE_TAG: ${{ github.sha }} # Use Git SHA as image tag for uniqueness
        run: |
          echo "Building Docker image: $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG"
          docker build -t $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG .
          echo "Pushing Docker image to ECR..."
          docker push $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG
          echo "Docker image pushed successfully."

      - name: Generate Task Definition
        id: generate-task-definition
        uses: aws-actions/amazon-ecs-render-task-definition@v1
        with:
          task-definition: ${{ github.workspace }}/${{ env.ECS_TASK_DEFINITION_PATH }}
          container-name: ${{ env.CONTAINER_NAME }}
          image: ${{ steps.login-ecr.outputs.registry }}/${{ env.ECR_REPOSITORY }}:${{ github.sha }}

      - name: Save rendered task definition
        run: echo "${{ steps.generate-task-definition.outputs.task-definition }}" > rendered-task-definition.json

      - name: Upload rendered task definition as artifact
        uses: actions/upload-artifact@v4
        with:
          name: task-definition-artifact
          path: rendered-task-definition.json

  deploy-to-ecs:
    name: Deploy to AWS ECS
    runs-on: ubuntu-latest
    needs: build-and-push-docker # This job depends on build-and-push-docker succeeding
    environment: production # Use a GitHub Environment for deployment protection rules
    steps:
      - name: Configure AWS Credentials
        uses: aws-actions/configure-aws-credentials@v4
        with:
          aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
          aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          aws-region: ${{ env.AWS_REGION }}

      - name: Download rendered task definition artifact
        uses: actions/download-artifact@v4
        with:
          name: task-definition-artifact

      - name: Deploy Amazon ECS task definition
        uses: aws-actions/amazon-ecs-deploy-task-definition@v1
        with:
          task-definition: rendered-task-definition.json # Path to the downloaded artifact file
          service: ${{ env.ECS_SERVICE }}
          cluster: ${{ env.ECS_CLUSTER }}
          wait-for-service-stability: true # Wait for the ECS service to reach a stable state
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # Required for wait-for-service-stability

📋 Explanation of Pipeline Stages

The generated pipeline consists of three sequential jobs, ensuring a robust and reliable deployment process:

  1. ### lint-and-test

* Purpose: Ensures code quality, adherence to style guidelines, and functional correctness.

* Steps:

* Checkout code: Retrieves your project's source code.

* Setup Node.js: Configures the specified Node.js environment and caches npm dependencies for faster subsequent runs.

* Install dependencies: Installs all project dependencies using npm ci (clean install, recommended for CI).

* Run Lint: Executes your project's linting script (e.g., eslint .). Action Required: Ensure you have an npm run lint script defined in your package.json.

* Run Tests: Executes your project's test suite (e.g., jest). Action Required: Ensure you have an npm test script defined in your package.json.

* Failure Impact: If linting or testing fails, the pipeline stops, preventing faulty code from proceeding.

  1. ### build-and-push-docker

* Purpose: Creates a Docker image of your application and pushes it to Amazon ECR.

* Dependencies: Runs only if lint-and-test succeeds.

* Steps:

* Checkout code: Retrieves your project's source code.

* Configure AWS Credentials: Sets up AWS authentication using secrets.

* Login to Amazon ECR: Authenticates the Docker client with your ECR registry.

* Build and Push Docker Image: Builds the Docker image based on your Dockerfile and pushes it to the specified ECR repository, tagged with the Git SHA for unique versioning.

* Generate Task Definition: Uses the aws-actions/amazon-ecs-render-task-definition action to dynamically update your base ECS task definition with the newly pushed Docker image's URI.

* Save rendered task definition: Saves the dynamically generated task definition to a file.

* Upload rendered task definition as artifact: Makes the generated task definition available for the subsequent deploy-to-ecs job.

* Failure Impact: If the Docker image cannot be built or pushed, the deployment process is halted.

  1. ### deploy-to-ecs

* Purpose: Deploys the new Docker image by updating your Amazon ECS service.

* Dependencies: Runs only if build-and-push-docker succeeds.

* Steps:

* Configure AWS Credentials: Sets up AWS authentication.

* Download rendered task definition artifact: Retrieves the task definition generated in the previous job.

* Deploy Amazon ECS task definition: Updates your ECS service with the new task definition, triggering a rolling update of your application instances. The wait-for-service-stability option ensures the deployment is successful before the job completes.

* Environment: Uses a GitHub production environment, allowing you to enforce deployment protection rules (e.g., manual approval, specific branch deployment).


🛠️ Prerequisites and Setup

Before enabling this GitHub Actions workflow, you need to configure your AWS environment and GitHub repository:

  1. ### AWS Configuration

* AWS Account & Region: Ensure you have an AWS account and have specified your desired AWS_REGION in the workflow's env section (e.g., us-east-1).

* IAM User/Role for GitHub Actions:

* Create an IAM user or, preferably, an IAM Role for GitHub Actions (using OIDC for enhanced security).

* Grant this user/role the necessary permissions for ECR and ECS:

* ecr:GetAuthorizationToken

* ecr:BatchCheckLayerAvailability

* ecr:GetDownloadUrlForLayer

* ecr:GetRepositoryPolicy

* ecr:DescribeRepositories

* ecr:ListImages

* ecr:DescribeImages

* ecr:BatchGetImage

* ecr:InitiateLayerUpload

* ecr:UploadLayerPart

* ecr:CompleteLayerUpload

* ecr:PutImage

* ecs:DescribeServices

* ecs:UpdateService

* ecs:DescribeTaskDefinition

* ecs:RegisterTaskDefinition

* iam:PassRole (for the task execution role and task role)

* ECR Repository: Create an ECR repository named test-project-name (or whatever you set for ECR_REPOSITORY in the workflow).

* ECS Cluster & Service: Create an ECS Cluster (test-project-name-cluster) and an ECS Service (test-project-name-service) within that cluster.

* ECS Task Definition File (.aws/task-definition.json):

* Create a directory .aws/ in your project root.

* Create a file .aws/task-definition.json with your base ECS task definition. This file will be updated by the pipeline.

* Important: Replace YOUR_AWS_ACCOUNT_ID with your actual AWS account ID and ensure the image field in containerDefinitions uses a placeholder like YOUR_ECR_REGISTRY/test-project-name:latest as it will be dynamically replaced by the pipeline.

  1. ### GitHub Repository Configuration

* AWS Credentials Secrets:

* Go to your GitHub repository settings -> Secrets and variables -> Actions -> Repository secrets.

* Add two new repository secrets:

* AWS_ACCESS_KEY_ID: Your AWS IAM user/role access key ID.

* AWS_SECRET_ACCESS_KEY: Your AWS IAM user/role secret access key.

* Security Best Practice: Consider using OpenID Connect (OIDC) with GitHub Actions for more secure, keyless authentication to AWS.

* GitHub Environment (Optional but Recommended):

* Go to your GitHub repository settings -> Environments.

* Create a new environment named production.

* You can add protection rules here, such as "Required reviewers" or "Wait timer," to control deployments to production.

  1. ### Project Files

* Dockerfile: Create a Dockerfile in the root of your project.

* package.json: Ensure your package.json includes lint and test scripts.


📁 Example Supporting Files

To make the generated pipeline immediately actionable, here are examples of the Dockerfile, .aws/task-definition.json, and package.json that the pipeline expects.

Dockerfile (root of your project)


# Use a slim Node.js base image for building
FROM node:20-alpine AS builder

# Set working directory inside the container
WORKDIR /app

# Copy package.json and package-lock.json to leverage Docker cache
COPY package*.json ./

# Install production dependencies
RUN npm ci --only=production

# Copy the rest of your application code
COPY . .

# If your Node.js app has a build step (e.g., for React or TypeScript), uncomment and adjust:
# RUN npm run build

# Expose the port your application listens on (e.g., for an Express app)
EXPOSE 3000

# Command to run your application
CMD ["node", "src/index.js"]

.aws/task-definition.json (inside .aws/ directory)


{
  "family": "test-project-name-task",
  "networkMode": "awsvpc",
  "requiresCompatibilities": ["FARGATE"],
  "cpu": "256",
  "memory": "512",
  "executionRoleArn": "arn:aws:iam::YOUR_AWS_ACCOUNT_ID:role/ecsTaskExecutionRole",
  "taskRoleArn": "arn:aws:iam::YOUR_AWS_ACCOUNT_ID:role/ecsTaskRole",
  "containerDefinitions": [
    {
      "name": "test-project-name-container",
      "image": "YOUR_ECR_REGISTRY/test-project-name:latest",
      "portMappings": [
        {
          "containerPort": 3000,
          "hostPort": 3000,
          "protocol": "tcp"
        }
      ],
      "essential": true,
      "logConfiguration": {
        "logDriver": "awslogs",
        "options": {
          "awslogs-group": "/ecs/test-project-name-logs",
          "awslogs-region": "us-east-1",
          "awslogs-stream-prefix": "ecs"
        }
      },
      "environment": [
        {
          "name": "NODE_ENV",
          "value": "production"
        }
      ]
    }
  ]
}

Important Customizations for task-definition.json:

  • Replace YOUR_AWS_ACCOUNT_ID with your actual AWS account ID.
  • Update executionRoleArn and taskRoleArn with the ARNs of your ECS task execution and task roles. These roles grant permissions for ECS to pull images, send logs, and for your application to interact with other AWS services.
  • Adjust cpu and memory based on your application's resource requirements.
  • Ensure containerPort matches the EXPOSE port in your Dockerfile and the port your application listens on.
  • Configure logConfiguration to send container logs to CloudWatch Logs. Create the /ecs/test-project-name-logs log group in CloudWatch if it doesn't exist.
  • The image field will be dynamically updated by the aws-actions/amazon-ecs-render-task-definition@v1 action.

package.json (root of your project)


{
  "name": "test-project-name",
  "version": "1.0.0",
  "description": "A sample Node.js project for CI/CD.",
  "main": "src/index.js",
  "scripts": {
    "start": "node src/index.js",
    "test": "jest",
    "lint": "eslint ."
  },
  "dependencies": {
    "express": "^4.19.2"
  },
  "devDependencies": {
    "eslint": "^8.57.0",
    "jest": "^29.7.0"
  }
}

Action Required:

  • Ensure your main entry point is correct (e.g., src/index.js).
  • Install eslint and jest (or your preferred linting/testing tools) as dev dependencies.
  • Create src/index.js (or your application's entry point) and include some basic Express app for testing purposes.

📈 Customization and Best Practices

  • Environment Variables: Adjust the env section at the top of the workflow file for your specific project names, region, and resource identifiers.
  • Node.js Version: Update node-version: '20' in the lint-and-test job and in your Dockerfile to match your project's Node.js version.
  • Linting & Testing Commands: Modify npm run lint and npm test scripts if your project uses different commands or testing frameworks.
  • Deployment Strategy: This pipeline uses a rolling update strategy via ECS service update. For zero-downtime deployments, consider blue/green deployments with AWS CodeDeploy, which can be integrated into GitHub Actions.
  • Multiple Environments: Extend this pipeline to support multiple environments (e.g., staging, production) by introducing conditional deployments based on branches or manual triggers, and using different GitHub Environments for each.
  • Notifications: Integrate Slack, Microsoft Teams, or email notifications to alert your team about pipeline successes or failures.
  • Security Scanning: Add steps for dependency vulnerability scanning (e.g., Snyk, Trivy) or static application security testing (SAST) to the lint-and-test job.
  • Infrastructure as Code (IaC): Manage your AWS resources (ECR, ECS cluster, service, task definitions, IAM roles) using IaC tools like AWS CloudFormation or
devops_pipeline_generator.txt
Download source file
Copy all content
Full output as text
Download ZIP
IDE-ready project ZIP
Copy share link
Permanent URL for this run
Get Embed Code
Embed this result on any website
Print / Save PDF
Use browser print dialog
\n\n\n"); var hasSrcMain=Object.keys(extracted).some(function(k){return k.indexOf("src/main")>=0;}); if(!hasSrcMain) zip.file(folder+"src/main."+ext,"import React from 'react'\nimport ReactDOM from 'react-dom/client'\nimport App from './App'\nimport './index.css'\n\nReactDOM.createRoot(document.getElementById('root')!).render(\n \n \n \n)\n"); var hasSrcApp=Object.keys(extracted).some(function(k){return k==="src/App."+ext||k==="App."+ext;}); if(!hasSrcApp) zip.file(folder+"src/App."+ext,"import React from 'react'\nimport './App.css'\n\nfunction App(){\n return(\n
\n
\n

"+slugTitle(pn)+"

\n

Built with PantheraHive BOS

\n
\n
\n )\n}\nexport default App\n"); zip.file(folder+"src/index.css","*{margin:0;padding:0;box-sizing:border-box}\nbody{font-family:system-ui,-apple-system,sans-serif;background:#f0f2f5;color:#1a1a2e}\n.app{min-height:100vh;display:flex;flex-direction:column}\n.app-header{flex:1;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:12px;padding:40px}\nh1{font-size:2.5rem;font-weight:700}\n"); zip.file(folder+"src/App.css",""); zip.file(folder+"src/components/.gitkeep",""); zip.file(folder+"src/pages/.gitkeep",""); zip.file(folder+"src/hooks/.gitkeep",""); Object.keys(extracted).forEach(function(p){ var fp=p.startsWith("src/")?p:"src/"+p; zip.file(folder+fp,extracted[p]); }); zip.file(folder+"README.md","# "+slugTitle(pn)+"\n\nGenerated by PantheraHive BOS.\n\n## Setup\n\`\`\`bash\nnpm install\nnpm run dev\n\`\`\`\n\n## Build\n\`\`\`bash\nnpm run build\n\`\`\`\n\n## Open in IDE\nOpen the project folder in VS Code or WebStorm.\n"); zip.file(folder+".gitignore","node_modules/\ndist/\n.env\n.DS_Store\n*.local\n"); } /* --- Vue (Vite + Composition API + TypeScript) --- */ function buildVue(zip,folder,app,code,panelTxt){ var pn=pkgName(app); var C=cc(pn); var extracted=extractCode(panelTxt); zip.file(folder+"package.json",'{\n "name": "'+pn+'",\n "version": "0.0.0",\n "type": "module",\n "scripts": {\n "dev": "vite",\n "build": "vue-tsc -b && vite build",\n "preview": "vite preview"\n },\n "dependencies": {\n "vue": "^3.5.13",\n "vue-router": "^4.4.5",\n "pinia": "^2.3.0",\n "axios": "^1.7.9"\n },\n "devDependencies": {\n "@vitejs/plugin-vue": "^5.2.1",\n "typescript": "~5.7.3",\n "vite": "^6.0.5",\n "vue-tsc": "^2.2.0"\n }\n}\n'); zip.file(folder+"vite.config.ts","import { defineConfig } from 'vite'\nimport vue from '@vitejs/plugin-vue'\nimport { resolve } from 'path'\n\nexport default defineConfig({\n plugins: [vue()],\n resolve: { alias: { '@': resolve(__dirname,'src') } }\n})\n"); zip.file(folder+"tsconfig.json",'{"files":[],"references":[{"path":"./tsconfig.app.json"},{"path":"./tsconfig.node.json"}]}\n'); zip.file(folder+"tsconfig.app.json",'{\n "compilerOptions":{\n "target":"ES2020","useDefineForClassFields":true,"module":"ESNext","lib":["ES2020","DOM","DOM.Iterable"],\n "skipLibCheck":true,"moduleResolution":"bundler","allowImportingTsExtensions":true,\n "isolatedModules":true,"moduleDetection":"force","noEmit":true,"jsxImportSource":"vue",\n "strict":true,"paths":{"@/*":["./src/*"]}\n },\n "include":["src/**/*.ts","src/**/*.d.ts","src/**/*.tsx","src/**/*.vue"]\n}\n'); zip.file(folder+"env.d.ts","/// \n"); zip.file(folder+"index.html","\n\n\n \n \n "+slugTitle(pn)+"\n\n\n
\n \n\n\n"); var hasMain=Object.keys(extracted).some(function(k){return k==="src/main.ts"||k==="main.ts";}); if(!hasMain) zip.file(folder+"src/main.ts","import { createApp } from 'vue'\nimport { createPinia } from 'pinia'\nimport App from './App.vue'\nimport './assets/main.css'\n\nconst app = createApp(App)\napp.use(createPinia())\napp.mount('#app')\n"); var hasApp=Object.keys(extracted).some(function(k){return k.indexOf("App.vue")>=0;}); if(!hasApp) zip.file(folder+"src/App.vue","\n\n\n\n\n"); zip.file(folder+"src/assets/main.css","*{margin:0;padding:0;box-sizing:border-box}body{font-family:system-ui,sans-serif;background:#fff;color:#213547}\n"); zip.file(folder+"src/components/.gitkeep",""); zip.file(folder+"src/views/.gitkeep",""); zip.file(folder+"src/stores/.gitkeep",""); Object.keys(extracted).forEach(function(p){ var fp=p.startsWith("src/")?p:"src/"+p; zip.file(folder+fp,extracted[p]); }); zip.file(folder+"README.md","# "+slugTitle(pn)+"\n\nGenerated by PantheraHive BOS.\n\n## Setup\n\`\`\`bash\nnpm install\nnpm run dev\n\`\`\`\n\n## Build\n\`\`\`bash\nnpm run build\n\`\`\`\n\nOpen in VS Code or WebStorm.\n"); zip.file(folder+".gitignore","node_modules/\ndist/\n.env\n.DS_Store\n*.local\n"); } /* --- Angular (v19 standalone) --- */ function buildAngular(zip,folder,app,code,panelTxt){ var pn=pkgName(app); var C=cc(pn); var sel=pn.replace(/_/g,"-"); var extracted=extractCode(panelTxt); zip.file(folder+"package.json",'{\n "name": "'+pn+'",\n "version": "0.0.0",\n "scripts": {\n "ng": "ng",\n "start": "ng serve",\n "build": "ng build",\n "test": "ng test"\n },\n "dependencies": {\n "@angular/animations": "^19.0.0",\n "@angular/common": "^19.0.0",\n "@angular/compiler": "^19.0.0",\n "@angular/core": "^19.0.0",\n "@angular/forms": "^19.0.0",\n "@angular/platform-browser": "^19.0.0",\n "@angular/platform-browser-dynamic": "^19.0.0",\n "@angular/router": "^19.0.0",\n "rxjs": "~7.8.0",\n "tslib": "^2.3.0",\n "zone.js": "~0.15.0"\n },\n "devDependencies": {\n "@angular-devkit/build-angular": "^19.0.0",\n "@angular/cli": "^19.0.0",\n "@angular/compiler-cli": "^19.0.0",\n "typescript": "~5.6.0"\n }\n}\n'); zip.file(folder+"angular.json",'{\n "$schema": "./node_modules/@angular/cli/lib/config/schema.json",\n "version": 1,\n "newProjectRoot": "projects",\n "projects": {\n "'+pn+'": {\n "projectType": "application",\n "root": "",\n "sourceRoot": "src",\n "prefix": "app",\n "architect": {\n "build": {\n "builder": "@angular-devkit/build-angular:application",\n "options": {\n "outputPath": "dist/'+pn+'",\n "index": "src/index.html",\n "browser": "src/main.ts",\n "tsConfig": "tsconfig.app.json",\n "styles": ["src/styles.css"],\n "scripts": []\n }\n },\n "serve": {"builder":"@angular-devkit/build-angular:dev-server","configurations":{"production":{"buildTarget":"'+pn+':build:production"},"development":{"buildTarget":"'+pn+':build:development"}},"defaultConfiguration":"development"}\n }\n }\n }\n}\n'); zip.file(folder+"tsconfig.json",'{\n "compileOnSave": false,\n "compilerOptions": {"baseUrl":"./","outDir":"./dist/out-tsc","forceConsistentCasingInFileNames":true,"strict":true,"noImplicitOverride":true,"noPropertyAccessFromIndexSignature":true,"noImplicitReturns":true,"noFallthroughCasesInSwitch":true,"paths":{"@/*":["src/*"]},"skipLibCheck":true,"esModuleInterop":true,"sourceMap":true,"declaration":false,"experimentalDecorators":true,"moduleResolution":"bundler","importHelpers":true,"target":"ES2022","module":"ES2022","useDefineForClassFields":false,"lib":["ES2022","dom"]},\n "references":[{"path":"./tsconfig.app.json"}]\n}\n'); zip.file(folder+"tsconfig.app.json",'{\n "extends":"./tsconfig.json",\n "compilerOptions":{"outDir":"./dist/out-tsc","types":[]},\n "files":["src/main.ts"],\n "include":["src/**/*.d.ts"]\n}\n'); zip.file(folder+"src/index.html","\n\n\n \n "+slugTitle(pn)+"\n \n \n \n\n\n \n\n\n"); zip.file(folder+"src/main.ts","import { bootstrapApplication } from '@angular/platform-browser';\nimport { appConfig } from './app/app.config';\nimport { AppComponent } from './app/app.component';\n\nbootstrapApplication(AppComponent, appConfig)\n .catch(err => console.error(err));\n"); zip.file(folder+"src/styles.css","* { margin: 0; padding: 0; box-sizing: border-box; }\nbody { font-family: system-ui, -apple-system, sans-serif; background: #f9fafb; color: #111827; }\n"); var hasComp=Object.keys(extracted).some(function(k){return k.indexOf("app.component")>=0;}); if(!hasComp){ zip.file(folder+"src/app/app.component.ts","import { Component } from '@angular/core';\nimport { RouterOutlet } from '@angular/router';\n\n@Component({\n selector: 'app-root',\n standalone: true,\n imports: [RouterOutlet],\n templateUrl: './app.component.html',\n styleUrl: './app.component.css'\n})\nexport class AppComponent {\n title = '"+pn+"';\n}\n"); zip.file(folder+"src/app/app.component.html","
\n
\n

"+slugTitle(pn)+"

\n

Built with PantheraHive BOS

\n
\n \n
\n"); zip.file(folder+"src/app/app.component.css",".app-header{display:flex;flex-direction:column;align-items:center;justify-content:center;min-height:60vh;gap:16px}h1{font-size:2.5rem;font-weight:700;color:#6366f1}\n"); } zip.file(folder+"src/app/app.config.ts","import { ApplicationConfig, provideZoneChangeDetection } from '@angular/core';\nimport { provideRouter } from '@angular/router';\nimport { routes } from './app.routes';\n\nexport const appConfig: ApplicationConfig = {\n providers: [\n provideZoneChangeDetection({ eventCoalescing: true }),\n provideRouter(routes)\n ]\n};\n"); zip.file(folder+"src/app/app.routes.ts","import { Routes } from '@angular/router';\n\nexport const routes: Routes = [];\n"); Object.keys(extracted).forEach(function(p){ var fp=p.startsWith("src/")?p:"src/"+p; zip.file(folder+fp,extracted[p]); }); zip.file(folder+"README.md","# "+slugTitle(pn)+"\n\nGenerated by PantheraHive BOS.\n\n## Setup\n\`\`\`bash\nnpm install\nng serve\n# or: npm start\n\`\`\`\n\n## Build\n\`\`\`bash\nng build\n\`\`\`\n\nOpen in VS Code with Angular Language Service extension.\n"); zip.file(folder+".gitignore","node_modules/\ndist/\n.env\n.DS_Store\n*.local\n.angular/\n"); } /* --- Python --- */ function buildPython(zip,folder,app,code){ var title=slugTitle(app); var pn=pkgName(app); var src=code.replace(/^\`\`\`[\w]*\n?/m,"").replace(/\n?\`\`\`$/m,"").trim(); var reqMap={"numpy":"numpy","pandas":"pandas","sklearn":"scikit-learn","tensorflow":"tensorflow","torch":"torch","flask":"flask","fastapi":"fastapi","uvicorn":"uvicorn","requests":"requests","sqlalchemy":"sqlalchemy","pydantic":"pydantic","dotenv":"python-dotenv","PIL":"Pillow","cv2":"opencv-python","matplotlib":"matplotlib","seaborn":"seaborn","scipy":"scipy"}; var reqs=[]; Object.keys(reqMap).forEach(function(k){if(src.indexOf("import "+k)>=0||src.indexOf("from "+k)>=0)reqs.push(reqMap[k]);}); var reqsTxt=reqs.length?reqs.join("\n"):"# add dependencies here\n"; zip.file(folder+"main.py",src||"# "+title+"\n# Generated by PantheraHive BOS\n\nprint(title+\" loaded\")\n"); zip.file(folder+"requirements.txt",reqsTxt); zip.file(folder+".env.example","# Environment variables\n"); zip.file(folder+"README.md","# "+title+"\n\nGenerated by PantheraHive BOS.\n\n## Setup\n\`\`\`bash\npython3 -m venv .venv\nsource .venv/bin/activate\npip install -r requirements.txt\n\`\`\`\n\n## Run\n\`\`\`bash\npython main.py\n\`\`\`\n"); zip.file(folder+".gitignore",".venv/\n__pycache__/\n*.pyc\n.env\n.DS_Store\n"); } /* --- Node.js --- */ function buildNode(zip,folder,app,code){ var title=slugTitle(app); var pn=pkgName(app); var src=code.replace(/^\`\`\`[\w]*\n?/m,"").replace(/\n?\`\`\`$/m,"").trim(); var depMap={"mongoose":"^8.0.0","dotenv":"^16.4.5","axios":"^1.7.9","cors":"^2.8.5","bcryptjs":"^2.4.3","jsonwebtoken":"^9.0.2","socket.io":"^4.7.4","uuid":"^9.0.1","zod":"^3.22.4","express":"^4.18.2"}; var deps={}; Object.keys(depMap).forEach(function(k){if(src.indexOf(k)>=0)deps[k]=depMap[k];}); if(!deps["express"])deps["express"]="^4.18.2"; var pkgJson=JSON.stringify({"name":pn,"version":"1.0.0","main":"src/index.js","scripts":{"start":"node src/index.js","dev":"nodemon src/index.js"},"dependencies":deps,"devDependencies":{"nodemon":"^3.0.3"}},null,2)+"\n"; zip.file(folder+"package.json",pkgJson); var fallback="const express=require(\"express\");\nconst app=express();\napp.use(express.json());\n\napp.get(\"/\",(req,res)=>{\n res.json({message:\""+title+" API\"});\n});\n\nconst PORT=process.env.PORT||3000;\napp.listen(PORT,()=>console.log(\"Server on port \"+PORT));\n"; zip.file(folder+"src/index.js",src||fallback); zip.file(folder+".env.example","PORT=3000\n"); zip.file(folder+".gitignore","node_modules/\n.env\n.DS_Store\n"); zip.file(folder+"README.md","# "+title+"\n\nGenerated by PantheraHive BOS.\n\n## Setup\n\`\`\`bash\nnpm install\n\`\`\`\n\n## Run\n\`\`\`bash\nnpm run dev\n\`\`\`\n"); } /* --- Vanilla HTML --- */ function buildVanillaHtml(zip,folder,app,code){ var title=slugTitle(app); var isFullDoc=code.trim().toLowerCase().indexOf("=0||code.trim().toLowerCase().indexOf("=0; var indexHtml=isFullDoc?code:"\n\n\n\n\n"+title+"\n\n\n\n"+code+"\n\n\n\n"; zip.file(folder+"index.html",indexHtml); zip.file(folder+"style.css","/* "+title+" — styles */\n*{margin:0;padding:0;box-sizing:border-box}\nbody{font-family:system-ui,-apple-system,sans-serif;background:#fff;color:#1a1a2e}\n"); zip.file(folder+"script.js","/* "+title+" — scripts */\n"); zip.file(folder+"assets/.gitkeep",""); zip.file(folder+"README.md","# "+title+"\n\nGenerated by PantheraHive BOS.\n\n## Open\nDouble-click \`index.html\` in your browser.\n\nOr serve locally:\n\`\`\`bash\nnpx serve .\n# or\npython3 -m http.server 3000\n\`\`\`\n"); zip.file(folder+".gitignore",".DS_Store\nnode_modules/\n.env\n"); } /* ===== MAIN ===== */ var sc=document.createElement("script"); sc.src="https://cdnjs.cloudflare.com/ajax/libs/jszip/3.10.1/jszip.min.js"; sc.onerror=function(){ if(lbl)lbl.textContent="Download ZIP"; alert("JSZip load failed — check connection."); }; sc.onload=function(){ var zip=new JSZip(); var base=(_phFname||"output").replace(/\.[^.]+$/,""); var app=base.toLowerCase().replace(/[^a-z0-9]+/g,"_").replace(/^_+|_+$/g,"")||"my_app"; var folder=app+"/"; var vc=document.getElementById("panel-content"); var panelTxt=vc?(vc.innerText||vc.textContent||""):""; var lang=detectLang(_phCode,panelTxt); if(_phIsHtml){ buildVanillaHtml(zip,folder,app,_phCode); } else if(lang==="flutter"){ buildFlutter(zip,folder,app,_phCode,panelTxt); } else if(lang==="react-native"){ buildReactNative(zip,folder,app,_phCode,panelTxt); } else if(lang==="swift"){ buildSwift(zip,folder,app,_phCode,panelTxt); } else if(lang==="kotlin"){ buildKotlin(zip,folder,app,_phCode,panelTxt); } else if(lang==="react"){ buildReact(zip,folder,app,_phCode,panelTxt); } else if(lang==="vue"){ buildVue(zip,folder,app,_phCode,panelTxt); } else if(lang==="angular"){ buildAngular(zip,folder,app,_phCode,panelTxt); } else if(lang==="python"){ buildPython(zip,folder,app,_phCode); } else if(lang==="node"){ buildNode(zip,folder,app,_phCode); } else { /* Document/content workflow */ var title=app.replace(/_/g," "); var md=_phAll||_phCode||panelTxt||"No content"; zip.file(folder+app+".md",md); var h=""+title+""; h+="

"+title+"

"; var hc=md.replace(/&/g,"&").replace(//g,">"); hc=hc.replace(/^### (.+)$/gm,"

$1

"); hc=hc.replace(/^## (.+)$/gm,"

$1

"); hc=hc.replace(/^# (.+)$/gm,"

$1

"); hc=hc.replace(/\*\*(.+?)\*\*/g,"$1"); hc=hc.replace(/\n{2,}/g,"

"); h+="

"+hc+"

Generated by PantheraHive BOS
"; zip.file(folder+app+".html",h); zip.file(folder+"README.md","# "+title+"\n\nGenerated by PantheraHive BOS.\n\nFiles:\n- "+app+".md (Markdown)\n- "+app+".html (styled HTML)\n"); } zip.generateAsync({type:"blob"}).then(function(blob){ var a=document.createElement("a"); a.href=URL.createObjectURL(blob); a.download=app+".zip"; a.click(); URL.revokeObjectURL(a.href); if(lbl)lbl.textContent="Download ZIP"; }); }; document.head.appendChild(sc); } function phShare(){navigator.clipboard.writeText(window.location.href).then(function(){var el=document.getElementById("ph-share-lbl");if(el){el.textContent="Link copied!";setTimeout(function(){el.textContent="Copy share link";},2500);}});}function phEmbed(){var runId=window.location.pathname.split("/").pop().replace(".html","");var embedUrl="https://pantherahive.com/embed/"+runId;var code='';navigator.clipboard.writeText(code).then(function(){var el=document.getElementById("ph-embed-lbl");if(el){el.textContent="Embed code copied!";setTimeout(function(){el.textContent="Get Embed Code";},2500);}});}