fetchium 0.1.1 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (104) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/README.md +1 -1
  3. package/dist/cjs/development/QueryAdapter-DUo338ga.js +2 -0
  4. package/dist/cjs/development/QueryAdapter-DUo338ga.js.map +1 -0
  5. package/dist/cjs/development/QueryClient-m7BzCIe9.js +2 -0
  6. package/dist/cjs/development/QueryClient-m7BzCIe9.js.map +1 -0
  7. package/dist/cjs/development/index.js +1 -1
  8. package/dist/cjs/development/mutation-wUhcGxKl.js +2 -0
  9. package/dist/cjs/development/mutation-wUhcGxKl.js.map +1 -0
  10. package/dist/cjs/development/react/index.js +1 -1
  11. package/dist/cjs/development/rest/index.js +1 -1
  12. package/dist/cjs/development/rest/index.js.map +1 -1
  13. package/dist/cjs/development/topic/index.js +1 -1
  14. package/dist/cjs/development/topic/index.js.map +1 -1
  15. package/dist/cjs/production/QueryAdapter-DUo338ga.js +2 -0
  16. package/dist/cjs/production/QueryAdapter-DUo338ga.js.map +1 -0
  17. package/dist/cjs/production/QueryClient-4T90peFN.js +2 -0
  18. package/dist/cjs/production/QueryClient-4T90peFN.js.map +1 -0
  19. package/dist/cjs/production/index.js +1 -1
  20. package/dist/cjs/production/mutation-Dk0gznwX.js +2 -0
  21. package/dist/cjs/production/mutation-Dk0gznwX.js.map +1 -0
  22. package/dist/cjs/production/react/index.js +1 -1
  23. package/dist/cjs/production/rest/index.js +1 -1
  24. package/dist/cjs/production/rest/index.js.map +1 -1
  25. package/dist/cjs/production/topic/index.js +1 -1
  26. package/dist/cjs/production/topic/index.js.map +1 -1
  27. package/dist/esm/{QueryController.d.ts → QueryAdapter.d.ts} +7 -7
  28. package/dist/esm/QueryAdapter.d.ts.map +1 -0
  29. package/dist/esm/QueryClient.d.ts +6 -6
  30. package/dist/esm/QueryClient.d.ts.map +1 -1
  31. package/dist/esm/QueryResult.d.ts +2 -2
  32. package/dist/esm/QueryResult.d.ts.map +1 -1
  33. package/dist/esm/development/{QueryController-Ch_ncxiI.js → QueryAdapter-Bu5UJjE4.js} +2 -2
  34. package/dist/esm/development/QueryAdapter-Bu5UJjE4.js.map +1 -0
  35. package/dist/esm/development/{QueryClient-Dtde3pss.js → QueryClient-BajBmpnA.js} +532 -532
  36. package/dist/esm/development/QueryClient-BajBmpnA.js.map +1 -0
  37. package/dist/esm/development/index.js +14 -14
  38. package/dist/esm/development/{mutation-UZshUQAf.js → mutation-DAOZE4Ok.js} +13 -13
  39. package/dist/esm/development/mutation-DAOZE4Ok.js.map +1 -0
  40. package/dist/esm/development/react/index.js +1 -1
  41. package/dist/esm/development/rest/index.js +26 -26
  42. package/dist/esm/development/rest/index.js.map +1 -1
  43. package/dist/esm/development/topic/index.js +11 -11
  44. package/dist/esm/development/topic/index.js.map +1 -1
  45. package/dist/esm/index.d.ts +2 -2
  46. package/dist/esm/index.d.ts.map +1 -1
  47. package/dist/esm/mutation.d.ts +3 -3
  48. package/dist/esm/mutation.d.ts.map +1 -1
  49. package/dist/esm/production/{QueryController-Ch_ncxiI.js → QueryAdapter-Bu5UJjE4.js} +2 -2
  50. package/dist/esm/production/QueryAdapter-Bu5UJjE4.js.map +1 -0
  51. package/dist/esm/production/{QueryClient-YqnBxFy1.js → QueryClient-KH0Ex_8m.js} +708 -708
  52. package/dist/esm/production/QueryClient-KH0Ex_8m.js.map +1 -0
  53. package/dist/esm/production/index.js +14 -14
  54. package/dist/esm/production/{mutation-pgFl1uIY.js → mutation-C7BOChR2.js} +13 -13
  55. package/dist/esm/production/mutation-C7BOChR2.js.map +1 -0
  56. package/dist/esm/production/react/index.js +1 -1
  57. package/dist/esm/production/rest/index.js +26 -26
  58. package/dist/esm/production/rest/index.js.map +1 -1
  59. package/dist/esm/production/topic/index.js +11 -11
  60. package/dist/esm/production/topic/index.js.map +1 -1
  61. package/dist/esm/query.d.ts +6 -6
  62. package/dist/esm/query.d.ts.map +1 -1
  63. package/dist/esm/rest/RESTMutation.d.ts +2 -2
  64. package/dist/esm/rest/RESTMutation.d.ts.map +1 -1
  65. package/dist/esm/rest/RESTQuery.d.ts +2 -2
  66. package/dist/esm/rest/RESTQuery.d.ts.map +1 -1
  67. package/dist/esm/rest/{RESTQueryController.d.ts → RESTQueryAdapter.d.ts} +6 -6
  68. package/dist/esm/rest/RESTQueryAdapter.d.ts.map +1 -0
  69. package/dist/esm/rest/index.d.ts +2 -2
  70. package/dist/esm/rest/index.d.ts.map +1 -1
  71. package/dist/esm/topic/TopicQuery.d.ts +2 -2
  72. package/dist/esm/topic/TopicQuery.d.ts.map +1 -1
  73. package/dist/esm/topic/{TopicQueryController.d.ts → TopicQueryAdapter.d.ts} +3 -3
  74. package/dist/esm/topic/TopicQueryAdapter.d.ts.map +1 -0
  75. package/dist/esm/topic/index.d.ts +1 -1
  76. package/dist/esm/topic/index.d.ts.map +1 -1
  77. package/package.json +1 -1
  78. package/plugin/docs/api/fetchium.md +40 -40
  79. package/plugin/docs/core/queries.md +15 -15
  80. package/plugin/docs/core/streaming.md +18 -18
  81. package/plugin/docs/data/mutations.md +5 -5
  82. package/plugin/docs/quickstart.md +1 -1
  83. package/plugin/docs/setup/project-setup.md +19 -19
  84. package/dist/cjs/development/QueryClient-CLi3ONNM.js +0 -2
  85. package/dist/cjs/development/QueryClient-CLi3ONNM.js.map +0 -1
  86. package/dist/cjs/development/QueryController-BQA49OYU.js +0 -2
  87. package/dist/cjs/development/QueryController-BQA49OYU.js.map +0 -1
  88. package/dist/cjs/development/mutation-CikIl_6k.js +0 -2
  89. package/dist/cjs/development/mutation-CikIl_6k.js.map +0 -1
  90. package/dist/cjs/production/QueryClient-N0MJmuHW.js +0 -2
  91. package/dist/cjs/production/QueryClient-N0MJmuHW.js.map +0 -1
  92. package/dist/cjs/production/QueryController-BQA49OYU.js +0 -2
  93. package/dist/cjs/production/QueryController-BQA49OYU.js.map +0 -1
  94. package/dist/cjs/production/mutation-P_Yb4LI9.js +0 -2
  95. package/dist/cjs/production/mutation-P_Yb4LI9.js.map +0 -1
  96. package/dist/esm/QueryController.d.ts.map +0 -1
  97. package/dist/esm/development/QueryClient-Dtde3pss.js.map +0 -1
  98. package/dist/esm/development/QueryController-Ch_ncxiI.js.map +0 -1
  99. package/dist/esm/development/mutation-UZshUQAf.js.map +0 -1
  100. package/dist/esm/production/QueryClient-YqnBxFy1.js.map +0 -1
  101. package/dist/esm/production/QueryController-Ch_ncxiI.js.map +0 -1
  102. package/dist/esm/production/mutation-pgFl1uIY.js.map +0 -1
  103. package/dist/esm/rest/RESTQueryController.d.ts.map +0 -1
  104. package/dist/esm/topic/TopicQueryController.d.ts.map +0 -1
