Fix wws runtime compatibility - use module.exports pattern
- Update api/index.js to use handler export format
- Update chat/index.js to use handler export format
- Update webhook/index.js to use handler export format
- Remove addEventListener('fetch') pattern incompatible with wws
- Remove URL API usage (not available in wws JS runtime)
- Remove spread operator for better compatibility
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
19
api/index.js
19
api/index.js
@@ -1,22 +1,17 @@
|
|||||||
// Health check and API info endpoint
|
// Health check and API info endpoint
|
||||||
// Path: /api
|
// Path: /api
|
||||||
|
|
||||||
addEventListener('fetch', event => {
|
async function handler(request) {
|
||||||
event.respondWith(handleRequest(event.request))
|
|
||||||
})
|
|
||||||
|
|
||||||
async function handleRequest(request) {
|
|
||||||
const url = new URL(request.url)
|
|
||||||
|
|
||||||
// CORS headers for browser requests
|
// CORS headers for browser requests
|
||||||
const corsHeaders = {
|
const corsHeaders = {
|
||||||
'Access-Control-Allow-Origin': '*',
|
'Access-Control-Allow-Origin': '*',
|
||||||
'Access-Control-Allow-Methods': 'GET, POST, OPTIONS',
|
'Access-Control-Allow-Methods': 'GET, POST, OPTIONS',
|
||||||
'Access-Control-Allow-Headers': 'Content-Type, Authorization',
|
'Access-Control-Allow-Headers': 'Content-Type, Authorization',
|
||||||
|
'Content-Type': 'application/json'
|
||||||
}
|
}
|
||||||
|
|
||||||
if (request.method === 'OPTIONS') {
|
if (request.method === 'OPTIONS') {
|
||||||
return new Response(null, { headers: corsHeaders })
|
return new Response('', { headers: corsHeaders })
|
||||||
}
|
}
|
||||||
|
|
||||||
const response = {
|
const response = {
|
||||||
@@ -38,9 +33,9 @@ async function handleRequest(request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return new Response(JSON.stringify(response, null, 2), {
|
return new Response(JSON.stringify(response, null, 2), {
|
||||||
headers: {
|
headers: corsHeaders
|
||||||
'Content-Type': 'application/json',
|
|
||||||
...corsHeaders
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Export for wws
|
||||||
|
module.exports = { handler }
|
||||||
|
|||||||
@@ -1,36 +1,34 @@
|
|||||||
// Chat proxy - routes requests to n8n workflow
|
// Chat proxy - routes requests to n8n workflow
|
||||||
// Path: /chat
|
// Path: /chat
|
||||||
|
|
||||||
addEventListener('fetch', event => {
|
async function handler(request) {
|
||||||
event.respondWith(handleRequest(event.request))
|
|
||||||
})
|
|
||||||
|
|
||||||
async function handleRequest(request) {
|
|
||||||
const corsHeaders = {
|
const corsHeaders = {
|
||||||
'Access-Control-Allow-Origin': '*',
|
'Access-Control-Allow-Origin': '*',
|
||||||
'Access-Control-Allow-Methods': 'GET, POST, OPTIONS',
|
'Access-Control-Allow-Methods': 'GET, POST, OPTIONS',
|
||||||
'Access-Control-Allow-Headers': 'Content-Type, Authorization',
|
'Access-Control-Allow-Headers': 'Content-Type, Authorization',
|
||||||
|
'Content-Type': 'application/json'
|
||||||
}
|
}
|
||||||
|
|
||||||
if (request.method === 'OPTIONS') {
|
if (request.method === 'OPTIONS') {
|
||||||
return new Response(null, { headers: corsHeaders })
|
return new Response('', { headers: corsHeaders })
|
||||||
}
|
}
|
||||||
|
|
||||||
if (request.method !== 'POST') {
|
if (request.method !== 'POST') {
|
||||||
return new Response(JSON.stringify({ error: 'Method not allowed' }), {
|
return new Response(JSON.stringify({ error: 'Method not allowed' }), {
|
||||||
status: 405,
|
status: 405,
|
||||||
headers: { 'Content-Type': 'application/json', ...corsHeaders }
|
headers: corsHeaders
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const body = await request.json()
|
const body = await request.json()
|
||||||
const { message, project_id, user_id, provider = 'zai' } = body
|
const { message, project_id, user_id, provider } = body
|
||||||
|
const selectedProvider = provider || 'zai'
|
||||||
|
|
||||||
if (!message) {
|
if (!message) {
|
||||||
return new Response(JSON.stringify({ error: 'Message is required' }), {
|
return new Response(JSON.stringify({ error: 'Message is required' }), {
|
||||||
status: 400,
|
status: 400,
|
||||||
headers: { 'Content-Type': 'application/json', ...corsHeaders }
|
headers: corsHeaders
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -39,10 +37,10 @@ async function handleRequest(request) {
|
|||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: { 'Content-Type': 'application/json' },
|
headers: { 'Content-Type': 'application/json' },
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
message,
|
message: message,
|
||||||
project_id: project_id || null,
|
project_id: project_id || null,
|
||||||
user_id: user_id || null,
|
user_id: user_id || null,
|
||||||
provider,
|
provider: selectedProvider,
|
||||||
source: 'wws-proxy',
|
source: 'wws-proxy',
|
||||||
timestamp: new Date().toISOString()
|
timestamp: new Date().toISOString()
|
||||||
})
|
})
|
||||||
@@ -53,10 +51,10 @@ async function handleRequest(request) {
|
|||||||
return new Response(JSON.stringify({
|
return new Response(JSON.stringify({
|
||||||
success: true,
|
success: true,
|
||||||
response: result.response || result,
|
response: result.response || result,
|
||||||
provider,
|
provider: selectedProvider,
|
||||||
timestamp: new Date().toISOString()
|
timestamp: new Date().toISOString()
|
||||||
}), {
|
}), {
|
||||||
headers: { 'Content-Type': 'application/json', ...corsHeaders }
|
headers: corsHeaders
|
||||||
})
|
})
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -65,7 +63,9 @@ async function handleRequest(request) {
|
|||||||
error: error.message || 'Internal server error'
|
error: error.message || 'Internal server error'
|
||||||
}), {
|
}), {
|
||||||
status: 500,
|
status: 500,
|
||||||
headers: { 'Content-Type': 'application/json', ...corsHeaders }
|
headers: corsHeaders
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
module.exports = { handler }
|
||||||
|
|||||||
@@ -1,50 +1,60 @@
|
|||||||
// Webhook receiver for external integrations
|
// Webhook receiver for external integrations
|
||||||
// Path: /webhook
|
// Path: /webhook
|
||||||
|
|
||||||
addEventListener('fetch', event => {
|
async function handler(request) {
|
||||||
event.respondWith(handleRequest(event.request))
|
|
||||||
})
|
|
||||||
|
|
||||||
async function handleRequest(request) {
|
|
||||||
const corsHeaders = {
|
const corsHeaders = {
|
||||||
'Access-Control-Allow-Origin': '*',
|
'Access-Control-Allow-Origin': '*',
|
||||||
'Access-Control-Allow-Methods': 'GET, POST, OPTIONS',
|
'Access-Control-Allow-Methods': 'GET, POST, OPTIONS',
|
||||||
'Access-Control-Allow-Headers': 'Content-Type, Authorization, X-Webhook-Secret',
|
'Access-Control-Allow-Headers': 'Content-Type, Authorization, X-Webhook-Secret',
|
||||||
|
'Content-Type': 'application/json'
|
||||||
}
|
}
|
||||||
|
|
||||||
if (request.method === 'OPTIONS') {
|
if (request.method === 'OPTIONS') {
|
||||||
return new Response(null, { headers: corsHeaders })
|
return new Response('', { headers: corsHeaders })
|
||||||
}
|
}
|
||||||
|
|
||||||
const url = new URL(request.url)
|
// GET request - return webhook info
|
||||||
const path = url.pathname
|
if (request.method === 'GET') {
|
||||||
|
return new Response(JSON.stringify({
|
||||||
// Log incoming webhook
|
endpoint: '/webhook',
|
||||||
const logEntry = {
|
method: 'POST',
|
||||||
timestamp: new Date().toISOString(),
|
supported_sources: ['gitea', 'stripe', 'supabase', 'default'],
|
||||||
method: request.method,
|
usage: 'POST /webhook?source=gitea with JSON body'
|
||||||
path: path,
|
}, null, 2), {
|
||||||
headers: Object.fromEntries(request.headers.entries()),
|
headers: corsHeaders
|
||||||
query: Object.fromEntries(url.searchParams.entries())
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// POST request - receive and forward webhook
|
||||||
if (request.method === 'POST') {
|
if (request.method === 'POST') {
|
||||||
try {
|
try {
|
||||||
|
const timestamp = new Date().toISOString()
|
||||||
|
|
||||||
|
// Parse request body
|
||||||
|
let payload
|
||||||
const contentType = request.headers.get('content-type') || ''
|
const contentType = request.headers.get('content-type') || ''
|
||||||
|
|
||||||
let payload
|
|
||||||
if (contentType.includes('application/json')) {
|
if (contentType.includes('application/json')) {
|
||||||
payload = await request.json()
|
payload = await request.json()
|
||||||
} else if (contentType.includes('form')) {
|
|
||||||
payload = Object.fromEntries(await request.formData())
|
|
||||||
} else {
|
} else {
|
||||||
payload = await request.text()
|
payload = await request.text()
|
||||||
}
|
}
|
||||||
|
|
||||||
logEntry.payload = payload
|
// Get source from query params (wws provides request.url as string)
|
||||||
|
let source = 'default'
|
||||||
// Route based on webhook type/source
|
if (request.url && request.url.includes('?')) {
|
||||||
const source = url.searchParams.get('source') || 'unknown'
|
const queryString = request.url.split('?')[1]
|
||||||
|
if (queryString) {
|
||||||
|
const params = queryString.split('&')
|
||||||
|
for (let i = 0; i < params.length; i++) {
|
||||||
|
const pair = params[i].split('=')
|
||||||
|
if (pair[0] === 'source' && pair[1]) {
|
||||||
|
source = decodeURIComponent(pair[1])
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Forward to appropriate n8n workflow based on source
|
// Forward to appropriate n8n workflow based on source
|
||||||
const webhookMap = {
|
const webhookMap = {
|
||||||
@@ -56,44 +66,43 @@ async function handleRequest(request) {
|
|||||||
|
|
||||||
const targetUrl = webhookMap[source] || webhookMap['default']
|
const targetUrl = webhookMap[source] || webhookMap['default']
|
||||||
|
|
||||||
// Async forward (fire and forget for speed)
|
// Forward to n8n (fire and forget)
|
||||||
fetch(targetUrl, {
|
fetch(targetUrl, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: { 'Content-Type': 'application/json' },
|
headers: { 'Content-Type': 'application/json' },
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
source,
|
source: source,
|
||||||
payload,
|
payload: payload,
|
||||||
received_at: logEntry.timestamp,
|
received_at: timestamp
|
||||||
headers: logEntry.headers
|
|
||||||
})
|
})
|
||||||
}).catch(err => console.error('Forward failed:', err))
|
}).catch(function(err) {
|
||||||
|
console.error('Forward failed:', err)
|
||||||
|
})
|
||||||
|
|
||||||
return new Response(JSON.stringify({
|
return new Response(JSON.stringify({
|
||||||
received: true,
|
received: true,
|
||||||
source,
|
source: source,
|
||||||
timestamp: logEntry.timestamp
|
timestamp: timestamp
|
||||||
}), {
|
}), {
|
||||||
headers: { 'Content-Type': 'application/json', ...corsHeaders }
|
headers: corsHeaders
|
||||||
})
|
})
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return new Response(JSON.stringify({
|
return new Response(JSON.stringify({
|
||||||
received: false,
|
received: false,
|
||||||
error: error.message
|
error: error.message || 'Parse error'
|
||||||
}), {
|
}), {
|
||||||
status: 400,
|
status: 400,
|
||||||
headers: { 'Content-Type': 'application/json', ...corsHeaders }
|
headers: corsHeaders
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// GET request - return webhook info
|
// Method not allowed
|
||||||
return new Response(JSON.stringify({
|
return new Response(JSON.stringify({ error: 'Method not allowed' }), {
|
||||||
endpoint: '/webhook',
|
status: 405,
|
||||||
method: 'POST',
|
headers: corsHeaders
|
||||||
supported_sources: ['gitea', 'stripe', 'supabase', 'default'],
|
|
||||||
usage: 'POST /webhook?source=gitea with JSON body'
|
|
||||||
}), {
|
|
||||||
headers: { 'Content-Type': 'application/json', ...corsHeaders }
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
module.exports = { handler }
|
||||||
|
|||||||
Reference in New Issue
Block a user