5.5 KiB
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 |
|
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.tsmaps route names to@useautumn/sdkmethods.executeRoute.tsauto-injectscustomerIdfromresolveIdentity()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.multiAttachmaps toPOST /api/autumn/multiAttach). useCustomerActionswraps client methods with redirect logic andwindow.location.hrefdefaults. It bridges the TanStack Query-baseduseCustomerhook 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
buildSdkArgspasses camelCase directly to the SDK. Never use snake_case inparams.ts,IAutumnClient.ts, or hook types. ProtectedFields: Client param types alwaysOmit<SdkParams, "customerId" | "customerData">. The backend injects these viaresolveIdentity. 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). TheuseCustomerActionslayer reads it and callsredirectToUrl.successUrl/returnUrldefaults: Actions inuseCustomerActionsdefault these towindow.location.href. If you change this default, update all actions consistently.- Route name must match everywhere: The string in
ROUTE_NAMES,routeConfigs[].route,AutumnClient'shttp.request({ route: "..." }), and the rou3 path segment must all be identical. bodySchemais 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 forbodySchemavalidation in better-auth. Not all routes need them. - operationId renames cause SDK file renames: When you change an
operationIdin a contract (e.g.billingAttach→attach), Speakeasy renames the generated model file (e.g.billing-attach-op.ts→attach-op.ts) and all its exported types (e.g.BillingAttachResponse→AttachResponse). You must update: (1)packages/openapi/utils/zodSchemaGeneration.ts— change thesdkFileandoutputFileinSCHEMA_SOURCES, (2) delete the old generated schema file frompackages/autumn-js/src/generated/, and (3) update all imports of the old type names acrossIAutumnClient.ts,AutumnClient.ts,useCustomerActions.ts, anduseCustomer.ts.
Validation
bunx biome check --write <paths to changed files>