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,eslocale forcing, and garbage → original-text fallback.search-test: empty index, chunk mapping, missingq, 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)¶
- Zone routing. The
swapps.comzone is on this account; routes are declared inwrangler.jsonc. - WAF Skip rule for
/api/ai/*. See below. - 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. - 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.
Populating AI Search¶
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.