A lightweight Cloudflare Workers api and proxy service for HERE API endpoints, iOS universal links, etc. with Sentry monitoring.
- pnpm installed
- Cloudflare account
- HERE API key
- Sentry account (optional but recommended for error logging)
pnpm installCopy the example file and fill in your credentials:
cp .dev.vars.example .dev.varsEdit .dev.vars with your actual values:
HERE_API_KEY=your_here_api_key
SENTRY_DSN=https://your-sentry-dsn@sentry.io/project-idRun the development server:
pnpm run devThe service will be available at http://localhost:8787
# Autocomplete
curl "http://localhost:8787/autocomplete?q=cincinnati&limit=5"
# Geocode
curl "http://localhost:8787/geocode?q=48 Muir+Rd,+Rogers,+KY+41365"
# Health check
curl "http://localhost:8787/health"Set secrets (one-time setup):
pnpm exec wrangler secret put HERE_API_KEY
# Paste your HERE API key when prompted
pnpm exec wrangler secret put SENTRY_DSN
# Paste your Sentry DSN when promptedVerify secrets are set:
pnpm exec wrangler secret listDeploy to Cloudflare Workers:
pnpm run deployThe project includes CI/CD that deploys automatically on git tags.
Go to your repo → Settings → Secrets and variables → Actions
Add these secrets:
CLOUDFLARE_API_TOKEN- Get from Cloudflare DashboardHERE_API_KEY- Your HERE API keySENTRY_DSN- Your Sentry DSN
- Go to Cloudflare API Tokens
- Click "Create Token"
- Use "Edit Cloudflare Workers" template
- Copy the token and add it to GitHub secrets as
CLOUDFLARE_API_TOKEN
git tag v1.0.0
git push origin v1.0.0GitHub Actions will automatically deploy to Cloudflare Workers. Monitor deployment in the Actions tab.
Proxies to HERE Autocomplete API.
Example request:
curl "https://your-worker.workers.dev/autocomplete?q=Seattle&limit=5"Query parameters:
q: Search query (required)limit: Max number of suggestionsin: Geographic filter (e.g.,circle:47.6,-122.3;r=50000)- All other HERE Autocomplete API parameters and docs
Note: The apiKey parameter is automatically injected by the proxy. Any apiKey sent by the client will be removed.
Proxies to HERE Geocode API.
Example request:
curl "https://your-worker.workers.dev/geocode?q=1600+Amphitheatre+Parkway"Query parameters:
q: Address to geocode (required)- All other HERE Geocode API parameters and docs
Note: The apiKey parameter is automatically injected by the proxy. Any apiKey sent by the client will be removed.
Serves the AASA JSON used by iOS to validate universal links for contact
sharing. Lists the prod (com.leviwilkerson.jwtime), beta
(com.leviwilkerson.jwtimebeta), and dev (com.leviwilkerson.jwtimedev) bundle
IDs, prefixed with APPLE_TEAM_ID.
Matches /c with a non-empty fragment (/c#<payload>) and, for links shared
by older app versions, any URL under /c/*.
Universal-link landing page for shared WitnessWork contacts
(/c#<payload>). iOS hands the link off to the WitnessWork app when
installed; otherwise this endpoint serves a fallback HTML page with an App
Store CTA.
The page, accessibility labels, and Open Graph/Twitter preview strings support
the same 18 locales as witness-work/src/lib/locales.ts. Pass ?lang=pt-pt
before the fragment (/c?lang=pt-pt#<payload>) to choose a language explicitly;
otherwise the worker uses Accept-Language preferences, including quality
weights, and defaults to English (en-us). Unsupported or malformed lang
values fall back to browser preferences. Regional variants fall back to the
same language; Portuguese defaults to pt-br, and Chinese uses Simplified
unless Traditional script or a Taiwan/Hong Kong/Macau region is requested.
Responses include Content-Language and Vary: Accept-Language. Preview
crawlers without a language preference receive English unless lang is set.
The canonical og:url remains the bare /c, without language or contact data.
The same localization rules apply to legacy /c/:payload links.
The payload is an opaque gzip + base64url–encoded contact export produced by
the app. It rides in the URL fragment, which clients never send, so the worker
never sees it; the page's inline script builds the
witnesswork://import-contact/<payload> "Open app" link in the browser.
Legacy links from older app versions, with the payload in the path. Serves the
same page with a server-rendered "Open app" link; the payload stays out of
og:url and the other meta tags, and Sentry events redact it to
/c/[redacted]. The worker never decodes it.
LLM-backed parsing of free-form ministry notes into structured WitnessWork
records. The proxy owns the prompt + JSON schema, calls the model through
OpenRouter with routing pinned ZDR-only (zdr: true + data_collection: 'deny',
restricted to a vetted Western provider allowlist) so the request can only reach
a zero-data-retention host that never trains on or stores it — failing rather
than ever downgrading to a data-retaining provider (ADR 0008). It persists
non-content authentication/runtime metadata in KV and aggregate usage plus
permanent replay/refinement records in a per-user Durable Object—never imported
text or model output in either meter store.
Core routes (all rate-limited):
POST /notes-import/challenge→{ challenge }. One-time App Attest nonce.POST /notes-import/attestperforms the App Attest handshake.POST /notes-import/kickoffstarts a streaming run and returns its handle, capability token, and strictcreditspreview;GET .../events/.../resultcarry the terminal result and authoritativecreditssnapshot.POST /notes-importis the synchronous fallback under identical rules.GET /notes-import/statusis public and supplies a fresh allowance schedule only when availability is confirmed.
Auth is enforced by Apple App Attest on every inference kickoff. A dev worker
may set NOTES_IMPORT_DEV_BYPASS_TOKEN so the simulator can send
x-ww-dev-bypass: <token> to skip attestation. It overrides both effective usage
allowances to unlimited while keeping real Supporter status false and retaining
hash/refinement accounting. Existing active-concurrency behavior is unchanged.
Never set this token in production.
One-time setup (beyond HERE/Sentry):
pnpm exec wrangler kv namespace create NOTES_KV
# → paste the printed id into wrangler.toml [[kv_namespaces]] id
pnpm exec wrangler secret put OPENROUTER_API_KEY
pnpm exec wrangler secret put REVENUECAT_API_KEY
pnpm exec wrangler secret put ADMIN_API_TOKEN
pnpm exec wrangler secret put ADMIN_API_TOKEN --env dev # use a DIFFERENT valueEach environment's NOTES_KV may contain notes-import:limits:
{"importsFree":5,"importsSupporter":-1,"refinementsFree":5,"refinementsSupporter":-1,"windowDays":30}Allowance values are integer -1 (unlimited), 0 (none), or positive finite;
windowDays is any positive finite number and may be fractional in development.
Each field independently resolves KV → environment variable → code default. KV
reads use a 60-second edge cache. Model/provider, concurrency, and Empty Import
grace controls remain environment-only; see src/notesImport/config.ts and
wrangler.toml.
Generate distinct prod/dev tokens with openssl rand -base64 32, configure the
Wrangler secrets above, copy .env.example to the gitignored .env, and set the
matching local tokens plus the dev Worker URL. Then run:
pnpm run admin:reset-usage <meterId> # production
pnpm run admin:reset-usage --dev <meterId> # developmentThe secret route clears only the aggregate import window and Empty Import rows;
permanent hash replay and refinement records survive. Missing configuration or
bad auth returns 404. Data Studio remains the manual emergency fallback. Never
reuse NOTES_IMPORT_DEV_BYPASS_TOKEN as the admin secret.
Health check endpoint.
Response:
{
"status": "ok",
"timestamp": "2024-11-27T12:34:56.789Z"
}All errors return JSON with an error field:
{
"error": "Error message"
}All errors are automatically reported to Sentry with full context.
Client Request
↓
Cloudflare Workers (Global Edge)
↓
Hono Router
↓
API Key Injection & Sanitization
↓
HERE API
↓
Response to Client
(Sentry monitors all errors)
- Runtime: Cloudflare Workers with
nodejs_compat - Framework: Hono
- Language: TypeScript
- Package Manager: pnpm
- Monitoring: Sentry
- Wrangler: v4.42.2