From c9ca9ce28fb61a0c5be808f93c18fc7ea18cfa80 Mon Sep 17 00:00:00 2001 From: jofthev Date: Wed, 18 Jun 2025 00:48:41 -0500 Subject: [PATCH 01/10] Add Neon Covenant WhatsApp webhook + sender script --- twilio-neon/README.md | 0 twilio-neon/cloudflare/inbox-handler.ts | 0 twilio-neon/package.json | 0 twilio-neon/scripts/send-whatsapp.js | 0 4 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 twilio-neon/README.md create mode 100644 twilio-neon/cloudflare/inbox-handler.ts create mode 100644 twilio-neon/package.json create mode 100644 twilio-neon/scripts/send-whatsapp.js diff --git a/twilio-neon/README.md b/twilio-neon/README.md new file mode 100644 index 0000000000..e69de29bb2 diff --git a/twilio-neon/cloudflare/inbox-handler.ts b/twilio-neon/cloudflare/inbox-handler.ts new file mode 100644 index 0000000000..e69de29bb2 diff --git a/twilio-neon/package.json b/twilio-neon/package.json new file mode 100644 index 0000000000..e69de29bb2 diff --git a/twilio-neon/scripts/send-whatsapp.js b/twilio-neon/scripts/send-whatsapp.js new file mode 100644 index 0000000000..e69de29bb2 From 2fb6c00fa14ced28214a88c21cdde9e93f3bf570 Mon Sep 17 00:00:00 2001 From: jofthev Date: Wed, 18 Jun 2025 02:51:06 -0500 Subject: [PATCH 02/10] Setup automated build & deploy workflow --- twilio-neon/dist/inbox-handler.js | 1 + twilio-neon/inbox-handler.ts | 9 +++++++++ twilio-neon/package.json | 18 ++++++++++++++++++ twilio-neon/tsconfig.json | 14 ++++++++++++++ twilio-neon/wrangler.toml | 10 ++++++++++ 5 files changed, 52 insertions(+) create mode 100644 twilio-neon/dist/inbox-handler.js create mode 100644 twilio-neon/inbox-handler.ts create mode 100644 twilio-neon/tsconfig.json create mode 100644 twilio-neon/wrangler.toml diff --git a/twilio-neon/dist/inbox-handler.js b/twilio-neon/dist/inbox-handler.js new file mode 100644 index 0000000000..3918c74e44 --- /dev/null +++ b/twilio-neon/dist/inbox-handler.js @@ -0,0 +1 @@ +"use strict"; diff --git a/twilio-neon/inbox-handler.ts b/twilio-neon/inbox-handler.ts new file mode 100644 index 0000000000..885aab69e7 --- /dev/null +++ b/twilio-neon/inbox-handler.ts @@ -0,0 +1,9 @@ +addEventListener('fetch', event => { + event.respondWith( + new Response('Hello from Neon WhatsApp Bot!', { + status: 200, + headers: { 'Content-Type': 'text/plain' }, + }) + ) +}) + diff --git a/twilio-neon/package.json b/twilio-neon/package.json index e69de29bb2..786c26bda3 100644 --- a/twilio-neon/package.json +++ b/twilio-neon/package.json @@ -0,0 +1,18 @@ +{ + "name": "twilio-neon", + "version": "1.0.0", + "main": "index.js", + "scripts": { + "send": "node scripts/send-whatsapp.js", + "build": "tsc" + }, + "dependencies": { + "dotenv": "^16.0.0", + "php": "^1.1.0", + "twilio": "^4.0.0" + }, + "devDependencies": { + "@cloudflare/workers-types": "^4.20250618.0", + "typescript": "^5.8.3" + } +} diff --git a/twilio-neon/tsconfig.json b/twilio-neon/tsconfig.json new file mode 100644 index 0000000000..3dc8ab30f4 --- /dev/null +++ b/twilio-neon/tsconfig.json @@ -0,0 +1,14 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "ESNext", + "moduleResolution": "node", + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "outDir": "dist", + "types": ["@cloudflare/workers-types"] + }, + "include": ["cloudflare/**/*.ts"] +} + diff --git a/twilio-neon/wrangler.toml b/twilio-neon/wrangler.toml new file mode 100644 index 0000000000..ea8f3d7b5d --- /dev/null +++ b/twilio-neon/wrangler.toml @@ -0,0 +1,10 @@ +name = "neon-whatsapp-bot" +main = "dist/inbox-handler.js" +compatibility_date = "2025-06-18" + +[vars] +API_VERSION = "v1" + +[dev] +port = 8787 + From 9f921fef5a0ad3473ea76f6067d3abc059698abd Mon Sep 17 00:00:00 2001 From: jofthev Date: Wed, 18 Jun 2025 05:29:43 -0500 Subject: [PATCH 03/10] Deploy Twilio Neon TypeScript Worker --- twilio-neon/cloudflare/inbox-handler.ts | 28 +++++++++++++++++++++++++ twilio-neon/dist/inbox-handler.js | 25 +++++++++++++++++++++- twilio-neon/package.json | 5 +++-- twilio-neon/tsconfig.json | 13 ++++++------ twilio-neon/wrangler.toml | 9 ++++---- 5 files changed, 66 insertions(+), 14 deletions(-) diff --git a/twilio-neon/cloudflare/inbox-handler.ts b/twilio-neon/cloudflare/inbox-handler.ts index e69de29bb2..5894cbca36 100644 --- a/twilio-neon/cloudflare/inbox-handler.ts +++ b/twilio-neon/cloudflare/inbox-handler.ts @@ -0,0 +1,28 @@ +const handler = { + async fetch(request: Request): Promise { + const form = await request.formData(); + const message = (form.get("Body") || "").toString().toLowerCase(); + const sender = form.get("From") || "unknown"; + + let reply = "🤖 Neon Covenant AI: Reply with 'confirm', 'reschedule', or 'help'."; + + if (message.includes("confirm")) { + reply = "✅ Delivery confirmed for Dec 1 at 3pm. Thank you."; + } else if (message.includes("reschedule")) { + reply = "📆 Please reply with your new desired delivery time."; + } else if (message.includes("help")) { + reply = "🧙‍♂️ Support: Visit https://help.neoncovenant.com for assistance."; + } + + const twiml = `${reply}`; + + return new Response(twiml, { + headers: { + "Content-Type": "application/xml", + }, + }); + }, +}; + +export default handler; + diff --git a/twilio-neon/dist/inbox-handler.js b/twilio-neon/dist/inbox-handler.js index 3918c74e44..25ca498c70 100644 --- a/twilio-neon/dist/inbox-handler.js +++ b/twilio-neon/dist/inbox-handler.js @@ -1 +1,24 @@ -"use strict"; +const handler = { + async fetch(request) { + const form = await request.formData(); + const message = (form.get("Body") || "").toString().toLowerCase(); + const sender = form.get("From") || "unknown"; + let reply = "🤖 Neon Covenant AI: Reply with 'confirm', 'reschedule', or 'help'."; + if (message.includes("confirm")) { + reply = "✅ Delivery confirmed for Dec 1 at 3pm. Thank you."; + } + else if (message.includes("reschedule")) { + reply = "📆 Please reply with your new desired delivery time."; + } + else if (message.includes("help")) { + reply = "🧙‍♂️ Support: Visit https://help.neoncovenant.com for assistance."; + } + const twiml = `${reply}`; + return new Response(twiml, { + headers: { + "Content-Type": "application/xml", + }, + }); + }, +}; +export default handler; diff --git a/twilio-neon/package.json b/twilio-neon/package.json index 786c26bda3..cf1cf2aa0c 100644 --- a/twilio-neon/package.json +++ b/twilio-neon/package.json @@ -3,8 +3,9 @@ "version": "1.0.0", "main": "index.js", "scripts": { - "send": "node scripts/send-whatsapp.js", - "build": "tsc" + "build": "tsc", + "deploy": "wrangler deploy", + "send": "node scripts/send-whatsapp.js" }, "dependencies": { "dotenv": "^16.0.0", diff --git a/twilio-neon/tsconfig.json b/twilio-neon/tsconfig.json index 3dc8ab30f4..91033c31b9 100644 --- a/twilio-neon/tsconfig.json +++ b/twilio-neon/tsconfig.json @@ -1,14 +1,13 @@ { "compilerOptions": { - "target": "ES2020", + "target": "ES2022", "module": "ESNext", - "moduleResolution": "node", - "strict": true, - "esModuleInterop": true, - "skipLibCheck": true, "outDir": "dist", - "types": ["@cloudflare/workers-types"] + "moduleResolution": "Node", + "esModuleInterop": true, + "strict": true, + "skipLibCheck": true }, - "include": ["cloudflare/**/*.ts"] + "include": ["cloudflare"] } diff --git a/twilio-neon/wrangler.toml b/twilio-neon/wrangler.toml index ea8f3d7b5d..b0e0a4b8a0 100644 --- a/twilio-neon/wrangler.toml +++ b/twilio-neon/wrangler.toml @@ -1,10 +1,11 @@ name = "neon-whatsapp-bot" main = "dist/inbox-handler.js" compatibility_date = "2025-06-18" +compatibility_flags = ["nodejs_compat"] +usage_model = "bundled" +modules = true -[vars] -API_VERSION = "v1" +[build] +command = "npm run build" -[dev] -port = 8787 From 6665d9756c95a74d4d96cd3d59f47544d61449c2 Mon Sep 17 00:00:00 2001 From: JoftheV <162925657+JoftheV@users.noreply.github.com> Date: Wed, 18 Jun 2025 05:43:55 -0500 Subject: [PATCH 04/10] Create deploy.yml --- .github/workflows/deploy.yml | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 .github/workflows/deploy.yml diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml new file mode 100644 index 0000000000..f85f5e856f --- /dev/null +++ b/.github/workflows/deploy.yml @@ -0,0 +1,30 @@ +name: Deploy Twilio Neon Worker + +on: + push: + branches: + - main + +jobs: + deploy: + runs-on: ubuntu-latest + + steps: + - name: ⬇️ Checkout Repository + uses: actions/checkout@v4 + + - name: 🟦 Set up Node.js + uses: actions/setup-node@v4 + with: + node-version: '20' + + - name: 📦 Install Dependencies + run: npm install + + - name: ⚙️ Build Worker + run: npm run build + + - name: ☁️ Deploy to Cloudflare Workers + run: npx wrangler deploy + env: + CF_API_TOKEN: ${{ secrets.CF_API_TOKEN }} From 81dc972424cee1299042854c9117d678409a4ac8 Mon Sep 17 00:00:00 2001 From: JoftheV <162925657+JoftheV@users.noreply.github.com> Date: Wed, 18 Jun 2025 06:11:46 -0500 Subject: [PATCH 05/10] Update deploy.yml --- .github/workflows/deploy.yml | 32 +++++++++++++------------------- 1 file changed, 13 insertions(+), 19 deletions(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index f85f5e856f..92c9333642 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -2,29 +2,23 @@ name: Deploy Twilio Neon Worker on: push: - branches: - - main + branches: [main] + workflow_dispatch: jobs: deploy: runs-on: ubuntu-latest - steps: - - name: ⬇️ Checkout Repository - uses: actions/checkout@v4 - - - name: 🟦 Set up Node.js - uses: actions/setup-node@v4 + - uses: actions/checkout@v3 + - uses: pnpm/action-setup@v2 with: - node-version: '20' - - - name: 📦 Install Dependencies - run: npm install - - - name: ⚙️ Build Worker - run: npm run build - - - name: ☁️ Deploy to Cloudflare Workers - run: npx wrangler deploy + version: 8 + - uses: actions/setup-node@v3 + with: + node-version: 20 + - name: Install dependencies + run: pnpm install + - name: Publish Worker + run: npx wrangler deploy --config=twilio-neon/wrangler.toml env: - CF_API_TOKEN: ${{ secrets.CF_API_TOKEN }} + CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }} From ef2b17688fc1e858c1e152659c1fb5324088f453 Mon Sep 17 00:00:00 2001 From: jofthev Date: Wed, 18 Jun 2025 06:36:23 -0500 Subject: [PATCH 06/10] refactor: Modularize Twilio Neon worker core logic --- twilio-neon/inbox-handler.ts | 35 +++++++++++++++++++++++++-------- twilio-neon/messageProcessor.ts | 7 +++++++ twilio-neon/twilioClient.ts | 5 +++++ 3 files changed, 39 insertions(+), 8 deletions(-) create mode 100644 twilio-neon/messageProcessor.ts create mode 100644 twilio-neon/twilioClient.ts diff --git a/twilio-neon/inbox-handler.ts b/twilio-neon/inbox-handler.ts index 885aab69e7..e2a86080bc 100644 --- a/twilio-neon/inbox-handler.ts +++ b/twilio-neon/inbox-handler.ts @@ -1,9 +1,28 @@ -addEventListener('fetch', event => { - event.respondWith( - new Response('Hello from Neon WhatsApp Bot!', { - status: 200, - headers: { 'Content-Type': 'text/plain' }, - }) - ) -}) +import { createTwilioClient } from './twilioClient'; +import { generateReply } from './messageProcessor'; +export default { + async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise { + const { searchParams } = new URL(request.url); + const body = await request.text(); + + const params = new URLSearchParams(body); + const incomingMsg = params.get('Body') || ''; + const from = params.get('From') || ''; + + const twilio = createTwilioClient(env.TWILIO_SID, env.TWILIO_TOKEN); + const reply = generateReply(incomingMsg); + + try { + await twilio.messages.create({ + from: env.TO_WHATSAPP_NUMBER, + to: from, + body: reply, + }); + } catch (error) { + return new Response('Failed to send message', { status: 500 }); + } + + return new Response('OK', { status: 200 }); + }, +}; diff --git a/twilio-neon/messageProcessor.ts b/twilio-neon/messageProcessor.ts new file mode 100644 index 0000000000..165c4ebbac --- /dev/null +++ b/twilio-neon/messageProcessor.ts @@ -0,0 +1,7 @@ +export function generateReply(msg: string): string { + msg = msg.toLowerCase(); + if (msg.includes('confirm')) return '✅ Confirmed. Thank you!'; + if (msg.includes('reschedule')) return '📆 Let us know a new time.'; + if (msg.includes('help')) return '🧠 How can we assist you today?'; + return '🤖 Message received. A representative will reply shortly.'; +} diff --git a/twilio-neon/twilioClient.ts b/twilio-neon/twilioClient.ts new file mode 100644 index 0000000000..43c073601f --- /dev/null +++ b/twilio-neon/twilioClient.ts @@ -0,0 +1,5 @@ +import { Twilio } from 'twilio'; + +export function createTwilioClient(accountSid: string, authToken: string) { + return new Twilio(accountSid, authToken); +} From d630f3acf9d3fe00ef2b7761ce8f48f49632fdc0 Mon Sep 17 00:00:00 2001 From: jofthev Date: Wed, 18 Jun 2025 06:41:31 -0500 Subject: [PATCH 07/10] chore: finalize modularization, add tests, linting, and deploy workflow --- twilio-neon/git-auto.sh | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100755 twilio-neon/git-auto.sh diff --git a/twilio-neon/git-auto.sh b/twilio-neon/git-auto.sh new file mode 100755 index 0000000000..3d32992796 --- /dev/null +++ b/twilio-neon/git-auto.sh @@ -0,0 +1,28 @@ +#!/bin/bash + +# Commit message (customize this) +COMMIT_MSG="chore: finalize modularization, add tests, linting, and deploy workflow" + +echo "Adding all changes..." +git add . + +echo "Committing with message: $COMMIT_MSG" +git commit -m "$COMMIT_MSG" + +echo "Pulling remote changes with rebase..." +git pull --rebase origin main + +if [ $? -ne 0 ]; then + echo "Rebase failed. Please resolve conflicts, then run 'git rebase --continue'." + exit 1 +fi + +echo "Pushing commits to origin/main..." +git push origin main + +if [ $? -eq 0 ]; then + echo "Push successful! 🎉" +else + echo "Push failed. Check your network or remote repository status." +fi + From 2e5ff641da46056a591e11017a98b871d80154f3 Mon Sep 17 00:00:00 2001 From: JoftheV <162925657+JoftheV@users.noreply.github.com> Date: Wed, 18 Jun 2025 18:13:08 -0500 Subject: [PATCH 08/10] Update wrangler.toml --- twilio-neon/wrangler.toml | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/twilio-neon/wrangler.toml b/twilio-neon/wrangler.toml index b0e0a4b8a0..037377695c 100644 --- a/twilio-neon/wrangler.toml +++ b/twilio-neon/wrangler.toml @@ -1,11 +1,18 @@ -name = "neon-whatsapp-bot" -main = "dist/inbox-handler.js" +name = "twilio-neon" compatibility_date = "2025-06-18" -compatibility_flags = ["nodejs_compat"] -usage_model = "bundled" -modules = true +main = "./dist/index.mjs" # Or wherever your compiled entry point lives [build] command = "npm run build" +[vars] +TWILIO_ACCOUNT_SID = "your_sid_here" +TWILIO_AUTH_TOKEN = "your_token_here" +# Add other environment variables here +[triggers] +# Optional: add for Git-based auto deploys, etc. + +[env.production] +name = "twilio-neon-prod" +# Add overrides if you need them in production only From 1d4a1ab2024fe8066df38003a30aaf47b702ba6c Mon Sep 17 00:00:00 2001 From: JoftheV <162925657+JoftheV@users.noreply.github.com> Date: Wed, 18 Jun 2025 18:23:51 -0500 Subject: [PATCH 09/10] Create deploy.sh --- deploy.sh | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 deploy.sh diff --git a/deploy.sh b/deploy.sh new file mode 100644 index 0000000000..c8d4e2a270 --- /dev/null +++ b/deploy.sh @@ -0,0 +1,12 @@ +#!/bin/bash + +if [ -z "$CF_API_TOKEN" ]; then + echo "Error: CF_API_TOKEN is not set." + exit 1 +fi + +export CLOUDFLARE_API_TOKEN="$CF_API_TOKEN" +echo "Exported CLOUDFLARE_API_TOKEN from CF_API_TOKEN" + +# Run wrangler deploy with your config +pnpm exec wrangler deploy --config=twilio-neon/wrangler.toml From 2af4b78a92573e4c7cda1c0c24fefc10158d2de9 Mon Sep 17 00:00:00 2001 From: JoftheV <162925657+JoftheV@users.noreply.github.com> Date: Thu, 19 Jun 2025 01:26:24 -0500 Subject: [PATCH 10/10] Update deploy.yml --- .github/workflows/deploy.yml | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 92c9333642..201d810d87 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -1,24 +1,29 @@ -name: Deploy Twilio Neon Worker +name: Deploy Cloudflare Worker on: push: - branches: [main] - workflow_dispatch: + branches: + - main jobs: deploy: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 - - uses: pnpm/action-setup@v2 - with: - version: 8 - - uses: actions/setup-node@v3 + - name: Checkout repo + uses: actions/checkout@v3 + + - name: Setup Node.js + uses: actions/setup-node@v3 with: - node-version: 20 + node-version: 18 + - name: Install dependencies run: pnpm install - - name: Publish Worker - run: npx wrangler deploy --config=twilio-neon/wrangler.toml + + - name: Build project + run: pnpm run build + + - name: Deploy to Cloudflare Workers env: CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }} + run: npx wrangler deploy --config=twilio-neon/wrangler.toml