Add Netlify deploy workflow and unify edge handler

Introduces a new GitHub Actions workflow for deploying to Netlify, updates the Vercel workflow name, and refactors the edge function handler to support both Netlify and Vercel platforms with runtime detection. Adds Netlify-specific configuration and redirect files to enable shared handler logic, reducing code duplication and simplifying multi-platform deployments.
This commit is contained in:
xixu-me committed 2025-11-25 17:55:32 +08:00
1 parent 18ec41125f
commit 0e7aad4755
3 files changed
+113 -36

No files matched your search

+41
View File
@@ -0,0 +1,41 @@
name: Deploy to Netlify
on:
workflow_run:
workflows: ["Sync to Pages and Functions"]
types:
- completed
branches:
- main
workflow_dispatch:
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: false
jobs:
deploy:
runs-on: ubuntu-latest
timeout-minutes: 15
permissions:
contents: read
deployments: write
if: ${{ github.event.workflow_run.conclusion == 'success' }}
steps:
- name: Checkout functions branch
uses: actions/checkout@v6
with:
ref: functions
- name: Setup Node.js
uses: actions/setup-node@v6
with:
node-version: "20"
cache: "npm"
- name: Install Netlify CLI
run: npm install --global netlify-cli@latest
- name: Deploy to Netlify
run: netlify deploy --prod --dir=. --auth=${{ secrets.NETLIFY_AUTH_TOKEN }} --site=${{ secrets.NETLIFY_SITE_ID }}
+1 -1
View File
@@ -1,4 +1,4 @@
name: Deploy to Vercel Functions name: Deploy to Vercel
on: on:
workflow_run: workflow_run:
+71 -35
View File
@@ -212,7 +212,7 @@ jobs:
cp package-lock.json /tmp/functions-conversion/ 2>/dev/null || true cp package-lock.json /tmp/functions-conversion/ 2>/dev/null || true
cp LICENSE /tmp/functions-conversion/ cp LICENSE /tmp/functions-conversion/
- name: Create Vercel Edge Function handler - name: Create Edge Function handler
run: | run: |
mkdir -p /tmp/functions-conversion/api mkdir -p /tmp/functions-conversion/api
cat > /tmp/functions-conversion/api/index.js << 'EOF' cat > /tmp/functions-conversion/api/index.js << 'EOF'
@@ -237,51 +237,56 @@ jobs:
import { handleRequest } from '../src/index.js'; import { handleRequest } from '../src/index.js';
/** /**
* Vercel Edge Function handler for all routes. * Edge Function handler.
* *
* This adapter enables Xget to run on Vercel's Edge Runtime by mapping * @param {Request} request - Standard Web API Request object
* Vercel's environment model to Cloudflare Workers' expected format. * @param {Object} [context] - Platform-specific context (Netlify only)
* * @param {Object} [context.geo] - Geolocation data (Netlify)
* The Vercel Edge Runtime uses standard Web APIs (Request, Response, fetch), * @param {string} [context.ip] - Client IP address (Netlify)
* making it compatible with the existing Cloudflare Workers code. * @param {Object} [context.env] - Environment variables (Netlify)
* * @param {Function} [context.waitUntil] - Background task extension (Netlify)
* @param {Request} request - Standard Web API Request
* @returns {Promise<Response>} Standard Web API Response * @returns {Promise<Response>} Standard Web API Response
* *
* @example * @example
* // This is called automatically by Vercel Edge Runtime * // Netlify invokes with context
* // Runtime invokes: handler(request) * handler(request, { geo: {...}, ip: '1.2.3.4', env: {...}, waitUntil: fn })
* // Returns: Response with proxied content
* *
* @example * @example
* // Environment variables usage * // Vercel invokes without context
* // Vercel dashboard or vercel.json: TIMEOUT_SECONDS = "60" * handler(request)
* // process.env contains: { TIMEOUT_SECONDS: "60" }
* // Mapped to env object and passed to handleRequest
*/ */
export default async function handler(request) { export default async function handler(request, context) {
// Map process.env to Cloudflare Workers env format // Detect runtime environment
const isNetlify = context && (context.geo !== undefined || context.ip !== undefined);
// Normalize environment variables
const envSource = isNetlify && context.env ? context.env : process.env;
const env = { const env = {
TIMEOUT_SECONDS: process.env.TIMEOUT_SECONDS, TIMEOUT_SECONDS: envSource.TIMEOUT_SECONDS,
MAX_RETRIES: process.env.MAX_RETRIES, MAX_RETRIES: envSource.MAX_RETRIES,
RETRY_DELAY_MS: process.env.RETRY_DELAY_MS, RETRY_DELAY_MS: envSource.RETRY_DELAY_MS,
CACHE_DURATION: process.env.CACHE_DURATION, CACHE_DURATION: envSource.CACHE_DURATION,
ALLOWED_METHODS: process.env.ALLOWED_METHODS, ALLOWED_METHODS: envSource.ALLOWED_METHODS,
ALLOWED_ORIGINS: process.env.ALLOWED_ORIGINS, ALLOWED_ORIGINS: envSource.ALLOWED_ORIGINS,
MAX_PATH_LENGTH: process.env.MAX_PATH_LENGTH, MAX_PATH_LENGTH: envSource.MAX_PATH_LENGTH,
}; };
// Create minimal execution context // Create normalized execution context
// Note: Vercel Edge Runtime doesn't support waitUntil or passThroughOnException
const ctx = { const ctx = {
waitUntil: (promise) => { waitUntil: isNetlify && context.waitUntil
// No-op: Vercel doesn't support background tasks ? (promise) => context.waitUntil(promise)
// Cache writes will run synchronously instead : (promise) => {
console.warn('waitUntil is not supported in Vercel Edge Runtime'); // No-op on Vercel: background tasks not supported
}, // Cache writes will run synchronously instead
if (process.env.NODE_ENV !== 'production') {
console.warn('waitUntil is not supported in Vercel Edge Runtime');
}
},
passThroughOnException: () => { passThroughOnException: () => {
// No-op: Vercel-specific error handling // Not supported on either platform in this context
console.warn('passThroughOnException is not supported in Vercel Edge Runtime'); if (process.env.NODE_ENV !== 'production') {
console.warn('passThroughOnException is not universally supported');
}
} }
}; };
@@ -289,7 +294,7 @@ jobs:
return handleRequest(request, env, ctx); return handleRequest(request, env, ctx);
} }
// Vercel Edge Runtime configuration // Vercel Edge Runtime configuration (ignored by Netlify)
export const config = { export const config = {
runtime: 'edge', runtime: 'edge',
}; };
@@ -323,6 +328,37 @@ jobs:
} }
EOF EOF
- name: Create netlify.toml
run: |
cd /tmp/functions-conversion
cat > netlify.toml << 'EOF'
[[edge_functions]]
function = "edge-handler"
path = "/*"
[build]
publish = "."
EOF
- name: Create Netlify Edge Function redirect
run: |
cd /tmp/functions-conversion
mkdir -p netlify/edge-functions
cat > netlify/edge-functions/edge-handler.js << 'EOF'
/**
* Netlify Edge Function entry point.
*
* This file serves as a redirect to the edge function handler
* located at /api/index.js. Both Netlify and Vercel can use the same
* handler code, with platform detection handling the differences.
*
* Netlify requires edge functions to be in netlify/edge-functions/,
* while Vercel uses /api/ directory. This approach maintains a single
* source of truth at /api/index.js.
*/
export { default, config } from '../../api/index.js';
EOF
- name: Export handleRequest from src/index.js - name: Export handleRequest from src/index.js
run: | run: |
cd /tmp/functions-conversion cd /tmp/functions-conversion