fetchium 0.1.0 → 0.1.1
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.
- package/CHANGELOG.md +6 -5
- package/dist/cjs/development/QueryClient-CLi3ONNM.js +2 -0
- package/dist/cjs/development/QueryClient-CLi3ONNM.js.map +1 -0
- package/dist/cjs/development/QueryController-BQA49OYU.js +2 -0
- package/dist/cjs/development/QueryController-BQA49OYU.js.map +1 -0
- package/dist/cjs/development/index.js +1 -1
- package/dist/cjs/development/index.js.map +1 -1
- package/dist/cjs/development/mutation-CikIl_6k.js +2 -0
- package/dist/cjs/development/mutation-CikIl_6k.js.map +1 -0
- package/dist/cjs/development/react/index.js +1 -1
- package/dist/cjs/development/rest/index.js +2 -0
- package/dist/cjs/development/rest/index.js.map +1 -0
- package/dist/cjs/development/topic/index.js +2 -0
- package/dist/cjs/development/topic/index.js.map +1 -0
- package/dist/cjs/production/QueryClient-N0MJmuHW.js +2 -0
- package/dist/cjs/production/QueryClient-N0MJmuHW.js.map +1 -0
- package/dist/cjs/production/QueryController-BQA49OYU.js +2 -0
- package/dist/cjs/production/QueryController-BQA49OYU.js.map +1 -0
- package/dist/cjs/production/index.js +1 -1
- package/dist/cjs/production/index.js.map +1 -1
- package/dist/cjs/production/mutation-P_Yb4LI9.js +2 -0
- package/dist/cjs/production/mutation-P_Yb4LI9.js.map +1 -0
- package/dist/cjs/production/react/index.js +1 -1
- package/dist/cjs/production/rest/index.js +2 -0
- package/dist/cjs/production/rest/index.js.map +1 -0
- package/dist/cjs/production/topic/index.js +2 -0
- package/dist/cjs/production/topic/index.js.map +1 -0
- package/dist/esm/MutationResult.d.ts +0 -1
- package/dist/esm/MutationResult.d.ts.map +1 -1
- package/dist/esm/QueryClient.d.ts +26 -4
- package/dist/esm/QueryClient.d.ts.map +1 -1
- package/dist/esm/QueryController.d.ts +49 -0
- package/dist/esm/QueryController.d.ts.map +1 -0
- package/dist/esm/QueryResult.d.ts +10 -10
- package/dist/esm/QueryResult.d.ts.map +1 -1
- package/dist/esm/development/QueryClient-Dtde3pss.js +2572 -0
- package/dist/esm/development/QueryClient-Dtde3pss.js.map +1 -0
- package/dist/esm/development/QueryController-Ch_ncxiI.js +14 -0
- package/dist/esm/development/QueryController-Ch_ncxiI.js.map +1 -0
- package/dist/esm/development/index.js +29 -100
- package/dist/esm/development/index.js.map +1 -1
- package/dist/esm/development/mutation-UZshUQAf.js +58 -0
- package/dist/esm/development/mutation-UZshUQAf.js.map +1 -0
- package/dist/esm/development/react/index.js +1 -1
- package/dist/esm/development/rest/index.js +142 -0
- package/dist/esm/development/rest/index.js.map +1 -0
- package/dist/esm/development/{shared-Dq2yW78d.js → shared-DcuVH8Pf.js} +5 -5
- package/dist/esm/development/{shared-Dq2yW78d.js.map → shared-DcuVH8Pf.js.map} +1 -1
- package/dist/esm/development/stores/async.js +6 -6
- package/dist/esm/development/stores/sync.js +5 -5
- package/dist/esm/development/topic/index.js +86 -0
- package/dist/esm/development/topic/index.js.map +1 -0
- package/dist/esm/index.d.ts +5 -4
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/mutation.d.ts +6 -19
- package/dist/esm/mutation.d.ts.map +1 -1
- package/dist/esm/production/{QueryClient-BP0Z1rQV.js → QueryClient-YqnBxFy1.js} +972 -968
- package/dist/esm/production/QueryClient-YqnBxFy1.js.map +1 -0
- package/dist/esm/production/QueryController-Ch_ncxiI.js +14 -0
- package/dist/esm/production/QueryController-Ch_ncxiI.js.map +1 -0
- package/dist/esm/production/index.js +29 -100
- package/dist/esm/production/index.js.map +1 -1
- package/dist/esm/production/mutation-pgFl1uIY.js +58 -0
- package/dist/esm/production/mutation-pgFl1uIY.js.map +1 -0
- package/dist/esm/production/react/index.js +1 -1
- package/dist/esm/production/rest/index.js +142 -0
- package/dist/esm/production/rest/index.js.map +1 -0
- package/dist/esm/production/{shared-Dq2yW78d.js → shared-DcuVH8Pf.js} +5 -5
- package/dist/esm/production/{shared-Dq2yW78d.js.map → shared-DcuVH8Pf.js.map} +1 -1
- package/dist/esm/production/stores/async.js +6 -6
- package/dist/esm/production/stores/sync.js +5 -5
- package/dist/esm/production/topic/index.js +86 -0
- package/dist/esm/production/topic/index.js.map +1 -0
- package/dist/esm/query-types.d.ts +2 -4
- package/dist/esm/query-types.d.ts.map +1 -1
- package/dist/esm/query.d.ts +17 -39
- package/dist/esm/query.d.ts.map +1 -1
- package/dist/esm/rest/RESTMutation.d.ts +18 -0
- package/dist/esm/rest/RESTMutation.d.ts.map +1 -0
- package/dist/esm/rest/RESTQuery.d.ts +24 -0
- package/dist/esm/rest/RESTQuery.d.ts.map +1 -0
- package/dist/esm/rest/RESTQueryController.d.ts +34 -0
- package/dist/esm/rest/RESTQueryController.d.ts.map +1 -0
- package/dist/esm/rest/index.d.ts +5 -0
- package/dist/esm/rest/index.d.ts.map +1 -0
- package/dist/esm/stores/shared.d.ts.map +1 -1
- package/dist/esm/testing/MockClient.d.ts +64 -0
- package/dist/esm/testing/MockClient.d.ts.map +1 -0
- package/dist/esm/testing/auto-generate.d.ts +20 -0
- package/dist/esm/testing/auto-generate.d.ts.map +1 -0
- package/dist/esm/testing/entity-factory.d.ts +13 -0
- package/dist/esm/testing/entity-factory.d.ts.map +1 -0
- package/dist/esm/testing/index.d.ts +6 -0
- package/dist/esm/testing/index.d.ts.map +1 -0
- package/dist/esm/testing/types.d.ts +37 -0
- package/dist/esm/testing/types.d.ts.map +1 -0
- package/dist/esm/topic/TopicQuery.d.ts +10 -0
- package/dist/esm/topic/TopicQuery.d.ts.map +1 -0
- package/dist/esm/topic/TopicQueryController.d.ts +43 -0
- package/dist/esm/topic/TopicQueryController.d.ts.map +1 -0
- package/dist/esm/topic/index.d.ts +3 -0
- package/dist/esm/topic/index.d.ts.map +1 -0
- package/dist/esm/typeDefs.d.ts +1 -1
- package/dist/esm/types.d.ts +9 -4
- package/dist/esm/types.d.ts.map +1 -1
- package/package.json +51 -4
- package/plugin/.claude-plugin/plugin.json +10 -0
- package/plugin/agents/fetchium.md +168 -0
- package/plugin/docs/api/fetchium-react.md +135 -0
- package/plugin/docs/api/fetchium.md +674 -0
- package/plugin/docs/api/stores-async.md +219 -0
- package/plugin/docs/api/stores-sync.md +133 -0
- package/plugin/docs/core/entities.md +351 -0
- package/plugin/docs/core/queries.md +600 -0
- package/plugin/docs/core/streaming.md +550 -0
- package/plugin/docs/core/types.md +374 -0
- package/plugin/docs/data/caching.md +298 -0
- package/plugin/docs/data/live-data.md +435 -0
- package/plugin/docs/data/mutations.md +465 -0
- package/plugin/docs/guides/auth.md +318 -0
- package/plugin/docs/guides/error-handling.md +351 -0
- package/plugin/docs/guides/offline.md +270 -0
- package/plugin/docs/guides/testing.md +301 -0
- package/plugin/docs/quickstart.md +170 -0
- package/plugin/docs/reference/pagination.md +519 -0
- package/plugin/docs/reference/rest-queries.md +107 -0
- package/plugin/docs/reference/why-signalium.md +364 -0
- package/plugin/docs/setup/project-setup.md +319 -0
- package/plugin/install.mjs +88 -0
- package/plugin/skills/design/SKILL.md +140 -0
- package/plugin/skills/teach/SKILL.md +105 -0
- package/dist/cjs/development/QueryClient-CpmwggOn.js +0 -2
- package/dist/cjs/development/QueryClient-CpmwggOn.js.map +0 -1
- package/dist/cjs/production/QueryClient-qi3bR0eD.js +0 -2
- package/dist/cjs/production/QueryClient-qi3bR0eD.js.map +0 -1
- package/dist/esm/development/QueryClient-DRZtPKFD.js +0 -2568
- package/dist/esm/development/QueryClient-DRZtPKFD.js.map +0 -1
- package/dist/esm/production/QueryClient-BP0Z1rQV.js.map +0 -1
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: fetchium/stores/async
|
|
3
|
+
description: API reference for the asynchronous query store.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# fetchium/stores/async
|
|
7
|
+
|
|
8
|
+
Asynchronous query store implementation for Fetchium. Designed for multi-threaded or cross-context architectures (e.g., Web Workers, Service Workers, React Native bridge) where storage operations must be serialized through a message channel.
|
|
9
|
+
|
|
10
|
+
```ts
|
|
11
|
+
import { AsyncQueryStore } from 'fetchium/stores/async';
|
|
12
|
+
import type {
|
|
13
|
+
AsyncQueryStoreConfig,
|
|
14
|
+
AsyncPersistentStore,
|
|
15
|
+
StoreMessage,
|
|
16
|
+
} from 'fetchium/stores/async';
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## Classes
|
|
22
|
+
|
|
23
|
+
### `AsyncQueryStore`
|
|
24
|
+
|
|
25
|
+
Implements the `QueryStore` interface with an asynchronous message-passing architecture. Operates in one of two modes:
|
|
26
|
+
|
|
27
|
+
- **Writer mode** (`isWriter: true`): Receives messages from readers and processes them serially against an `AsyncPersistentStore` delegate. Must be provided a `delegate`.
|
|
28
|
+
- **Reader mode** (`isWriter: false`): Sends all write operations as messages to the writer via the `sendMessage` channel. Does not perform storage operations directly.
|
|
29
|
+
|
|
30
|
+
Both modes share the same `QueryStore` interface so they can be used interchangeably with `QueryClient`.
|
|
31
|
+
|
|
32
|
+
#### Constructor
|
|
33
|
+
|
|
34
|
+
```ts
|
|
35
|
+
new AsyncQueryStore(config: AsyncQueryStoreConfig)
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
| Parameter | Type | Description |
|
|
39
|
+
| --------- | ----------------------- | ------------------------------------------- |
|
|
40
|
+
| `config` | `AsyncQueryStoreConfig` | Configuration object (see interface below). |
|
|
41
|
+
|
|
42
|
+
#### Methods
|
|
43
|
+
|
|
44
|
+
| Method | Signature | Description |
|
|
45
|
+
| ------------------- | -------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
46
|
+
| `loadQuery` | `(queryDef: QueryDefinition, queryKey: number): Promise<CachedQuery \| undefined>` | Loads a cached query. Only works when a `delegate` is available (writer mode). Returns `undefined` if no delegate, if the entry has expired, or if it does not exist. Preloads referenced entities. |
|
|
47
|
+
| `saveQuery` | `(queryDef: QueryDefinition, queryKey: number, value: unknown, updatedAt: number, refIds?: Set<number>): void` | Dispatches a save-query message. In writer mode, enqueues for serial processing. In reader mode, sends via `sendMessage`. |
|
|
48
|
+
| `saveEntity` | `(entityKey: number, value: unknown, refIds?: Set<number>): void` | Dispatches a save-entity message. |
|
|
49
|
+
| `activateQuery` | `(queryDef: QueryDefinition, queryKey: number): void` | Dispatches an activate-query message to update the LRU queue. |
|
|
50
|
+
| `deleteQuery` | `(queryKey: number): void` | Dispatches a delete-query message. |
|
|
51
|
+
| `purgeStaleQueries` | `(): Promise<void>` | Scans all stored query classes and removes expired entries. Only operates when a `delegate` is available. |
|
|
52
|
+
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
## Interfaces
|
|
56
|
+
|
|
57
|
+
### `AsyncQueryStoreConfig`
|
|
58
|
+
|
|
59
|
+
Configuration for constructing an `AsyncQueryStore`.
|
|
60
|
+
|
|
61
|
+
```ts
|
|
62
|
+
interface AsyncQueryStoreConfig {
|
|
63
|
+
isWriter: boolean;
|
|
64
|
+
connect: (handleMessage: (msg: StoreMessage) => void) => {
|
|
65
|
+
sendMessage: (msg: StoreMessage) => void;
|
|
66
|
+
};
|
|
67
|
+
delegate?: AsyncPersistentStore;
|
|
68
|
+
}
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
| Property | Type | Description |
|
|
72
|
+
| ---------- | ---------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
73
|
+
| `isWriter` | `boolean` | Whether this instance is the writer (processes storage operations) or a reader (sends messages to the writer). |
|
|
74
|
+
| `connect` | `(handleMessage: (msg: StoreMessage) => void) => { sendMessage: (msg: StoreMessage) => void }` | Called during construction. Receives a `handleMessage` callback for incoming messages and must return an object with a `sendMessage` function for outgoing messages. This is the bidirectional message channel. |
|
|
75
|
+
| `delegate` | `AsyncPersistentStore \| undefined` | The async persistent storage backend. **Required for writers**, not used by readers. |
|
|
76
|
+
|
|
77
|
+
---
|
|
78
|
+
|
|
79
|
+
### `AsyncPersistentStore`
|
|
80
|
+
|
|
81
|
+
The interface for asynchronous key-value storage backends. All methods return Promises. Implement this to plug in async storage (e.g., IndexedDB, AsyncStorage, SQLite with async bridge).
|
|
82
|
+
|
|
83
|
+
```ts
|
|
84
|
+
interface AsyncPersistentStore {
|
|
85
|
+
has(key: string): Promise<boolean>;
|
|
86
|
+
|
|
87
|
+
getString(key: string): Promise<string | undefined>;
|
|
88
|
+
setString(key: string, value: string): Promise<void>;
|
|
89
|
+
|
|
90
|
+
getNumber(key: string): Promise<number | undefined>;
|
|
91
|
+
setNumber(key: string, value: number): Promise<void>;
|
|
92
|
+
|
|
93
|
+
getBuffer(key: string): Promise<Uint32Array | undefined>;
|
|
94
|
+
setBuffer(key: string, value: Uint32Array): Promise<void>;
|
|
95
|
+
|
|
96
|
+
delete(key: string): Promise<void>;
|
|
97
|
+
|
|
98
|
+
getAllKeys(): Promise<string[]>;
|
|
99
|
+
}
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
| Method | Signature | Description |
|
|
103
|
+
| ------------ | -------------------------------------------------- | ---------------------------------------------- |
|
|
104
|
+
| `has` | `(key: string): Promise<boolean>` | Returns `true` if the key exists in the store. |
|
|
105
|
+
| `getString` | `(key: string): Promise<string \| undefined>` | Retrieves a string value by key. |
|
|
106
|
+
| `setString` | `(key: string, value: string): Promise<void>` | Stores a string value. |
|
|
107
|
+
| `getNumber` | `(key: string): Promise<number \| undefined>` | Retrieves a numeric value by key. |
|
|
108
|
+
| `setNumber` | `(key: string, value: number): Promise<void>` | Stores a numeric value. |
|
|
109
|
+
| `getBuffer` | `(key: string): Promise<Uint32Array \| undefined>` | Retrieves a `Uint32Array` buffer by key. |
|
|
110
|
+
| `setBuffer` | `(key: string, value: Uint32Array): Promise<void>` | Stores a `Uint32Array` buffer. |
|
|
111
|
+
| `delete` | `(key: string): Promise<void>` | Deletes a key and its associated value. |
|
|
112
|
+
| `getAllKeys` | `(): Promise<string[]>` | Returns all keys in the store. |
|
|
113
|
+
|
|
114
|
+
---
|
|
115
|
+
|
|
116
|
+
### `StoreMessage`
|
|
117
|
+
|
|
118
|
+
The message types sent between reader and writer instances. This is a discriminated union on the `type` field.
|
|
119
|
+
|
|
120
|
+
```ts
|
|
121
|
+
type StoreMessage =
|
|
122
|
+
| {
|
|
123
|
+
type: 0; // SaveQuery
|
|
124
|
+
queryDefId: string;
|
|
125
|
+
queryKey: number;
|
|
126
|
+
value: unknown;
|
|
127
|
+
updatedAt: number;
|
|
128
|
+
cacheTime: number;
|
|
129
|
+
refIds?: number[];
|
|
130
|
+
}
|
|
131
|
+
| {
|
|
132
|
+
type: 1; // SaveEntity
|
|
133
|
+
entityKey: number;
|
|
134
|
+
value: unknown;
|
|
135
|
+
refIds?: number[];
|
|
136
|
+
}
|
|
137
|
+
| {
|
|
138
|
+
type: 2; // ActivateQuery
|
|
139
|
+
queryDefId: string;
|
|
140
|
+
queryKey: number;
|
|
141
|
+
cacheTime: number;
|
|
142
|
+
}
|
|
143
|
+
| {
|
|
144
|
+
type: 3; // DeleteQuery
|
|
145
|
+
queryKey: number;
|
|
146
|
+
};
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
| Type value | Name | Description |
|
|
150
|
+
| ---------- | --------------- | --------------------------------------------------------------- |
|
|
151
|
+
| `0` | `SaveQuery` | Persist a query result with its metadata and entity references. |
|
|
152
|
+
| `1` | `SaveEntity` | Persist an entity's data and child references. |
|
|
153
|
+
| `2` | `ActivateQuery` | Move a query to the front of the LRU queue. |
|
|
154
|
+
| `3` | `DeleteQuery` | Delete a query and decrement its entity reference counts. |
|
|
155
|
+
|
|
156
|
+
---
|
|
157
|
+
|
|
158
|
+
## Architecture
|
|
159
|
+
|
|
160
|
+
```
|
|
161
|
+
┌─────────────────┐ messages ┌─────────────────────┐
|
|
162
|
+
│ Main Thread │ ───────────────────────> │ Worker Thread │
|
|
163
|
+
│ (Reader) │ │ (Writer) │
|
|
164
|
+
│ │ <─────────────────────── │ │
|
|
165
|
+
│ AsyncQueryStore │ sendMessage │ AsyncQueryStore │
|
|
166
|
+
│ isWriter=false │ │ isWriter=true │
|
|
167
|
+
│ │ │ delegate=IndexedDB │
|
|
168
|
+
└─────────────────┘ └─────────────────────┘
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
- The **reader** (main thread) calls `saveQuery`, `saveEntity`, etc. These are serialized as `StoreMessage` objects and sent to the writer via `sendMessage`.
|
|
172
|
+
- The **writer** (worker thread) receives messages and processes them serially against the `AsyncPersistentStore` delegate. Serial processing prevents race conditions.
|
|
173
|
+
- `loadQuery` reads directly from the delegate (only available on the writer). For reader-side cache loading, load from the writer during initialization.
|
|
174
|
+
|
|
175
|
+
---
|
|
176
|
+
|
|
177
|
+
## Example: Web Worker setup
|
|
178
|
+
|
|
179
|
+
**Main thread (reader):**
|
|
180
|
+
|
|
181
|
+
```ts
|
|
182
|
+
import { QueryClient } from 'fetchium';
|
|
183
|
+
import { AsyncQueryStore } from 'fetchium/stores/async';
|
|
184
|
+
|
|
185
|
+
const worker = new Worker('./store-worker.js');
|
|
186
|
+
|
|
187
|
+
const store = new AsyncQueryStore({
|
|
188
|
+
isWriter: false,
|
|
189
|
+
connect(handleMessage) {
|
|
190
|
+
worker.onmessage = (e) => handleMessage(e.data);
|
|
191
|
+
return {
|
|
192
|
+
sendMessage: (msg) => worker.postMessage(msg),
|
|
193
|
+
};
|
|
194
|
+
},
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
const client = new QueryClient(store, {
|
|
198
|
+
fetch: globalThis.fetch,
|
|
199
|
+
baseUrl: 'https://api.example.com',
|
|
200
|
+
});
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
**Worker thread (writer):**
|
|
204
|
+
|
|
205
|
+
```ts
|
|
206
|
+
import { AsyncQueryStore } from 'fetchium/stores/async';
|
|
207
|
+
import { MyIndexedDBStore } from './my-indexeddb-store';
|
|
208
|
+
|
|
209
|
+
const store = new AsyncQueryStore({
|
|
210
|
+
isWriter: true,
|
|
211
|
+
delegate: new MyIndexedDBStore(),
|
|
212
|
+
connect(handleMessage) {
|
|
213
|
+
self.onmessage = (e) => handleMessage(e.data);
|
|
214
|
+
return {
|
|
215
|
+
sendMessage: (msg) => self.postMessage(msg),
|
|
216
|
+
};
|
|
217
|
+
},
|
|
218
|
+
});
|
|
219
|
+
```
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: fetchium/stores/sync
|
|
3
|
+
description: API reference for the synchronous query store.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# fetchium/stores/sync
|
|
7
|
+
|
|
8
|
+
Synchronous query store implementation for Fetchium. Provides in-memory and pluggable persistent storage with LRU cache eviction and reference-counted entity cleanup.
|
|
9
|
+
|
|
10
|
+
```ts
|
|
11
|
+
import { SyncQueryStore, MemoryPersistentStore } from 'fetchium/stores/sync';
|
|
12
|
+
import type { SyncPersistentStore } from 'fetchium/stores/sync';
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## Classes
|
|
18
|
+
|
|
19
|
+
### `SyncQueryStore`
|
|
20
|
+
|
|
21
|
+
Implements the `QueryStore` interface using a synchronous key-value backend. Manages an LRU queue per query class and automatically evicts the oldest entries when the queue exceeds `maxCount`. Entity data is reference-counted; entities are cascade-deleted when their reference count reaches zero.
|
|
22
|
+
|
|
23
|
+
#### Constructor
|
|
24
|
+
|
|
25
|
+
```ts
|
|
26
|
+
new SyncQueryStore(kv: SyncPersistentStore)
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
| Parameter | Type | Description |
|
|
30
|
+
| --------- | --------------------- | ------------------------------------------- |
|
|
31
|
+
| `kv` | `SyncPersistentStore` | The underlying synchronous key-value store. |
|
|
32
|
+
|
|
33
|
+
#### Methods
|
|
34
|
+
|
|
35
|
+
| Method | Signature | Description |
|
|
36
|
+
| ------------------- | -------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
37
|
+
| `loadQuery` | `(queryDef: QueryDefinition, queryKey: number): CachedQuery \| undefined` | Loads a cached query by key. Returns `undefined` if the cache entry has expired (beyond `cacheTime`) or does not exist. Also preloads referenced entities. |
|
|
38
|
+
| `saveQuery` | `(queryDef: QueryDefinition, queryKey: number, value: unknown, updatedAt: number, refIds?: Set<number>): void` | Persists a query result, its timestamp, and entity reference IDs. Activates the query in the LRU queue. |
|
|
39
|
+
| `saveEntity` | `(entityKey: number, value: unknown, refIds?: Set<number>): void` | Persists an entity's serialized data and its child entity references. Manages reference counts for nested entities. |
|
|
40
|
+
| `activateQuery` | `(queryDef: QueryDefinition, queryKey: number): void` | Moves a query to the front of the LRU queue for its query class. If the queue is full, the oldest entry is evicted. |
|
|
41
|
+
| `deleteQuery` | `(queryKey: number): void` | Deletes a query's stored value, reference IDs, and decrements reference counts for all referenced entities. |
|
|
42
|
+
| `purgeStaleQueries` | `(): void` | Scans all query classes and removes those whose `lastUsedAt` timestamp exceeds their `cacheTime`. Called automatically on `QueryClient` construction. |
|
|
43
|
+
|
|
44
|
+
---
|
|
45
|
+
|
|
46
|
+
### `MemoryPersistentStore`
|
|
47
|
+
|
|
48
|
+
In-memory implementation of `SyncPersistentStore`. Stores all data in a plain JavaScript object. Suitable for development, testing, and applications that do not need persistence across sessions.
|
|
49
|
+
|
|
50
|
+
#### Constructor
|
|
51
|
+
|
|
52
|
+
```ts
|
|
53
|
+
new MemoryPersistentStore();
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
No parameters. Creates an empty store.
|
|
57
|
+
|
|
58
|
+
#### Methods
|
|
59
|
+
|
|
60
|
+
Implements all methods of `SyncPersistentStore` (see interface below).
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
|
|
64
|
+
## Interfaces
|
|
65
|
+
|
|
66
|
+
### `SyncPersistentStore`
|
|
67
|
+
|
|
68
|
+
The interface for synchronous key-value storage backends. Implement this to plug in custom storage (e.g., `localStorage`, synchronous SQLite, shared memory).
|
|
69
|
+
|
|
70
|
+
```ts
|
|
71
|
+
interface SyncPersistentStore {
|
|
72
|
+
has(key: string): boolean;
|
|
73
|
+
|
|
74
|
+
getString(key: string): string | undefined;
|
|
75
|
+
setString(key: string, value: string): void;
|
|
76
|
+
|
|
77
|
+
getNumber(key: string): number | undefined;
|
|
78
|
+
setNumber(key: string, value: number): void;
|
|
79
|
+
|
|
80
|
+
getBuffer(key: string): Uint32Array | undefined;
|
|
81
|
+
setBuffer(key: string, value: Uint32Array): void;
|
|
82
|
+
|
|
83
|
+
delete(key: string): void;
|
|
84
|
+
|
|
85
|
+
getAllKeys(): string[];
|
|
86
|
+
}
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
| Method | Signature | Description |
|
|
90
|
+
| ------------ | ----------------------------------------- | ------------------------------------------------------------------------------------------- |
|
|
91
|
+
| `has` | `(key: string): boolean` | Returns `true` if the key exists in the store. |
|
|
92
|
+
| `getString` | `(key: string): string \| undefined` | Retrieves a string value by key. |
|
|
93
|
+
| `setString` | `(key: string, value: string): void` | Stores a string value. |
|
|
94
|
+
| `getNumber` | `(key: string): number \| undefined` | Retrieves a numeric value by key. |
|
|
95
|
+
| `setNumber` | `(key: string, value: number): void` | Stores a numeric value. |
|
|
96
|
+
| `getBuffer` | `(key: string): Uint32Array \| undefined` | Retrieves a `Uint32Array` buffer by key. Used for LRU queues and entity reference ID lists. |
|
|
97
|
+
| `setBuffer` | `(key: string, value: Uint32Array): void` | Stores a `Uint32Array` buffer. |
|
|
98
|
+
| `delete` | `(key: string): void` | Deletes a key and its associated value. |
|
|
99
|
+
| `getAllKeys` | `(): string[]` | Returns all keys in the store. Used by `purgeStaleQueries` to scan for expired entries. |
|
|
100
|
+
|
|
101
|
+
---
|
|
102
|
+
|
|
103
|
+
## Storage key layout
|
|
104
|
+
|
|
105
|
+
Internally, `SyncQueryStore` uses the following key prefixes in the underlying `SyncPersistentStore`:
|
|
106
|
+
|
|
107
|
+
| Prefix / Pattern | Value type | Description |
|
|
108
|
+
| ----------------- | ------------- | --------------------------------------------------- |
|
|
109
|
+
| `v:{id}` | `string` | JSON-serialized value for a query or entity. |
|
|
110
|
+
| `u:{id}` | `number` | `updatedAt` timestamp (ms since epoch) for a query. |
|
|
111
|
+
| `r:{id}` | `Uint32Array` | Entity reference IDs for a query or entity. |
|
|
112
|
+
| `rc:{id}` | `number` | Reference count for an entity. |
|
|
113
|
+
| `q:{queryDefId}` | `Uint32Array` | LRU queue buffer for a query class. |
|
|
114
|
+
| `lu:{queryDefId}` | `number` | Last-used timestamp for a query class. |
|
|
115
|
+
| `ct:{queryDefId}` | `number` | Cache time (minutes) for a query class. |
|
|
116
|
+
|
|
117
|
+
---
|
|
118
|
+
|
|
119
|
+
## Example
|
|
120
|
+
|
|
121
|
+
```ts
|
|
122
|
+
import { QueryClient } from 'fetchium';
|
|
123
|
+
import { SyncQueryStore, MemoryPersistentStore } from 'fetchium/stores/sync';
|
|
124
|
+
|
|
125
|
+
// Create an in-memory store
|
|
126
|
+
const store = new SyncQueryStore(new MemoryPersistentStore());
|
|
127
|
+
|
|
128
|
+
// Create the query client
|
|
129
|
+
const client = new QueryClient(store, {
|
|
130
|
+
fetch: globalThis.fetch,
|
|
131
|
+
baseUrl: 'https://api.example.com',
|
|
132
|
+
});
|
|
133
|
+
```
|