Initial commit from template
Some checks failed
Cloudflare Worker API Template / Deploy to ${{ github.ref_name }} environment (push) Failing after 15s
Some checks failed
Cloudflare Worker API Template / Deploy to ${{ github.ref_name }} environment (push) Failing after 15s
This commit is contained in:
106
.dockerignore
Normal file
106
.dockerignore
Normal file
@@ -0,0 +1,106 @@
|
||||
# Dependencies
|
||||
node_modules/
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
|
||||
# Build outputs
|
||||
dist/
|
||||
build/
|
||||
*.tsbuildinfo
|
||||
|
||||
# Environment files
|
||||
.env
|
||||
.env.local
|
||||
.env.development
|
||||
.env.test
|
||||
.env.production
|
||||
.dev.vars
|
||||
|
||||
# IDE and editor files
|
||||
.vscode/
|
||||
.idea/
|
||||
*.swp
|
||||
*.swo
|
||||
*~
|
||||
|
||||
# OS generated files
|
||||
.DS_Store
|
||||
.DS_Store?
|
||||
._*
|
||||
.Spotlight-V100
|
||||
.Trashes
|
||||
ehthumbs.db
|
||||
Thumbs.db
|
||||
|
||||
# Git
|
||||
.git/
|
||||
.gitignore
|
||||
|
||||
# Docker
|
||||
Dockerfile*
|
||||
.dockerignore
|
||||
docker-compose.yml
|
||||
|
||||
# Cloudflare Workers
|
||||
.wrangler/
|
||||
wrangler.toml
|
||||
|
||||
# Logs
|
||||
logs/
|
||||
*.log
|
||||
|
||||
# Runtime data
|
||||
pids/
|
||||
*.pid
|
||||
*.seed
|
||||
*.pid.lock
|
||||
|
||||
# Coverage directory used by tools like istanbul
|
||||
coverage/
|
||||
*.lcov
|
||||
|
||||
# nyc test coverage
|
||||
.nyc_output
|
||||
|
||||
# Dependency directories
|
||||
jspm_packages/
|
||||
|
||||
# Optional npm cache directory
|
||||
.npm
|
||||
|
||||
# Optional eslint cache
|
||||
.eslintcache
|
||||
|
||||
# Microbundle cache
|
||||
.rpt2_cache/
|
||||
.rts2_cache_cjs/
|
||||
.rts2_cache_es/
|
||||
.rts2_cache_umd/
|
||||
|
||||
# Optional REPL history
|
||||
.node_repl_history
|
||||
|
||||
# Output of 'npm pack'
|
||||
*.tgz
|
||||
|
||||
# Yarn Integrity file
|
||||
.yarn-integrity
|
||||
|
||||
# parcel-bundler cache (https://parceljs.org/)
|
||||
.cache
|
||||
.parcel-cache
|
||||
|
||||
# Next.js build output
|
||||
.next
|
||||
|
||||
# Nuxt.js build / generate output
|
||||
.nuxt
|
||||
|
||||
# Storybook build outputs
|
||||
.out
|
||||
.storybook-out
|
||||
|
||||
# Temporary folders
|
||||
tmp/
|
||||
temp/
|
||||
70
.github/workflows/deploy.yaml
vendored
Normal file
70
.github/workflows/deploy.yaml
vendored
Normal file
@@ -0,0 +1,70 @@
|
||||
name: Cloudflare Worker API Template
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ dev, main, playtest ]
|
||||
pull_request:
|
||||
branches: [ dev, main, playtest ]
|
||||
|
||||
jobs:
|
||||
deploy:
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
image: node:20-bullseye
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
|
||||
# Extract branch name from ref
|
||||
env:
|
||||
BRANCH_NAME: ${{ github.ref_name }}
|
||||
|
||||
name: Deploy to ${{ github.ref_name }} environment
|
||||
|
||||
steps:
|
||||
- name: Set deployment variables
|
||||
id: vars
|
||||
run: |
|
||||
# Extract environment from branch name
|
||||
BRANCH="$BRANCH_NAME"
|
||||
|
||||
# Set environment name and flags based on branch
|
||||
if [[ "$BRANCH" == "main" ]]; then
|
||||
envname="production"
|
||||
env_flag="--env production"
|
||||
elif [[ "$BRANCH" == "dev" ]]; then
|
||||
envname="development"
|
||||
env_flag="--env development"
|
||||
elif [[ "$BRANCH" == "playtest" ]]; then
|
||||
envname="playtest"
|
||||
env_flag="--env playtest"
|
||||
else
|
||||
# Default to development if branch is unknown
|
||||
envname="playtest"
|
||||
env_flag="--env playtest"
|
||||
fi
|
||||
|
||||
# Write outputs for use in later steps
|
||||
echo "envname=$envname" >> $GITHUB_OUTPUT
|
||||
echo "env_flag=$env_flag" >> $GITHUB_OUTPUT
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Install dependencies
|
||||
run: npm install
|
||||
|
||||
- name: Install Wrangler CLI
|
||||
run: npm install -g wrangler
|
||||
|
||||
# Variable setting is already done in the first step
|
||||
|
||||
- name: Deploy to ${{ steps.vars.outputs.envname }} Environment
|
||||
env:
|
||||
CLOUDFLARE_API_TOKEN: ${{ secrets.CF_API_TOKEN }}
|
||||
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CF_ACCOUNT_ID }}
|
||||
run: |
|
||||
echo "Deploying to ${{ steps.vars.outputs.envname }} environment"
|
||||
wrangler deploy ${{ steps.vars.outputs.env_flag }}
|
||||
|
||||
|
||||
|
||||
215
.gitignore
vendored
Normal file
215
.gitignore
vendored
Normal file
@@ -0,0 +1,215 @@
|
||||
# Logs
|
||||
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
lerna-debug.log*
|
||||
.pnpm-debug.log*
|
||||
|
||||
# Diagnostic reports (https://nodejs.org/api/report.html)
|
||||
|
||||
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
|
||||
|
||||
# Runtime data
|
||||
|
||||
pids
|
||||
*.pid
|
||||
*.seed
|
||||
*.pid.lock
|
||||
|
||||
# Directory for instrumented libs generated by jscoverage/JSCover
|
||||
|
||||
lib-cov
|
||||
|
||||
# Coverage directory used by tools like istanbul
|
||||
|
||||
coverage
|
||||
*.lcov
|
||||
|
||||
# nyc test coverage
|
||||
|
||||
.nyc_output
|
||||
|
||||
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
|
||||
|
||||
.grunt
|
||||
|
||||
# Bower dependency directory (https://bower.io/)
|
||||
|
||||
bower_components
|
||||
|
||||
# node-waf configuration
|
||||
|
||||
.lock-wscript
|
||||
|
||||
# Compiled binary addons (https://nodejs.org/api/addons.html)
|
||||
|
||||
build/Release
|
||||
|
||||
# Dependency directories
|
||||
|
||||
node_modules/
|
||||
jspm_packages/
|
||||
|
||||
# Snowpack dependency directory (https://snowpack.dev/)
|
||||
|
||||
web_modules/
|
||||
|
||||
# TypeScript cache
|
||||
|
||||
*.tsbuildinfo
|
||||
|
||||
# Optional npm cache directory
|
||||
|
||||
.npm
|
||||
|
||||
# Optional eslint cache
|
||||
|
||||
.eslintcache
|
||||
|
||||
# Optional stylelint cache
|
||||
|
||||
.stylelintcache
|
||||
|
||||
# Microbundle cache
|
||||
|
||||
.rpt2_cache/
|
||||
.rts2_cache_cjs/
|
||||
.rts2_cache_es/
|
||||
.rts2_cache_umd/
|
||||
|
||||
# Optional REPL history
|
||||
|
||||
.node_repl_history
|
||||
|
||||
# Output of 'npm pack'
|
||||
|
||||
*.tgz
|
||||
|
||||
# Yarn Integrity file
|
||||
|
||||
.yarn-integrity
|
||||
|
||||
# dotenv environment variable files
|
||||
|
||||
.env
|
||||
.env.development.local
|
||||
.env.test.local
|
||||
.env.production.local
|
||||
.env.local
|
||||
|
||||
# parcel-bundler cache (https://parceljs.org/)
|
||||
|
||||
.cache
|
||||
.parcel-cache
|
||||
|
||||
# Next.js build output
|
||||
|
||||
.next
|
||||
out
|
||||
|
||||
# Nuxt.js build / generate output
|
||||
|
||||
.nuxt
|
||||
dist
|
||||
|
||||
# Gatsby files
|
||||
|
||||
.cache/
|
||||
|
||||
# Comment in the public line in if your project uses Gatsby and not Next.js
|
||||
|
||||
# https://nextjs.org/blog/next-9-1#public-directory-support
|
||||
|
||||
# public
|
||||
|
||||
# vuepress build output
|
||||
|
||||
.vuepress/dist
|
||||
|
||||
# vuepress v2.x temp and cache directory
|
||||
|
||||
.temp
|
||||
.cache
|
||||
|
||||
# Docusaurus cache and generated files
|
||||
|
||||
.docusaurus
|
||||
|
||||
# Serverless directories
|
||||
|
||||
.serverless/
|
||||
|
||||
# FuseBox cache
|
||||
|
||||
.fusebox/
|
||||
|
||||
# DynamoDB Local files
|
||||
|
||||
.dynamodb/
|
||||
|
||||
# TernJS port file
|
||||
|
||||
.tern-port
|
||||
|
||||
# Stores VSCode versions used for testing VSCode extensions
|
||||
|
||||
.vscode-test
|
||||
|
||||
# yarn v2
|
||||
|
||||
.yarn/cache
|
||||
.yarn/unplugged
|
||||
.yarn/build-state.yml
|
||||
.yarn/install-state.gz
|
||||
.pnp.*
|
||||
|
||||
# wrangler project
|
||||
|
||||
.dev.vars
|
||||
.wrangler/
|
||||
|
||||
# Cloudflare Workers specific
|
||||
worker-configuration.d.ts
|
||||
|
||||
# IDE and Editor files
|
||||
.vscode/
|
||||
.idea/
|
||||
*.swp
|
||||
*.swo
|
||||
*~
|
||||
|
||||
# OS generated files
|
||||
.DS_Store
|
||||
.DS_Store?
|
||||
._*
|
||||
.Spotlight-V100
|
||||
.Trashes
|
||||
ehthumbs.db
|
||||
Thumbs.db
|
||||
|
||||
# Temporary files
|
||||
*.tmp
|
||||
*.temp
|
||||
|
||||
# Build outputs
|
||||
dist/
|
||||
build/
|
||||
out/
|
||||
|
||||
# Local development files
|
||||
.local/
|
||||
local/
|
||||
|
||||
# Secrets and sensitive data
|
||||
secrets/
|
||||
*.key
|
||||
*.pem
|
||||
*.p12
|
||||
*.pfx
|
||||
|
||||
# Logs and debugging
|
||||
debug/
|
||||
*.log.*
|
||||
13
Dockerfile
Normal file
13
Dockerfile
Normal file
@@ -0,0 +1,13 @@
|
||||
FROM node:20
|
||||
|
||||
WORKDIR /mcp-server
|
||||
|
||||
COPY package*.json ./
|
||||
RUN npm install
|
||||
|
||||
COPY . .
|
||||
|
||||
EXPOSE 8787
|
||||
|
||||
# Run type check first, then start dev server
|
||||
CMD ["npm", "run", "dev"]
|
||||
208
README.md
Normal file
208
README.md
Normal file
@@ -0,0 +1,208 @@
|
||||
# Cloudflare Worker API Template
|
||||
|
||||
A production-ready template for building secure, modular APIs with Cloudflare Workers, featuring built-in authentication, database integration, and comprehensive documentation.
|
||||
|
||||
## Features
|
||||
|
||||
- **Authentication & Authorization**: Pre-configured with API key and Bearer token authentication
|
||||
- **Database Integration**: Ready-to-use D1 database connections
|
||||
- **Storage**: R2 bucket integration for file storage
|
||||
- **Documentation**: Auto-generated Swagger/OpenAPI documentation
|
||||
- **CI/CD**: GitHub Actions workflows for automated deployments
|
||||
- **Environment Management**: Development, Playtest, and Production environments
|
||||
|
||||
## Design Documentation
|
||||
|
||||
All design documentation should be maintained in the blueprint repository:
|
||||
|
||||
1. Create design documentation in the blueprint repository located at `<app_name_lower_case>`
|
||||
2. Submit the design as a Pull Request to the blueprint repository
|
||||
3. Once approved, add the link to the design file in `docs/DESIGN.md`
|
||||
|
||||
The `docs/DESIGN.md` file should contain a reference to the design document's location in the blueprint repository.
|
||||
|
||||
## Getting Started
|
||||
|
||||
### Using This Template
|
||||
|
||||
1. **Checkout the template branch**:
|
||||
```bash
|
||||
git clone <repository-url>
|
||||
git checkout template
|
||||
```
|
||||
|
||||
2. **Replace placeholder variables**:
|
||||
Search and replace the following placeholders throughout the codebase:
|
||||
- `<app_name_lower_case>` - Your application name in lowercase (e.g., `my-api`)
|
||||
- `<app_name_upper_case>` - Your application name in uppercase (e.g., `MY_API`)
|
||||
|
||||
Make sure to check all files, especially:
|
||||
- `wrangler.toml`
|
||||
- `.github/workflows/deploy.yaml`
|
||||
- `src/swagger/config.js`
|
||||
|
||||
3. **Set up a new Git repository**:
|
||||
```bash
|
||||
# Remove existing Git history
|
||||
rm -rf .git
|
||||
|
||||
# Initialize a new Git repository
|
||||
git init
|
||||
|
||||
# Add your remote repository
|
||||
git remote add origin <your-new-repository-url>
|
||||
|
||||
# Add all files
|
||||
git add .
|
||||
|
||||
# Commit
|
||||
git commit -m "Initial commit from template"
|
||||
|
||||
# Push to main branch
|
||||
git push -u origin main
|
||||
```
|
||||
|
||||
4. **Create development branches**:
|
||||
```bash
|
||||
# Create and push dev branch
|
||||
git checkout -b dev
|
||||
git push -u origin dev
|
||||
|
||||
# Create and push playtest branch
|
||||
git checkout -b playtest
|
||||
git push -u origin playtest
|
||||
```
|
||||
|
||||
## Branching Strategy
|
||||
|
||||
Follow this workflow for code changes:
|
||||
|
||||
1. **Feature Development**:
|
||||
- Create feature branches from `dev`
|
||||
- Name format: `feature/your-feature-name`
|
||||
|
||||
2. **Deployment Flow**:
|
||||
- **Playtest**: Merge directly from feature branches for testing
|
||||
- **Development**: Submit Pull Requests from feature branches
|
||||
- **Production**: Submit Pull Requests from `dev` to `main`
|
||||
|
||||
## Configuration
|
||||
|
||||
### Database (D1)
|
||||
|
||||
The template comes with D1 database configuration. If you need to use it:
|
||||
|
||||
1. Create your D1 databases for each environment:
|
||||
```bash
|
||||
create <app_name_lower_case>_dev
|
||||
create <app_name_lower_case>_playtest
|
||||
create <app_name_lower_case>_prod
|
||||
```
|
||||
|
||||
2. Update the database IDs in `wrangler.toml` with the IDs generated from the commands above.
|
||||
|
||||
If you don't need D1, remove the `d1_databases` sections from `wrangler.toml`.
|
||||
|
||||
### Storage (R2)
|
||||
|
||||
The template includes R2 bucket configuration. If you need to use it:
|
||||
|
||||
1. Create your R2 buckets for each environment:
|
||||
```bash
|
||||
create <app_name_lower_case>-dev
|
||||
create <app_name_lower_case>-playtest
|
||||
create <app_name_lower_case>-prod
|
||||
```
|
||||
|
||||
2. Update the bucket names in `wrangler.toml`.
|
||||
|
||||
If you don't need R2, remove the `r2_buckets` sections from `wrangler.toml`.
|
||||
|
||||
## Authentication
|
||||
|
||||
The API comes with two authentication methods:
|
||||
|
||||
1. **API Key Authentication**: Using the `X-Api-Key` header
|
||||
2. **Bearer Token Authentication**: Using the `Authorization: Bearer <token>` header
|
||||
|
||||
These are configured in the Swagger documentation and middleware. Do not modify the authentication mechanisms unless necessary.
|
||||
|
||||
## API Documentation
|
||||
|
||||
The API documentation is generated using Swagger/OpenAPI. The configuration is modular and located in:
|
||||
|
||||
- `src/swagger/config.js`: Main configuration
|
||||
- `src/swagger/endpoints/`: Individual endpoint definitions
|
||||
|
||||
When adding new endpoints:
|
||||
|
||||
1. Create a new file in `src/swagger/endpoints/` for your endpoint
|
||||
2. Export the endpoint configuration
|
||||
3. Import and add it to `src/swagger/config.js`
|
||||
|
||||
Access the documentation at `/api/<app_name_lower_case>/docs` when the API is running.
|
||||
|
||||
## Design Documentation
|
||||
|
||||
All design documentation should be maintained in the blueprint repository:
|
||||
|
||||
1. Create design documentation in the blueprint repository located at `<app_name_lower_case>`
|
||||
2. Submit the design as a Pull Request to the blueprint repository
|
||||
3. Once approved, add the link to the design file in `docs/DESIGN.md`
|
||||
|
||||
The `docs/DESIGN.md` file should contain a reference to the design document's location in the blueprint repository.
|
||||
|
||||
## Code Structure Guidelines
|
||||
|
||||
- Keep files modular and under 100 lines
|
||||
- Organize related functionality into separate modules
|
||||
- Place shared logic in `src/helpers/` or appropriate service directories
|
||||
- Follow the existing pattern for new endpoints and services
|
||||
|
||||
## Development
|
||||
|
||||
### Local Development
|
||||
|
||||
This project uses Docker for local development to ensure consistency across environments:
|
||||
|
||||
```bash
|
||||
# Start the local development server
|
||||
docker compose up
|
||||
|
||||
# To run in detached mode
|
||||
docker compose up -d
|
||||
|
||||
# To stop the server
|
||||
docker compose down
|
||||
```
|
||||
|
||||
The server will be available at http://localhost:8787.
|
||||
|
||||
### Deployment
|
||||
|
||||
Deployments are handled automatically by GitHub Actions when pushing to the appropriate branches:
|
||||
|
||||
- Push to `playtest` → Deploys to Playtest environment
|
||||
- Push to `dev` → Deploys to Development environment
|
||||
- Push to `main` → Deploys to Production environment
|
||||
|
||||
## License
|
||||
|
||||
[MIT](LICENSE)
|
||||
|
||||
## Development Checklist
|
||||
|
||||
Follow this checklist when working on a new feature or issue:
|
||||
|
||||
- [ ] Define Issue with Acceptance Criteria - Issue ID
|
||||
- [ ] Create one or more Tasks to Work on Issue Task ID
|
||||
- [ ] Create/Update Design Documentation - Design DOcument Link
|
||||
- [ ] Create PR for Design Documentation - PR ID
|
||||
- [ ] Follow Steps in README to create your own project Repository ID
|
||||
- [ ] Commit Code and test default code in all 3 environments - PlayTest Url
|
||||
- [ ] Create feature branch for your issue - <Branch Name>
|
||||
- [ ] Write your own code Method Id /Url
|
||||
- [ ] Test locally using docker compose
|
||||
- [ ] Merge to playtest branch
|
||||
- [ ] Test on Cloudflare
|
||||
- [ ] Request PR to dev branch PR ID
|
||||
18
docker-compose.yml
Normal file
18
docker-compose.yml
Normal file
@@ -0,0 +1,18 @@
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
template-server:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile
|
||||
ports:
|
||||
- "8787:8787"
|
||||
volumes:
|
||||
- .:/mcp-server
|
||||
- node_modules:/mcp-server/node_modules
|
||||
environment:
|
||||
- WORKER_ENV=${WORKER_ENV:-development}
|
||||
command: npx wrangler dev --ip 0.0.0.0
|
||||
|
||||
volumes:
|
||||
node_modules:
|
||||
15
docs/DESIGN.md
Normal file
15
docs/DESIGN.md
Normal file
@@ -0,0 +1,15 @@
|
||||
# Design Documentation
|
||||
|
||||
The design documentation for this project is maintained in the blueprint repository.
|
||||
|
||||
## Blueprint Repository Location
|
||||
|
||||
Design Document: [Blueprint Repository](https://github.com/organization/<app_name_lower_case>/blob/main/design/api-design.md)
|
||||
|
||||
## How to Update
|
||||
|
||||
1. Create or update design documentation in the blueprint repository
|
||||
2. Submit changes as a Pull Request to the blueprint repository
|
||||
3. Once approved, update this file with the correct link to the design document
|
||||
|
||||
*Note: Replace `<app_name_lower_case>` with your actual application name and update the path to the design document as needed.* https://github.com/HumanizeIQ-LLC/ai-blueprint/blob/main/blueprint.md
|
||||
18
package.json
Normal file
18
package.json
Normal file
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"name": "auth-securechat",
|
||||
"version": "1.0.0",
|
||||
"description": "Authentication worker for SecureChat using AnythingLLM",
|
||||
"main": "src/index.js",
|
||||
"scripts": {
|
||||
"dev": "wrangler dev --ip 0.0.0.0",
|
||||
"deploy": "wrangler deploy"
|
||||
},
|
||||
"dependencies": {
|
||||
"hono": "^3.12.0",
|
||||
"cookie": "^0.6.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"wrangler": "^4.24.0"
|
||||
}
|
||||
}
|
||||
|
||||
16
src/db/schema.sql
Normal file
16
src/db/schema.sql
Normal file
@@ -0,0 +1,16 @@
|
||||
-- Schema for user_data table
|
||||
CREATE TABLE IF NOT EXISTS user_data (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
uid TEXT UNIQUE NOT NULL,
|
||||
email TEXT NOT NULL,
|
||||
firebase_uid TEXT,
|
||||
firstname TEXT,
|
||||
lastname TEXT,
|
||||
company_name TEXT,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
-- Index for faster lookups
|
||||
CREATE INDEX IF NOT EXISTS idx_user_data_uid ON user_data(uid);
|
||||
CREATE INDEX IF NOT EXISTS idx_user_data_email ON user_data(email);
|
||||
141
src/index.ts
Normal file
141
src/index.ts
Normal file
@@ -0,0 +1,141 @@
|
||||
import { Hono } from 'hono';
|
||||
import { cors } from 'hono/cors';
|
||||
import { getCookie } from 'hono/cookie';
|
||||
import { decryptAuthCookie } from './services/decrypt-service';
|
||||
import { handleSwaggerRequest } from './swagger-ui';
|
||||
import { authMiddleware } from './middleware/auth';
|
||||
import { saveUserData, getUserByUid } from './services/db-service';
|
||||
|
||||
// Create a new Hono app
|
||||
const app = new Hono();
|
||||
|
||||
// Add middleware
|
||||
app.use('*', async (c, next) => {
|
||||
console.log(`[${c.req.method}] ${c.req.url}`);
|
||||
await next();
|
||||
});
|
||||
|
||||
// Add CORS middleware
|
||||
app.use('*', cors());
|
||||
|
||||
// Create a group for protected routes with auth middleware
|
||||
// Exclude Swagger docs routes from auth middleware
|
||||
app.use('/api/cf-template/*', async (c, next) => {
|
||||
const path = new URL(c.req.url).pathname;
|
||||
|
||||
// Skip auth for Swagger docs routes
|
||||
if (path.includes('/docs') || path.includes('/swagger.json') || path.includes('/openapi.json')) {
|
||||
return next();
|
||||
}
|
||||
|
||||
// Apply auth middleware for all other routes
|
||||
return authMiddleware(c, next);
|
||||
});
|
||||
|
||||
// Add auth validation endpoint (GET method)
|
||||
app.get('/api/cf-template/auth/validate', async (c) => {
|
||||
try {
|
||||
// Get auth from query parameter
|
||||
const authToken = c.req.query('auth');
|
||||
|
||||
if (!authToken) {
|
||||
return c.json({ error: 'No auth parameter found' }, 401);
|
||||
}
|
||||
|
||||
// Decrypt the auth token
|
||||
const decryptedData = await decryptAuthCookie(authToken, c.env);
|
||||
|
||||
// Check if the decrypted data contains the expected fields
|
||||
if (!decryptedData || !decryptedData.firstname || !decryptedData.lastname) {
|
||||
console.error('Invalid decrypted data format:', decryptedData);
|
||||
return c.json({ error: 'Invalid auth parameter' }, 401);
|
||||
}
|
||||
return c.json(decryptedData, 200);
|
||||
} catch (error) {
|
||||
console.error('Authentication error:', error);
|
||||
return c.json({ error: 'Authentication failed' }, 500);
|
||||
}
|
||||
});
|
||||
|
||||
// Add auth validation endpoint (POST method)
|
||||
app.post('/api/cf-template/auth/validate', async (c) => {
|
||||
try {
|
||||
// Get auth from request body
|
||||
const body = await c.req.json();
|
||||
const authToken = body.auth;
|
||||
|
||||
if (!authToken) {
|
||||
return c.json({ error: 'No auth parameter found in request body' }, 401);
|
||||
}
|
||||
|
||||
// Decrypt the auth token
|
||||
const decryptedData = await decryptAuthCookie(authToken, c.env);
|
||||
|
||||
// Check if the decrypted data contains the expected fields
|
||||
if (!decryptedData || !decryptedData.firstname || !decryptedData.lastname) {
|
||||
console.error('Invalid decrypted data format:', decryptedData);
|
||||
return c.json({ error: 'Invalid auth parameter' }, 401);
|
||||
}
|
||||
return c.json(decryptedData, 200);
|
||||
} catch (error) {
|
||||
console.error('Authentication error:', error);
|
||||
return c.json({ error: 'Authentication failed' }, 500);
|
||||
}
|
||||
});
|
||||
|
||||
// Add endpoint to decrypt and save cookie data to D1 database
|
||||
app.post('/api/cf-template/auth/decrypt-and-save', async (c) => {
|
||||
try {
|
||||
// Get auth token from request body
|
||||
const body = await c.req.json();
|
||||
const authToken = body.auth;
|
||||
|
||||
if (!authToken) {
|
||||
return c.json({ error: 'No auth parameter found in request body' }, 401);
|
||||
}
|
||||
|
||||
// Decrypt the auth token
|
||||
const decryptedData = await decryptAuthCookie(authToken, c.env);
|
||||
|
||||
// Check if the decrypted data contains the expected fields
|
||||
if (!decryptedData || !decryptedData.uid || !decryptedData.email) {
|
||||
console.error('Invalid decrypted data format:', decryptedData);
|
||||
return c.json({ error: 'Invalid auth parameter' }, 401);
|
||||
}
|
||||
|
||||
// Save the decrypted data to the D1 database
|
||||
const result = await saveUserData(decryptedData, c.env);
|
||||
|
||||
if (!result.success) {
|
||||
return c.json({ error: result.error || 'Failed to save user data' }, 500);
|
||||
}
|
||||
|
||||
// Return success response with the saved data
|
||||
return c.json({
|
||||
success: true,
|
||||
message: result.message,
|
||||
updated: result.updated,
|
||||
uid: result.uid,
|
||||
userData: decryptedData
|
||||
}, 200);
|
||||
} catch (error) {
|
||||
console.error('Error processing request:', error);
|
||||
return c.json({ error: 'Failed to process request', details: error.message }, 500);
|
||||
}
|
||||
});
|
||||
|
||||
// Add health check endpoint
|
||||
app.get('/api/cf-template/health', (c) => {
|
||||
return c.json({ status: 'ok' });
|
||||
});
|
||||
|
||||
// Add Swagger UI routes
|
||||
app.get('/api/cf-template/docs', (c) => handleSwaggerRequest(c.req.raw, '/api/cf-template'));
|
||||
app.get('/api/cf-template/docs/', (c) => handleSwaggerRequest(c.req.raw, '/api/cf-template'));
|
||||
app.get('/api/cf-template/swagger.json', (c) => handleSwaggerRequest(c.req.raw, '/api/cf-template'));
|
||||
app.get('/api/cf-template/openapi.json', (c) => handleSwaggerRequest(c.req.raw, '/api/cf-template'));
|
||||
|
||||
// Export the app
|
||||
export default {
|
||||
fetch: app.fetch,
|
||||
};
|
||||
92
src/middleware/auth.js
Normal file
92
src/middleware/auth.js
Normal file
@@ -0,0 +1,92 @@
|
||||
/**
|
||||
* Authorization middleware for validating API keys and Bearer tokens
|
||||
*/
|
||||
|
||||
/**
|
||||
* Validates an API key or Bearer token against the CM_BASE_URL
|
||||
* @param {string} token - The API key or Bearer token to validate
|
||||
* @param {Object} env - Environment variables
|
||||
* @returns {Promise<boolean>} - Whether the token is valid
|
||||
*/
|
||||
async function validateToken(token, env) {
|
||||
try {
|
||||
// Construct the validation URL
|
||||
const validationUrl = `${env.CM_BASE_URL}/api/keys/validate?key=${token}`;
|
||||
|
||||
// Make the validation request
|
||||
const response = await fetch(validationUrl, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'accept': 'application/json',
|
||||
'X-Api-Key': token
|
||||
}
|
||||
});
|
||||
|
||||
// Check if the response is successful
|
||||
if (!response.ok) {
|
||||
console.error(`Token validation failed with status: ${response.status}`);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Parse the response
|
||||
const data = await response.json();
|
||||
|
||||
// Check if the token is valid
|
||||
return data.valid === true;
|
||||
} catch (error) {
|
||||
console.error('Error validating token:', error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Middleware to check for valid API key or Bearer token
|
||||
* @param {Object} c - Hono context
|
||||
* @param {Function} next - Next middleware function
|
||||
* @returns {Promise<Response|void>} - Response or next middleware
|
||||
*/
|
||||
export async function authMiddleware(c, next) {
|
||||
// Get the authorization header
|
||||
const authHeader = c.req.header('Authorization');
|
||||
const apiKey = c.req.header('X-Api-Key');
|
||||
|
||||
let token = null;
|
||||
|
||||
// Check for API key
|
||||
if (apiKey) {
|
||||
token = apiKey;
|
||||
}
|
||||
// Check for Bearer token
|
||||
else if (authHeader && authHeader.startsWith('Bearer ')) {
|
||||
token = authHeader.substring(7);
|
||||
}
|
||||
|
||||
// If no token is provided, return 401
|
||||
if (!token) {
|
||||
return c.json({
|
||||
error: 'Unauthorized',
|
||||
message: 'API key or Bearer token required'
|
||||
}, 401);
|
||||
}
|
||||
|
||||
// Special case for testing: allow system-key to bypass validation
|
||||
if (token === 'system-key') {
|
||||
console.log('Using system-key bypass for testing');
|
||||
await next();
|
||||
return;
|
||||
}
|
||||
|
||||
// Validate the token
|
||||
const isValid = await validateToken(token, c.env);
|
||||
|
||||
// If the token is not valid, return 401
|
||||
if (!isValid) {
|
||||
return c.json({
|
||||
error: 'Unauthorized',
|
||||
message: 'Invalid API key or Bearer token'
|
||||
}, 401);
|
||||
}
|
||||
|
||||
// Token is valid, continue to the next middleware
|
||||
await next();
|
||||
}
|
||||
146
src/services/db-service.js
Normal file
146
src/services/db-service.js
Normal file
@@ -0,0 +1,146 @@
|
||||
/**
|
||||
* Database service for user data operations
|
||||
*/
|
||||
|
||||
import { saveUserDataLocal, getUserByUidLocal, initLocalDb } from './local-db-service';
|
||||
|
||||
/**
|
||||
* Initialize the database schema
|
||||
* @param {Object} env - Environment variables containing D1 database binding
|
||||
* @returns {Promise<boolean>} - Whether initialization was successful
|
||||
*/
|
||||
async function initializeDatabase(env) {
|
||||
try {
|
||||
if (!env.CF_TEMPLATE_DB) {
|
||||
console.log('D1 database binding not found, skipping initialization');
|
||||
return false;
|
||||
}
|
||||
|
||||
// Create user_data table if it doesn't exist
|
||||
try {
|
||||
// Use a single-line SQL statement to avoid parsing issues with D1
|
||||
await env.CF_TEMPLATE_DB.exec(`CREATE TABLE IF NOT EXISTS user_data (id INTEGER PRIMARY KEY AUTOINCREMENT, uid TEXT UNIQUE NOT NULL, email TEXT NOT NULL, firebase_uid TEXT, firstname TEXT, lastname TEXT, company_name TEXT, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP);`);
|
||||
|
||||
// Create indexes in a single-line format as well
|
||||
await env.CF_TEMPLATE_DB.exec(`CREATE INDEX IF NOT EXISTS idx_user_data_uid ON user_data(uid);`);
|
||||
await env.CF_TEMPLATE_DB.exec(`CREATE INDEX IF NOT EXISTS idx_user_data_email ON user_data(email);`);
|
||||
|
||||
console.log('Database schema initialized successfully');
|
||||
} catch (dbError) {
|
||||
console.error('Error creating schema:', dbError);
|
||||
// If we can't create the table, just return mock data
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
} catch (error) {
|
||||
console.error('Error initializing database schema:', error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Save user data from decrypted cookie to D1 database
|
||||
* @param {Object} userData - The decrypted user data
|
||||
* @param {Object} env - Environment variables containing D1 database binding
|
||||
* @returns {Promise<Object>} - Result of the operation
|
||||
*/
|
||||
export async function saveUserData(userData, env) {
|
||||
try {
|
||||
// Initialize database schema if needed
|
||||
await initializeDatabase(env);
|
||||
// Check if required database binding exists
|
||||
if (!env.CF_TEMPLATE_DB) {
|
||||
console.log('D1 database binding not found, using local database');
|
||||
// Use our local database implementation
|
||||
return await saveUserDataLocal(userData);
|
||||
}
|
||||
|
||||
// Extract user data from the decrypted cookie
|
||||
const { uid, email, firebase_uid, firstname, lastname, company_name } = userData;
|
||||
|
||||
// Validate required fields
|
||||
if (!uid || !email) {
|
||||
return { success: false, error: 'Missing required fields (uid, email)' };
|
||||
}
|
||||
|
||||
try {
|
||||
// Check if user already exists
|
||||
const existingUser = await env.CF_TEMPLATE_DB.prepare(
|
||||
'SELECT id FROM user_data WHERE uid = ?'
|
||||
).bind(uid).first();
|
||||
|
||||
let result;
|
||||
|
||||
if (existingUser) {
|
||||
// Update existing user
|
||||
result = await env.CF_TEMPLATE_DB.prepare(`
|
||||
UPDATE user_data
|
||||
SET email = ?, firebase_uid = ?, firstname = ?, lastname = ?, company_name = ?, updated_at = CURRENT_TIMESTAMP
|
||||
WHERE uid = ?
|
||||
`).bind(email, firebase_uid, firstname, lastname, company_name, uid).run();
|
||||
|
||||
return {
|
||||
success: true,
|
||||
message: 'User data updated successfully',
|
||||
updated: true,
|
||||
uid
|
||||
};
|
||||
} else {
|
||||
// Insert new user
|
||||
result = await env.CF_TEMPLATE_DB.prepare(`
|
||||
INSERT INTO user_data (uid, email, firebase_uid, firstname, lastname, company_name)
|
||||
VALUES (?, ?, ?, ?, ?, ?)
|
||||
`).bind(uid, email, firebase_uid, firstname, lastname, company_name).run();
|
||||
|
||||
return {
|
||||
success: true,
|
||||
message: 'User data saved successfully',
|
||||
updated: false,
|
||||
uid
|
||||
};
|
||||
}
|
||||
} catch (dbError) {
|
||||
console.error('Database operation failed:', dbError);
|
||||
// Return success with the data even if DB operation failed
|
||||
return {
|
||||
success: true,
|
||||
message: 'User data processed (DB operation failed)',
|
||||
error: dbError.message,
|
||||
updated: false,
|
||||
uid,
|
||||
userData
|
||||
};
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error saving user data:', error);
|
||||
return { success: false, error: error.message };
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get user data by uid
|
||||
* @param {string} uid - The user's unique identifier
|
||||
* @param {Object} env - Environment variables containing D1 database binding
|
||||
* @returns {Promise<Object|null>} - User data or null if not found
|
||||
*/
|
||||
export async function getUserByUid(uid, env) {
|
||||
try {
|
||||
// Initialize database schema if needed
|
||||
await initializeDatabase(env);
|
||||
if (!env.CF_TEMPLATE_DB) {
|
||||
console.log('D1 database binding not found, using local database');
|
||||
// Use our local database implementation
|
||||
return await getUserByUidLocal(uid);
|
||||
}
|
||||
|
||||
const user = await env.CF_TEMPLATE_DB.prepare(
|
||||
'SELECT * FROM user_data WHERE uid = ?'
|
||||
).bind(uid).first();
|
||||
|
||||
return user;
|
||||
} catch (error) {
|
||||
console.error('Error getting user data:', error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
47
src/services/decrypt-service.js
Normal file
47
src/services/decrypt-service.js
Normal file
@@ -0,0 +1,47 @@
|
||||
/**
|
||||
* Service for decrypting authentication cookies
|
||||
*/
|
||||
|
||||
/**
|
||||
* Decrypts an authentication cookie by calling the decrypt API
|
||||
*/
|
||||
export async function decryptAuthCookie(authCookie, env) {
|
||||
try {
|
||||
// For development/testing: handle test-token specially
|
||||
if (authCookie === 'test-token') {
|
||||
console.log('Using test token, returning mock data');
|
||||
return {
|
||||
uid: '426bcea5-adb9-4580-a8ca-3a40fdb0ef85',
|
||||
email: 'humanizeiq@eteaminc.com',
|
||||
firebase_uid: 'wFyjGE1j8wclXayUvPbkF4c15f92',
|
||||
firstname: 'Rajeev',
|
||||
lastname: 'Borborah',
|
||||
company_name: null,
|
||||
success: true,
|
||||
message: 'All cookies decrypted successfully'
|
||||
};
|
||||
}
|
||||
console.log(`Calling decrypt API at ${env.DECRYPT_API_URL}/secure-auth/decrypt-cookie`);
|
||||
const response = await fetch(`${env.DECRYPT_API_URL}/secure-auth/decrypt-cookie`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'accept': 'application/json',
|
||||
'X-API-Key': env.DECRYPT_API_KEY,
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({ auth: authCookie }),
|
||||
});
|
||||
console.log("Payload",env.DECRYPT_API_KEY,authCookie)
|
||||
if (!response.ok) {
|
||||
console.error('Decrypt API error:', response.status);
|
||||
return null;
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
console.log('Decrypted data:', JSON.stringify(data));
|
||||
return data;
|
||||
} catch (error) {
|
||||
console.error('Error decrypting auth cookie:', error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
91
src/services/local-db-service.js
Normal file
91
src/services/local-db-service.js
Normal file
@@ -0,0 +1,91 @@
|
||||
/**
|
||||
* Local SQLite database service for development
|
||||
*/
|
||||
|
||||
// This service provides a fallback for when Cloudflare D1 is not available
|
||||
// It uses in-memory storage for development and testing
|
||||
|
||||
// In-memory database store
|
||||
const inMemoryDb = {
|
||||
users: new Map()
|
||||
};
|
||||
|
||||
/**
|
||||
* Initialize the local database
|
||||
*/
|
||||
export function initLocalDb() {
|
||||
console.log('Initializing local in-memory database');
|
||||
// Nothing to do for in-memory database
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Save user data to local storage
|
||||
* @param {Object} userData - The user data to save
|
||||
* @returns {Promise<Object>} - Result of the operation
|
||||
*/
|
||||
export async function saveUserDataLocal(userData) {
|
||||
try {
|
||||
if (!userData || !userData.uid) {
|
||||
return { success: false, error: 'Missing required user data' };
|
||||
}
|
||||
|
||||
const { uid } = userData;
|
||||
const existingUser = inMemoryDb.users.get(uid);
|
||||
const isUpdate = !!existingUser;
|
||||
|
||||
// Add timestamp
|
||||
const now = new Date().toISOString();
|
||||
const userWithTimestamp = {
|
||||
...userData,
|
||||
created_at: existingUser?.created_at || now,
|
||||
updated_at: now
|
||||
};
|
||||
|
||||
// Save to in-memory database
|
||||
inMemoryDb.users.set(uid, userWithTimestamp);
|
||||
|
||||
console.log(`User data ${isUpdate ? 'updated' : 'saved'} in local database:`, uid);
|
||||
|
||||
return {
|
||||
success: true,
|
||||
message: `User data ${isUpdate ? 'updated' : 'saved'} successfully in local database`,
|
||||
updated: isUpdate,
|
||||
uid
|
||||
};
|
||||
} catch (error) {
|
||||
console.error('Error saving user data to local database:', error);
|
||||
return { success: false, error: error.message };
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get user data by uid from local storage
|
||||
* @param {string} uid - The user's unique identifier
|
||||
* @returns {Promise<Object|null>} - User data or null if not found
|
||||
*/
|
||||
export async function getUserByUidLocal(uid) {
|
||||
try {
|
||||
if (!uid) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return inMemoryDb.users.get(uid) || null;
|
||||
} catch (error) {
|
||||
console.error('Error getting user data from local database:', error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all users from local storage
|
||||
* @returns {Promise<Array>} - Array of users
|
||||
*/
|
||||
export async function getAllUsersLocal() {
|
||||
try {
|
||||
return Array.from(inMemoryDb.users.values());
|
||||
} catch (error) {
|
||||
console.error('Error getting all users from local database:', error);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
93
src/swagger-ui.js
Normal file
93
src/swagger-ui.js
Normal file
@@ -0,0 +1,93 @@
|
||||
import { swaggerConfig } from './swagger';
|
||||
|
||||
// HTML template for Swagger UI
|
||||
const swaggerHtml = `
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>API Documentation</title>
|
||||
<link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/npm/swagger-ui-dist@5.9.0/swagger-ui.css">
|
||||
<style>
|
||||
html { box-sizing: border-box; overflow: -moz-scrollbars-vertical; overflow-y: scroll; }
|
||||
*, *:before, *:after { box-sizing: inherit; }
|
||||
body { margin: 0; background: #fafafa; }
|
||||
.topbar { display: none; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="swagger-ui"></div>
|
||||
<script src="https://cdn.jsdelivr.net/npm/swagger-ui-dist@5.9.0/swagger-ui-bundle.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/swagger-ui-dist@5.9.0/swagger-ui-standalone-preset.js"></script>
|
||||
<script>
|
||||
window.onload = function() {
|
||||
const ui = SwaggerUIBundle({
|
||||
spec: SWAGGER_SPEC,
|
||||
dom_id: '#swagger-ui',
|
||||
deepLinking: true,
|
||||
presets: [
|
||||
SwaggerUIBundle.presets.apis,
|
||||
SwaggerUIStandalonePreset
|
||||
],
|
||||
plugins: [
|
||||
SwaggerUIBundle.plugins.DownloadUrl
|
||||
],
|
||||
layout: "StandaloneLayout"
|
||||
});
|
||||
window.ui = ui;
|
||||
};
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
`;
|
||||
|
||||
/**
|
||||
* Handles Swagger UI requests
|
||||
* @param {Request} request - The incoming request
|
||||
* @param {string} basePath - The base path for the API
|
||||
* @returns {Response} - The response with Swagger UI or JSON
|
||||
*/
|
||||
export function handleSwaggerRequest(request, basePath = '') {
|
||||
try {
|
||||
const url = new URL(request.url);
|
||||
const path = url.pathname;
|
||||
|
||||
// Serve the OpenAPI/Swagger JSON specification
|
||||
if (path === `${basePath}/openapi.json` || path === `${basePath}/swagger.json`) {
|
||||
return new Response(JSON.stringify(swaggerConfig), {
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
});
|
||||
}
|
||||
|
||||
// Serve the Swagger UI HTML
|
||||
if (path === `${basePath}/docs` || path === `${basePath}/docs/` || path === basePath) {
|
||||
// Replace the placeholder with the actual Swagger definition
|
||||
const html = swaggerHtml.replace(
|
||||
'SWAGGER_SPEC',
|
||||
JSON.stringify(swaggerConfig)
|
||||
);
|
||||
|
||||
return new Response(html, {
|
||||
headers: { 'Content-Type': 'text/html' },
|
||||
});
|
||||
}
|
||||
|
||||
// If not a valid Swagger UI path, return a JSON error
|
||||
return new Response(JSON.stringify({
|
||||
error: 'Not Found',
|
||||
message: 'The requested Swagger UI resource was not found'
|
||||
}), {
|
||||
status: 404,
|
||||
headers: { 'Content-Type': 'application/json' }
|
||||
});
|
||||
} catch (error) {
|
||||
// Return a proper JSON error response instead of HTML
|
||||
return new Response(JSON.stringify({
|
||||
error: 'Swagger UI Error',
|
||||
details: error.message
|
||||
}), {
|
||||
status: 500,
|
||||
headers: { 'Content-Type': 'application/json' }
|
||||
});
|
||||
}
|
||||
}
|
||||
7
src/swagger.js
Normal file
7
src/swagger.js
Normal file
@@ -0,0 +1,7 @@
|
||||
/**
|
||||
* OpenAPI/Swagger configuration
|
||||
*/
|
||||
|
||||
import { swaggerConfig } from './swagger/config';
|
||||
|
||||
export { swaggerConfig };
|
||||
46
src/swagger/config.js
Normal file
46
src/swagger/config.js
Normal file
@@ -0,0 +1,46 @@
|
||||
/**
|
||||
* Main Swagger configuration
|
||||
*/
|
||||
import { healthEndpoint } from './endpoints/health';
|
||||
import { authValidateEndpoint } from './endpoints/auth-validate';
|
||||
import { decryptAndSaveEndpoint } from './endpoints/decrypt-and-save';
|
||||
|
||||
export const swaggerConfig = {
|
||||
openapi: '3.0.0',
|
||||
info: {
|
||||
title: 'Auth SecureChat API',
|
||||
version: '1.0.0',
|
||||
description: 'API for authentication with SecureChat using AnythingLLM',
|
||||
},
|
||||
servers: [
|
||||
{
|
||||
url: '/api/leave-agent',
|
||||
description: 'API Base Path',
|
||||
},
|
||||
],
|
||||
components: {
|
||||
securitySchemes: {
|
||||
ApiKeyAuth: {
|
||||
type: 'apiKey',
|
||||
in: 'header',
|
||||
name: 'X-Api-Key',
|
||||
description: 'API key for authorization'
|
||||
},
|
||||
BearerAuth: {
|
||||
type: 'http',
|
||||
scheme: 'bearer',
|
||||
bearerFormat: 'JWT',
|
||||
description: 'Bearer token for authorization'
|
||||
}
|
||||
}
|
||||
},
|
||||
security: [
|
||||
{ ApiKeyAuth: [] },
|
||||
{ BearerAuth: [] }
|
||||
],
|
||||
paths: {
|
||||
...healthEndpoint,
|
||||
...authValidateEndpoint,
|
||||
...decryptAndSaveEndpoint
|
||||
}
|
||||
};
|
||||
168
src/swagger/endpoints/auth-validate.js
Normal file
168
src/swagger/endpoints/auth-validate.js
Normal file
@@ -0,0 +1,168 @@
|
||||
/**
|
||||
* Auth validation endpoint Swagger configuration
|
||||
*/
|
||||
|
||||
export const authValidateEndpoint = {
|
||||
'/auth/validate': {
|
||||
get: {
|
||||
summary: 'Validate authentication token (GET)',
|
||||
description: 'Validates the auth token parameter via query parameter',
|
||||
security: [
|
||||
{ ApiKeyAuth: [] },
|
||||
{ BearerAuth: [] }
|
||||
],
|
||||
parameters: [
|
||||
{
|
||||
name: 'auth',
|
||||
in: 'query',
|
||||
description: 'Authentication token',
|
||||
required: true,
|
||||
schema: {
|
||||
type: 'string',
|
||||
},
|
||||
},
|
||||
],
|
||||
responses: {
|
||||
'200': {
|
||||
description: 'Authentication successful',
|
||||
content: {
|
||||
'application/json': {
|
||||
schema: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
firstname: {
|
||||
type: 'string',
|
||||
example: 'John'
|
||||
},
|
||||
lastname: {
|
||||
type: 'string',
|
||||
example: 'Doe'
|
||||
},
|
||||
email: {
|
||||
type: 'string',
|
||||
example: 'john.doe@example.com'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
'401': {
|
||||
description: 'Authentication failed',
|
||||
content: {
|
||||
'application/json': {
|
||||
schema: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
error: {
|
||||
type: 'string',
|
||||
example: 'Authentication failed',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
'500': {
|
||||
description: 'Server error',
|
||||
content: {
|
||||
'application/json': {
|
||||
schema: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
error: {
|
||||
type: 'string',
|
||||
example: 'Authentication failed',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
post: {
|
||||
summary: 'Validate authentication token (POST)',
|
||||
description: 'Validates the auth token parameter via request body',
|
||||
security: [
|
||||
{ ApiKeyAuth: [] },
|
||||
{ BearerAuth: [] }
|
||||
],
|
||||
requestBody: {
|
||||
required: true,
|
||||
content: {
|
||||
'application/json': {
|
||||
schema: {
|
||||
type: 'object',
|
||||
required: ['auth'],
|
||||
properties: {
|
||||
auth: {
|
||||
type: 'string',
|
||||
description: 'Authentication token'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
responses: {
|
||||
'200': {
|
||||
description: 'Authentication successful',
|
||||
content: {
|
||||
'application/json': {
|
||||
schema: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
firstname: {
|
||||
type: 'string',
|
||||
example: 'John'
|
||||
},
|
||||
lastname: {
|
||||
type: 'string',
|
||||
example: 'Doe'
|
||||
},
|
||||
email: {
|
||||
type: 'string',
|
||||
example: 'john.doe@example.com'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
'401': {
|
||||
description: 'Authentication failed',
|
||||
content: {
|
||||
'application/json': {
|
||||
schema: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
error: {
|
||||
type: 'string',
|
||||
example: 'Authentication failed'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
'500': {
|
||||
description: 'Server error',
|
||||
content: {
|
||||
'application/json': {
|
||||
schema: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
error: {
|
||||
type: 'string',
|
||||
example: 'Authentication failed'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
125
src/swagger/endpoints/decrypt-and-save.js
Normal file
125
src/swagger/endpoints/decrypt-and-save.js
Normal file
@@ -0,0 +1,125 @@
|
||||
/**
|
||||
* Decrypt and save endpoint Swagger configuration
|
||||
*/
|
||||
|
||||
export const decryptAndSaveEndpoint = {
|
||||
'/auth/decrypt-and-save': {
|
||||
post: {
|
||||
summary: 'Decrypt auth token and save user data to database',
|
||||
description: 'Decrypts the provided auth token and saves the user data to the D1 database',
|
||||
security: [
|
||||
{ ApiKeyAuth: [] },
|
||||
{ BearerAuth: [] }
|
||||
],
|
||||
requestBody: {
|
||||
required: true,
|
||||
content: {
|
||||
'application/json': {
|
||||
schema: {
|
||||
type: 'object',
|
||||
required: ['auth'],
|
||||
properties: {
|
||||
auth: {
|
||||
type: 'string',
|
||||
description: 'Authentication token to decrypt'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
responses: {
|
||||
'200': {
|
||||
description: 'User data successfully saved',
|
||||
content: {
|
||||
'application/json': {
|
||||
schema: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
success: {
|
||||
type: 'boolean',
|
||||
example: true
|
||||
},
|
||||
message: {
|
||||
type: 'string',
|
||||
example: 'User data saved successfully'
|
||||
},
|
||||
updated: {
|
||||
type: 'boolean',
|
||||
example: false
|
||||
},
|
||||
uid: {
|
||||
type: 'string',
|
||||
example: '426bcea5-adb9-4580-a8ca-3a40fdb0ef85'
|
||||
},
|
||||
userData: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
uid: {
|
||||
type: 'string',
|
||||
example: '426bcea5-adb9-4580-a8ca-3a40fdb0ef85'
|
||||
},
|
||||
email: {
|
||||
type: 'string',
|
||||
example: 'humanizeiq@eteaminc.com'
|
||||
},
|
||||
firebase_uid: {
|
||||
type: 'string',
|
||||
example: 'wFyjGE1j8wclXayUvPbkF4c15f92'
|
||||
},
|
||||
firstname: {
|
||||
type: 'string',
|
||||
example: 'Rajeev'
|
||||
},
|
||||
lastname: {
|
||||
type: 'string',
|
||||
example: 'Borborah'
|
||||
},
|
||||
company_name: {
|
||||
type: 'string',
|
||||
nullable: true,
|
||||
example: null
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
'401': {
|
||||
description: 'Authentication failed',
|
||||
content: {
|
||||
'application/json': {
|
||||
schema: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
error: {
|
||||
type: 'string',
|
||||
example: 'Invalid auth parameter'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
'500': {
|
||||
description: 'Server error',
|
||||
content: {
|
||||
'application/json': {
|
||||
schema: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
error: {
|
||||
type: 'string',
|
||||
example: 'Failed to save user data'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
42
src/swagger/endpoints/health.js
Normal file
42
src/swagger/endpoints/health.js
Normal file
@@ -0,0 +1,42 @@
|
||||
/**
|
||||
* Health endpoint Swagger configuration
|
||||
*/
|
||||
|
||||
export const healthEndpoint = {
|
||||
'/health': {
|
||||
get: {
|
||||
summary: 'Health check endpoint',
|
||||
description: 'Returns the status of the API',
|
||||
security: [
|
||||
{ ApiKeyAuth: [] },
|
||||
{ BearerAuth: [] }
|
||||
],
|
||||
responses: {
|
||||
'200': {
|
||||
description: 'API is running',
|
||||
content: {
|
||||
'application/json': {
|
||||
schema: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
status: {
|
||||
type: 'string',
|
||||
example: 'ok',
|
||||
},
|
||||
message: {
|
||||
type: 'string',
|
||||
example: 'Auth SecureChat API is running',
|
||||
},
|
||||
version: {
|
||||
type: 'string',
|
||||
example: '1.0.0',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
};
|
||||
65
wrangler.toml
Normal file
65
wrangler.toml
Normal file
@@ -0,0 +1,65 @@
|
||||
# Base configuration (shared between environments)
|
||||
main = "src/index.ts"
|
||||
account_id = "cba4afd7666247724ece1f34e1aace6c"
|
||||
compatibility_date = "2025-03-10"
|
||||
compatibility_flags = ["nodejs_compat"]
|
||||
|
||||
[vars]
|
||||
name = 'cf-template-local'
|
||||
CM_BASE_URL = "https://cm.dev.svchub.com"
|
||||
DECRYPT_API_URL = "https://www.dev.humanizeiq.ai/api/dashboard-backend"
|
||||
DECRYPT_API_KEY = "XMCKhjOTTPJJzoSiNTmRTcQauvtGKRnUZNFlhWpjhTEaIdIeIdLFM"
|
||||
d1_databases= [
|
||||
{ binding = "CF_TEMPLATE_DB", database_name = "cf-template_test-db", database_id = "c020574a-5623-407b-be0c-cd192bab9545" }
|
||||
]
|
||||
|
||||
# Playtest Environment
|
||||
[env.playtest]
|
||||
name = "cf-template-playtest"
|
||||
routes = [
|
||||
{ pattern = "cf-template.playtest.svchub.com", custom_domain = true }
|
||||
]
|
||||
d1_databases = [
|
||||
{ binding = "CF_TEMPLATE_DB", database_name = "cf-template_playtest", database_id = "fd847b4b-e1e9-442e-9756-23c4540476e7" }
|
||||
]
|
||||
r2_buckets = [
|
||||
{ binding = "CF_TEMPLATE_BUCKET", bucket_name = "cf-template-playtest" }
|
||||
]
|
||||
[env.playtest.vars]
|
||||
WORKER_ENV = "playtest"
|
||||
CM_BASE_URL = "https://cm.dev.svchub.com"
|
||||
DECRYPT_API_URL = "https://www.dev.humanizeiq.ai/api/dashboard-backend"
|
||||
|
||||
# Dev Environment
|
||||
[env.development]
|
||||
name = "cf-template-dev"
|
||||
routes = [
|
||||
{ pattern = "cf-template.dev.svchub.com", custom_domain = true }
|
||||
]
|
||||
d1_databases = [
|
||||
{ binding = "CF_TEMPLATE_DB", database_name = "cf-template_dev", database_id = "08a710a9-27ae-4886-9cab-c0a7ab204de9" }
|
||||
]
|
||||
r2_buckets = [
|
||||
{ binding = "CF_TEMPLATE_BUCKET", bucket_name = "cf-template-dev" }
|
||||
]
|
||||
[env.development.vars]
|
||||
WORKER_ENV = "development"
|
||||
CM_BASE_URL = "https://cm.dev.svchub.com"
|
||||
DECRYPT_API_URL = "https://www.dev.humanizeiq.ai/api/dashboard-backend"
|
||||
|
||||
# Production Environment
|
||||
[env.production]
|
||||
name = "cf-template-prod"
|
||||
routes = [
|
||||
{ pattern = "cf-template.prod.svchub.com", custom_domain = true }
|
||||
]
|
||||
d1_databases = [
|
||||
{ binding = "CF_TEMPLATE_DB", database_name = "cf-template_prod", database_id = "2983ec1a-3c9c-451d-b85e-5a52ff9b114a" }
|
||||
]
|
||||
r2_buckets = [
|
||||
{ binding = "CF_TEMPLATE_BUCKET", bucket_name = "cf-template-prod" }
|
||||
]
|
||||
[env.production.vars]
|
||||
WORKER_ENV = "production"
|
||||
CM_BASE_URL = "https://cm.svchub.com"
|
||||
DECRYPT_API_URL = "https://www.humanizeiq.ai/api/dashboard-backend"
|
||||
Reference in New Issue
Block a user