Documentation menu

Guides

Generated integration code

Uses the Ahena CLI (beta). Install it with npm install -g @ahena/cli, or prefix commands with npx @ahena/cli. See Installation. The dashboard covers projects, connections, Doctor, the Stack Graph, plans and approvals without it.

ahena generate [-e development] [--framework nextjs|node] [--dry-run] [--force]
ahena generate <provider>      # just one provider

Writes readable TypeScript into your app for every provider connected to the environment:

src/ahena/
  client.ts                 # import { ahena } from "./ahena/client"
  providers/<provider>.ts   # SDK client setup, keys from env
  database/ auth/           # Supabase
  storage/                  # Cloudflare R2 (S3-compatible)
  email/                    # Resend
  generated/
    config.ts               # project + providers (no secrets)
    env.ts                  # AHENA_ENV, missingEnv(), assertEnv()
src/app/api/webhooks/resend/route.ts   # with --framework nextjs
.env.example                # one block per provider, merged in place
.ahena/generated.json       # hashes of what Ahena wrote (commit this)

Where generated files may go

Generated files come from the Ahena API, so the CLI only writes paths the generators actually emit and refuses everything else before writing anything:

  • src/ahena/** (.ts, .tsx, .sql, .md, .json)
  • .env.example
  • docs/ahena/<pack>.md (feature packs)
  • src/app/api/webhooks/{stripe,resend}/route.ts or app/api/webhooks/… (webhook routes)
  • src/app/api/ahena/**/route.ts or app/api/ahena/… (feature-pack routes)
  • GoogleService-Info.plist and google-services.json in the configured iosDir / androidDir

Absolute paths, .., any dot-directory or dotfile other than .env.example (.git/, .github/, .npmrc, .env), node_modules/, package.json and any other path are refused with "Refusing to write …". Feature-pack migrations are written by the CLI from the packs it ships (supabase/migrations/<timestamp>_ahena_<pack>.sql), not from API responses.

import { ahena } from "./ahena/client";

await ahena.email.send({ to: user.email, subject: "Welcome", text: "Hi!" });
await ahena.storage.upload("avatars/1.png", bytes, "image/png");
const { data } = await ahena.database.from("profiles").select("*"); // anon role on the server
const s3 = ahena.storage.raw; // escape hatch: the provider's own client

Runtime

The generated code calls each provider directly with its official SDK. ahena.email.send() → Resend. Nothing goes through Ahena's servers, and an Ahena outage doesn't affect your app.

Supabase sessions on the server

In the browser, the generated Supabase layer keeps one shared client that holds the user's session. On the server, every supabase() call returns a new client that never stores a session, so one request's sign-in can't leak into another request and row level security never runs as the wrong user. To act as the signed-in user on the server, pass their access token: supabaseForRequest(accessToken).from("profiles"), ahena.auth.getUser(accessToken). For Next.js cookie-based sessions use @supabase/ssr, which Ahena doesn't install. See providers/supabase.md.

Regenerating safely

  • Unchanged files are left alone.
  • A file you edited since the last generate is kept, and the CLI tells you. --force replaces it.
  • .env.example blocks between # --- ahena:<provider> … and # --- /ahena:<provider> --- are replaced. Everything outside them is yours.
  • Generated code never contains secrets. Values come from your environment, and assertEnv() fails fast with the missing names.

Verified

All eight generators' output is typechecked against the real provider SDKs in CI. Supabase, Cloudflare, Resend and Stripe, plus a usage file in the style above, are checked in packages/cli/test/generate.test.ts. Firebase, OpenAI, Anthropic and Ollama are checked in their own provider suites.

The generated code is also run, with the real SDKs and fakes only at the network boundary:

  • Validation flow E (packages/cli/test/validation/e-offline.test.ts) runs the generated Supabase, Resend and Ollama code with Ahena stopped.
  • packages/cli/test/generated-runtime.test.ts bundles the generated layer and runs Cloudflare R2 (upload, download, missing key, delete, presigned upload/download URLs) through the AWS SDK, Firebase Cloud Messaging through firebase-admin (a signed token request, then send), and the OpenAI and Anthropic adapters behind ahena.ai (including a refusal). It posts signed, unsigned, tampered, wrong-secret and stale requests to the generated Stripe and Resend webhook routes: a valid signature is handled (204), anything else gets 400 (Stripe) or 401 (Resend), and a missing secret gets 500.
  • The Supabase suite also runs the generated layer against a fake Supabase and checks that two server callers never share a session.

Not yet run: Stripe Checkout and billing portal calls (the Stripe SDK's own HTTP client is only constructed), and the generated Supabase auth helpers against a real auth server.