Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 10 additions & 9 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,15 +61,16 @@ See `project_structure.md`. Summary: one Next.js app (`app/`, `components/`, `li

Installed and verified 2026-11-04 with **pnpm 11** (`packageManager` is pinned; esbuild's build script is approved in `pnpm-workspace.yaml`). Exact versions are pinned in `package.json`; add new ones pinned too. Keep this table accurate.

| Task | Command |
| ---------------------------------- | ----------------------------------------------------------------------------------------------------- |
| Install | `pnpm install` |
| Dev app / worker | `pnpm dev` / `pnpm worker` |
| **Demo mode (zero config)** | `pnpm demo` |
| Typecheck / lint / format | `pnpm typecheck` / `pnpm lint` / `pnpm format` (check without writing: `pnpm format:check`) |
| Tests / E2E | `pnpm test` / `pnpm e2e` |
| DB | `pnpm db:generate && pnpm db:migrate` |
| Storage payer (S0.10, 👤 funds it) | `pnpm payer` status · `pnpm payer:generate` local key → `.env` · `pnpm payer:check` read-only balance |
| Task | Command |
| ---------------------------------- | ---------------------------------------------------------------------------------------------------------------------------- |
| Install | `pnpm install` |
| Dev app / worker | `pnpm dev` / `pnpm worker` |
| **Demo mode (zero config)** | `pnpm demo` |
| Typecheck / lint / format | `pnpm typecheck` / `pnpm lint` / `pnpm format` (check without writing: `pnpm format:check`) |
| Tests / E2E | `pnpm test` / `pnpm e2e` |
| DB | `pnpm db:generate && pnpm db:migrate` |
| Storage payer (S0.10, 👤 funds it) | `pnpm payer` status · `pnpm payer:generate` local key → `.env` · `pnpm payer:check` read-only balance |
| 1Click credential (S8.7) | `pnpm oneclick:check` (dry preview) · `pnpm oneclick:check --real <near-account>` (proves a deposit address; moves no funds) |

Before saying done: `pnpm format && pnpm typecheck && pnpm lint && pnpm test`. CI does not run the formatter, so an edit that skips `pnpm format` leaves drift in the tree — it came back within three days of the last sweep (#97). `pnpm demo` must work on a fresh clone with **no `.env`, no keys, no external DB**.

Expand Down
2 changes: 1 addition & 1 deletion ARCHITECTURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ Conventions every route follows:

### 3.2 1Click integration (`lib/oneclick`)

Base `https://1click.chaindefuser.com`; `ONECLICK_JWT` is the partner credential. Measured 2026-11-10: unauthenticated `POST /v0/quote` answers `400 Internal server error` on every route tried, dry or not, where the same body returned 200 on 2026-11-09; a bogus bearer answers `401 Invalid token`, and `GET /v0/tokens` still answers 200. Treat the JWT as required for any quote (§8), not merely as a fee discount.
Base `https://1click.chaindefuser.com`; `ONECLICK_JWT` is the partner credential. Measured 2026-11-10 (S8.7): a **dry** quote answers 200 without a token, while a **non-dry** quote — the one that carries `depositAddress` — answers `400 Internal server error` without one and `401 Invalid token` with a bogus one; `GET /v0/tokens` answers 200 either way. The vendor's docs agree: unauthenticated quotes are allowed at +25 bps, but an address is issued only to a partner credential. So the JWT is required for a real quote, not for a preview (§8, S8.4/S8.7).

Invoice quote:

Expand Down
23 changes: 20 additions & 3 deletions DEPLOY.md
Original file line number Diff line number Diff line change
Expand Up @@ -148,11 +148,26 @@ Point the host's health check at it, and use it to confirm S8.3 from the outside
| `SESSION_SECRET` | yes | yes | ≥ 32 chars; without it nobody can sign in |
| `PUBLIC_APP_URL` | yes | yes | the `https://` URL; also decides cookie `Secure` |
| `NEAR_RPC_URL` | no | yes | signed actions fail closed with `not_configured` |
| `ONECLICK_JWT` | no | no | optional; 0.2% fee without it (Q-006) |
| `ONECLICK_JWT` | no | **yes** | a non-dry quote needs it; previews work without it |
| `DEMO_MODE` | no | never | must be **unset** on a host, per §3 |

`pnpm check-env` prints what is set and what is missing without echoing a secret.

### Obtaining the 1Click credential (S8.4, 👤)

`ONECLICK_JWT` is the only secret that cannot be generated here: it is issued by a partner account.
Without it, previews price but no deposit address is issued.

1. Sign in at https://partners.near-intents.org (WorkOS email/SSO) and copy the API key (JWT) from
the Partner Dashboard. An API key is per integration; never paste it into chat or a commit.
2. Local: add `ONECLICK_JWT=…` to `.env.local`, then
`set -a; . ./.env.local; set +a; pnpm oneclick:check`.
`pnpm oneclick:check --real <your-near-account>` additionally proves that a deposit address is
issued; it quotes 10.5 USDC on NEAR into itself, sends nothing, and the quote expires.
3. Hosted: `vercel env add ONECLICK_JWT production`, then redeploy — the Vercel project is not
Git-connected, so a merge alone does not ship it. Verify with the same command locally against
the stored value; the hosted pay page then issues real addresses.

## 6. Host options, read on 2026-11-08

S8.1 has to buy the shape proven in §3: **two long-lived processes and one Postgres, all reachable
Expand Down Expand Up @@ -214,8 +229,10 @@ Two limits of this host, stated so nobody is surprised by them:
live quote, and even with the JWT a deposit would not be driven to `paid` without a worker. Live
payments need a §1 two-process host (Render/Railway/Fly or one machine under a supervisor). This
is why the full walkthrough stays `pnpm demo` — offline, no JWT, no worker, all statuses reachable.
- **No `ONECLICK_JWT`** (S0.8, the partner credential), so quotes are refused by design. The rest of
the app is exercisable; payment pricing is not.
- **No `ONECLICK_JWT`** (S0.8, the partner credential), so a deposit address is refused by design.
A dry preview still prices (measured 2026-11-10), but a real quote answers `400 Internal server
error` without the credential. The app now checks the deployment first and answers
`server_misconfigured` instead of blaming the caller (S8.7).

What was found by deploying and not by testing: the app returned `503 database:unreachable` on a cold
serverless boot with `Error: Can't find meta/_journal.json`. Drizzle's migrator reads `./drizzle` from
Expand Down
Loading
Loading