Development

swapps-ai is a Wrangler-managed Cloudflare Worker (TypeScript, ES modules). It has no runtime dependencies and only dev dependencies: typescript, vitest, and wrangler.

Local development

npm install
npm run types     # generate worker-configuration.d.ts from wrangler.jsonc
npm run dev       # wrangler dev → http://localhost:8787

npm run dev runs wrangler dev, serving the Worker at http://localhost:8787.

Port clash with the Platform worker (8787)

Both swapps-ai and swapps-worker (the Platform API) default to port 8787 under wrangler dev, so they cannot run on the default port at the same time. If you need both locally, start one on a different port, e.g. npm run dev -- --port 8788. This is noted in the platform README's local ports table.

AI bindings always hit remote resources

The AI and SWAPPS_AI_SEARCH bindings call live Cloudflare services even in local dev. There is no local emulation, so wrangler dev incurs real Workers AI usage when you exercise the endpoints.

Smoke tests

curl -X POST http://localhost:8787/api/ai/recommend-plan \
  -H "Content-Type: application/json" \
  -d '{"message":"landing page for a campaign"}'

curl -X POST http://localhost:8787/api/ai/refine \
  -H "Content-Type: application/json" \
  -d '{"message":"need site for company that sells courses online","locale":"en"}'

curl "http://localhost:8787/api/ai/search-test?q=plans"

Testing

npm run typecheck   # tsc --noEmit
npm test            # vitest run — no network

The Vitest suite (test/index.test.ts) runs in Node, with no Workers runtime, and mocks both AI.run and SWAPPS_AI_SEARCH.search — it makes no network calls. Coverage includes:

  • Validation: missing / empty / oversize message, invalid JSON.
  • Each Swapps path (Build / Launch / Scale / Custom / Technical Review).
  • Defensive JSON parsing: raw, fenced, embedded-in-prose, and garbage → fallback.
  • Method (405), unknown path (404), preflight (204), and unapproved origin (no echo).
  • Recommendation still succeeds (200) when AI Search throws.
  • refine: section de-dupe / sort / placeholder stripping, field classification, the service↔choice safety net, es locale forcing, and garbage → original-text fallback.
  • search-test: empty index, chunk mapping, missing q, and wrong method.

Configuration and vars

Everything is configured in wrangler.jsonc — bindings, the model var, and zone routes. No code change is needed to swap the model.

{
  "ai":        { "binding": "AI" },
  "ai_search": [{ "binding": "SWAPPS_AI_SEARCH", "instance_name": "swapps-ai-search" }],
  "vars":      { "AI_MODEL": "@cf/meta/llama-3.2-3b-instruct" },
  "routes": [
    { "pattern": "swapps.com/api/ai/*",     "zone_name": "swapps.com" },
    { "pattern": "www.swapps.com/api/ai/*", "zone_name": "swapps.com" }
  ]
}
Name Kind Purpose
AI_MODEL var Workers AI model id. Code falls back to @cf/meta/llama-3.2-3b-instruct if unset. Change it here and redeploy — no code change.
AI binding Workers AI.
SWAPPS_AI_SEARCH binding AI Search instance swapps-ai-search.

The Worker also enables nodejs_compat, observability, and is pinned to a compatibility_date.

Secrets

This Worker needs no application secrets — the frontend calls it over the same zone with no tokens, and AI Search uses its own service token internally (not read by the Worker). Never commit secret values; use wrangler secret put <NAME> if a future feature requires one.

Deployment

npm test && npm run typecheck && npx wrangler deploy

Production smoke test after deploy:

curl -X POST https://swapps.com/api/ai/recommend-plan \
  -H "Content-Type: application/json" \
  -d '{"message":"I need a landing page"}'

Deploys publish to the routes declared in wrangler.jsonc on the swapps.com zone. In the platform's CI / deploy workflow this Worker ships like the other Cloudflare Workers via wrangler deploy.

Cloudflare prerequisites (one-time)

  1. Zone routing. The swapps.com zone is on this account; routes are declared in wrangler.jsonc.
  2. WAF Skip rule for /api/ai/*. See below.
  3. AI Search service token. Created at dashboard → AI → AI Search → Tokens. The Worker does not use this token — it's the credential AI Search itself uses for its storage.
  4. AI Search instance. Created via Wrangler: npx wrangler ai-search create swapps-ai-search --type builtin.

WAF skip for /api/ai/* (server-to-server)

Why the WAF skip exists

Super Bot Fight Mode / Managed Challenges intercept browser-less requests by default. Because /api/ai/* is hit server-to-server (and by fetch without a full browser challenge flow), a Cloudflare challenge page would otherwise reach the request before the Worker. A WAF Custom Rule with action Skip is configured for starts_with(http.request.uri.path, "/api/ai/") so these requests reach the Worker directly.

The builtin instance starts empty. Add content with Wrangler (npx wrangler ai-search items --help). Until items are indexed, recommend-plan still works using only the hard-coded Swapps context; AI Search context is layered in as supporting evidence once available. See Architecture → RAG.