fetchium 0.2.0 → 0.2.2

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 (77) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/dist/cjs/development/QueryAdapter-DUo338ga.js.map +1 -1
  3. package/dist/cjs/development/QueryClient-BZpqASy3.js +2 -0
  4. package/dist/cjs/development/QueryClient-BZpqASy3.js.map +1 -0
  5. package/dist/cjs/development/index.js +1 -1
  6. package/dist/cjs/{production/mutation-Dk0gznwX.js → development/mutation-COeBCn7p.js} +2 -2
  7. package/dist/cjs/development/mutation-COeBCn7p.js.map +1 -0
  8. package/dist/cjs/development/react/index.js +1 -1
  9. package/dist/cjs/development/rest/index.js +1 -1
  10. package/dist/cjs/development/topic/index.js +1 -1
  11. package/dist/cjs/development/topic/index.js.map +1 -1
  12. package/dist/cjs/production/QueryAdapter-DUo338ga.js.map +1 -1
  13. package/dist/cjs/production/QueryClient-BmoHLlvu.js +2 -0
  14. package/dist/cjs/production/QueryClient-BmoHLlvu.js.map +1 -0
  15. package/dist/cjs/production/index.js +1 -1
  16. package/dist/cjs/{development/mutation-wUhcGxKl.js → production/mutation-CfFdNkYV.js} +2 -2
  17. package/dist/cjs/production/mutation-CfFdNkYV.js.map +1 -0
  18. package/dist/cjs/production/react/index.js +1 -1
  19. package/dist/cjs/production/rest/index.js +1 -1
  20. package/dist/cjs/production/topic/index.js +1 -1
  21. package/dist/cjs/production/topic/index.js.map +1 -1
  22. package/dist/esm/QueryAdapter.d.ts +11 -0
  23. package/dist/esm/QueryAdapter.d.ts.map +1 -1
  24. package/dist/esm/QueryClient.d.ts +5 -5
  25. package/dist/esm/QueryClient.d.ts.map +1 -1
  26. package/dist/esm/QueryResult.d.ts.map +1 -1
  27. package/dist/esm/development/QueryAdapter-Bu5UJjE4.js.map +1 -1
  28. package/dist/esm/development/{QueryClient-BajBmpnA.js → QueryClient-4co72n4i.js} +636 -628
  29. package/dist/esm/development/QueryClient-4co72n4i.js.map +1 -0
  30. package/dist/esm/development/index.js +2 -2
  31. package/dist/esm/development/{mutation-DAOZE4Ok.js → mutation-BMAWDUP4.js} +2 -2
  32. package/dist/esm/development/mutation-BMAWDUP4.js.map +1 -0
  33. package/dist/esm/development/react/index.js +1 -1
  34. package/dist/esm/development/rest/index.js +2 -2
  35. package/dist/esm/development/topic/index.js +1 -1
  36. package/dist/esm/development/topic/index.js.map +1 -1
  37. package/dist/esm/mutation.d.ts +3 -3
  38. package/dist/esm/mutation.d.ts.map +1 -1
  39. package/dist/esm/production/QueryAdapter-Bu5UJjE4.js.map +1 -1
  40. package/dist/esm/production/{QueryClient-KH0Ex_8m.js → QueryClient-CS4iUKWj.js} +782 -774
  41. package/dist/esm/production/QueryClient-CS4iUKWj.js.map +1 -0
  42. package/dist/esm/production/index.js +2 -2
  43. package/dist/esm/production/{mutation-C7BOChR2.js → mutation-B1EiA34B.js} +2 -2
  44. package/dist/esm/production/mutation-B1EiA34B.js.map +1 -0
  45. package/dist/esm/production/react/index.js +1 -1
  46. package/dist/esm/production/rest/index.js +2 -2
  47. package/dist/esm/production/topic/index.js +1 -1
  48. package/dist/esm/production/topic/index.js.map +1 -1
  49. package/dist/esm/query.d.ts +3 -3
  50. package/dist/esm/query.d.ts.map +1 -1
  51. package/dist/esm/retry.d.ts.map +1 -1
  52. package/dist/esm/topic/TopicQuery.d.ts +2 -1
  53. package/dist/esm/topic/TopicQuery.d.ts.map +1 -1
  54. package/package.json +1 -1
  55. package/plugin/docs/api/fetchium.md +2 -2
  56. package/plugin/docs/api/stores-async.md +9 -3
  57. package/plugin/docs/api/stores-sync.md +9 -3
  58. package/plugin/docs/core/entities.md +2 -2
  59. package/plugin/docs/core/queries.md +12 -19
  60. package/plugin/docs/data/mutations.md +1 -1
  61. package/plugin/docs/guides/auth.md +65 -42
  62. package/plugin/docs/guides/error-handling.md +9 -5
  63. package/plugin/docs/guides/offline.md +11 -8
  64. package/plugin/docs/guides/testing.md +1 -1
  65. package/plugin/docs/quickstart.md +1 -1
  66. package/plugin/docs/reference/rest-queries.md +9 -9
  67. package/plugin/docs/setup/project-setup.md +5 -5
  68. package/dist/cjs/development/QueryClient-m7BzCIe9.js +0 -2
  69. package/dist/cjs/development/QueryClient-m7BzCIe9.js.map +0 -1
  70. package/dist/cjs/development/mutation-wUhcGxKl.js.map +0 -1
  71. package/dist/cjs/production/QueryClient-4T90peFN.js +0 -2
  72. package/dist/cjs/production/QueryClient-4T90peFN.js.map +0 -1
  73. package/dist/cjs/production/mutation-Dk0gznwX.js.map +0 -1
  74. package/dist/esm/development/QueryClient-BajBmpnA.js.map +0 -1
  75. package/dist/esm/development/mutation-DAOZE4Ok.js.map +0 -1
  76. package/dist/esm/production/QueryClient-KH0Ex_8m.js.map +0 -1
  77. package/dist/esm/production/mutation-C7BOChR2.js.map +0 -1
@@ -1,6 +1,6 @@
1
- import { A as r, E as s, G as t, L as o, a as n, M as i, N as M, b as g, c as u, d as y, e as f, Q as C, f as N, g as Q, h as d, R as k, i as l, j as p, k as m, q as E, r as R, t as w } from "./QueryClient-KH0Ex_8m.js";
1
+ import { A as r, E as s, G as t, L as o, a as n, M as i, N as M, b as g, c as u, d as y, e as f, Q as C, f as N, g as Q, h as d, R as k, i as l, j as p, k as m, q as E, r as R, t as w } from "./QueryClient-CS4iUKWj.js";
2
2
  import { Q as F } from "./QueryAdapter-Bu5UJjE4.js";
