diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
new file mode 100644
index 0000000..f15a95b
--- /dev/null
+++ b/.github/workflows/ci.yml
@@ -0,0 +1,55 @@
+name: CI
+
+on:
+ push:
+ branches:
+ - main
+ paths-ignore:
+ - "**.md"
+ - "LICENSE"
+ - ".gitignore"
+ - ".editorconfig"
+ - ".vscode/**"
+ - "docs/**"
+ pull_request:
+ branches:
+ - main
+ paths-ignore:
+ - "**.md"
+ - "LICENSE"
+ - ".gitignore"
+ - ".editorconfig"
+ - ".vscode/**"
+ - "docs/**"
+ workflow_dispatch:
+
+concurrency:
+ group: ${{ github.workflow }}-${{ github.ref }}
+ cancel-in-progress: true
+
+jobs:
+ test:
+ runs-on: ubuntu-latest
+ timeout-minutes: 10
+
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@v4
+
+ - name: Setup Node.js
+ uses: actions/setup-node@v4
+ with:
+ node-version: '20'
+ cache: 'npm'
+
+ - name: Install dependencies
+ run: npm ci
+
+ - name: Run lint
+ run: npm run lint
+
+ - name: Run type check
+ run: npm run type-check
+
+ - name: Run tests
+ run: npm run test:run
diff --git a/.github/workflows/sync.yml b/.github/workflows/sync.yml
index f5733b6..45b7176 100644
--- a/.github/workflows/sync.yml
+++ b/.github/workflows/sync.yml
@@ -40,94 +40,18 @@ jobs:
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
- - name: Create temporary working directory
+ - name: Setup adapter files
run: |
mkdir -p /tmp/pages-conversion
- cd /tmp/pages-conversion
-
- - name: Copy source code files only
+ cp -r adapters/pages/* /tmp/pages-conversion/
+
+ - name: Copy source code files
run: |
- # Copy only runtime-required files (no documentation, tests, or dev configs)
cp -r src /tmp/pages-conversion/
cp package.json /tmp/pages-conversion/
cp package-lock.json /tmp/pages-conversion/ 2>/dev/null || true
- cp wrangler.toml /tmp/pages-conversion/
cp LICENSE /tmp/pages-conversion/
- - name: Create Pages Function handler
- run: |
- mkdir -p /tmp/pages-conversion/functions
- cat > /tmp/pages-conversion/functions/[[path]].js << 'EOF'
- /**
- * Xget - High-performance acceleration engine for developer resources
- * Copyright (C) 2025 Xi Xu
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
- import { handleRequest } from '../src/index.js';
-
- /**
- * Pages Function handler for all routes.
- *
- * This catch-all route handler processes all incoming requests to the Xget
- * acceleration engine. It delegates request processing to the main handleRequest
- * function from the Workers code, maintaining full compatibility with the
- * existing implementation.
- *
- * 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 {Function} context.waitUntil - Extend function execution for background tasks
- * @param {Function} context.next - Call next middleware in chain (not used here)
- * @param {Object} context.data - Shared data between functions
- * @returns {Promise} The HTTP response to return to the client
- *
- * @example
- * // This is called automatically by Pages
- * // Runtime invokes: onRequest(context)
- * // Returns: Response with package data
- *
- * @example
- * // Environment variables usage
- * // wrangler.toml: [vars] TIMEOUT_SECONDS = "60"
- * // context.env contains: { TIMEOUT_SECONDS: "60" }
- * // handleRequest uses createConfig(env) to override defaults
- */
- export async function onRequest(context) {
- // Extract request, env, and create an execution context compatible with Workers
- const { request, env, waitUntil } = context;
-
- // Create a minimal ExecutionContext-like object for compatibility
- const ctx = {
- waitUntil: waitUntil,
- passThroughOnException: () => {
- // Pages doesn't support passThroughOnException, so this is a no-op
- console.warn('passThroughOnException is not supported in Pages Functions');
- }
- };
-
- // Delegate to the main request handler
- return handleRequest(request, env, ctx);
- }
- EOF
-
- name: Export handleRequest from src/index.js
run: |
cd /tmp/pages-conversion
@@ -135,18 +59,6 @@ jobs:
sed -i '/^export default {$/i\
export { handleRequest };' src/index.js
- - name: Update wrangler.toml for Pages (remove observability)
- run: |
- cd /tmp/pages-conversion
- # Remove observability section (Pages doesn't support it)
- cat > wrangler.toml << 'EOF'
- #:schema node_modules/wrangler/config-schema.json
- name = "xget"
- pages_build_output_dir = "."
- compatibility_date = "2024-10-22"
- compatibility_flags = ["nodejs_compat"]
- EOF
-
- name: Update package.json for Pages
run: |
cd /tmp/pages-conversion
@@ -199,243 +111,21 @@ jobs:
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
- - name: Create temporary working directory
+ - name: Setup adapter files
run: |
mkdir -p /tmp/functions-conversion
- cd /tmp/functions-conversion
+ # Copy all content from adapters/functions excluding package.json first
+ cp -r adapters/functions/* /tmp/functions-conversion/
+ # Copy the specific package.json for functions (overwriting if needed, but we do it later anyway)
- - name: Copy source code files only
+ - name: Copy source code files
run: |
# Copy only runtime-required files
cp -r src /tmp/functions-conversion/
- cp package.json /tmp/functions-conversion/
+ # Note: We do NOT copy the root package.json here as we use the one from adapters/functions
cp package-lock.json /tmp/functions-conversion/ 2>/dev/null || true
cp LICENSE /tmp/functions-conversion/
- - name: Create Edge Function handler
- run: |
- mkdir -p /tmp/functions-conversion/api
- cat > /tmp/functions-conversion/api/index.js << 'EOF'
- /**
- * Xget - High-performance acceleration engine for developer resources
- * Copyright (C) 2025 Xi Xu
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
- import { handleRequest } from '../src/index.js';
-
- /**
- * 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 {Function} [context.waitUntil] - Background task extension (Netlify)
- * @returns {Promise} Standard Web API Response
- *
- * @example
- * // Netlify invokes with context
- * handler(request, { geo: {...}, ip: '1.2.3.4', env: {...}, waitUntil: fn })
- *
- * @example
- * // Vercel invokes without context
- * handler(request)
- */
- export default async function handler(request, context) {
- // Detect runtime environment
- const isNetlify = context && (context.geo !== undefined || context.ip !== undefined);
- const isVercel = !isNetlify && context;
-
- // Normalize environment variables
- // Netlify provides context.env, Vercel Edge uses globalThis
- let envSource;
- if (isNetlify) {
- envSource = context.env || {};
- } else if (typeof process !== 'undefined' && process.env) {
- // Vercel or Node.js environment
- envSource = process.env;
- } else {
- // Fallback for other environments
- envSource = {};
- }
-
- const env = {
- TIMEOUT_SECONDS: envSource.TIMEOUT_SECONDS,
- MAX_RETRIES: envSource.MAX_RETRIES,
- RETRY_DELAY_MS: envSource.RETRY_DELAY_MS,
- CACHE_DURATION: envSource.CACHE_DURATION,
- ALLOWED_METHODS: envSource.ALLOWED_METHODS,
- ALLOWED_ORIGINS: envSource.ALLOWED_ORIGINS,
- MAX_PATH_LENGTH: envSource.MAX_PATH_LENGTH,
- };
-
- // Create normalized execution context
- const ctx = {
- waitUntil: isNetlify && context.waitUntil
- ? (promise) => context.waitUntil(promise)
- : (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');
- },
- passThroughOnException: () => {
- // Not supported on either platform in this context
- console.warn('passThroughOnException is not universally supported');
- }
- };
-
- // Delegate to the main request handler
- return handleRequest(request, env, ctx);
- }
-
- // Vercel Edge Runtime configuration (ignored by Netlify)
- export const config = {
- runtime: 'edge',
- };
- EOF
-
- - name: Create vercel.json
- run: |
- cd /tmp/functions-conversion
- cat > vercel.json << 'EOF'
- {
- "$schema": "https://openapi.vercel.sh/vercel.json",
- "name": "xget",
- "version": 2,
- "rewrites": [
- {
- "source": "/(.*)",
- "destination": "/api/index.js"
- }
- ],
- "headers": [
- {
- "source": "/(.*)",
- "headers": [
- {
- "key": "X-Powered-By",
- "value": "Xget/Vercel"
- }
- ]
- }
- ]
- }
- 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: Create Deno Deploy handler
- run: |
- cd /tmp/functions-conversion
- cat > deno.js << 'EOF'
- /**
- * Xget - High-performance acceleration engine for developer resources
- * Copyright (C) 2025 Xi Xu
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
- import { handleRequest } from './src/index.js';
-
- /**
- * Deno Deploy handler.
- *
- * This is the entry point for Deno Deploy deployments. It uses the
- * standard Deno.serve() API to handle incoming HTTP requests.
- *
- * @param {Request} request - Standard Web API Request object
- * @returns {Promise} Standard Web API Response
- *
- * @example
- * // Deno Deploy invokes automatically:
- * // Deno.serve((request) => handler(request))
- */
- async function handler(request) {
- // Extract environment variables from Deno.env
- const env = {
- TIMEOUT_SECONDS: Deno.env.get('TIMEOUT_SECONDS'),
- MAX_RETRIES: Deno.env.get('MAX_RETRIES'),
- RETRY_DELAY_MS: Deno.env.get('RETRY_DELAY_MS'),
- 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'),
- };
-
- // Create minimal ExecutionContext-like object
- // Deno Deploy doesn't support waitUntil, so cache writes are synchronous
- const ctx = {
- waitUntil: (promise) => {
- // No-op on Deno: background tasks not supported
- console.warn('waitUntil is not supported in Deno Deploy');
- },
- passThroughOnException: () => {
- console.warn('passThroughOnException is not supported in Deno Deploy');
- }
- };
-
- // Delegate to the main request handler
- return handleRequest(request, env, ctx);
- }
-
- // Start the server
- Deno.serve(handler);
- EOF
-
- name: Export handleRequest from src/index.js
run: |
cd /tmp/functions-conversion
@@ -443,29 +133,6 @@ jobs:
sed -i '/^export default {$/i\
export { handleRequest };' src/index.js
- - name: Update package.json for Vercel
- run: |
- cd /tmp/functions-conversion
- cat > package.json << 'EOF'
- {
- "name": "xget",
- "version": "1.0.0",
- "type": "module",
- "private": false,
- "scripts": {
- "dev": "vercel dev",
- "deploy": "vercel --prod",
- "vercel-build": "echo 'No build step required'"
- },
- "dependencies": {
- "express": "^4.19.2"
- },
- "devDependencies": {
- "@vercel/node": "^3.0.0"
- }
- }
- EOF
-
- name: Initialize functions branch
run: |
cd /tmp/functions-conversion
diff --git a/adapters/functions/api/index.js b/adapters/functions/api/index.js
new file mode 100644
index 0000000..1618d7a
--- /dev/null
+++ b/adapters/functions/api/index.js
@@ -0,0 +1,91 @@
+/**
+ * Xget - High-performance acceleration engine for developer resources
+ * Copyright (C) 2025 Xi Xu
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+/* eslint-disable no-undef, no-unused-vars */
+
+import { handleRequest } from '../src/index.js';
+
+/**
+ * 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 {Function} [context.waitUntil] - Background task extension (Netlify)
+ * @returns {Promise} Standard Web API Response
+ *
+ * @example
+ * // Netlify invokes with context
+ * handler(request, { geo: {...}, ip: '1.2.3.4', env: {...}, waitUntil: fn })
+ *
+ * @example
+ * // Vercel invokes without context
+ * handler(request)
+ */
+export default async function handler(request, context) {
+ // Detect runtime environment
+ const isNetlify = context && (context.geo !== undefined || context.ip !== undefined);
+
+ // Normalize environment variables
+ // Netlify provides context.env, Vercel Edge uses globalThis
+ let envSource;
+ if (isNetlify) {
+ envSource = context.env || {};
+ } else if (typeof process !== 'undefined' && process.env) {
+ // Vercel or Node.js environment
+ envSource = process.env;
+ } else {
+ // Fallback for other environments
+ envSource = {};
+ }
+
+ const env = {
+ TIMEOUT_SECONDS: envSource.TIMEOUT_SECONDS,
+ MAX_RETRIES: envSource.MAX_RETRIES,
+ RETRY_DELAY_MS: envSource.RETRY_DELAY_MS,
+ CACHE_DURATION: envSource.CACHE_DURATION,
+ ALLOWED_METHODS: envSource.ALLOWED_METHODS,
+ ALLOWED_ORIGINS: envSource.ALLOWED_ORIGINS,
+ MAX_PATH_LENGTH: envSource.MAX_PATH_LENGTH,
+ };
+
+ // Create normalized execution context
+ const ctx = {
+ waitUntil: isNetlify && context.waitUntil
+ ? (promise) => context.waitUntil(promise)
+ : (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');
+ },
+ passThroughOnException: () => {
+ // Not supported on either platform in this context
+ console.warn('passThroughOnException is not universally supported');
+ }
+ };
+
+ // Delegate to the main request handler
+ return handleRequest(request, env, ctx);
+}
+
+// Vercel Edge Runtime configuration (ignored by Netlify)
+export const config = {
+ runtime: 'edge',
+};
diff --git a/adapters/functions/deno.js b/adapters/functions/deno.js
new file mode 100644
index 0000000..1605205
--- /dev/null
+++ b/adapters/functions/deno.js
@@ -0,0 +1,65 @@
+/**
+ * Xget - High-performance acceleration engine for developer resources
+ * Copyright (C) 2025 Xi Xu
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+/* eslint-disable no-undef, no-unused-vars */
+
+import { handleRequest } from './src/index.js';
+
+/**
+ * Deno Deploy handler.
+ *
+ * This is the entry point for Deno Deploy deployments. It uses the
+ * standard Deno.serve() API to handle incoming HTTP requests.
+ *
+ * @param {Request} request - Standard Web API Request object
+ * @returns {Promise} Standard Web API Response
+ *
+ * @example
+ * // Deno Deploy invokes automatically:
+ * // Deno.serve((request) => handler(request))
+ */
+async function handler(request) {
+ // Extract environment variables from Deno.env
+ const env = {
+ TIMEOUT_SECONDS: Deno.env.get('TIMEOUT_SECONDS'),
+ MAX_RETRIES: Deno.env.get('MAX_RETRIES'),
+ RETRY_DELAY_MS: Deno.env.get('RETRY_DELAY_MS'),
+ 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'),
+ };
+
+ // Create minimal ExecutionContext-like object
+ // Deno Deploy doesn't support waitUntil, so cache writes are synchronous
+ const ctx = {
+ waitUntil: (promise) => {
+ // No-op on Deno: background tasks not supported
+ console.warn('waitUntil is not supported in Deno Deploy');
+ },
+ passThroughOnException: () => {
+ console.warn('passThroughOnException is not supported in Deno Deploy');
+ }
+ };
+
+ // Delegate to the main request handler
+ return handleRequest(request, env, ctx);
+}
+
+// Start the server
+Deno.serve(handler);
diff --git a/adapters/functions/netlify.toml b/adapters/functions/netlify.toml
new file mode 100644
index 0000000..02c5c2d
--- /dev/null
+++ b/adapters/functions/netlify.toml
@@ -0,0 +1,6 @@
+[[edge_functions]]
+function = "edge-handler"
+path = "/*"
+
+[build]
+publish = "."
diff --git a/adapters/functions/netlify/edge-functions/edge-handler.js b/adapters/functions/netlify/edge-functions/edge-handler.js
new file mode 100644
index 0000000..7379ec4
--- /dev/null
+++ b/adapters/functions/netlify/edge-functions/edge-handler.js
@@ -0,0 +1,13 @@
+/**
+ * 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 { config, default } from '../../api/index.js';
+
diff --git a/adapters/functions/package.json b/adapters/functions/package.json
new file mode 100644
index 0000000..3d8630e
--- /dev/null
+++ b/adapters/functions/package.json
@@ -0,0 +1,17 @@
+{
+ "name": "xget",
+ "version": "1.0.0",
+ "type": "module",
+ "private": false,
+ "scripts": {
+ "dev": "vercel dev",
+ "deploy": "vercel --prod",
+ "vercel-build": "echo 'No build step required'"
+ },
+ "dependencies": {
+ "express": "^4.19.2"
+ },
+ "devDependencies": {
+ "@vercel/node": "^3.0.0"
+ }
+}
diff --git a/adapters/functions/vercel.json b/adapters/functions/vercel.json
new file mode 100644
index 0000000..df8cb2f
--- /dev/null
+++ b/adapters/functions/vercel.json
@@ -0,0 +1,22 @@
+{
+ "$schema": "https://openapi.vercel.sh/vercel.json",
+ "name": "xget",
+ "version": 2,
+ "rewrites": [
+ {
+ "source": "/(.*)",
+ "destination": "/api/index.js"
+ }
+ ],
+ "headers": [
+ {
+ "source": "/(.*)",
+ "headers": [
+ {
+ "key": "X-Powered-By",
+ "value": "Xget/Vercel"
+ }
+ ]
+ }
+ ]
+}
diff --git a/adapters/pages/functions/[[path]].js b/adapters/pages/functions/[[path]].js
new file mode 100644
index 0000000..fdefbc5
--- /dev/null
+++ b/adapters/pages/functions/[[path]].js
@@ -0,0 +1,70 @@
+/**
+ * Xget - High-performance acceleration engine for developer resources
+ * Copyright (C) 2025 Xi Xu
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+/* eslint-disable no-undef */
+
+import { handleRequest } from '../src/index.js';
+
+/**
+ * Pages Function handler for all routes.
+ *
+ * This catch-all route handler processes all incoming requests to the Xget
+ * acceleration engine. It delegates request processing to the main handleRequest
+ * function from the Workers code, maintaining full compatibility with the
+ * existing implementation.
+ *
+ * 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 {Function} context.waitUntil - Extend function execution for background tasks
+ * @param {Function} context.next - Call next middleware in chain (not used here)
+ * @param {Object} context.data - Shared data between functions
+ * @returns {Promise} The HTTP response to return to the client
+ *
+ * @example
+ * // This is called automatically by Pages
+ * // Runtime invokes: onRequest(context)
+ * // Returns: Response with package data
+ *
+ * @example
+ * // Environment variables usage
+ * // wrangler.toml: [vars] TIMEOUT_SECONDS = "60"
+ * // context.env contains: { TIMEOUT_SECONDS: "60" }
+ * // handleRequest uses createConfig(env) to override defaults
+ */
+export async function onRequest(context) {
+ // Extract request, env, and create an execution context compatible with Workers
+ const { request, env, waitUntil } = context;
+
+ // Create a minimal ExecutionContext-like object for compatibility
+ const ctx = {
+ waitUntil: waitUntil,
+ passThroughOnException: () => {
+ // Pages doesn't support passThroughOnException, so this is a no-op
+ console.warn('passThroughOnException is not supported in Pages Functions');
+ }
+ };
+
+ // Delegate to the main request handler
+ return handleRequest(request, env, ctx);
+}
diff --git a/adapters/pages/wrangler.toml b/adapters/pages/wrangler.toml
new file mode 100644
index 0000000..3e2a24c
--- /dev/null
+++ b/adapters/pages/wrangler.toml
@@ -0,0 +1,5 @@
+#:schema node_modules/wrangler/config-schema.json
+name = "xget"
+pages_build_output_dir = "."
+compatibility_date = "2024-10-22"
+compatibility_flags = ["nodejs_compat"]
diff --git a/package.json b/package.json
index c0be6ea..f89b791 100644
--- a/package.json
+++ b/package.json
@@ -20,8 +20,8 @@
"dev": "wrangler dev",
"format": "prettier --write src/ test/ *.js *.json",
"format:check": "prettier --check src/ test/ *.js *.json",
- "lint": "eslint src/ test/",
- "lint:fix": "eslint src/ test/ --fix",
+ "lint": "eslint src/ test/ adapters/",
+ "lint:fix": "eslint src/ test/ adapters/ --fix",
"start": "wrangler dev",
"test": "vitest",
"test:coverage": "vitest run --coverage",
diff --git a/src/index.js b/src/index.js
index ae19c10..007d73e 100644
--- a/src/index.js
+++ b/src/index.js
@@ -138,9 +138,9 @@ async function handleRequest(request, env, ctx) {
// Check cache first (skip cache for Git, Git LFS, Docker, and AI inference operations)
/** @type {Cache | null} */
+ /** @type {Cache | null} */
// @ts-ignore - Cloudflare Workers cache API
- const cache =
- typeof caches !== 'undefined' && caches.default ? caches.default : null;
+ const cache = typeof caches !== 'undefined' && /** @type {any} */ (caches).default ? /** @type {any} */ (caches).default : null;
if (cache && !isGit && !isGitLFS && !isDocker && !isAI) {
try {
@@ -655,6 +655,11 @@ async function handleRequest(request, env, ctx) {
}
export default {
+ /**
+ * @param {Request} request
+ * @param {Object} env
+ * @param {ExecutionContext} ctx
+ */
fetch(request, env, ctx) {
return handleRequest(request, env, ctx);
}
diff --git a/test/features/security.test.js b/test/features/security.test.js
index bc8ce05..21540a0 100644
--- a/test/features/security.test.js
+++ b/test/features/security.test.js
@@ -183,7 +183,7 @@ describe('Security Features', () => {
// If it doesn't throw, it should not be a server error
} catch (error) {
// Expected to throw TypeError for invalid header value
- expect(error.message).toMatch(/[Ii]nvalid|[Hh]eader/);
+ expect((/** @type {Error} */ (error)).message).toMatch(/[Ii]nvalid|[Hh]eader/);
}
});
});