CLI
Two commands — one writes the wiring, the other checks the parts it cannot write.
npx @cosmoops/connect-sdk init # scaffold the bridge route, /plans and .env.local
npx @cosmoops/connect-sdk doctor # check an existing setup and report what is missingBoth take an optional project directory and default to the current one. A bare
path runs init, so connect-sdk init ./my-app and connect-sdk ./my-app are
the same command. --help prints the pair.
init
Writes three files into a Next.js App Router project:
| File | What it is |
|---|---|
app/api/connect/[...connect]/route.ts | The bridge — the only place your API key is used |
app/plans/page.tsx | The full pricing page, one line of it |
.env.local | The two variables, ready to fill in |
Nothing is ever overwritten. A file that already exists is reported as skipped, so re-running after a partial setup is safe, and running it on an app that already has Connect wired up does nothing at all.
It then prints the three steps a scaffolder must not do for you, and the reason each is excluded is worth knowing:
- Wrapping your layout in
ConnectProviderwould mean parsing and rewriting JSX somebody else wrote. - Importing the theme has to happen in your stylesheet, in a specific
position — Tailwind, then
@heroui/styles, then@cosmoops/connect-sdk/theme.cssso its values win. Imported fromnode_modulesinstead, Tailwind roots its content scan there and skips your app. - Registering the redirect URI happens inside Connect, not in your repo.
Why this is a CLI and not a plugin
Next has no plugin API that injects routes. next.config can rewrite and
redirect, but both need a real route to point at, and the App Router discovers
routes by walking your own app/ directory and nothing else — so a package
cannot add /plans to an app by being installed. What it can do is make the
file that must exist a single line, and then write that file for you.
doctor
check is an alias for the same command, if that reads better in a CI step.
Checks the setup init cannot write, which is exactly where integrations
break. Each of those failures is silent or misdirected on its own: a missing
provider throws from a hook, a mis-ordered theme import quietly loses to
HeroUI's defaults, and an unregistered redirect URI only surfaces as an OAuth
error after a round trip to Connect.
ok Bridge route handler (app/api/connect/[...connect]/route.ts)
ok ConnectProvider in a layout (app/layout.tsx)
ok Theme stylesheet imported (app/globals.css)
ok CONNECT_API_KEY set
FAIL CONNECT_CLIENT_ID set
note Redirect URI registered in Connect- It is offline and needs no credentials, so it is safe to run in CI on a pull request. Connect exposes no endpoint listing a client's registered redirect URIs, so there is nothing to check remotely that would justify the cost.
.env.localis read from disk, not throughprocess.env— the interesting case is a developer running this in a shell that never loaded it, which is exactly the shellnext devwill inherit. A variable declared but left empty is reported as missing, not as set.- The bridge is found by what it exports, not by where it sits, because
createConnectHandlers({ basePath })exists precisely so the route can be mounted elsewhere. - The exit code is the point.
FAILmeans the app is broken and returns1;notemeans this cannot tell from the outside and returns0. The redirect URI is always a note. - It catches the split integration. If
CONNECT_APP_URLis set and your layout passes noappUrl, the provider check downgrades to a note: your server talks to that instance while every link the browser builds opens production Connect. It is a note rather than a failure because the prop may be threaded from the layout into a"use client"shell, which this cannot see. See Environments.
note ConnectProvider in a layout
CONNECT_APP_URL is set, but app/layout.tsx passes no appUrl - so your
server talks to that instance while every link the browser builds opens
production Connect. Spread it in:
<ConnectProvider {...connectProviderProps()}>Next steps
- Getting started — what
initwrites, by hand, with the reasoning. - Environments — the variables
doctorchecks, and which Connect instance they point at.