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
14 changes: 7 additions & 7 deletions .changeset/README.md
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
# Changesets

Add a non-empty Changeset when a pull request changes the published package's runtime behavior, types,
exports, peer or runtime dependency ranges, or metadata that affects installation:
If a pull request changes the published package's runtime behavior, types, exports, or peer or runtime dependency ranges, add a non-empty Changeset.
Changes to metadata that affects installation also require a non-empty Changeset:

```sh
vp run changeset
```

Choose the pre-1.0 bump deliberately and describe the consumer-visible change. The version workflow
formats generated changelogs and manifests through Vite+'s Oxfmt task, and the Changeset Bot leaves
an advisory pull-request comment when changes to `src/**` or the root `package.json` may need a Changeset.
Choose the pre-1.0 version bump and describe the change that consumers see.
The version workflow uses Vite+'s Oxfmt task to format generated changelogs and manifests.
If changes to `src/**` or the root `package.json` can require a Changeset, the Changeset Bot leaves an advisory pull-request comment.

Documentation, examples, tests, internal tooling, and CI do not require a Changeset. Do not add an
empty Changeset as a process marker; explain an intentional omission during review instead.
Documentation, examples, tests, internal tooling, and CI do not require a Changeset.
Explain an intentional omission during review. Do not add an empty Changeset as a process marker.

Only the root `effect-api-query` package is versioned and published. The private example workspace
packages remain unversioned.
514 changes: 300 additions & 214 deletions .intent/review-state.json

Large diffs are not rendered by default.

38 changes: 19 additions & 19 deletions GLOSSARY.md
Original file line number Diff line number Diff line change
@@ -1,85 +1,85 @@
# Effect API Query

This glossary defines the project-specific language for deriving TanStack Query utilities from Effect RPC and HTTP contracts.
These terms describe how the package builds TanStack Query utilities from Effect RPC and HTTP contracts.

## Generated API

**RPC utility tree**:
A nested object derived from literal Effect RPC tags. Branches represent RPC namespaces; unary and streaming leaves provide their typed key and option builders.
A nested object built from literal Effect RPC tags. Branches represent RPC namespaces. Unary and streaming leaves provide typed key and option builders.
_Avoid_: Router, generated client

**HTTP utility tree**:
A nested object derived from an Effect HttpApi's literal group and endpoint identifiers. Supported buffered and SSE endpoints provide typed key and option builders, with multipart endpoints limited to buffered mutations; endpoints in top-level groups appear at the root.
A nested object built from the literal group and endpoint identifiers in an Effect HttpApi. Supported buffered and SSE endpoints provide typed key and option builders. Multipart endpoints support buffered mutations only. Endpoints in top-level groups appear at the root.
_Avoid_: RPC utility tree, generated client

**Query data**:
The successful decoded RPC or HTTP value presented to TanStack Query. Buffered queries and live queries convert successful `undefined` to `null`; accumulated stream elements and mutation data remain unchanged.
The successful decoded RPC or HTTP value that TanStack Query receives. Buffered queries and live queries convert successful `undefined` to `null`. Accumulated stream elements and mutation data keep their original values.
_Avoid_: RPC success value when it is `undefined`

**Accumulated streamed query**:
A streaming RPC or HTTP SSE view that caches emitted values in order, optionally retaining only a bounded recent history. Refetches may reset, append to, or replace the cached sequence.
A streaming RPC or HTTP SSE view that caches emitted values in order. It can limit the cache to a recent history. Refetches can reset, append to, or replace the cached sequence.
_Avoid_: Live query, infinite query

**Live query**:
A streaming RPC or HTTP SSE view that caches only the latest emitted value, converting `undefined` to `null`. Stream completion preserves that value; completion before the first emission produces a package error.
A streaming RPC or HTTP SSE view that caches only the latest emitted value. It converts `undefined` to `null`. Stream completion preserves the latest value. Completion before the first emission produces a package error.
_Avoid_: Accumulated streamed query, subscription

**HTTP metadata view**:
A buffered HTTP query view containing decoded query data and an immutable snapshot of the response status and raw string headers. Declared decoded header wrappers remain part of its data.
A buffered HTTP query view with decoded query data and an immutable snapshot of the response status and raw string headers. Declared decoded header wrappers remain part of the data.
_Avoid_: Raw response, header-wrapped success

## Payloads and keys

**HTTP request input**:
The decoded request parts accepted by a ready HTTP API client: declared params, query, headers, and payload. It excludes response controls; RPC payload constructors do not apply to it.
The decoded request parts that a ready HTTP API client accepts: declared params, query, headers, and payload. Response controls are excluded. RPC payload constructors do not apply to HTTP request input.
_Avoid_: Payload constructor input, wire request