3
- import { M as A, g as K, m as Y } from "./mutation-C7BOChR2.js";
3
+ import { M as A, g as K, m as Y } from "./mutation-B1EiA34B.js";
4
4
  export {
5
5
  r as ARRAY_KEY,
6
6
  s as Entity,
@@ -1,5 +1,5 @@
1
1
  import { getContext as h } from "signalium";
2
- import { l as y, h as D, m as w, V as u, t as d } from "./QueryClient-KH0Ex_8m.js";
2
+ import { l as y, h as D, m as w, V as u, t as d } from "./QueryClient-CS4iUKWj.js";
3
3
  class x {
4
4
  static adapter;
5
5
  params;
@@ -55,4 +55,4 @@ export {
55
55
  S as g,
56
56
  C as m
57
57
  };
58
- //# sourceMappingURL=mutation-C7BOChR2.js.map
58
+ //# sourceMappingURL=mutation-B1EiA34B.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mutation-B1EiA34B.js","sources":["../../../src/mutation.ts"],"sourcesContent":["import { getContext, ReactiveTask } from 'signalium';\nimport { ExtractType, InternalTypeDef, MutationEffects, TypeDef, RetryConfig, TypeDefShape } from './types.js';\nimport { QueryClientContext, type QueryContext } from './QueryClient.js';\nimport { ValidatorDef, t } from './typeDefs.js';\nimport { createDefinitionProxy, extractDefinition, type CapturedDefinition } from './fieldRef.js';\nimport type { QueryAdapter, QueryAdapterClass } from './QueryAdapter.js';\n\n// ================================\n// Mutation Definition Types\n// ================================\n\nexport interface MutationConfigOptions {\n retry?: RetryConfig | number | false;\n}\n\nexport interface MutationDefinition<Request, Response> {\n id: string;\n requestShape: InternalTypeDef;\n responseShape: InternalTypeDef | undefined;\n captured: CapturedDefinition<Mutation>;\n optimisticUpdates: boolean;\n config?: MutationConfigOptions;\n effects?: MutationEffects;\n hasGetEffects: boolean;\n adapterClass: QueryAdapterClass;\n}\n\n// ================================\n// Mutation base class\n// ================================\n\nexport abstract class Mutation {\n static adapter?: QueryAdapterClass;\n\n readonly params?: TypeDefShape;\n readonly result?: TypeDefShape;\n readonly optimisticUpdates?: boolean;\n readonly config?: MutationConfigOptions;\n readonly effects?: Readonly<MutationEffects>;\n\n declare context: QueryContext;\n\n abstract getIdentityKey(): unknown;\n\n getEffects?(): MutationEffects;\n\n constructor() {\n return createDefinitionProxy(this);\n }\n}\n\n// ================================\n// Mutation definition cache and lookup\n// ================================\n\nconst mutationDefCache = new WeakMap<new () => Mutation, () => MutationDefinition<any, any>>();\n\nexport const mutationKeyForClass = (cls: new () => Mutation): string => {\n const getMutationDef = mutationDefCache.get(cls);\n\n if (getMutationDef === undefined) {\n throw new Error('Mutation definition not found');\n }\n\n return getMutationDef().id;\n};\n\n// ================================\n// Internal: build mutation definition from class\n// ================================\n\nfunction buildMutationDefinition(MutationClass: new () => Mutation): () => MutationDefinition<any, any> {\n let cached = mutationDefCache.get(MutationClass);\n\n if (cached !== undefined) {\n return cached;\n }\n\n let mutationDefinition: MutationDefinition<any, any> | undefined;\n\n const getter = (): MutationDefinition<any, any> => {\n if (mutationDefinition !== undefined) {\n return mutationDefinition;\n }\n\n const instance = new MutationClass();\n const captured = extractDefinition(instance);\n const { fields } = captured;\n\n const id = `mutation:${String(captured.methods.getIdentityKey.call(fields))}`;\n\n const requestDef = fields.params ?? {};\n const requestShape = (requestDef instanceof ValidatorDef\n ? requestDef\n : t.object(requestDef)) as unknown as InternalTypeDef;\n const responseDef = fields.result;\n const responseShape =\n responseDef !== undefined\n ? ((responseDef instanceof ValidatorDef ? responseDef : t.object(responseDef)) as unknown as InternalTypeDef)\n : undefined;\n\n const adapterClass = (MutationClass as typeof Mutation).adapter;\n if (!adapterClass) {\n throw new Error(\n `Mutation class \"${MutationClass.name}\" must define a static \\`adapter\\` property. ` +\n `Extend RESTMutation (from fetchium/rest) or set \\`static adapter = MyAdapter\\` on your mutation class.`,\n );\n }\n\n mutationDefinition = {\n id,\n requestShape,\n responseShape,\n captured,\n optimisticUpdates: fields.optimisticUpdates ?? false,\n config: fields.config,\n effects: fields.effects,\n hasGetEffects: typeof captured.methods.getEffects === 'function',\n adapterClass,\n };\n\n return mutationDefinition;\n };\n\n mutationDefCache.set(MutationClass, getter);\n return getter;\n}\n\n// ================================\n// Public API\n// ================================\n\nexport function getMutation<T extends Mutation>(\n MutationClass: new () => T,\n): ReactiveTask<Readonly<ExtractType<T['result']>>, [ExtractType<T['params']>]> {\n const getMutationDef = buildMutationDefinition(MutationClass);\n\n const queryClient = getContext(QueryClientContext);\n\n if (queryClient === undefined) {\n throw new Error('QueryClient not found');\n }\n\n return queryClient.getMutation<any, any>(getMutationDef());\n}\n"],"names":["Mutation","createDefinitionProxy","mutationDefCache","mutationKeyForClass","cls","getMutationDef","buildMutationDefinition","MutationClass","cached","mutationDefinition","getter","instance","captured","extractDefinition","fields","id","requestDef","requestShape","ValidatorDef","t","responseDef","responseShape","adapterClass","getMutation","queryClient","getContext","QueryClientContext"],"mappings":";;AA+BO,MAAeA,EAAS;AAAA,EAC7B,OAAO;AAAA,EAEE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAQT,cAAc;AACZ,WAAOC,EAAsB,IAAI;AAAA,EACnC;AACF;AAMA,MAAMC,wBAAuB,QAAA,GAEhBC,IAAsB,CAACC,MAAoC;AACtE,QAAMC,IAAiBH,EAAiB,IAAIE,CAAG;AAE/C,MAAIC,MAAmB;AACrB,UAAM,IAAI,MAAM,+BAA+B;AAGjD,SAAOA,IAAiB;AAC1B;AAMA,SAASC,EAAwBC,GAAuE;AACtG,MAAIC,IAASN,EAAiB,IAAIK,CAAa;AAE/C,MAAIC,MAAW;AACb,WAAOA;AAGT,MAAIC;AAEJ,QAAMC,IAAS,MAAoC;AACjD,QAAID,MAAuB;AACzB,aAAOA;AAGT,UAAME,IAAW,IAAIJ,EAAA,GACfK,IAAWC,EAAkBF,CAAQ,GACrC,EAAE,QAAAG,MAAWF,GAEbG,IAAK,YAAY,OAAOH,EAAS,QAAQ,eAAe,KAAKE,CAAM,CAAC,CAAC,IAErEE,IAAaF,EAAO,UAAU,CAAA,GAC9BG,IAAgBD,aAAsBE,IACxCF,IACAG,EAAE,OAAOH,CAAU,GACjBI,IAAcN,EAAO,QACrBO,IACJD,MAAgB,SACVA,aAAuBF,IAAeE,IAAcD,EAAE,OAAOC,CAAW,IAC1E,QAEAE,IAAgBf,EAAkC;AACxD,QAAI,CAACe;AACH,YAAM,IAAI;AAAA,QACR,mBAAmBf,EAAc,IAAI;AAAA,MAAA;AAKzC,WAAAE,IAAqB;AAAA,MACnB,IAAAM;AAAA,MACA,cAAAE;AAAA,MACA,eAAAI;AAAA,MACA,UAAAT;AAAA,MACA,mBAAmBE,EAAO,qBAAqB;AAAA,MAC/C,QAAQA,EAAO;AAAA,MACf,SAASA,EAAO;AAAA,MAChB,eAAe,OAAOF,EAAS,QAAQ,cAAe;AAAA,MACtD,cAAAU;AAAA,IAAA,GAGKb;AAAA,EACT;AAEA,SAAAP,EAAiB,IAAIK,GAAeG,CAAM,GACnCA;AACT;AAMO,SAASa,EACdhB,GAC8E;AAC9E,QAAMF,IAAiBC,EAAwBC,CAAa,GAEtDiB,IAAcC,EAAWC,CAAkB;AAEjD,MAAIF,MAAgB;AAClB,UAAM,IAAI,MAAM,uBAAuB;AAGzC,SAAOA,EAAY,YAAsBnB,GAAgB;AAC3D;"}
@@ -1,6 +1,6 @@
1
1
  import { useReactive as i } from "signalium/react";
2
2
  import { reactive as f } from "signalium";
3
- import { k as u } from "../QueryClient-KH0Ex_8m.js";
3
+ import { k as u } from "../QueryClient-CS4iUKWj.js";
4
4
  function n(e) {
5
5
  if (Array.isArray(e))
6
6
  return e.map(n);
@@ -1,6 +1,6 @@
1
- import { n as v, o as U, f as O } from "../QueryClient-KH0Ex_8m.js";
1
+ import { n as v, o as U, f as O } from "../QueryClient-CS4iUKWj.js";
2
2
  import { Q as T } from "../QueryAdapter-Bu5UJjE4.js";
3
- import { M as w } from "../mutation-C7BOChR2.js";
3
+ import { M as w } from "../mutation-B1EiA34B.js";
4
4
  class P extends T {
5
5
  _fetch;
6
6
  _baseUrl;
@@ -1,4 +1,4 @@
1
- import { f as l } from "../QueryClient-KH0Ex_8m.js";
1
+ import { f as l } from "../QueryClient-CS4iUKWj.js";
2
2
  import { Q as d } from "../QueryAdapter-Bu5UJjE4.js";
3
3
  class g extends l {
4
4
  static adapter;
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../../../../src/topic/TopicQuery.ts","../../../../src/topic/TopicQueryAdapter.ts"],"sourcesContent":["import { Query } from '../query.js';\nimport type { TopicQueryAdapter } from './TopicQueryAdapter.js';\nimport type { QueryConfigOptions } from '../query-types.js';\n\n// ================================\n// TopicQuery — declarative topic-based query definition\n// ================================\n\nexport abstract class TopicQuery extends Query {\n static override adapter: typeof TopicQueryAdapter;\n\n abstract topic: string;\n\n getIdentityKey(): string {\n return `topic:${this.topic}`;\n }\n\n getConfig(): QueryConfigOptions {\n return {\n staleTime: 0,\n subscribe: () => {\n return () => {\n const adapter = (this as Record<string, any>)._topicAdapter as TopicQueryAdapter | undefined;\n adapter?.unsubscribe(this.topic);\n };\n },\n };\n }\n}\n","import { QueryAdapter } from '../QueryAdapter.js';\nimport type { Query } from '../query.js';\nimport type { MutationEvent } from '../types.js';\n\n// ================================\n// TopicQueryAdapter — abstract adapter for topic-based subscriptions\n// ================================\n\ninterface TopicCtx extends Query {\n topic: string;\n _topicAdapter?: TopicQueryAdapter;\n}\n\ninterface TopicState {\n status: 'pending' | 'fulfilled' | 'rejected';\n promise?: Promise<unknown>;\n resolve?: (data: unknown) => void;\n reject?: (error: unknown) => void;\n data?: unknown;\n error?: unknown;\n}\n\nexport abstract class TopicQueryAdapter extends QueryAdapter {\n private _topics = new Map<string, TopicState>();\n\n /**\n * Called when a query activates for a given topic.\n * Implementations should start delivering data for this topic,\n * calling `fulfillTopic()` when initial data is available and\n * `sendMutationEvent()` for ongoing updates.\n */\n abstract subscribe(topic: string): void;\n\n /**\n * Called when the query deactivates. Implementations should\n * tear down any resources for this topic.\n */\n abstract unsubscribe(topic: string): void;\n\n /**\n * Resolve the pending promise for a topic with initial data.\n * Can be called before `send()` — the data will be picked up\n * when the query activates.\n */\n protected fulfillTopic(topic: string, data: unknown): void {\n const state = this._topics.get(topic);\n\n if (state === undefined) {\n this._topics.set(topic, { status: 'fulfilled', data });\n return;\n }\n\n if (state.status === 'pending') {\n state.status = 'fulfilled';\n state.data = data;\n state.resolve!(data);\n }\n }\n\n /**\n * Reject the pending promise for a topic.\n * Can be called before `send()` — the error will be propagated\n * when the query activates.\n */\n protected rejectTopic(topic: string, error: unknown): void {\n const state = this._topics.get(topic);\n\n if (state === undefined) {\n this._topics.set(topic, { status: 'rejected', error });\n return;\n }\n\n if (state.status === 'pending') {\n state.status = 'rejected';\n state.error = error;\n state.reject!(error);\n }\n }\n\n /**\n * Clears internal state for a topic. Called automatically by\n * `unsubscribe` — subclasses generally don't need to call this.\n */\n protected clearTopic(topic: string): void {\n this._topics.delete(topic);\n }\n\n protected clearAll(): void {\n this._topics.clear();\n }\n\n override async send(ctx: Query, _signal: AbortSignal): Promise<unknown> {\n const topicCtx = ctx as TopicCtx;\n topicCtx._topicAdapter = this;\n const topic = topicCtx.topic;\n\n const existing = this._topics.get(topic);\n\n if (existing) {\n switch (existing.status) {\n case 'fulfilled':\n return existing.data;\n case 'rejected':\n throw existing.error;\n case 'pending':\n return existing.promise;\n }\n }\n\n // No state yet — create a deferred and subscribe\n let resolve!: (data: unknown) => void;\n let reject!: (error: unknown) => void;\n const promise = new Promise<unknown>((res, rej) => {\n resolve = res;\n reject = rej;\n });\n\n this._topics.set(topic, { status: 'pending', promise, resolve, reject });\n this.subscribe(topic);\n\n return promise;\n }\n\n /**\n * Convenience wrapper — pushes a mutation event through the QueryClient\n * so that entities and live collections are updated reactively.\n */\n protected sendMutationEvent(event: MutationEvent): void {\n this.queryClient!.applyMutationEvent(event);\n }\n}\n"],"names":["TopicQuery","Query","TopicQueryAdapter","QueryAdapter","topic","data","state","error","ctx","_signal","topicCtx","existing","resolve","reject","promise","res","rej","event"],"mappings":";;AAQO,MAAeA,UAAmBC,EAAM;AAAA,EAC7C,OAAgB;AAAA,EAIhB,iBAAyB;AACvB,WAAO,SAAS,KAAK,KAAK;AAAA,EAC5B;AAAA,EAEA,YAAgC;AAC9B,WAAO;AAAA,MACL,WAAW;AAAA,MACX,WAAW,MACF,MAAM;AAEX,QADiB,KAA6B,eACrC,YAAY,KAAK,KAAK;AAAA,MACjC;AAAA,IACF;AAAA,EAEJ;AACF;ACNO,MAAeC,UAA0BC,EAAa;AAAA,EACnD,8BAAc,IAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAqBZ,aAAaC,GAAeC,GAAqB;AACzD,UAAMC,IAAQ,KAAK,QAAQ,IAAIF,CAAK;AAEpC,QAAIE,MAAU,QAAW;AACvB,WAAK,QAAQ,IAAIF,GAAO,EAAE,QAAQ,aAAa,MAAAC,GAAM;AACrD;AAAA,IACF;AAEA,IAAIC,EAAM,WAAW,cACnBA,EAAM,SAAS,aACfA,EAAM,OAAOD,GACbC,EAAM,QAASD,CAAI;AAAA,EAEvB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOU,YAAYD,GAAeG,GAAsB;AACzD,UAAMD,IAAQ,KAAK,QAAQ,IAAIF,CAAK;AAEpC,QAAIE,MAAU,QAAW;AACvB,WAAK,QAAQ,IAAIF,GAAO,EAAE,QAAQ,YAAY,OAAAG,GAAO;AACrD;AAAA,IACF;AAEA,IAAID,EAAM,WAAW,cACnBA,EAAM,SAAS,YACfA,EAAM,QAAQC,GACdD,EAAM,OAAQC,CAAK;AAAA,EAEvB;AAAA;AAAA;AAAA;AAAA;AAAA,EAMU,WAAWH,GAAqB;AACxC,SAAK,QAAQ,OAAOA,CAAK;AAAA,EAC3B;AAAA,EAEU,WAAiB;AACzB,SAAK,QAAQ,MAAA;AAAA,EACf;AAAA,EAEA,MAAe,KAAKI,GAAYC,GAAwC;AACtE,UAAMC,IAAWF;AACjB,IAAAE,EAAS,gBAAgB;AACzB,UAAMN,IAAQM,EAAS,OAEjBC,IAAW,KAAK,QAAQ,IAAIP,CAAK;AAEvC,QAAIO;AACF,cAAQA,EAAS,QAAA;AAAA,QACf,KAAK;AACH,iBAAOA,EAAS;AAAA,QAClB,KAAK;AACH,gBAAMA,EAAS;AAAA,QACjB,KAAK;AACH,iBAAOA,EAAS;AAAA,MAAA;AAKtB,QAAIC,GACAC;AACJ,UAAMC,IAAU,IAAI,QAAiB,CAACC,GAAKC,MAAQ;AACjD,MAAAJ,IAAUG,GACVF,IAASG;AAAA,IACX,CAAC;AAED,gBAAK,QAAQ,IAAIZ,GAAO,EAAE,QAAQ,WAAW,SAAAU,GAAS,SAAAF,GAAS,QAAAC,GAAQ,GACvE,KAAK,UAAUT,CAAK,GAEbU;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA,EAMU,kBAAkBG,GAA4B;AACtD,SAAK,YAAa,mBAAmBA,CAAK;AAAA,EAC5C;AACF;"}
1
+ {"version":3,"file":"index.js","sources":["../../../../src/topic/TopicQuery.ts","../../../../src/topic/TopicQueryAdapter.ts"],"sourcesContent":["import { Query } from '../query.js';\nimport type { TopicQueryAdapter } from './TopicQueryAdapter.js';\nimport type { QueryAdapterClass } from '../QueryAdapter.js';\nimport type { QueryConfigOptions } from '../query-types.js';\n\n// ================================\n// TopicQuery — declarative topic-based query definition\n// ================================\n\nexport abstract class TopicQuery extends Query {\n static override adapter: QueryAdapterClass<TopicQueryAdapter>;\n\n abstract topic: string;\n\n getIdentityKey(): string {\n return `topic:${this.topic}`;\n }\n\n getConfig(): QueryConfigOptions {\n return {\n staleTime: 0,\n subscribe: () => {\n return () => {\n const adapter = (this as Record<string, any>)._topicAdapter as TopicQueryAdapter | undefined;\n adapter?.unsubscribe(this.topic);\n };\n },\n };\n }\n}\n","import { QueryAdapter } from '../QueryAdapter.js';\nimport type { Query } from '../query.js';\nimport type { MutationEvent } from '../types.js';\n\n// ================================\n// TopicQueryAdapter — abstract adapter for topic-based subscriptions\n// ================================\n\ninterface TopicCtx extends Query {\n topic: string;\n _topicAdapter?: TopicQueryAdapter;\n}\n\ninterface TopicState {\n status: 'pending' | 'fulfilled' | 'rejected';\n promise?: Promise<unknown>;\n resolve?: (data: unknown) => void;\n reject?: (error: unknown) => void;\n data?: unknown;\n error?: unknown;\n}\n\nexport abstract class TopicQueryAdapter extends QueryAdapter {\n private _topics = new Map<string, TopicState>();\n\n /**\n * Called when a query activates for a given topic.\n * Implementations should start delivering data for this topic,\n * calling `fulfillTopic()` when initial data is available and\n * `sendMutationEvent()` for ongoing updates.\n */\n abstract subscribe(topic: string): void;\n\n /**\n * Called when the query deactivates. Implementations should\n * tear down any resources for this topic.\n */\n abstract unsubscribe(topic: string): void;\n\n /**\n * Resolve the pending promise for a topic with initial data.\n * Can be called before `send()` — the data will be picked up\n * when the query activates.\n */\n protected fulfillTopic(topic: string, data: unknown): void {\n const state = this._topics.get(topic);\n\n if (state === undefined) {\n this._topics.set(topic, { status: 'fulfilled', data });\n return;\n }\n\n if (state.status === 'pending') {\n state.status = 'fulfilled';\n state.data = data;\n state.resolve!(data);\n }\n }\n\n /**\n * Reject the pending promise for a topic.\n * Can be called before `send()` — the error will be propagated\n * when the query activates.\n */\n protected rejectTopic(topic: string, error: unknown): void {\n const state = this._topics.get(topic);\n\n if (state === undefined) {\n this._topics.set(topic, { status: 'rejected', error });\n return;\n }\n\n if (state.status === 'pending') {\n state.status = 'rejected';\n state.error = error;\n state.reject!(error);\n }\n }\n\n /**\n * Clears internal state for a topic. Called automatically by\n * `unsubscribe` — subclasses generally don't need to call this.\n */\n protected clearTopic(topic: string): void {\n this._topics.delete(topic);\n }\n\n protected clearAll(): void {\n this._topics.clear();\n }\n\n override async send(ctx: Query, _signal: AbortSignal): Promise<unknown> {\n const topicCtx = ctx as TopicCtx;\n topicCtx._topicAdapter = this;\n const topic = topicCtx.topic;\n\n const existing = this._topics.get(topic);\n\n if (existing) {\n switch (existing.status) {\n case 'fulfilled':\n return existing.data;\n case 'rejected':\n throw existing.error;\n case 'pending':\n return existing.promise;\n }\n }\n\n // No state yet — create a deferred and subscribe\n let resolve!: (data: unknown) => void;\n let reject!: (error: unknown) => void;\n const promise = new Promise<unknown>((res, rej) => {\n resolve = res;\n reject = rej;\n });\n\n this._topics.set(topic, { status: 'pending', promise, resolve, reject });\n this.subscribe(topic);\n\n return promise;\n }\n\n /**\n * Convenience wrapper — pushes a mutation event through the QueryClient\n * so that entities and live collections are updated reactively.\n */\n protected sendMutationEvent(event: MutationEvent): void {\n this.queryClient!.applyMutationEvent(event);\n }\n}\n"],"names":["TopicQuery","Query","TopicQueryAdapter","QueryAdapter","topic","data","state","error","ctx","_signal","topicCtx","existing","resolve","reject","promise","res","rej","event"],"mappings":";;AASO,MAAeA,UAAmBC,EAAM;AAAA,EAC7C,OAAgB;AAAA,EAIhB,iBAAyB;AACvB,WAAO,SAAS,KAAK,KAAK;AAAA,EAC5B;AAAA,EAEA,YAAgC;AAC9B,WAAO;AAAA,MACL,WAAW;AAAA,MACX,WAAW,MACF,MAAM;AAEX,QADiB,KAA6B,eACrC,YAAY,KAAK,KAAK;AAAA,MACjC;AAAA,IACF;AAAA,EAEJ;AACF;ACPO,MAAeC,UAA0BC,EAAa;AAAA,EACnD,8BAAc,IAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAqBZ,aAAaC,GAAeC,GAAqB;AACzD,UAAMC,IAAQ,KAAK,QAAQ,IAAIF,CAAK;AAEpC,QAAIE,MAAU,QAAW;AACvB,WAAK,QAAQ,IAAIF,GAAO,EAAE,QAAQ,aAAa,MAAAC,GAAM;AACrD;AAAA,IACF;AAEA,IAAIC,EAAM,WAAW,cACnBA,EAAM,SAAS,aACfA,EAAM,OAAOD,GACbC,EAAM,QAASD,CAAI;AAAA,EAEvB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOU,YAAYD,GAAeG,GAAsB;AACzD,UAAMD,IAAQ,KAAK,QAAQ,IAAIF,CAAK;AAEpC,QAAIE,MAAU,QAAW;AACvB,WAAK,QAAQ,IAAIF,GAAO,EAAE,QAAQ,YAAY,OAAAG,GAAO;AACrD;AAAA,IACF;AAEA,IAAID,EAAM,WAAW,cACnBA,EAAM,SAAS,YACfA,EAAM,QAAQC,GACdD,EAAM,OAAQC,CAAK;AAAA,EAEvB;AAAA;AAAA;AAAA;AAAA;AAAA,EAMU,WAAWH,GAAqB;AACxC,SAAK,QAAQ,OAAOA,CAAK;AAAA,EAC3B;AAAA,EAEU,WAAiB;AACzB,SAAK,QAAQ,MAAA;AAAA,EACf;AAAA,EAEA,MAAe,KAAKI,GAAYC,GAAwC;AACtE,UAAMC,IAAWF;AACjB,IAAAE,EAAS,gBAAgB;AACzB,UAAMN,IAAQM,EAAS,OAEjBC,IAAW,KAAK,QAAQ,IAAIP,CAAK;AAEvC,QAAIO;AACF,cAAQA,EAAS,QAAA;AAAA,QACf,KAAK;AACH,iBAAOA,EAAS;AAAA,QAClB,KAAK;AACH,gBAAMA,EAAS;AAAA,QACjB,KAAK;AACH,iBAAOA,EAAS;AAAA,MAAA;AAKtB,QAAIC,GACAC;AACJ,UAAMC,IAAU,IAAI,QAAiB,CAACC,GAAKC,MAAQ;AACjD,MAAAJ,IAAUG,GACVF,IAASG;AAAA,IACX,CAAC;AAED,gBAAK,QAAQ,IAAIZ,GAAO,EAAE,QAAQ,WAAW,SAAAU,GAAS,SAAAF,GAAS,QAAAC,GAAQ,GACvE,KAAK,UAAUT,CAAK,GAEbU;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA,EAMU,kBAAkBG,GAA4B;AACtD,SAAK,YAAa,mBAAmBA,CAAK;AAAA,EAC5C;AACF;"}
@@ -3,7 +3,7 @@ import { QueryCacheOptions, QueryConfigOptions, FetchNextConfig, QueryParams } f
3
3
  import { ValidatorDef } from './typeDefs.js';
4
4
  import { HasRequiredKeys, Optionalize, Signalize } from './type-utils.js';
5
5
  import { type CapturedDefinition } from './fieldRef.js';
6
- import type { QueryAdapter } from './QueryAdapter.js';
6
+ import type { QueryAdapterClass } from './QueryAdapter.js';
7
7
  export interface ResolvedRetryConfig {
8
8
  retries: number;
9
9
  retryDelay: (attempt: number) => number;
@@ -15,7 +15,7 @@ export declare abstract class Query {
15
15
  * The adapter class responsible for sending requests for this query type.
16
16
  * Must be set on each concrete Query subclass (or inherited from a base like RESTQuery).
17
17
  */
18
- static adapter?: typeof QueryAdapter;
18
+ static adapter?: QueryAdapterClass;
19
19
  params?: Record<string, TypeDef>;
20
20
  abstract result: TypeDefShape;
21
21
  config?: QueryConfigOptions;
@@ -45,7 +45,7 @@ export interface QueryDefinitionStatics {
45
45
  /** Whether the result shape is already an entity (vs synthetic wrapper). */
46
46
  readonly isEntityResult: boolean;
47
47
  /** The adapter class responsible for sending requests. */
48
- readonly adapterClass: typeof QueryAdapter;
48
+ readonly adapterClass: QueryAdapterClass;
49
49
  }
50
50
  export declare class QueryDefinition<Params extends QueryParams | undefined, Result, StreamType> {
51
51
  readonly captured: CapturedDefinition<Query>;
@@ -1 +1 @@
1
- {"version":3,"file":"query.d.ts","sourceRoot":"","sources":["../../src/query.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"query.d.ts","sourceRoot":"","sources":["../../src/query.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"retry.d.ts","sourceRoot":"","sources":["../../src/retry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAEtD,wBAAgB,KAAK,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAgBrE;AAED,wBAAsB,SAAS,CAAC,CAAC,EAC/B,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EACpB,MAAM,EAAE,mBAAmB,EAC3B,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,CAAC,CAAC,CAiBZ"}
1
+ {"version":3,"file":"retry.d.ts","sourceRoot":"","sources":["../../src/retry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAgBtD,wBAAgB,KAAK,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAgBrE;AAED,wBAAsB,SAAS,CAAC,CAAC,EAC/B,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EACpB,MAAM,EAAE,mBAAmB,EAC3B,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,CAAC,CAAC,CAmBZ"}
@@ -1,8 +1,9 @@
1
1
  import { Query } from '../query.js';
2
2
  import type { TopicQueryAdapter } from './TopicQueryAdapter.js';
3
+ import type { QueryAdapterClass } from '../QueryAdapter.js';
3
4
  import type { QueryConfigOptions } from '../query-types.js';
4
5
  export declare abstract class TopicQuery extends Query {
5
- static adapter: typeof TopicQueryAdapter;
6
+ static adapter: QueryAdapterClass<TopicQueryAdapter>;
6
7
  abstract topic: string;
7
8
  getIdentityKey(): string;
8
9
  getConfig(): QueryConfigOptions;
@@ -1 +1 @@
1
- {"version":3,"file":"TopicQuery.d.ts","sourceRoot":"","sources":["../../../src/topic/TopicQuery.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AACpC,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAChE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAM5D,8BAAsB,UAAW,SAAQ,KAAK;IAC5C,OAAgB,OAAO,EAAE,OAAO,iBAAiB,CAAC;IAElD,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IAEvB,cAAc,IAAI,MAAM;IAIxB,SAAS,IAAI,kBAAkB;CAWhC"}
1
+ {"version":3,"file":"TopicQuery.d.ts","sourceRoot":"","sources":["../../../src/topic/TopicQuery.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AACpC,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAChE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAC5D,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAM5D,8BAAsB,UAAW,SAAQ,KAAK;IAC5C,OAAgB,OAAO,EAAE,iBAAiB,CAAC,iBAAiB,CAAC,CAAC;IAE9D,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IAEvB,cAAc,IAAI,MAAM;IAIxB,SAAS,IAAI,kBAAkB;CAWhC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fetchium",
3
- "version": "0.2.0",
3
+ "version": "0.2.2",
4
4
  "type": "module",
5
5
  "repository": {
6
6
  "type": "git",
@@ -226,7 +226,7 @@ new QueryClient(config: QueryClientConfig)
226
226
 
227
227
  | Field | Type | Default | Description |
228
228
  | -------------------- | ---------------------------- | ---------------------- | ------------------------------------------------------------------------------------ |
229
- | `store` | `QueryStore` | | **(required)** Persistent storage backend. |
229
+ | `store` | `QueryStore` | In-memory | Persistent storage backend. Defaults to `SyncQueryStore(MemoryPersistentStore)`. |
230
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. |
@@ -604,7 +604,7 @@ The `t` object provides a declarative type definition DSL for describing query p
604
604
  | `QueryCacheOptions` | `{ maxCount?: number; cacheTime?: number }` | Persistent storage cache settings. `cacheTime` is in minutes (default: 1440 / 24 hours). `maxCount` is the LRU queue size. |
605
605
  | `QueryConfigOptions` | `{ gcTime?, staleTime?, debounce?, networkMode?, retry?, refreshStaleOnReconnect?, subscribe? }` | Instance-level query configuration. See property table below. |
606
606
  | `QueryRequestOptions` | `{ baseUrl?, credentials?, mode?, cache?, redirect?, referrer?, referrerPolicy?, integrity?, keepalive?, signal? }` | Extended fetch options for individual queries. |
607
- | `QueryContext` | `{ fetch, baseUrl?, log?, evictionMultiplier? }` | Context object provided to the `QueryClient`. |
607
+ | `QueryContext` | `{ log?, evictionMultiplier? }` | Context object provided to the `QueryClient`. |
608
608
  | `QueryParams` | `Record<string, string \| number \| boolean \| undefined \| null \| Signal<...> \| unknown[] \| Record<string, unknown>>` | The shape of query parameters at runtime. |
609
609
  | `FetchNextConfig` | `{ url?: unknown; searchParams?: Record<string, unknown> }` | Pagination configuration. Values can be FieldRefs. |
610
610
 
@@ -181,6 +181,7 @@ type StoreMessage =
181
181
  ```ts
182
182
  import { QueryClient } from 'fetchium';
183
183
  import { AsyncQueryStore } from 'fetchium/stores/async';
184
+ import { RESTQueryAdapter } from 'fetchium/rest';
184
185
 
185
186
  const worker = new Worker('./store-worker.js');
186
187
 
@@ -194,9 +195,14 @@ const store = new AsyncQueryStore({
194
195
  },
195
196
  });
196
197
 
197
- const client = new QueryClient(store, {
198
- fetch: globalThis.fetch,
199
- baseUrl: 'https://api.example.com',
198
+ const client = new QueryClient({
199
+ store,
200
+ adapters: [
201
+ new RESTQueryAdapter({
202
+ fetch: globalThis.fetch,
203
+ baseUrl: 'https://api.example.com',
204
+ }),
205
+ ],
200
206
  });
201
207
  ```
202
208
 
@@ -121,13 +121,19 @@ Internally, `SyncQueryStore` uses the following key prefixes in the underlying `
121
121
  ```ts
122
122
  import { QueryClient } from 'fetchium';
123
123
  import { SyncQueryStore, MemoryPersistentStore } from 'fetchium/stores/sync';
124
+ import { RESTQueryAdapter } from 'fetchium/rest';
124
125
 
125
126
  // Create an in-memory store
126
127
  const store = new SyncQueryStore(new MemoryPersistentStore());
127
128
 
128
129
  // Create the query client
129
- const client = new QueryClient(store, {
130
- fetch: globalThis.fetch,
131
- baseUrl: 'https://api.example.com',
130
+ const client = new QueryClient({
131
+ store,
132
+ adapters: [
133
+ new RESTQueryAdapter({
134
+ fetch: globalThis.fetch,
135
+ baseUrl: 'https://api.example.com',
136
+ }),
137
+ ],
132
138
  });
133
139
  ```
@@ -171,7 +171,7 @@ class User extends Entity {
171
171
  }
172
172
 
173
173
  greet() {
174
- return `Hello, ${this.name}!`;
174
+ return `Hello, ${this.fullName}!`;
175
175
  }
176
176
 
177
177
  isAdult() {
@@ -185,7 +185,7 @@ Methods work on entity proxies just like regular methods:
185
185
  ```tsx
186
186
  const user = result.user;
187
187
  user.fullName; // "Alice Smith"
188
- user.greet(); // "Hello, Alice!"
188
+ user.greet(); // "Hello, Alice Smith!"
189
189
  user.isAdult(); // true
190
190
  ```
191
191
 
@@ -163,17 +163,16 @@ interface ReactivePromise<T> {
163
163
 
164
164
  ```ts
165
165
  type QueryResult<Q extends Query> = Q['result'] & {
166
- __refetch(): Promise<Q['result']>;
166
+ __refetch(): QueryPromise<Q>;
167
167
  __fetchNext(): Promise<Q['result']>;
168
+ __hasNext: boolean;
169
+ __isFetchingNext: boolean;
168
170
  };
169
171
 
170
172
  declare function useQuery<Q extends Query>(
171
- query: Q,
172
- params: Q['params'],
173
- opts?: {
174
- suspended?: boolean;
175
- },
176
- ): ReactivePromise<QueryResult<Q>>;
173
+ QueryClass: new () => Q,
174
+ params?: ExtractQueryParams<Q>,
175
+ ): QueryPromise<Q>;
177
176
  ```
178
177
 
179
178
  The reason `__refetch` and `__fetchNext` are defined on the _result_ of the query and not the `ReactivePromise` is about composability, which leads us into usage within Signalium.
@@ -190,27 +189,21 @@ import { GetCurrentUser, GetUserProfile } from './queries';
190
189
 
191
190
  export function UserProfile() {
192
191
  const userResult = useQuery(GetCurrentUser);
193
- const userProfileResult = useQuery(
194
- GetUserProfile,
195
- { user },
196
- { suspended: !user },
192
+ const userProfileResult = useQuery(GetUserProfile, {
193
+ user: userResult.value,
197
194
  });
198
195
 
199
196
  if (userResult.isRejected || userProfileResult.isRejected) {
200
197
  const message =
201
- userResult.error?.message ||
202
- userProfileResult.error?.message;
198
+ userResult.error?.message || userProfileResult.error?.message;
203
199
 
204
- return <div>
205
- Error: {message}
206
- </div>;
200
+ return <div>Error: {message}</div>;
207
201
  }
208
202
 
209
203
  if (!userResult.isReady || !userProfileResult.isReady) {
210
- return <div>Loading...</div>;
204
+ return <div>Loading...</div>;
211
205
  }
212
206
 
213
-
214
207
  return (
215
208
  <div>
216
209
  <h1>{userProfileResult.value.name}</h1>
@@ -344,7 +337,7 @@ class GetUser extends RESTQuery {
344
337
  }
345
338
  ```
346
339
 
347
- By convention, every field provided by `RESTQuery` and other query implementations has a corresponding `get*` method. So for `path` there is `getPath`, for `headers` there is `getHeaders`, etc.
340
+ By convention, most fields provided by `RESTQuery` and other query implementations have a corresponding `get*` method. So for `path` there is `getPath`, for `searchParams` there is `getSearchParams`, for `body` there is `getBody`, and so on.
348
341
 
349
342
  {% callout title="API design by TypeScript limitations" type="note" %}
350
343
  The original API design for this feature allowed getters in place of fields, so `get path() {}` would work as well. The issue was that TypeScript does not allow this specific combination on abstract classes at the moment. See [this issue](https://github.com/microsoft/TypeScript/issues/40635) for more information.
@@ -364,7 +364,7 @@ import { Mutation, t } from 'fetchium';
364
364
  class UploadAvatar extends Mutation {
365
365
  static override adapter = MyAdapter;
366
366
 
367
- params = { userId: t.id, file: t.any };
367
+ params = { userId: t.id };
368
368
  result = { url: t.string };
369
369
 
370
370
  getIdentityKey() {
@@ -2,7 +2,7 @@
2
2
  title: Auth & Headers
3
3
  ---
4
4
 
5
- In most data-fetching libraries, authentication is handled through interceptors, middleware chains, or framework-specific hooks. Fetchium takes a different approach: authentication is handled through the `fetch` function you pass to the `QueryClient`.
5
+ In most data-fetching libraries, authentication is handled through interceptors, middleware chains, or framework-specific hooks. Fetchium takes a different approach: authentication is handled through the `fetch` function you pass to the `RESTQueryAdapter`.
6
6
 
7
7
  This is intentional. Rather than adding a framework-specific interceptor system, Fetchium leverages the web platform's standard `fetch` API. Your auth logic is a _plain JavaScript function_ --- testable, portable, and completely decoupled from the library. You can unit test it without importing Fetchium, reuse it across projects, or swap it out without touching a single query definition.
8
8
 
@@ -12,7 +12,7 @@ This page covers the common patterns for adding authentication and custom header
12
12
 
13
13
  ## Global Headers via a Fetch Wrapper
14
14
 
15
- The simplest and most common pattern is wrapping the native `fetch` with a function that injects your auth token on every request. You pass this wrapper to the `QueryClient` at setup time, and every query uses it automatically.
15
+ The simplest and most common pattern is wrapping the native `fetch` with a function that injects your auth token on every request. You pass this wrapper to the `RESTQueryAdapter` at setup time, and every query uses it automatically.
16
16
 
17
17
  ```ts
18
18
  function createAuthFetch(getToken: () => string | null) {
@@ -28,9 +28,13 @@ function createAuthFetch(getToken: () => string | null) {
28
28
  };
29
29
  }
30
30
 
31
- const client = new QueryClient(store, {
32
- fetch: createAuthFetch(() => localStorage.getItem('auth_token')),
33
- baseUrl: 'https://api.example.com',
31
+ const client = new QueryClient({
32
+ adapters: [
33
+ new RESTQueryAdapter({
34
+ fetch: createAuthFetch(() => localStorage.getItem('auth_token')),
35
+ baseUrl: 'https://api.example.com',
36
+ }),
37
+ ],
34
38
  });
35
39
  ```
36
40
 
@@ -45,13 +49,17 @@ Notice that `createAuthFetch` accepts a _getter function_ rather than the token
45
49
  If your API uses a static key rather than a user token, the pattern is even simpler:
46
50
 
47
51
  ```ts
48
- const client = new QueryClient(store, {
49
- fetch: async (url, init) => {
50
- const headers = new Headers(init?.headers);
51
- headers.set('X-API-Key', process.env.API_KEY!);
52
- return fetch(url, { ...init, headers });
53
- },
54
- baseUrl: 'https://api.example.com',
52
+ const client = new QueryClient({
53
+ adapters: [
54
+ new RESTQueryAdapter({
55
+ fetch: async (url, init) => {
56
+ const headers = new Headers(init?.headers);
57
+ headers.set('X-API-Key', process.env.API_KEY!);
58
+ return fetch(url, { ...init, headers });
59
+ },
60
+ baseUrl: 'https://api.example.com',
61
+ }),
62
+ ],
55
63
  });
56
64
  ```
57
65
 
@@ -93,9 +101,13 @@ function createReactiveAuthFetch() {
93
101
  };
94
102
  }
95
103
 
96
- const client = new QueryClient(store, {
97
- fetch: createReactiveAuthFetch(),
98
- baseUrl: 'https://api.example.com',
104
+ const client = new QueryClient({
105
+ adapters: [
106
+ new RESTQueryAdapter({
107
+ fetch: createReactiveAuthFetch(),
108
+ baseUrl: 'https://api.example.com',
109
+ }),
110
+ ],
99
111
  });
100
112
  ```
101
113
 
@@ -132,7 +144,7 @@ class UploadAvatar extends RESTQuery {
132
144
 
133
145
  The layering is straightforward: your global fetch wrapper handles _auth_ (the concern that applies everywhere), and per-query headers handle _API-specific needs_ (the concerns that vary by endpoint). The two are composed naturally --- `headers` from the query class are passed through `init.headers` to your fetch wrapper, which can merge them with auth headers using `new Headers(init?.headers)`.
134
146
 
135
- For dynamic per-query headers that depend on runtime conditions, use the `getHeaders()` method:
147
+ For dynamic per-query headers that depend on runtime conditions, use `getRequestOptions()` to include headers as part of the fetch options:
136
148
 
137
149
  ```ts
138
150
  class GetReport extends RESTQuery {
@@ -143,14 +155,11 @@ class GetReport extends RESTQuery {
143
155
 
144
156
  path = `/reports/${this.params.reportId}`;
145
157
 
146
- getHeaders() {
147
- const headers: Record<string, string> = {};
148
-
158
+ getRequestOptions() {
149
159
  if (this.params.format === 'csv') {
150
- headers['Accept'] = 'text/csv';
160
+ return { headers: { Accept: 'text/csv' } };
151
161
  }
152
-
153
- return headers;
162
+ return undefined;
154
163
  }
155
164
 
156
165
  result = {
@@ -159,7 +168,7 @@ class GetReport extends RESTQuery {
159
168
  }
160
169
  ```
161
170
 
162
- As described in the [Queries](/core/queries) guide, every field on `RESTQuery` has a corresponding `get*()` method for when you need logic that goes beyond simple references and interpolations.
171
+ As described in the [Queries](/core/queries) guide, most fields on `RESTQuery` have a corresponding `get*()` method for when you need logic that goes beyond simple references and interpolations.
163
172
 
164
173
  ---
165
174
 
@@ -215,13 +224,17 @@ A few things to note in this pattern:
215
224
  Wire it into your client the same way:
216
225
 
217
226
  ```ts
218
- const client = new QueryClient(store, {
219
- fetch: createAuthFetchWithRefresh(
220
- () => authToken.value,
221
- () => api.refreshSession(),
222
- (token) => authToken.set(token),
223
- ),
224
- baseUrl: 'https://api.example.com',
227
+ const client = new QueryClient({
228
+ adapters: [
229
+ new RESTQueryAdapter({
230
+ fetch: createAuthFetchWithRefresh(
231
+ () => authToken.value,
232
+ () => api.refreshSession(),
233
+ (token) => authToken.set(token),
234
+ ),
235
+ baseUrl: 'https://api.example.com',
236
+ }),
237
+ ],
225
238
  });
226
239
  ```
227
240
 
@@ -236,18 +249,28 @@ If your application talks to multiple APIs with different auth schemes --- for i
236
249
  The cleanest approach is creating a dedicated `QueryClient` for each backend:
237
250
 
238
251
  ```ts
239
- const appClient = new QueryClient(appStore, {
240
- fetch: createAuthFetch(() => authToken.value),
241
- baseUrl: 'https://api.myapp.com',
252
+ const appClient = new QueryClient({
253
+ store: appStore,
254
+ adapters: [
255
+ new RESTQueryAdapter({
256
+ fetch: createAuthFetch(() => authToken.value),
257
+ baseUrl: 'https://api.myapp.com',
258
+ }),
259
+ ],
242
260
  });
243
261
 
244
- const analyticsClient = new QueryClient(analyticsStore, {
245
- fetch: async (url, init) => {
246
- const headers = new Headers(init?.headers);
247
- headers.set('X-API-Key', ANALYTICS_API_KEY);
248
- return fetch(url, { ...init, headers });
249
- },
250
- baseUrl: 'https://analytics.example.com',
262
+ const analyticsClient = new QueryClient({
263
+ store: analyticsStore,
264
+ adapters: [
265
+ new RESTQueryAdapter({
266
+ fetch: async (url, init) => {
267
+ const headers = new Headers(init?.headers);
268
+ headers.set('X-API-Key', ANALYTICS_API_KEY);
269
+ return fetch(url, { ...init, headers });
270
+ },
271
+ baseUrl: 'https://analytics.example.com',
272
+ }),
273
+ ],
251
274
  });
252
275
  ```
253
276
 
@@ -294,12 +317,12 @@ This is a deliberate design decision. Fetchium favors _composition over configur
294
317
  | Global fetch wrapper | Auth that applies to all requests (JWT, session cookies, API keys) |
295
318
  | Reactive signal token | SPAs where auth state changes at runtime (login/logout) |
296
319
  | Per-query `headers` | Endpoint-specific headers (content types, API versions) |
297
- | `getHeaders()` method | Dynamic per-query headers based on runtime conditions |
320
+ | `getRequestOptions()` method | Dynamic per-query headers based on runtime conditions |
298
321
  | 401 catch + refresh + retry | Token expiration with automatic renewal |
299
322
  | Multiple `QueryClient` instances | Different APIs with different auth schemes or stores |
300
323
  | Per-query `requestOptions.baseUrl` | Same auth, different host |
301
324
 
302
- The common thread is that Fetchium does not own your auth logic. It provides the _seam_ --- the `fetch` option on `QueryClient` --- and you fill it with whatever your application needs. This keeps the library small, your auth testable, and your options open.
325
+ The common thread is that Fetchium does not own your auth logic. It provides the _seam_ --- the `fetch` option on `RESTQueryAdapter` --- and you fill it with whatever your application needs. This keeps the library small, your auth testable, and your options open.
303
326
 
304
327
  ---
305
328
 
@@ -202,7 +202,7 @@ function UserProfile({ userId }: { userId: number }) {
202
202
 
203
203
  Sometimes you need to intercept errors _before_ they reach individual queries --- for instance, redirecting to a login page on a 401, refreshing an auth token, or logging all failures to a telemetry service.
204
204
 
205
- The `QueryClient` accepts a `fetch` function, which is the standard place to add global error handling. You can wrap the native `fetch` with your own logic:
205
+ The `RESTQueryAdapter` accepts a `fetch` function, which is the standard place to add global error handling. You can wrap the native `fetch` with your own logic:
206
206
 
207
207
  ```ts
208
208
  function createFetchWithErrorHandling(baseFetch: typeof fetch) {
@@ -227,15 +227,19 @@ Then pass it when constructing the client:
227
227
  ```tsx
228
228
  import { QueryClient, QueryClientContext } from 'fetchium';
229
229
  import { SyncQueryStore, MemoryPersistentStore } from 'fetchium/stores/sync';
230
+ import { RESTQueryAdapter } from 'fetchium/rest';
230
231
  import { ContextProvider } from 'signalium/react';
231
232
 
232
233
  const store = new SyncQueryStore(new MemoryPersistentStore());
233
234
  const customFetch = createFetchWithErrorHandling(fetch);
234
- const client = new QueryClient(store, { fetch: customFetch });
235
+ const client = new QueryClient({
236
+ store,
237
+ adapters: [new RESTQueryAdapter({ fetch: customFetch })],
238
+ });
235
239
 
236
240
  function App() {
237
241
  return (
238
- <ContextProvider value={client} context={QueryClientContext}>
242
+ <ContextProvider contexts={[[QueryClientContext, client]]}>
239
243
  <YourApp />
240
244
  </ContextProvider>
241
245
  );
@@ -253,8 +257,8 @@ Non-fatal parse failures (optional fields falling back to `undefined`, array ite
253
257
  Fetchium routes these warnings through `QueryContext.log.warn`. You can plug in a custom logger when creating the `QueryClient`:
254
258
 
255
259
  ```ts
256
- const client = new QueryClient(store, {
257
- fetch,
260
+ const client = new QueryClient({
261
+ store,
258
262
  log: {
259
263
  warn: (message: string, ...args: unknown[]) => {
260
264
  console.warn(message, ...args);
@@ -29,7 +29,7 @@ import { SyncQueryStore, MemoryPersistentStore } from 'fetchium/stores/sync';
29
29
  const store = new SyncQueryStore(new MemoryPersistentStore());
30
30
  const networkManager = new NetworkManager();
31
31
 
32
- const client = new QueryClient(store, { fetch }, networkManager);
32
+ const client = new QueryClient({ store, networkManager });
33
33
  ```
34
34
 
35
35
  If you do not provide a `NetworkManager`, the `QueryClient` creates one automatically.
@@ -124,7 +124,7 @@ The `SyncQueryStore` wraps a synchronous key-value store. It is the simplest opt
124
124
  import { SyncQueryStore, MemoryPersistentStore } from 'fetchium/stores/sync';
125
125
 
126
126
  const store = new SyncQueryStore(new MemoryPersistentStore());
127
- const client = new QueryClient(store, { fetch });
127
+ const client = new QueryClient({ store });
128
128
  ```
129
129
 
130
130
  The `MemoryPersistentStore` keeps everything in memory --- data is lost when the page is refreshed. For persistence across sessions, implement the `SyncPersistentStore` interface with a durable backend like `localStorage`.
@@ -220,18 +220,21 @@ Here is a complete example that sets up a `QueryClient` with persistence and net
220
220
  ```tsx
221
221
  import { QueryClient, NetworkManager } from 'fetchium';
222
222
  import { SyncQueryStore } from 'fetchium/stores/sync';
223
+ import { RESTQueryAdapter } from 'fetchium/rest';
223
224
 
224
225
  const store = new SyncQueryStore(new LocalStoragePersistentStore());
225
226
  const networkManager = new NetworkManager();
226
227
 
227
- const client = new QueryClient(
228
+ const client = new QueryClient({
228
229
  store,
229
- {
230
- fetch: globalThis.fetch,
231
- baseUrl: 'https://api.example.com',
232
- },
233
230
  networkManager,
234
- );
231
+ adapters: [
232
+ new RESTQueryAdapter({
233
+ fetch: globalThis.fetch,
234
+ baseUrl: 'https://api.example.com',
235
+ }),
236
+ ],
237
+ });
235
238
  ```
236
239
 
237
240
  With this setup:
@@ -41,7 +41,7 @@ export function renderApp(
41
41
  { client }: { client: QueryClient },
42
42
  ) {
43
43
  return render(
44
- <ContextProvider value={client} context={QueryClientContext}>
44
+ <ContextProvider contexts={[[QueryClientContext, client]]}>
45
45
  {ui}
46
46
  </ContextProvider>,
47
47
  );