Cloudflare Worker
apps/worker es el servidor de la aplicación. Corre en Cloudflare Workers (edge runtime) y expone todos los endpoints que requieren lógica de servidor: autenticación, reservaciones, pagos y emails.
Por qué un Worker separado
apps/web usa output: "export" — genera HTML/CSS/JS estático sin servidor Node. Esto significa que no puede tener API Routes ni middleware. Todo lo que requiere acceso a base de datos, secretos o servicios externos vive en el Worker.
Stack
| Herramienta | Rol |
|---|---|
| Hono | Router HTTP para Workers |
@supabase/supabase-js | Base de datos (admin client con service role key) |
resend | Envío de emails transaccionales |
| Web Crypto API | JWT (HMAC-SHA256) y hashing de contraseñas (PBKDF2), nativo en Workers |
Estructura
apps/worker/
├── src/
│ ├── index.ts # Punto de entrada, router principal, CORS
│ ├── auth.ts # JWT sign/verify + PBKDF2 hash/verify (Web Crypto API)
│ ├── supabase.ts # Inicializa cliente admin de Supabase
│ ├── email.ts # Envío de emails con Resend
│ ├── types.ts # Tipos compartidos + interface Env
│ └── routes/
│ ├── auth.ts # POST /auth/signup, POST /auth/signin
│ ├── reservations.ts # CRUD de reservaciones
│ └── paypal.ts # Crear y capturar órdenes PayPal
├── wrangler.toml # Configuración de Cloudflare Workers
├── package.json
└── tsconfig.jsonEndpoints
| Método | Ruta | Auth | Descripción |
|---|---|---|---|
GET | /health | No | Health check |
POST | /auth/signup | No | Registro de usuario |
POST | /auth/signin | No | Inicio de sesión |
GET | /api/reservations | Sí | Lista reservaciones del usuario |
POST | /api/reservations | Sí | Crea reservación |
GET | /api/reservations/check?slug= | Sí | Verifica reservación activa |
PATCH | /api/reservations/:id | Sí | Actualiza estado |
POST | /api/paypal/create-order | Sí | Crea orden PayPal |
POST | /api/paypal/capture-order | Sí | Captura pago + envía email |
Los endpoints marcados con Sí requieren Authorization: Bearer <token> en el header.
Desarrollo local
pnpm --filter @asamamx/worker dev
# Worker disponible en http://localhost:8787Wrangler sirve el worker localmente con hot reload. Las variables de entorno en desarrollo se leen de apps/worker/.dev.vars (no versionado).
.dev.vars de ejemplo
JWT_SECRET=
SUPABASE_URL=
SUPABASE_SECRET_KEY=
PAYPAL_CLIENT_ID=
PAYPAL_CLIENT_SECRET=
RESEND_API_KEY=Deploy a producción
# Configurar secrets (una sola vez)
pnpm --filter @asamamx/worker exec wrangler secret put JWT_SECRET
pnpm --filter @asamamx/worker exec wrangler secret put SUPABASE_URL
pnpm --filter @asamamx/worker exec wrangler secret put SUPABASE_SECRET_KEY
pnpm --filter @asamamx/worker exec wrangler secret put PAYPAL_CLIENT_ID
pnpm --filter @asamamx/worker exec wrangler secret put PAYPAL_CLIENT_SECRET
pnpm --filter @asamamx/worker exec wrangler secret put RESEND_API_KEY
# Deploy
pnpm --filter @asamamx/worker deployCORS
El Worker acepta requests solo desde el origen configurado en wrangler.toml:
[vars]
CORS_ORIGIN = "http://localhost:3000" # dev
[env.production.vars]
CORS_ORIGIN = "https://asamamx.com" # prodTodos los endpoints responden a OPTIONS (preflight) automáticamente via el middleware de Hono cors.