refactor(core): modularize request pipeline

This commit is contained in:
xixu-me committed 2026-03-20 15:36:10 +08:00
1 parent b86be36d67
commit 1b67fd2ff1
36 files changed
+2047 -1271

No files matched your search

+40 -13
View File
@@ -16,18 +16,33 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import { handleRequest } from '../../../src/app/handle-request.js';
/**
* @typedef {{
* ALLOWED_METHODS?: string,
* ALLOWED_ORIGINS?: string,
* CACHE_DURATION?: string,
* MAX_PATH_LENGTH?: string,
* MAX_RETRIES?: string,
* RETRY_DELAY_MS?: string,
* TIMEOUT_SECONDS?: string
* }} RuntimeEnv
*/
import { handleRequest } from '../src/index.js';
/**
* @typedef {{
* env?: RuntimeEnv,
* geo?: unknown,
* ip?: string,
* waitUntil?: (promise: Promise<unknown>) => void
* }} FunctionAdapterContext
*/
/**
* Edge Function handler.
* @param {Request} request - Standard Web API Request object
* @param {object} [context] - Platform-specific context (Netlify only)
* @param {object} [context.geo] - Geolocation data (Netlify)
* @param {string} [context.ip] - Client IP address (Netlify)
* @param {object} [context.env] - Environment variables (Netlify)
* @param {(promise: Promise<unknown>) => void} [context.waitUntil] - Background task extension (Netlify)
* @param {FunctionAdapterContext} [context] - Platform-specific context (Netlify only)
* @returns {Promise<Response>} Standard Web API Response
* @example
* // Netlify invokes with context
@@ -37,14 +52,17 @@ import { handleRequest } from '../src/index.js';
* handler(request)
*/
export default async function handler(request, context) {
const runtimeContext = context || /** @type {FunctionAdapterContext} */ ({});
// Detect runtime environment
const isNetlify = context && (context.geo !== undefined || context.ip !== undefined);
const isNetlify = runtimeContext.geo !== undefined || runtimeContext.ip !== undefined;
// Normalize environment variables
// Netlify provides context.env, Vercel Edge uses globalThis
/** @type {RuntimeEnv} */
let envSource;
if (isNetlify) {
envSource = context.env || {};
envSource = runtimeContext.env || {};
} else if (typeof process !== 'undefined' && process.env) {
// Vercel or Node.js environment
envSource = process.env;
@@ -60,14 +78,23 @@ export default async function handler(request, context) {
CACHE_DURATION: envSource.CACHE_DURATION,
ALLOWED_METHODS: envSource.ALLOWED_METHODS,
ALLOWED_ORIGINS: envSource.ALLOWED_ORIGINS,
MAX_PATH_LENGTH: envSource.MAX_PATH_LENGTH,
MAX_PATH_LENGTH: envSource.MAX_PATH_LENGTH
};
// Create normalized execution context
const waitUntil = isNetlify && runtimeContext.waitUntil ? runtimeContext.waitUntil : null;
const ctx = {
waitUntil: isNetlify && context.waitUntil
? (promise) => context.waitUntil(promise)
: (_promise) => {
waitUntil: waitUntil
? /**
* Forwards background work in runtimes that support waitUntil.
* @param {Promise<unknown>} promise
*/
promise => waitUntil(promise)
: (
/** @type {Promise<unknown>} */
_promise
) => {
void _promise;
// No-op on Vercel: background tasks not supported
// Cache writes will run synchronously instead
console.warn('waitUntil is not supported in Vercel Edge Runtime');
@@ -84,5 +111,5 @@ export default async function handler(request, context) {
// Vercel Edge Runtime configuration (ignored by Netlify)
export const config = {
runtime: 'edge',
runtime: 'edge'
};
+14 -6
View File
@@ -16,9 +16,9 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
/* eslint-disable no-undef, no-unused-vars */
/* eslint-disable no-undef */
import { handleRequest } from './src/index.js';
import { handleRequest } from '../../src/app/handle-request.js';
/**
* Deno Deploy handler.
@@ -40,13 +40,17 @@ async function handler(request) {
CACHE_DURATION: Deno.env.get('CACHE_DURATION'),
ALLOWED_METHODS: Deno.env.get('ALLOWED_METHODS'),
ALLOWED_ORIGINS: Deno.env.get('ALLOWED_ORIGINS'),
MAX_PATH_LENGTH: Deno.env.get('MAX_PATH_LENGTH'),
MAX_PATH_LENGTH: Deno.env.get('MAX_PATH_LENGTH')
};
// Create minimal ExecutionContext-like object
// Deno Deploy doesn't support waitUntil, so cache writes are synchronous
const ctx = {
waitUntil: (promise) => {
waitUntil: (
/** @type {Promise<unknown>} */
promise
) => {
void promise;
// No-op on Deno: background tasks not supported
console.warn('waitUntil is not supported in Deno Deploy');
},
@@ -59,5 +63,9 @@ async function handler(request) {
return handleRequest(request, env, ctx);
}
// Start the server
Deno.serve(handler);
// Start the server only when executing inside Deno.
if (typeof Deno !== 'undefined' && typeof Deno.serve === 'function') {
Deno.serve(handler);
}
export { handler };
+12 -9
View File
@@ -16,9 +16,18 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import { handleRequest } from '../../../src/app/handle-request.js';
import { handleRequest } from '../src/index.js';
/**
* @typedef {{
* request: Request,
* env: Record<string, unknown>,
* params: object,
* waitUntil: (promise: Promise<unknown>) => void,
* next: () => Promise<Response>,
* data: object
* }} PagesFunctionContext
*/
/**
* Pages Function handler for all routes.
@@ -31,13 +40,7 @@ import { handleRequest } from '../src/index.js';
* The [[path]] syntax in the filename creates a catch-all route that matches
* any path, allowing this single function to handle all requests to the Pages
* application.
* @param {object} context - Pages Function context
* @param {Request} context.request - The incoming HTTP request
* @param {object} context.env - Environment variables and bindings (KV, secrets, etc.)
* @param {object} context.params - Route parameters (path segments from [[path]])
* @param {(promise: Promise<unknown>) => void} context.waitUntil - Extend function execution for background tasks
* @param {() => Promise<Response>} context.next - Call next middleware in chain (not used here)
* @param {object} context.data - Shared data between functions
* @param {PagesFunctionContext} context - Pages Function context
* @returns {Promise<Response>} The HTTP response to return to the client
* @example
* // This is called automatically by Pages