**Payload constructor input**:
The call-site value accepted by an RPC payload Schema constructor. It may omit fields supplied by constructor defaults.
The value that a call site passes to an RPC payload Schema constructor. It can omit fields that constructor defaults supply.
_Avoid_: Normalized payload, encoded payload

**Normalized payload**:
The payload Schema's decoded `Type` after the constructor applies defaults and validates the input.
The payload Schema's decoded `Type` after its constructor applies defaults and validates the input.
_Avoid_: Payload constructor input, encoded payload

**Query-stable payload Schema**:
An RPC payload Schema whose normalized value can pass through its constructor again without changing its encoded meaning.
An RPC payload Schema whose constructor accepts its normalized value again without changing the value's encoded meaning.
_Avoid_: Deterministic encoder, universally idempotent Schema

**Canonical key payload**:
The immutable, JSON-safe representation of a normalized payload used for cache identity. It is independent of protocol-specific transport encoding.
The immutable, JSON-safe representation of a normalized payload that identifies a cache entry. It is independent of the transport encoding for a protocol.
_Avoid_: Wire payload, raw input

**Key prefix**:
A caller-supplied, non-empty tuple of JSON-safe values that namespaces a utility tree. Generated roots append an adapter discriminator and, for HTTP, the API identifier.
A non-empty tuple of JSON-safe values that the caller supplies to namespace a utility tree. Generated roots append an adapter discriminator. HTTP roots also append the API identifier.
_Avoid_: Automatic namespace, client identity

## Execution and failures

**Cancellable command**:
An application operation identified before work starts, with observable progress and an explicit cancellation request. Its terminal domain state is independent of the TanStack mutation state; cancellation stops future work without undoing completed work.
An application operation with an identifier assigned before work starts, observable progress, and an explicit cancellation request. Its terminal domain state is independent of the TanStack mutation state. Cancellation stops future work without undoing completed work.
_Avoid_: Mutation cancellation, rollback

**Ready RPC client**:
A flat, tag-first Effect RPC client acquired within a Scope that remains alive while an RPC utility tree uses it. The caller owns the Scope and disposal.
A flat, tag-first Effect RPC client acquired within a Scope. The Scope stays alive while an RPC utility tree uses the client. The caller owns the Scope and disposal.
_Avoid_: Client factory, owned client

**Ready HTTP API client**:
An acquired Effect HttpApiClient whose transport, middleware, runtime, and resource lifetime belong to the caller.
An acquired Effect HttpApiClient. The caller owns its transport, middleware, runtime, and resource lifetime.
_Avoid_: URL client, client factory, owned client

**RPC execution error**:
An `Error` produced when an RPC Effect returns a failed `Exit`. It identifies the RPC and operation and preserves the complete Effect `Cause` without retaining the input.
An `Error` that the package produces when an RPC Effect returns a failed `Exit`. It identifies the RPC and operation. It preserves the complete Effect `Cause` without retaining the input.
_Avoid_: Catch-all adapter error, configuration error

**HTTP execution error**:
An `Error` produced when an HTTP Effect returns a failed `Exit`. It identifies the declared API, group, endpoint, method, and operation and preserves the complete Effect `Cause`.
An `Error` that the package produces when an HTTP Effect returns a failed `Exit`. It identifies the declared API, group, endpoint, method, and operation. It preserves the complete Effect `Cause`.
_Avoid_: Sanitized Cause, configuration error

**Configuration error**:
An error that rejects invalid utility configuration during preparation or execution.
_Avoid_: RPC execution error

**Key-generation error**:
A synchronous error produced while deriving canonical cache identity from RPC payload constructor input or HTTP request input.
A synchronous error that occurs while the package derives canonical cache identity from RPC payload constructor input or HTTP request input.
_Avoid_: RPC execution error, configuration error
60 changes: 30 additions & 30 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# effect-api-query

Derive typed TanStack Query options and cache keys from your Effect RPC and HttpApi contracts.
Pass the generated options to QueryClient or your framework's Query hooks. Inputs and results
follow the contract; your application controls transport, client lifetime, and cache policy.
`effect-api-query` builds typed TanStack Query options and cache keys from Effect RPC and HttpApi contracts.
Pass these options to QueryClient or your framework's Query hooks. The contract defines the inputs and results.
Your application controls transport, client lifetime, and cache policy.

## Install

