Files
cfw-autumn/.claude/commands/update-autumn-js-route.md
2026-02-26 10:40:45 +00:00

5.5 KiB

description, argument-hint
description argument-hint
Update an existing autumn-js route after changes to its API contract, params, or response shape
route-name e.g. attach
multiAttach
setupPayment

Update Autumn JS Route

When modifying an existing API endpoint (params, response shape, JSDoc, etc.), check all of these locations for consistency.

Architecture

Request flow from React hook to Autumn API:

React Hook (useCustomer)
  → useCustomerActions (redirect logic, URL defaults)
    → AutumnClient / httpClient (POST /api/autumn/{routeName})
      → rou3 router (routeBuilder.ts)
        → executeRoute (resolveIdentity → inject customerId → SDK method)
          → @useautumn/sdk → Autumn API
  • The backend is a thin proxy. routeConfigs.ts maps route names to @useautumn/sdk methods. executeRoute.ts auto-injects customerId from resolveIdentity() before calling the SDK.
  • The React client (AutumnClient.ts) sends POST requests to {pathPrefix}/{routeName} with the body as JSON. The route name IS the URL segment (e.g. multiAttach maps to POST /api/autumn/multiAttach).
  • useCustomerActions wraps client methods with redirect logic and window.location.href defaults. It bridges the TanStack Query-based useCustomer hook and the imperative billing actions.

Files to inspect and update

Layer File What to check
ORPC contract packages/openapi/v2.1/contracts/billingContract.ts Input/output schemas match changes
Generated schemas packages/autumn-js/src/generated/ Re-run bun api if contract changed
Client params packages/autumn-js/src/types/params.ts Omit/extend fields still correct
Type exports packages/autumn-js/src/types/index.ts Alias still matches
React exports packages/autumn-js/src/react/index.ts Client param type exported
Route names packages/autumn-js/src/backend/core/types/routeTypes.ts ROUTE_NAMES has the route
Route config packages/autumn-js/src/backend/core/routes/routeConfigs.ts sdkMethod and bodySchema still match
Client interface packages/autumn-js/src/react/client/IAutumnClient.ts Method signature matches new types
Client impl packages/autumn-js/src/react/client/AutumnClient.ts Response type matches
Hook actions packages/autumn-js/src/react/hooks/internal/useCustomerActions.ts Action logic handles new fields (redirects, defaults)
Hook JSDoc packages/autumn-js/src/react/hooks/useCustomer.ts UseCustomerResult JSDoc describes current behavior
Zod schema gen packages/openapi/utils/zodSchemaGeneration.ts SCHEMA_SOURCES sdkFile/outputFile match current SDK model filenames
SDK test page apps/sdk-test/app/scenarios/core/use-autumn/page.tsx Test UI exposes new/changed params

Common update scenarios

Param added/removed: Update params.ts type -> check useCustomerActions passes it -> update sdk-test inputs.

Response shape changed: Update IAutumnClient + AutumnClient return types -> update useCustomer.ts JSDoc.

Redirect behavior changed: Check useCustomerActions redirect logic (paymentUrl, url, openInNewTab).

JSDoc only: Update useCustomer.ts UseCustomerResult type and the hook's @returns summary.

Gotchas

  • Casing: The SDK uses camelCase everywhere. The backend buildSdkArgs passes camelCase directly to the SDK. Never use snake_case in params.ts, IAutumnClient.ts, or hook types.
  • ProtectedFields: Client param types always Omit<SdkParams, "customerId" | "customerData">. The backend injects these via resolveIdentity. If you add a new field that should NOT be set by the frontend, add it to the Omit union.
  • openInNewTab: Frontend-only field (not sent to the API). Added via & { openInNewTab?: boolean } on client param types that trigger redirects (attach, multiAttach, setupPayment, updateSubscription, openCustomerPortal). The useCustomerActions layer reads it and calls redirectToUrl.
  • successUrl / returnUrl defaults: Actions in useCustomerActions default these to window.location.href. If you change this default, update all actions consistently.
  • Route name must match everywhere: The string in ROUTE_NAMES, routeConfigs[].route, AutumnClient's http.request({ route: "..." }), and the rou3 path segment must all be identical.
  • bodySchema is optional: Only needed if the route is used via the better-auth plugin. Standard routes work without it.
  • Response types come from @useautumn/sdk: Don't create custom response types. Import from the SDK (e.g. AttachResponse, SetupPaymentResponse). These are auto-generated by Speakeasy.
  • Generated schemas in packages/autumn-js/src/generated/ are only for bodySchema validation in better-auth. Not all routes need them.
  • operationId renames cause SDK file renames: When you change an operationId in a contract (e.g. billingAttachattach), Speakeasy renames the generated model file (e.g. billing-attach-op.tsattach-op.ts) and all its exported types (e.g. BillingAttachResponseAttachResponse). You must update: (1) packages/openapi/utils/zodSchemaGeneration.ts — change the sdkFile and outputFile in SCHEMA_SOURCES, (2) delete the old generated schema file from packages/autumn-js/src/generated/, and (3) update all imports of the old type names across IAutumnClient.ts, AutumnClient.ts, useCustomerActions.ts, and useCustomer.ts.

Validation

bunx biome check --write <paths to changed files>