Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,9 @@ src/.DS_Store
frontend/node_modules/
frontend/dist/
frontend/package-lock.json
frontend/.env.local

alerts/node_modules/
alerts/package-lock.json
alerts/.dev.vars
alerts/.wrangler/
2 changes: 2 additions & 0 deletions alerts/.dev.vars.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
RESEND_API_KEY=re_xxxxxxxx
VAPID_PRIVATE_KEY={"alg":"ES256","key_ops":["sign"],"ext":true,"kty":"EC","x":"...","y":"...","crv":"P-256","d":"..."}
56 changes: 56 additions & 0 deletions alerts/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
# Turbolong APY Alerts Worker

Cloudflare Worker for email and web-push APY alerts (negative net APY per pool/asset/leverage bracket).

## Setup

```bash
npm install
```

1. **D1** — Create the database (once), paste `database_id` into `wrangler.toml`:

```bash
npm run db:create
npm run db:migrate:remote
```

2. **Secrets** (never commit these):

```bash
wrangler secret put RESEND_API_KEY
wrangler secret put VAPID_PRIVATE_KEY # JWK JSON from `npm run vapid:generate`
```

`VAPID_PUBLIC_KEY` is set in `wrangler.toml` and must match the key pair used for `VAPID_PRIVATE_KEY`.

3. **Deploy** (after `npx wrangler login`):

```bash
npm run setup:remote
```

This creates D1 (if needed), runs the remote migration, uploads `VAPID_PRIVATE_KEY` from `.dev.vars`, prompts for `RESEND_API_KEY`, and deploys.

Or step by step: `npm run build` then `npm run deploy`.

## Web push (E5)

- `GET /vapid-public-key` — public VAPID key for `pushManager.subscribe`
- `POST /push/subscribe` — body: `{ subscription, pool_id, asset_symbol, leverage_bracket }`
- `GET /push/unsubscribe?token=` — remove subscription

Cron (every 15 min) sends push for the same negative-APY events as email, with the same 24h throttle.

## Local dev

```bash
wrangler dev
```

Point the frontend at the local worker:

```bash
# frontend/.env.local
VITE_ALERTS_WORKER_URL=http://127.0.0.1:8787
```
15 changes: 15 additions & 0 deletions alerts/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

13 changes: 10 additions & 3 deletions alerts/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,18 @@
"scripts": {
"dev": "wrangler dev",
"deploy": "wrangler deploy",
"build": "wrangler deploy --dry-run",
"db:create": "wrangler d1 create turbolong-alerts",
"db:migrate": "wrangler d1 execute turbolong-alerts --file=src/schema.sql"
"db:migrate": "wrangler d1 execute turbolong-alerts --local --file=src/schema.sql",
"db:migrate:remote": "wrangler d1 execute turbolong-alerts --remote --file=src/schema.sql",
"vapid:generate": "npx @pushforge/builder vapid",
"setup:remote": "powershell -ExecutionPolicy Bypass -File scripts/deploy-remote.ps1"
},
"devDependencies": {
"wrangler": "^3.99.0",
"typescript": "^5.7.3"
"typescript": "^5.7.3",
"wrangler": "^3.99.0"
},
"dependencies": {
"@pushforge/builder": "^2.0.5"
}
}
50 changes: 50 additions & 0 deletions alerts/scripts/deploy-remote.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# Deploy Turbolong alerts worker (D1 + VAPID secrets + worker).
# Prereq: npx wrangler login (or CLOUDFLARE_API_TOKEN in env)

$ErrorActionPreference = "Stop"
Set-Location $PSScriptRoot\..

Write-Host "Checking Wrangler auth..."
$whoami = npx wrangler whoami 2>&1 | Out-String
if ($whoami -match "not authenticated") {
Write-Host "Run: npx wrangler login"
exit 1
}

if ((Get-Content wrangler.toml -Raw) -match 'database_id = "<run') {
Write-Host "Creating D1 database..."
$out = npx wrangler d1 create turbolong-alerts 2>&1 | Out-String
Write-Host $out
if ($out -match 'database_id = "([a-f0-9-]+)"') {
$id = $Matches[1]
(Get-Content wrangler.toml -Raw) -replace 'database_id = "<[^"]+>"', "database_id = `"$id`"" |
Set-Content wrangler.toml -NoNewline
Write-Host "Updated wrangler.toml with database_id $id"
} else {
Write-Host "Could not parse database_id from wrangler output. Paste it into wrangler.toml manually."
exit 1
}
}

Write-Host "Migrating remote D1..."
npm run db:migrate:remote

$devVars = Get-Content .dev.vars -Raw
if ($devVars -notmatch 'VAPID_PRIVATE_KEY=(.+)') {
Write-Host "Missing VAPID_PRIVATE_KEY in alerts/.dev.vars — run: npm run vapid:generate"
exit 1
}
$jwk = $Matches[1].Trim()

Write-Host "Setting VAPID_PRIVATE_KEY secret..."
$jwk | npx wrangler secret put VAPID_PRIVATE_KEY

if (-not $env:SKIP_RESEND_SECRET) {
Write-Host "Set RESEND_API_KEY if not already set (interactive):"
npx wrangler secret put RESEND_API_KEY
}

Write-Host "Deploying worker..."
npm run deploy

Write-Host "Done. Worker: https://turbolong-alerts.workers.dev"
Loading