Expand All @@ -12,19 +12,19 @@ Install the package and TanStack Query Core:
pnpm add effect-api-query @tanstack/query-core
```

The package pins one exact Effect 4 release because its RPC and HTTP API modules are unstable.
With automatic peer installation enabled, pnpm installs that version. Existing applications must
match it. Use TypeScript 5.9 or newer with `strict: true`, ESM, and ES2022 support. See
The package requires one exact Effect 4 release because its RPC and HTTP API modules are unstable.
If automatic peer installation is enabled, pnpm installs that version. Existing applications must
use the same version. Use TypeScript 5.9 or newer with `strict: true`, ESM, and ES2022 support. See
[compatibility and stability](https://ueberbrot.github.io/effect-api-query/getting-started/compatibility-and-stability/).

## RPC

Import the shared contract from both your server and client. Acquire a matching **flat RPC client**
before calling `readUser`, and keep its Scope alive while the client is in use. The
Import the shared contract in both your server and client. Before calling `readUser`, acquire a matching flat RPC client.
Keep its Scope alive while you use the client. The
[RPC quick start](https://ueberbrot.github.io/effect-api-query/getting-started/quick-start/)
shows acquisition and cleanup.

**Shared contract — `rpc-contract.ts`**
Shared contract in `rpc-contract.ts`:

```ts
import { Schema } from 'effect'
Expand All @@ -38,7 +38,7 @@ export const usersRpc = RpcGroup.make(
)
```

**Client integration — `client.ts`**
Client integration in `client.ts`:

```ts
import { QueryClient } from '@tanstack/query-core'
Expand All @@ -57,17 +57,17 @@ async function readUser(
}
```

Dotted tags become nested utility paths: `users.get` becomes `rpc.users.get`. RPC inputs use the
payload Schema's constructor input.
Dotted tags become nested utility paths. For example, `users.get` becomes `rpc.users.get`.
RPC inputs use the payload Schema's constructor input, including fields that its defaults can supply.

## HTTP

Import the shared HttpApi from both your server and client. Acquire its **ready HttpApiClient**
before calling `readUser`, and keep its transport resources alive while the client is in use. The
Import the shared HttpApi in both your server and client. Before calling `readUser`, acquire its ready HttpApiClient.
Keep its transport resources alive while you use the client. The
[HTTP quick start](https://ueberbrot.github.io/effect-api-query/getting-started/http-quick-start/)
shows acquisition and cleanup.

**Shared contract — `http-contract.ts`**
Shared contract in `http-contract.ts`:

```ts
import { Schema } from 'effect'
Expand All @@ -83,7 +83,7 @@ export const usersApi = HttpApi.make('users-api').add(
)
```

**Client integration — `client.ts`**
Client integration in `client.ts`:

```ts
import { QueryClient } from '@tanstack/query-core'
Expand All @@ -102,22 +102,22 @@ async function readUser(client: HttpApiClient.ForApi<typeof usersApi>, queryClie
```

HTTP inputs use decoded `params`, `query`, `headers`, and `payload` containers. Both examples use
the default Effect runner; provide a signal-aware `runPromiseExit` when execution needs services.
Choose a `keyPrefix` that identifies your application and any user or tenant that affects its data.
the default Effect runner. If execution needs services, provide a signal-aware `runPromiseExit`.
Choose a `keyPrefix` that identifies your application and any user or tenant that affects the returned data.
Keep credentials out of keys.

## Capabilities

| Contract | Generated operations |
| --------------------------------------- | --------------------------------------------- |
| Unary RPC or buffered nonmultipart HTTP | Query, infinite query, mutation |
| Buffered nonmultipart HTTP | Separate response status/header metadata view |
| Buffered multipart HTTP | Mutation with explicit `FormData` |
| RPC stream or unambiguous HTTP SSE | Accumulated streamed query, live query |
| Contract | Generated operations |
| --------------------------------------- | -------------------------------------------- |
| Unary RPC or buffered nonmultipart HTTP | Query, infinite query, mutation |
| Buffered nonmultipart HTTP | Separate view of response status and headers |
| Buffered multipart HTTP | Mutation with explicit `FormData` |
| RPC stream or unambiguous HTTP SSE | Accumulated streamed query, live query |

Generated keys support cache reads, writes, and invalidation. Queries forward cancellation to
Effect. Use `withQueryPolicy` and `withMutationPolicy` to share typed defaults. Your application
invalidates affected queries after mutations. See
Use generated keys to read, write, and invalidate cache entries. Queries forward cancellation to
Effect. Use `withQueryPolicy` and `withMutationPolicy` to share typed defaults.
Your application decides which queries to invalidate after mutations. See
[feature support](https://ueberbrot.github.io/effect-api-query/getting-started/feature-support/)
for supported contracts and limits.

Expand All @@ -136,12 +136,12 @@ Install the library usage skill from this repository:
npx skills add ueberBrot/effect-api-query --full-depth --skill effect-api-query
```

The same skill ships in the npm package. With the library installed, run
The npm package includes the same skill. After installing the library, run
`npx @tanstack/intent@latest install` and enable `effect-api-query`, then load it with:

```sh
npx @tanstack/intent@latest load effect-api-query#effect-api-query
```

Intent uses the skill from the installed library version. GitHub skill installations update
separately through the Skills CLI.
Intent loads the skill from your installed library version. Update a skill installed from GitHub
through the Skills CLI.
Loading
Loading