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
4 changes: 2 additions & 2 deletions brain/architecture/shared-utils.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@
- `pluginClient` (`src/kubb/plugin.ts`) with its generators in `src/kubb/client/` and the operation component in `src/kubb/components/`. kubb 5 stable dropped `@kubb/plugin-client`, so the plugin shell lives here (comment in `plugin.ts`).
- Spec transforms (`src/kubb/spec-transforms.ts`): `fetchSpec` (throws on a timeout, a network failure, a non-OK status, a non-JSON body or a body without an `openapi`/`swagger` version and non-empty `paths`; every message names the URL, and the timeout, network and JSON errors keep the original as `cause`), `cleanOperationIds`, `sortArrays`, `addMissingPathParams`, `fixArrayItems`, `fixUnionConstraints`, `sanitizeEnumValues`, `camelCasePathParams`, `renameReservedWords`, `fixRegexPatterns`, `camelCaseProperties`.
- `./effect` (`src/effect/index.ts`): the runtime side, shipped inside each client's `effect` entry.
- Tagged errors `ValidationError`, `ApiError`, `NetworkError`, the `ApiConfig` context tag and `makeApiLayer` (`src/effect/errors.ts`). `ApiError.message` is `API error <status>: <message>`, the message taken from the fetcher's `{ status, payload }` payload first and then the error itself (`message`, `error` as a string or `{ message }`, `errors[0].message`, or a text body), and falls back to `API Error: <status>`. `NetworkError.message` reads `message` from an `Error` or a plain object cause. `errors.test.ts` covers both (#33).
- `createEffectApi` and `createEffectByPath` (`src/effect/proxy.ts`).
- Tagged errors `ValidationError`, `ApiError`, `NetworkError`, the `ApiConfig` context tag and `makeApiLayer` (`src/effect/errors.ts`). `ApiConfig` carries `token`, `baseUrl`, `fetchImpl` and `headers`, and `makeApiLayer` accepts all four (#46). `ApiError.message` is `API error <status>: <message>`, the message taken from the fetcher's `{ status, payload }` payload first and then the error itself (`message`, `error` as a string or `{ message }`, `errors[0].message`, or a text body), and falls back to `API Error: <status>`. `NetworkError.message` reads `message` from an `Error` or a plain object cause. `errors.test.ts` covers both (#33).
- `createEffectApi` and `createEffectByPath` (`src/effect/proxy.ts`). Each operation runs in `Effect.tryPromise` and passes the `AbortSignal` it provides to the operation as `config.signal`, which the generated operation hands to the client's fetcher, so `Effect.timeout`, `Fiber.interrupt` or a lost race aborts the `fetch` instead of leaving it running. The proxies read only own keys, so `Object.prototype` names such as `constructor` return `undefined` (#46).

## Why it matters

Expand Down
2 changes: 2 additions & 0 deletions brain/architecture/website.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
`apps/openapi` (`@sferadev/openapi-website`, private) is a Next.js app that lists the clients with install and usage snippets (`apps/openapi/src/app/page.tsx`). Changesets ignores it (`.changeset/config.json`).

- The page is statically rendered and revalidates every 6 hours (`revalidate = 21600` in `apps/openapi/src/app/page.tsx`). Each version it shows comes from the npm registry, and each lookup is cached for an hour (`apps/openapi/src/lib/npm.ts`), so a new release can take up to 6 hours to appear. A failed lookup renders `unknown` and logs one JSON line naming the package: `npm package not published` with `status: 404`, or `npm registry unavailable` with the other status, or a `reason` for a network or JSON parse error.
- The provider tabs (`apps/openapi/src/components/provider-card.tsx`) render the first provider on the server and on the first client render, then restore the tab stored under the `localStorage` key `activeProviderTab` after mount, ignoring a stored id that matches no provider. Reading storage during the first render caused a hydration mismatch, and the tab list wraps so it fits any number of clients (#48).
- `apps/openapi/AGENTS.md` is written by `next dev` and points agents at the Next.js docs in `node_modules/next/dist/docs/`; it is committed so the tree stays clean (#48).
- `GET /api/health` (`apps/openapi/src/app/api/health/route.ts`) runs `select 1` through the Drizzle `db` with a 3 second limit and returns `{ status, checks: { database } }`: 200 when it succeeds, 503 otherwise. A failure is logged server side with the driver error's name and message, never the connection string. The route is dynamic and sends `Cache-Control: no-store`, takes no auth and reads no new environment variables.
- Auth is Better Auth with a Vercel OAuth provider (`apps/openapi/src/lib/auth.ts`, `apps/openapi/src/app/api/auth/[...all]/route.ts`), stored in Postgres through Drizzle (`apps/openapi/src/lib/db.ts`, migrations in `apps/openapi/drizzle/`). The Vercel userinfo fetch and profile mapping live in `apps/openapi/src/lib/vercel-user-info.ts`, apart from Better Auth and the database so they can be unit-tested ([[development/testing]]).
- It imports no client package, so its build does not wait on any client build. The environment variables it reads, which `turbo.json` also lists for its build:
Expand Down
6 changes: 3 additions & 3 deletions brain/development/release.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ As of 2026-10-14 (`npm view <package> version`, unchanged since the 2026-10-08 c

## Pending changesets

As of 2026-10-15, `.changeset/` holds 34 changesets besides `README.md` and `config.json`. The first release will be a major for all eight published clients:
As of 2026-10-16, `.changeset/` holds 57 changesets besides `README.md` and `config.json`. The first release will be a major for all eight published clients:

- Majors: `effect-v4.md` for the five Effect clients (#6, [[decisions/2026-10-08-effect-4-major]]), and `http-errors-as-api-error.md` for all eight published clients, the new `{ status, payload }` rejection shape (#8, made a major in #9).
- Majors: `effect-v4.md` for the five published Effect clients, which leaves out the unpublished `clickhouse-cloud` (#6, [[decisions/2026-10-08-effect-4-major]]), and `http-errors-as-api-error.md` for all eight published clients, the new `{ status, payload }` rejection shape (#8, made a major in #9).
- Minors: `clickhouse-cloud-client.md` (#2); `path-encoding-clickhouse-cloud.md` and `path-encoding-vercel-api-js.md`, minors because their regenerated specs add operations (#17); `raw-request-bodies-netlify-api.md`, the `body` parameter for non-JSON request bodies (#25).
- Patches: `bundle-openapi-utils.md` (#1), `inline-effect-types.md` (#4), `fetcher-query-serialization.md` (#16), `path-encoding-*.md` for the other seven clients (#17), `path-params-keep-slashes-*.md` for `cloudflare-api-js`, `keycloak-api` and `netlify-api` (#23), `untagged-operations-*.md` for `cloudflare-api-js`, `keycloak-api`, `litellm-api` and `vercel-api-js` (#24), `request-via-operations-*.md` for all nine clients (#26), `fetcher-empty-body-header-case.md` for all nine clients (#28), and `zoom-refresh-basic-auth.md` (#30).
- Patches: `bundle-openapi-utils.md` (#1), `inline-effect-types.md` (#4), `fetcher-query-serialization.md` (#16), `path-encoding-*.md` for the other seven clients (#17), `path-params-keep-slashes-*.md` for `cloudflare-api-js`, `keycloak-api` and `netlify-api` (#23), `untagged-operations-*.md` for `cloudflare-api-js`, `keycloak-api`, `litellm-api` and `vercel-api-js` (#24), `request-via-operations-*.md` for all nine clients (#26), `fetcher-empty-body-header-case.md` for all nine clients (#28), `zoom-refresh-basic-auth.md` (#30), `effect-error-message-*.md` for the six Effect clients (#33), `fetcher-failure-detail-*.md` for all nine clients (#37), `dts-private-types-*.md` for `keycloak-api` and `v0-api` (#42), and `effect-abort-signal-*.md` for the six Effect clients (#46).
2 changes: 1 addition & 1 deletion brain/development/testing.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ Run alone with `pnpm turbo run test --filter=@sferadev/openapi-utils`.
- `src/kubb/components/client-operation.test.ts`: `buildUrlTemplate` percent-encodes single-segment path parameters (#17), keeps slashes in file path parameters and does not double-encode a path already passed through `encodeURI` (#23).
- `src/kubb/client/operations.test.ts`: runs kubb with `createConfig` on the fixture `src/kubb/client/fixtures/params.json` into a temp directory, then imports the emitted `components.ts` against a stub fetcher and a fake `fetch`. A path parameter that is not a JS identifier (`team-id`) is read with bracket access and percent-encoded, a falsy required value (`0`) is kept, query and header params are forwarded, an operation without parameters works, and a missing or empty path parameter, or an omitted `pathParams`, rejects with `Missing required path parameter` before `fetch` is called.
- `src/kubb/adapter.test.ts`: `rawRequestBodyFallback` keeps the first raw media type and leaves JSON-like and url-encoded bodies to the JSON parse (#25).
- `src/effect/proxy.test.ts`: the Effect proxies map a rejection with a `status` to `ApiError`, a missing path parameter to `ValidationError` naming the field and anything else to `NetworkError`, pass the `ApiConfig` service to the operation as `config`, and return `undefined` for an unknown tag, operation or endpoint (#33).
- `src/effect/proxy.test.ts`: the Effect proxies map a rejection with a `status` to `ApiError`, a missing path parameter to `ValidationError` naming the field and anything else to `NetworkError`, pass the `ApiConfig` service to the operation as `config`, and return `undefined` for an unknown tag, operation or endpoint (#33). They also abort the request signal when the effect times out, provide `fetchImpl` to the operation, and return `undefined` for `Object.prototype` keys (#46).
- `src/effect/errors.test.ts`: how `ApiError.message` and `NetworkError.message` read each provider's error shape (#33).
- `src/kubb/client/extra.test.ts`: reads every package's committed `src/**/generated/components.ts` and asserts that each exported operation appears in `operationsByTag` (#24).

Expand Down
4 changes: 2 additions & 2 deletions brain/plans/index.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# Plans

The repository has no roadmap file. Its one open issue, #15, concerns `hq-stack.yml`, which is rendered from sferarc/hq and not edited here ([[development/ci]]) (checked 2026-10-14). Known open work, from the sources cited:
The repository has no roadmap file. Its one open issue, #15, concerns `hq-stack.yml`, which is rendered from sferarc/hq and not edited here ([[development/ci]]) (checked 2026-10-16). Known open work, from the sources cited:

1. First release from this repository, which waits on the owner setting `RELEASE_ENABLED` ([[development/release]]). It ships the openapi-utils bundling fix (#1), the inlined Effect types (#4), the first `clickhouse-cloud` version (#2), the path encoding, raw body, untagged operation and `request()` fixes (#17, #23 to #26), the fetcher's empty body and header case fixes (#28) and Zoom's basic auth token refresh (#30).
1. First release from this repository, which waits on the owner setting `RELEASE_ENABLED` ([[development/release]]). It ships the openapi-utils bundling fix (#1), the inlined Effect types (#4), the first `clickhouse-cloud` version (#2), the path encoding, raw body, untagged operation and `request()` fixes (#17, #23 to #26), the fetcher's empty body and header case fixes (#28), Zoom's basic auth token refresh (#30), the API's message in `ApiError` (#33), the failure cause and response body kept on fetcher errors (#37), the exported fetcher types in the `keycloak-api` and `v0-api` declarations (#42) and aborting the request when an Effect operation is interrupted (#46).
2. That first release is a major for every published client: the five Effect clients for Effect 4 ([[decisions/2026-10-08-effect-4-major]]), and all eight for the HTTP error shape change (#9, `.changeset/http-errors-as-api-error.md`). The full list of pending changesets is in [[development/release]].

The older clients' fetchers used to report an HTTP error status as `NetworkError` rather than `ApiError` (#6). #8 fixed that, and each Effect client's `src/effect.test.ts` asserts `ApiError` with the status (checked 2026-10-13).
Expand Down
Loading