@@ -1,3 +1,3 @@
1
1
  export { TopicQuery } from './TopicQuery.js';
2
- export { TopicQueryController } from './TopicQueryController.js';
2
+ export { TopicQueryAdapter } from './TopicQueryAdapter.js';
3
3
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/topic/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/topic/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fetchium",
3
- "version": "0.1.1",
3
+ "version": "0.2.0",
4
4
  "type": "module",
5
5
  "repository": {
6
6
  "type": "git",
@@ -10,7 +10,7 @@ API reference for the main `fetchium` package — a data-fetching and query laye
10
10
  ```ts
11
11
  import {
12
12
  Query,
13
- QueryController,
13
+ QueryAdapter,
14
14
  fetchQuery,
15
15
  queryKeyForClass,
16
16
  Mutation,
@@ -30,7 +30,7 @@ import {
30
30
  } from 'fetchium';
31
31
 
32
32
  // REST adapter (JSON REST APIs)
33
- import { RESTQuery, RESTMutation, RESTQueryController } from 'fetchium/rest';
33
+ import { RESTQuery, RESTMutation, RESTQueryAdapter } from 'fetchium/rest';
34
34
  ```
35
35
 
36
36
  ---
@@ -49,10 +49,10 @@ Base class for all query definitions. Extend this to define custom data-fetching
49
49
 
50
50
  #### Static properties
51
51
 
52
- | Property | Type | Description |
53
- | ------------ | -------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
54
- | `cache` | `QueryCacheOptions \| undefined` | Class-level persistent cache settings (maxCount, cacheTime). |
55
- | `controller` | `typeof QueryController` | **(required)** The controller class responsible for sending requests. Set automatically on `RESTQuery`. Custom query types must set this to their own controller class. |
52
+ | Property | Type | Description |
53
+ | --------- | -------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- |
54
+ | `cache` | `QueryCacheOptions \| undefined` | Class-level persistent cache settings (maxCount, cacheTime). |
55
+ | `adapter` | `typeof QueryAdapter` | **(required)** The adapter class responsible for sending requests. Set automatically on `RESTQuery`. Custom query types must set this to their own adapter class. |
56
56
 
57
57
  #### Instance properties
58
58
 
@@ -79,16 +79,16 @@ Convenience base class for REST/JSON queries. Handles URL construction, search p
79
79
 
80
80
  #### Instance properties
81
81
 
82
- | Property | Type | Default | Description |
83
- | ---------------- | ------------------------------------------------- | ------- | ----------------------------------------------------------------------------------------------------------------------------------- |
84
- | `method` | `'GET' \| 'POST' \| 'PUT' \| 'DELETE' \| 'PATCH'` | `'GET'` | HTTP method. |
85
- | `path` | `string \| undefined` | — | URL path. Use template literal interpolation with `this.params` references. |
86
- | `searchParams` | `Record<string, unknown> \| undefined` | — | Query string parameters. |
87
- | `body` | `Record<string, unknown> \| undefined` | — | Request body (JSON-serialized). |
88
- | `headers` | `HeadersInit \| undefined` | — | Custom HTTP headers. |
89
- | `requestOptions` | `QueryRequestOptions \| undefined` | — | Additional fetch options (credentials, mode, baseUrl, etc.). |
90
- | `fetchNext` | `FetchNextConfig \| undefined` | — | Static pagination config. Values can be FieldRefs (e.g. `this.result.nextCursor`). |
91
- | `response` | `Response \| undefined` | — | The raw HTTP `Response` from the last fetch. Set by `RESTQueryController` after each request completes. Available in `getConfig()`. |
82
+ | Property | Type | Default | Description |
83
+ | ---------------- | ------------------------------------------------- | ------- | -------------------------------------------------------------------------------------------------------------------------------- |
84
+ | `method` | `'GET' \| 'POST' \| 'PUT' \| 'DELETE' \| 'PATCH'` | `'GET'` | HTTP method. |
85
+ | `path` | `string \| undefined` | — | URL path. Use template literal interpolation with `this.params` references. |
86
+ | `searchParams` | `Record<string, unknown> \| undefined` | — | Query string parameters. |
87
+ | `body` | `Record<string, unknown> \| undefined` | — | Request body (JSON-serialized). |
88
+ | `headers` | `HeadersInit \| undefined` | — | Custom HTTP headers. |
89
+ | `requestOptions` | `QueryRequestOptions \| undefined` | — | Additional fetch options (credentials, mode, baseUrl, etc.). |
90
+ | `fetchNext` | `FetchNextConfig \| undefined` | — | Static pagination config. Values can be FieldRefs (e.g. `this.result.nextCursor`). |
91
+ | `response` | `Response \| undefined` | — | The raw HTTP `Response` from the last fetch. Set by `RESTQueryAdapter` after each request completes. Available in `getConfig()`. |
92
92
 
93
93
  #### `getIdentityKey()` default
94
94
 
@@ -161,9 +161,9 @@ Base class for mutation definitions.
161
161
 
162
162
  #### Static properties
163
163
 
164
- | Property | Type | Description |
165
- | ------------ | ------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
166
- | `controller` | `typeof QueryController` | **(required)** The controller class that handles sending this mutation. Set automatically on `RESTMutation`. Custom mutation types must set this to their own controller class. |
164
+ | Property | Type | Description |
165
+ | --------- | --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
166
+ | `adapter` | `typeof QueryAdapter` | **(required)** The adapter class that handles sending this mutation. Set automatically on `RESTMutation`. Custom mutation types must set this to their own adapter class. |
167
167
 
168
168
  #### Instance properties
169
169
 
@@ -227,7 +227,7 @@ new QueryClient(config: QueryClientConfig)
227
227
  | Field | Type | Default | Description |
228
228
  | -------------------- | ---------------------------- | ---------------------- | ------------------------------------------------------------------------------------ |
229
229
  | `store` | `QueryStore` | — | **(required)** Persistent storage backend. |
230
- | `controllers` | `QueryController[]` | `[]` | Transport controllers (e.g. `new RESTQueryController({ fetch, baseUrl })`). |
230
+ | `adapters` | `QueryAdapter[]` | `[]` | Transport adapters (e.g. `new RESTQueryAdapter({ fetch, baseUrl })`). |
231
231
  | `log` | `LogContext \| undefined` | `console` | Logger with `error`, `warn`, `info`, `debug` methods. |
232
232
  | `evictionMultiplier` | `number \| undefined` | `1` | Scales all GC times for testing. Set to `0.001` to make timers fire in milliseconds. |
233
233
  | `networkManager` | `NetworkManager` | `new NetworkManager()` | Tracks network connectivity. |
@@ -244,35 +244,35 @@ new QueryClient(config: QueryClientConfig)
244
244
 
245
245
  ---
246
246
 
247
- ### `QueryController` (abstract)
247
+ ### `QueryAdapter` (abstract)
248
248
 
249
- Base class for transport adapters. A controller handles sending queries and mutations for all query/mutation classes that declare it via `static controller`. Register controllers with `QueryClient` at construction time.
249
+ Base class for transport adapters. An adapter handles sending queries and mutations for all query/mutation classes that declare it via `static adapter`. Register adapters with `QueryClient` at construction time.
250
250
 
251
251
  #### Methods
252
252
 
253
- | Method | Signature | Description |
254
- | ----------------------- | -------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------- |
255
- | `register` | `(queryClient: IQueryClientForController): void` | Called once when the controller is registered with a `QueryClient`. Override to do setup (e.g. open a WebSocket connection). |
256
- | `send` | `(ctx: Query, signal: AbortSignal): Promise<unknown>` | **(abstract)** Send a query and return the raw response data. |
257
- | `sendNext` | `(ctx: Query, signal: AbortSignal): Promise<unknown>` | Optional. Send the next-page request for a paginated query. |
258
- | `hasNext` | `(ctx: Query): boolean` | Optional. Return `true` if more pages are available for the current result. |
259
- | `sendMutation` | `(ctx: Mutation, signal: AbortSignal): Promise<unknown>` | Optional. Send a mutation and return the raw response data. |
260
- | `onNetworkStatusChange` | `(isOnline: boolean): void` | Optional. Called when the network comes online or goes offline. |
261
- | `destroy` | `(): void` | Optional. Called when the `QueryClient` is destroyed. Clean up connections or timers. |
253
+ | Method | Signature | Description |
254
+ | ----------------------- | -------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------- |
255
+ | `register` | `(queryClient: IQueryClientForAdapter): void` | Called once when the adapter is registered with a `QueryClient`. Override to do setup (e.g. open a WebSocket connection). |
256
+ | `send` | `(ctx: Query, signal: AbortSignal): Promise<unknown>` | **(abstract)** Send a query and return the raw response data. |
257
+ | `sendNext` | `(ctx: Query, signal: AbortSignal): Promise<unknown>` | Optional. Send the next-page request for a paginated query. |
258
+ | `hasNext` | `(ctx: Query): boolean` | Optional. Return `true` if more pages are available for the current result. |
259
+ | `sendMutation` | `(ctx: Mutation, signal: AbortSignal): Promise<unknown>` | Optional. Send a mutation and return the raw response data. |
260
+ | `onNetworkStatusChange` | `(isOnline: boolean): void` | Optional. Called when the network comes online or goes offline. |
261
+ | `destroy` | `(): void` | Optional. Called when the `QueryClient` is destroyed. Clean up connections or timers. |
262
262
 
263
263
  #### Protected properties
264
264
 
265
- | Property | Type | Description |
266
- | ------------- | ---------------------------------------- | ------------------------------------------------------------------------------------------------ |
267
- | `queryClient` | `IQueryClientForController \| undefined` | Set by `register()`. Use to access the shared query context via `this.queryClient.getContext()`. |
265
+ | Property | Type | Description |
266
+ | ------------- | ------------------------------------- | ------------------------------------------------------------------------------------------------ |
267
+ | `queryClient` | `IQueryClientForAdapter \| undefined` | Set by `register()`. Use to access the shared query context via `this.queryClient.getContext()`. |
268
268
 
269
269
  #### Example
270
270
 
271
271
  ```ts
272
- import { QueryController } from 'fetchium';
272
+ import { QueryAdapter } from 'fetchium';
273
273
  import type { Query } from 'fetchium';
274
274
 
275
- class GraphQLController extends QueryController {
275
+ class GraphQLAdapter extends QueryAdapter {
276
276
  async send(ctx: Query, signal: AbortSignal): Promise<unknown> {
277
277
  const q = ctx as GraphQLQuery;
278
278
  const response = await fetch('/graphql', {
@@ -289,22 +289,22 @@ class GraphQLController extends QueryController {
289
289
 
290
290
  new QueryClient({
291
291
  store,
292
- controllers: [new GraphQLController()],
292
+ adapters: [new GraphQLAdapter()],
293
293
  });
294
294
  ```
295
295
 
296
296
  ---
297
297
 
298
- ### `RESTQueryController` extends `QueryController`
298
+ ### `RESTQueryAdapter` extends `QueryAdapter`
299
299
 
300
- Transport controller for `RESTQuery` and `RESTMutation`. Handles URL construction, JSON serialization, search params, pagination, and `baseUrl` resolution.
300
+ Transport adapter for `RESTQuery` and `RESTMutation`. Handles URL construction, JSON serialization, search params, pagination, and `baseUrl` resolution.
301
301
 
302
302
  Import from `fetchium/rest`.
303
303
 
304
304
  #### Constructor
305
305
 
306
306
  ```ts
307
- new RESTQueryController(options?: RESTQueryControllerOptions)
307
+ new RESTQueryAdapter(options?: RESTQueryAdapterOptions)
308
308
  ```
309
309
 
310
310
  | Option | Type | Description |
@@ -451,19 +451,19 @@ For a more in depth guide to query configuration, see the [REST Queries referenc
451
451
 
452
452
  ## Custom Queries
453
453
 
454
- `RESTQuery` is an adapter for JSON REST APIs. But queries as a concept are protocol-agnostic. When your use case doesn't fit REST --- GraphQL, gRPC, WebSockets, local databases, or any other data source --- you build a **`QueryController`** that handles the transport, and a **`Query`** subclass that stays purely declarative.
454
+ `RESTQuery` is an adapter for JSON REST APIs. But queries as a concept are protocol-agnostic. When your use case doesn't fit REST --- GraphQL, gRPC, WebSockets, local databases, or any other data source --- you build a **`QueryAdapter`** that handles the transport, and a **`Query`** subclass that stays purely declarative.
455
455
 
456
- The split follows the same logic as the rest of Fetchium: the _definition_ (params, result, identity) lives on the `Query` class; the _transport_ (how to actually fetch data) lives on the controller.
456
+ The split follows the same logic as the rest of Fetchium: the _definition_ (params, result, identity) lives on the `Query` class; the _transport_ (how to actually fetch data) lives on the adapter.
457
457
 
458
- ### Defining a controller
458
+ ### Defining an adapter
459
459
 
460
- A `QueryController` handles sending requests on behalf of queries that declare it. Extend `QueryController` and implement `send(ctx, signal)`:
460
+ A `QueryAdapter` handles sending requests on behalf of queries that declare it. Extend `QueryAdapter` and implement `send(ctx, signal)`:
461
461
 
462
462
  ```ts
463
- import { QueryController } from 'fetchium';
463
+ import { QueryAdapter } from 'fetchium';
464
464
  import type { Query } from 'fetchium';
465
465
 
466
- class DBQueryController extends QueryController {
466
+ class DBQueryAdapter extends QueryAdapter {
467
467
  async send(ctx: Query, signal: AbortSignal): Promise<unknown> {
468
468
  const q = ctx as DBQuery;
469
469
  const db = await openDatabase();
@@ -478,24 +478,24 @@ Inside `send()`:
478
478
  - **`signal`** --- an `AbortSignal` for cancellation, passed automatically by the query lifecycle
479
479
  - **`this.queryClient`** --- the registered `QueryClient`; call `this.queryClient.getContext()` to access `log` and any other context properties you passed at setup
480
480
 
481
- Register the controller when creating the `QueryClient`:
481
+ Register the adapter when creating the `QueryClient`:
482
482
 
483
483
  ```ts
484
484
  new QueryClient({
485
485
  store,
486
- controllers: [new DBQueryController()],
486
+ adapters: [new DBQueryAdapter()],
487
487
  });
488
488
  ```
489
489
 
490
490
  ### Defining the query class
491
491
 
492
- The query class is purely declarative. It declares `static controller` to point at the controller, defines `params`, `result`, and `getIdentityKey()`, and can include any additional fields your controller reads:
492
+ The query class is purely declarative. It declares `static adapter` to point at the adapter, defines `params`, `result`, and `getIdentityKey()`, and can include any additional fields your adapter reads:
493
493
 
494
494
  ```ts
495
495
  import { Query, t } from 'fetchium';
496
496
 
497
497
  abstract class DBQuery extends Query {
498
- static override controller = DBQueryController;
498
+ static override adapter = DBQueryAdapter;
499
499
 
500
500
  abstract collection: string;
501
501
  abstract id: unknown;
@@ -520,10 +520,10 @@ class GetUser extends DBQuery {
520
520
  Here is a more complete example --- a GraphQL adapter:
521
521
 
522
522
  ```ts
523
- import { QueryController, Query, t } from 'fetchium';
523
+ import { QueryAdapter, Query, t } from 'fetchium';
524
524
 
525
- // Controller: owns the transport
526
- class GraphQLController extends QueryController {
525
+ // Adapter: owns the transport
526
+ class GraphQLAdapter extends QueryAdapter {
527
527
  async send(ctx: Query, signal: AbortSignal): Promise<unknown> {
528
528
  const q = ctx as GraphQLQuery;
529
529
  const { log } = this.queryClient!.getContext();
@@ -551,7 +551,7 @@ class GraphQLController extends QueryController {
551
551
 
552
552
  // Base query class: purely declarative
553
553
  abstract class GraphQLQuery extends Query {
554
- static override controller = GraphQLController;
554
+ static override adapter = GraphQLAdapter;
555
555
 
556
556
  abstract query: string;
557
557
  abstract variables?: Record<string, unknown>;
@@ -575,7 +575,7 @@ class GetUser extends GraphQLQuery {
575
575
  }
576
576
  ```
577
577
 
578
- Custom queries participate in all the same systems as `RESTQuery` --- caching, entity normalization, live data, refetching, and pagination (via `sendNext()` and `hasNext()` on the controller). The `Query` base class provides the full reactive lifecycle; your controller only needs to implement the transport.
578
+ Custom queries participate in all the same systems as `RESTQuery` --- caching, entity normalization, live data, refetching, and pagination (via `sendNext()` and `hasNext()` on the adapter). The `Query` base class provides the full reactive lifecycle; your adapter only needs to implement the transport.
579
579
 
580
580
  {% callout title="The identity key" type="note" %}
581
581
  `getIdentityKey()` returns a value that uniquely identifies this query's _definition_. Two query instances with the same identity key and the same params share the same cache entry and are deduplicated. For `RESTQuery`, the default is `${method}:${path}`. For custom adapters, choose a key that captures all the inputs that make a query unique.
@@ -85,7 +85,7 @@ class GetPrices extends RESTQuery {
85
85
  The `subscribe` function receives an `onEvent` callback that accepts `MutationEvent` objects and returns a cleanup function. Fetchium calls `subscribe` when the query activates (a component reads it) and calls the cleanup function when the query deactivates (all observers disconnect).
86
86
 
87
87
  {% callout %}
88
- The `subscribe` config is a low-level building block. For polling, use the built-in `poll()` helper. For topic-based streaming (WebSocket message buses, SSE, pub/sub), use [TopicQuery](#topic-queries) --- which provides a declarative, controller-based approach.
88
+ The `subscribe` config is a low-level building block. For polling, use the built-in `poll()` helper. For topic-based streaming (WebSocket message buses, SSE, pub/sub), use [TopicQuery](#topic-queries) --- which provides a declarative, adapter-based approach.
89
89
  {% /callout %}
90
90
 
91
91
  ### Polling
@@ -129,7 +129,7 @@ Both mechanisms feed into the same entity event system, so you can mix and match
129
129
 
130
130
  ## Topic Queries
131
131
 
132
- For applications with a centralized message bus --- a single WebSocket connection, an SSE endpoint, a pub/sub system --- `TopicQuery` provides a declarative adapter. Instead of manually wiring `subscribe` callbacks per query, you define _topics_ and let a controller manage the connection lifecycle.
132
+ For applications with a centralized message bus --- a single WebSocket connection, an SSE endpoint, a pub/sub system --- `TopicQuery` provides a declarative adapter. Instead of manually wiring `subscribe` callbacks per query, you define _topics_ and let an adapter manage the connection lifecycle.
133
133
 
134
134
  ### Defining a topic query
135
135
 
@@ -164,14 +164,14 @@ class GetBalances extends MyTopicQuery {
164
164
 
165
165
  The identity key for a topic query is `topic:${topic}` --- two queries with the same topic and params share the same cache entry and are deduplicated.
166
166
 
167
- ### Implementing a controller
167
+ ### Implementing an adapter
168
168
 
169
- The `TopicQueryController` is the bridge between your message bus and Fetchium. Extend it and implement two abstract methods:
169
+ The `TopicQueryAdapter` is the bridge between your message bus and Fetchium. Extend it and implement two abstract methods:
170
170
 
171
171
  ```tsx
172
- import { TopicQueryController } from 'fetchium/topic';
172
+ import { TopicQueryAdapter } from 'fetchium/topic';
173
173
 
174
- class MyStreamController extends TopicQueryController {
174
+ class MyStreamAdapter extends TopicQueryAdapter {
175
175
  private ws: WebSocket;
176
176
 
177
177
  constructor(url: string) {
@@ -205,7 +205,7 @@ class MyStreamController extends TopicQueryController {
205
205
  }
206
206
  ```
207
207
 
208
- The controller has several protected helper methods:
208
+ The adapter has several protected helper methods:
209
209
 
210
210
  | Method | Description |
211
211
  | --------------------------- | ------------------------------------------------------------------------------------------------------ |
@@ -215,33 +215,33 @@ The controller has several protected helper methods:
215
215
  | `clearTopic(topic)` | Clear buffered state for a topic. Call this in `unsubscribe` to reset for the next subscription cycle. |
216
216
  | `clearAll()` | Clear all buffered topic state. Useful when resetting the connection. |
217
217
 
218
- ### Registering the controller
218
+ ### Registering the adapter
219
219
 
220
- Pass the controller to `QueryClient` in the `controllers` array, the same way you register a `RESTQueryController`:
220
+ Pass the adapter to `QueryClient` in the `adapters` array, the same way you register a `RESTQueryAdapter`:
221
221
 
222
222
  ```tsx
223
223
  import { QueryClient } from 'fetchium';
224
- import { RESTQueryController } from 'fetchium/rest';
224
+ import { RESTQueryAdapter } from 'fetchium/rest';
225
225
 
226
226
  const queryClient = new QueryClient({
227
- controllers: [
228
- new RESTQueryController({ baseUrl: '/api' }),
229
- new MyStreamController('ws://api.example.com/stream'),
227
+ adapters: [
228
+ new RESTQueryAdapter({ baseUrl: '/api' }),
229
+ new MyStreamAdapter('ws://api.example.com/stream'),
230
230
  ],
231
231
  });
232
232
  ```
233
233
 
234
- Then make your topic query classes reference the controller:
234
+ Then make your topic query classes reference the adapter:
235
235
 
236
236
  ```tsx
237
237
  abstract class MyTopicQuery extends TopicQuery {
238
- static override controller = MyStreamController;
238
+ static override adapter = MyStreamAdapter;
239
239
  }
240
240
  ```
241
241
 
242
242
  ### Pre-fulfillment
243
243
 
244
- A powerful feature of the controller is that `fulfillTopic` can be called _before_ the query activates. If your message bus proactively sends data for topics it knows the page will need, the controller can buffer that data:
244
+ A powerful feature of the adapter is that `fulfillTopic` can be called _before_ the query activates. If your message bus proactively sends data for topics it knows the page will need, the adapter can buffer that data:
245
245
 
246
246
  ```tsx
247
247
  // Data arrives from the stream before any component subscribes
@@ -257,8 +257,8 @@ This enables smart pre-fetching strategies where the server pushes data ahead of
257
257
 
258
258
  The full lifecycle of a topic query:
259
259
 
260
- 1. **Component reads the query** --- Fetchium calls `send()` on the controller, which creates a deferred promise and calls your `subscribe(topic)` implementation.
261
- 2. **Controller subscribes** --- Your implementation connects to the message bus for this topic (e.g., sends a subscribe message over WebSocket).
260
+ 1. **Component reads the query** --- Fetchium calls `send()` on the adapter, which creates a deferred promise and calls your `subscribe(topic)` implementation.
261
+ 2. **Adapter subscribes** --- Your implementation connects to the message bus for this topic (e.g., sends a subscribe message over WebSocket).
262
262
  3. **Initial data arrives** --- Your `onmessage` handler calls `fulfillTopic(topic, data)`, resolving the deferred promise. The component renders with the data.
263
263
  4. **Ongoing updates** --- Your handler calls `sendMutationEvent(event)` for each update. Live arrays and live values react automatically.
264
264
  5. **Component unmounts** --- Fetchium calls your `unsubscribe(topic)` implementation. Your code disconnects from the message bus for this topic.
@@ -324,15 +324,15 @@ If a mutation with optimistic updates fails, the rollback restores the entity to
324
324
 
325
325
  ## Custom Mutations
326
326
 
327
- `RESTMutation` is an adapter for JSON REST APIs. But mutations as a concept are protocol-agnostic. When your use case doesn't fit REST --- GraphQL, file uploads, WebSocket messages, RPC calls --- you build a **`QueryController`** that handles the transport and a **`Mutation`** subclass that stays purely declarative.
327
+ `RESTMutation` is an adapter for JSON REST APIs. But mutations as a concept are protocol-agnostic. When your use case doesn't fit REST --- GraphQL, file uploads, WebSocket messages, RPC calls --- you build a **`QueryAdapter`** that handles the transport and a **`Mutation`** subclass that stays purely declarative.
328
328
 
329
- The same controller that handles queries can also handle mutations by implementing `sendMutation(ctx, signal)`. This means custom query and mutation transports for the same protocol live in one place:
329
+ The same adapter that handles queries can also handle mutations by implementing `sendMutation(ctx, signal)`. This means custom query and mutation transports for the same protocol live in one place:
330
330
 
331
331
  ```ts
332
- import { QueryController, Mutation, t } from 'fetchium';
332
+ import { QueryAdapter, Mutation, t } from 'fetchium';
333
333
  import type { Query } from 'fetchium';
334
334
 
335
- class MyController extends QueryController {
335
+ class MyAdapter extends QueryAdapter {
336
336
  async send(ctx: Query, signal: AbortSignal): Promise<unknown> {
337
337
  // ... query transport
338
338
  }
@@ -362,7 +362,7 @@ The mutation class is purely declarative:
362
362
  import { Mutation, t } from 'fetchium';
363
363
 
364
364
  class UploadAvatar extends Mutation {
365
- static override controller = MyController;
365
+ static override adapter = MyAdapter;
366
366
 
367
367
  params = { userId: t.id, file: t.any };
368
368
  result = { url: t.string };
@@ -79,7 +79,7 @@ function App() {
79
79
  }
80
80
  ```
81
81
 
82
- This is the minimal setup. The store defaults to an in-memory cache and `RESTQueryController` is auto-instantiated on first use with `globalThis.fetch`. When you need a `baseUrl`, auth headers, or persistent storage, pass explicit options --- see [Project Setup](/setup/project-setup).
82
+ This is the minimal setup. The store defaults to an in-memory cache and `RESTQueryAdapter` is auto-instantiated on first use with `globalThis.fetch`. When you need a `baseUrl`, auth headers, or persistent storage, pass explicit options --- see [Project Setup](/setup/project-setup).
83
83
 
84
84
  {% callout title="Want to go deeper?" type="note" %}
85
85
  For a complete guide to configuring `baseUrl`, auth headers, persistent stores, and project structure, see [Project Setup](/setup/project-setup).
@@ -26,12 +26,12 @@ The `QueryClient` constructor takes a single config object. The only required fi
26
26
  ```tsx
27
27
  import { QueryClient } from 'fetchium';
28
28
  import { SyncQueryStore, MemoryPersistentStore } from 'fetchium/stores/sync';
29
- import { RESTQueryController } from 'fetchium/rest';
29
+ import { RESTQueryAdapter } from 'fetchium/rest';
30
30
 
31
31
  const client = new QueryClient({
32
32
  store: new SyncQueryStore(new MemoryPersistentStore()),
33
- controllers: [
34
- new RESTQueryController({
33
+ adapters: [
34
+ new RESTQueryAdapter({
35
35
  fetch: globalThis.fetch,
36
36
  baseUrl: 'https://api.example.com',
37
37
  }),
@@ -43,29 +43,29 @@ The store is responsible for _persistent_ caching --- saving query results and e
43
43
 
44
44
  ### QueryClientConfig options
45
45
 
46
- | Option | Type | Default | Description |
47
- | ------------- | ------------------- | ---------------------------- | ---------------------------------------------------------------------------------------------------------------------------- |
48
- | `store` | `QueryStore` | `SyncQueryStore` (in-memory) | Persistent storage backend for query results and entity data. Defaults to an in-memory store — data is lost on page refresh. |
49
- | `controllers` | `QueryController[]` | `[]` | Transport controllers. Register a `RESTQueryController` to configure `fetch`, `baseUrl`, and headers for REST queries. |
50
- | `log` | `object` | `console` | A logger with `warn` and `error` methods. Fetchium uses `log.warn` for non-fatal parse failures. |
46
+ | Option | Type | Default | Description |
47
+ | ---------- | ---------------- | ---------------------------- | ---------------------------------------------------------------------------------------------------------------------------- |
48
+ | `store` | `QueryStore` | `SyncQueryStore` (in-memory) | Persistent storage backend for query results and entity data. Defaults to an in-memory store — data is lost on page refresh. |
49
+ | `adapters` | `QueryAdapter[]` | `[]` | Transport adapters. Register a `RESTQueryAdapter` to configure `fetch`, `baseUrl`, and headers for REST queries. |
50
+ | `log` | `object` | `console` | A logger with `warn` and `error` methods. Fetchium uses `log.warn` for non-fatal parse failures. |
51
51
 
52
52
  ### Auto-instantiation
53
53
 
54
- Both the store and controllers have sensible defaults, so the minimal `QueryClient` requires no configuration at all:
54
+ Both the store and adapters have sensible defaults, so the minimal `QueryClient` requires no configuration at all:
55
55
 
56
56
  ```tsx
57
- // Fully minimal — in-memory store, RESTQueryController auto-instantiated on first use
57
+ // Fully minimal — in-memory store, RESTQueryAdapter auto-instantiated on first use
58
58
  const client = new QueryClient();
59
59
  ```
60
60
 
61
61
  - `store` defaults to `SyncQueryStore(MemoryPersistentStore)` — data lives in memory and is lost on page refresh
62
- - Controllers are auto-instantiated from their base class the first time a query of that type runs. `RESTQueryController` has a no-arg constructor that defaults to `globalThis.fetch`
62
+ - Adapters are auto-instantiated from their base class the first time a query of that type runs. `RESTQueryAdapter` has a no-arg constructor that defaults to `globalThis.fetch`
63
63
 
64
64
  Once you need a `baseUrl`, auth headers, persistent storage, or a custom fetch wrapper, pass explicit options.
65
65
 
66
- ### The RESTQueryController
66
+ ### The RESTQueryAdapter
67
67
 
68
- `RESTQueryController` is the transport layer for all REST queries and mutations. It accepts:
68
+ `RESTQueryAdapter` is the transport layer for all REST queries and mutations. It accepts:
69
69
 
70
70
  | Option | Type | Default | Description |
71
71
  | --------- | ---------- | ------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------- |
@@ -85,13 +85,13 @@ The `QueryClient` is made available to your component tree through Signalium's `
85
85
  ```tsx
86
86
  import { QueryClient, QueryClientContext } from 'fetchium';
87
87
  import { SyncQueryStore, MemoryPersistentStore } from 'fetchium/stores/sync';
88
- import { RESTQueryController } from 'fetchium/rest';
88
+ import { RESTQueryAdapter } from 'fetchium/rest';
89
89
  import { ContextProvider } from 'signalium/react';
90
90
 
91
91
  const client = new QueryClient({
92
92
  store: new SyncQueryStore(new MemoryPersistentStore()),
93
- controllers: [
94
- new RESTQueryController({
93
+ adapters: [
94
+ new RESTQueryAdapter({
95
95
  fetch: globalThis.fetch,
96
96
  baseUrl: 'https://api.example.com',
97
97
  }),
@@ -248,12 +248,12 @@ A single file creates and exports the `QueryClient`. This is the place to config
248
248
  // src/api/client.ts
249
249
  import { QueryClient } from 'fetchium';
250
250
  import { SyncQueryStore, MemoryPersistentStore } from 'fetchium/stores/sync';
251
- import { RESTQueryController } from 'fetchium/rest';
251
+ import { RESTQueryAdapter } from 'fetchium/rest';
252
252
 
253
253
  export const queryClient = new QueryClient({
254
254
  store: new SyncQueryStore(new MemoryPersistentStore()),
255
- controllers: [
256
- new RESTQueryController({
255
+ adapters: [
256
+ new RESTQueryAdapter({
257
257
  fetch: globalThis.fetch,
258
258
  baseUrl: import.meta.env.VITE_API_URL ?? 'https://api.example.com',
259
259
  }),