qortex-core 0.1.3 → 0.1.4
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/README.md +14 -1
- package/index.d.ts +29 -10
- package/index.js +53 -55
- package/index.mjs +53 -55
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
[](https://badge.fury.io/js/qortex-core)
|
|
6
6
|
[](https://bundlephobia.com/package/qortex-core)
|
|
7
|
+
[](https://bundlephobia.com/package/qortex-core)
|
|
7
8
|
[](https://www.typescriptlang.org/)
|
|
8
9
|
|
|
9
10
|
## ✨ What makes this special?
|
|
@@ -92,6 +93,7 @@ function useAuth() {
|
|
|
92
93
|
|
|
93
94
|
queryManager.subscribeQuery(["auth", "user"], (state) => {
|
|
94
95
|
user.value = state.data;
|
|
96
|
+
console.log("Auth state:", state.isSuccess, state.isLoading);
|
|
95
97
|
});
|
|
96
98
|
|
|
97
99
|
return { user, isAuthenticated };
|
|
@@ -159,12 +161,23 @@ const { data, isLoading, error, refetch } = useQuery(["todos"]);
|
|
|
159
161
|
const todos = useQueryData(["todos"]);
|
|
160
162
|
```
|
|
161
163
|
|
|
162
|
-
### `queryManager.subscribeQuery(key, callback)`
|
|
164
|
+
### `queryManager.subscribeQuery(key, callback, options?)`
|
|
165
|
+
|
|
166
|
+
Subscribe to query state changes with flexible callback signatures.
|
|
163
167
|
|
|
164
168
|
```ts
|
|
169
|
+
// Callback receives the current state
|
|
165
170
|
const unsubscribe = queryManager.subscribeQuery(["todos"], (state) => {
|
|
166
171
|
console.log("State changed:", state);
|
|
172
|
+
console.log("Data:", state.data);
|
|
173
|
+
console.log("Loading:", state.isLoading);
|
|
174
|
+
console.log("Success:", state.isSuccess);
|
|
167
175
|
});
|
|
176
|
+
|
|
177
|
+
// With fetcher for automatic type inference
|
|
178
|
+
const unsubscribe = queryManager.subscribeQuery(["todos"], (state) => {
|
|
179
|
+
console.log("Todos:", state.data); // Automatically typed
|
|
180
|
+
}, { fetcher: fetchTodos });
|
|
168
181
|
```
|
|
169
182
|
|
|
170
183
|
### `queryManager.setDefaultConfig(config)`
|
package/index.d.ts
CHANGED
|
@@ -10,15 +10,24 @@ type Fetcher<T = any> = () => Promise<T> | T;
|
|
|
10
10
|
/** Function that compares two values for equality */
|
|
11
11
|
type EqualityFn<T = any> = (a: T | undefined, b: T | undefined) => boolean;
|
|
12
12
|
/**
|
|
13
|
-
* Infers the
|
|
14
|
-
*
|
|
13
|
+
* Infers the return type of a fetcher function
|
|
14
|
+
*
|
|
15
|
+
* This utility type extracts the return type from a fetcher function,
|
|
16
|
+
* handling both synchronous and asynchronous fetchers.
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* ```typescript
|
|
20
|
+
* const fetchUser = async (id: string): Promise<User> => { ... };
|
|
21
|
+
* type UserType = InferFetcherResult<typeof fetchUser>; // Promise<User>
|
|
22
|
+
*
|
|
23
|
+
* const fetchConfig = (): Config => { ... };
|
|
24
|
+
* type ConfigType = InferFetcherResult<typeof fetchConfig>; // Config
|
|
25
|
+
* ```
|
|
26
|
+
*
|
|
27
|
+
* @template F - The fetcher function type
|
|
28
|
+
* @returns The inferred return type of the fetcher, or `any` if inference fails
|
|
15
29
|
*/
|
|
16
|
-
type InferFetcherResult<F> = F extends
|
|
17
|
-
/**
|
|
18
|
-
* Infers the return type of a fetcher, handling both sync and async cases
|
|
19
|
-
* Falls back to any for user-friendly experience
|
|
20
|
-
*/
|
|
21
|
-
type InferFetcherReturnType<T> = T extends Fetcher<infer R> ? R : any;
|
|
30
|
+
type InferFetcherResult<F> = F extends Fetcher<infer R> ? R : any;
|
|
22
31
|
/**
|
|
23
32
|
* Query status types for better type safety
|
|
24
33
|
*/
|
|
@@ -120,12 +129,18 @@ declare class QueryManager {
|
|
|
120
129
|
* Handles mount logic to potentially start fetching
|
|
121
130
|
*/
|
|
122
131
|
getQueryData<T = any>(key: QueryKey, opts?: QueryOptions<T>): T | undefined;
|
|
132
|
+
getQueryData<F extends Fetcher>(key: QueryKey, opts: QueryOptions<InferFetcherResult<F>> & {
|
|
133
|
+
fetcher: F;
|
|
134
|
+
}): InferFetcherResult<F> | undefined;
|
|
123
135
|
/**
|
|
124
136
|
* Gets comprehensive query state including computed flags
|
|
125
137
|
* Handles placeholder data and error states appropriately
|
|
126
138
|
* Handles mount logic to potentially start fetching
|
|
127
139
|
*/
|
|
128
140
|
getQueryState<T = unknown>(key: QueryKey, opts?: QueryOptions<T>): QueryState<T>;
|
|
141
|
+
getQueryState<F extends Fetcher>(key: QueryKey, opts: QueryOptions<InferFetcherResult<F>> & {
|
|
142
|
+
fetcher: F;
|
|
143
|
+
}): QueryState<InferFetcherResult<F>>;
|
|
129
144
|
/**
|
|
130
145
|
* Marks a query as invalidated, triggering refetch
|
|
131
146
|
*/
|
|
@@ -134,7 +149,11 @@ declare class QueryManager {
|
|
|
134
149
|
* Subscribes to query state changes with automatic subscription management
|
|
135
150
|
* Handles mount logic to potentially start fetching
|
|
136
151
|
*/
|
|
137
|
-
subscribeQuery
|
|
152
|
+
subscribeQuery(key: QueryKey, cb: (state: QueryState<any>) => void): () => void;
|
|
153
|
+
subscribeQuery<F extends Fetcher>(key: QueryKey, cb: (state: QueryState<InferFetcherResult<F>>) => void, opts: QueryOptions<InferFetcherResult<F>> & {
|
|
154
|
+
fetcher: F;
|
|
155
|
+
}): () => void;
|
|
156
|
+
subscribeQuery<T = any>(key: QueryKey, cb: (state: QueryState<T>) => void, opts?: QueryOptions<T>): () => void;
|
|
138
157
|
/**
|
|
139
158
|
* Core mount logic that determines when to fetch
|
|
140
159
|
* Implements robust throttling and race condition prevention
|
|
@@ -149,4 +168,4 @@ declare const queryManager: QueryManager;
|
|
|
149
168
|
*/
|
|
150
169
|
declare function serializeKey(key: QueryKey): string;
|
|
151
170
|
|
|
152
|
-
export { DefaultConfig, EqualityFn, Fetcher, InferFetcherResult,
|
|
171
|
+
export { DefaultConfig, EqualityFn, Fetcher, InferFetcherResult, QueryKey, QueryKeyValue, QueryManager, QueryOptions, QueryState, QueryStatus, queryManager, serializeKey };
|
package/index.js
CHANGED
|
@@ -71,7 +71,47 @@ function createDefaultState(opts, refetch) {
|
|
|
71
71
|
usePlaceholderOnError: opts?.usePlaceholderOnError ?? false,
|
|
72
72
|
refetchOnSubscribe: opts?.refetchOnSubscribe ?? "stale",
|
|
73
73
|
enabled: opts?.enabled === false ? false : true,
|
|
74
|
-
refetch: refetch || (() => Promise.resolve(void 0))
|
|
74
|
+
refetch: refetch || (() => Promise.resolve(void 0)),
|
|
75
|
+
isSuccess: false,
|
|
76
|
+
isError: false
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
function createPublicState(state) {
|
|
80
|
+
const now = Date.now();
|
|
81
|
+
const isStale = state.updatedAt == null || now - (state.updatedAt || 0) > state.staleTime || state.isInvalidated;
|
|
82
|
+
let returnedData = state.data;
|
|
83
|
+
let isPlaceholderData = false;
|
|
84
|
+
switch (state.status) {
|
|
85
|
+
case "error":
|
|
86
|
+
if (state.usePlaceholderOnError && state.placeholderData !== void 0) {
|
|
87
|
+
returnedData = state.placeholderData;
|
|
88
|
+
isPlaceholderData = true;
|
|
89
|
+
}
|
|
90
|
+
break;
|
|
91
|
+
case "fetching":
|
|
92
|
+
if (!state.data && state.placeholderData) {
|
|
93
|
+
returnedData = state.placeholderData;
|
|
94
|
+
isPlaceholderData = true;
|
|
95
|
+
}
|
|
96
|
+
break;
|
|
97
|
+
case "success":
|
|
98
|
+
case "idle":
|
|
99
|
+
returnedData = state.data ?? state.placeholderData;
|
|
100
|
+
isPlaceholderData = state.data ? false : Boolean(state.placeholderData);
|
|
101
|
+
break;
|
|
102
|
+
}
|
|
103
|
+
return {
|
|
104
|
+
data: returnedData,
|
|
105
|
+
error: state.error,
|
|
106
|
+
status: state.status,
|
|
107
|
+
updatedAt: state.updatedAt,
|
|
108
|
+
isStale,
|
|
109
|
+
isPlaceholderData,
|
|
110
|
+
isLoading: state.status === "fetching" && !state.updatedAt,
|
|
111
|
+
isFetching: state.status === "fetching",
|
|
112
|
+
isError: state.isError,
|
|
113
|
+
isSuccess: state.isSuccess,
|
|
114
|
+
refetch: state.refetch
|
|
75
115
|
};
|
|
76
116
|
}
|
|
77
117
|
|
|
@@ -115,12 +155,14 @@ var QueryManager = class {
|
|
|
115
155
|
* Notifies all subscribers of a query state change
|
|
116
156
|
*/
|
|
117
157
|
emit(key, state) {
|
|
118
|
-
|
|
119
|
-
|
|
158
|
+
const stateKey = serializeKey(key);
|
|
159
|
+
this.cache.set(stateKey, state);
|
|
160
|
+
const set = this.subs.get(stateKey);
|
|
120
161
|
if (!set)
|
|
121
162
|
return;
|
|
163
|
+
const publicState = createPublicState(state);
|
|
122
164
|
for (const cb of Array.from(set))
|
|
123
|
-
cb();
|
|
165
|
+
cb(publicState);
|
|
124
166
|
}
|
|
125
167
|
registerFetcher(key, opts) {
|
|
126
168
|
this.ensureState(key, opts);
|
|
@@ -151,9 +193,13 @@ var QueryManager = class {
|
|
|
151
193
|
state.data = result2;
|
|
152
194
|
state.status = "success";
|
|
153
195
|
state.updatedAt = Date.now();
|
|
196
|
+
state.isError = false;
|
|
197
|
+
state.isSuccess = true;
|
|
154
198
|
}).catch((error) => {
|
|
155
199
|
state.error = error;
|
|
156
200
|
state.status = "error";
|
|
201
|
+
state.isError = true;
|
|
202
|
+
state.isSuccess = false;
|
|
157
203
|
}).finally(() => {
|
|
158
204
|
state.fetchPromise = void 0;
|
|
159
205
|
this.emit(key, state);
|
|
@@ -174,63 +220,19 @@ var QueryManager = class {
|
|
|
174
220
|
state.error = void 0;
|
|
175
221
|
state.status = "success";
|
|
176
222
|
state.isInvalidated = false;
|
|
223
|
+
state.isError = false;
|
|
224
|
+
state.isSuccess = true;
|
|
177
225
|
this.emit(key, state);
|
|
178
226
|
}
|
|
179
|
-
/**
|
|
180
|
-
* Gets query data
|
|
181
|
-
* Handles mount logic to potentially start fetching
|
|
182
|
-
*/
|
|
183
227
|
getQueryData(key, opts) {
|
|
184
228
|
const state = this.ensureState(key, opts);
|
|
185
229
|
this.handleMountLogic(key, state);
|
|
186
230
|
return state.data ?? state.placeholderData;
|
|
187
231
|
}
|
|
188
|
-
/**
|
|
189
|
-
* Gets comprehensive query state including computed flags
|
|
190
|
-
* Handles placeholder data and error states appropriately
|
|
191
|
-
* Handles mount logic to potentially start fetching
|
|
192
|
-
*/
|
|
193
232
|
getQueryState(key, opts) {
|
|
194
233
|
let state = this.ensureState(key, opts);
|
|
195
|
-
const now = Date.now();
|
|
196
|
-
const isStale = state.updatedAt == null || now - (state.updatedAt || 0) > state.staleTime || state.isInvalidated;
|
|
197
|
-
let returnedData = state.data;
|
|
198
|
-
let isPlaceholderData = false;
|
|
199
|
-
const status = state.status;
|
|
200
|
-
switch (status) {
|
|
201
|
-
case "error":
|
|
202
|
-
if (state.usePlaceholderOnError && state.placeholderData !== void 0) {
|
|
203
|
-
returnedData = state.placeholderData;
|
|
204
|
-
isPlaceholderData = true;
|
|
205
|
-
}
|
|
206
|
-
break;
|
|
207
|
-
case "fetching":
|
|
208
|
-
if (!state.data && state.placeholderData) {
|
|
209
|
-
returnedData = state.placeholderData;
|
|
210
|
-
isPlaceholderData = true;
|
|
211
|
-
}
|
|
212
|
-
break;
|
|
213
|
-
case "success":
|
|
214
|
-
case "idle":
|
|
215
|
-
returnedData = state.data ?? state.placeholderData;
|
|
216
|
-
isPlaceholderData = state.data ? false : Boolean(state.placeholderData);
|
|
217
|
-
break;
|
|
218
|
-
}
|
|
219
234
|
this.handleMountLogic(key, state);
|
|
220
|
-
const currentState =
|
|
221
|
-
data: returnedData,
|
|
222
|
-
error: state.error,
|
|
223
|
-
status: state.status,
|
|
224
|
-
updatedAt: state.updatedAt,
|
|
225
|
-
isStale,
|
|
226
|
-
isPlaceholderData,
|
|
227
|
-
isLoading: state.status === "fetching" && !state.updatedAt,
|
|
228
|
-
// true only for first fetch
|
|
229
|
-
isFetching: state.status === "fetching",
|
|
230
|
-
isError: state.status === "error",
|
|
231
|
-
isSuccess: state.status === "success",
|
|
232
|
-
refetch: state.refetch
|
|
233
|
-
};
|
|
235
|
+
const currentState = createPublicState(state);
|
|
234
236
|
const stateKey = serializeKey(key);
|
|
235
237
|
const lastState = this.lastReturnedState?.get(stateKey);
|
|
236
238
|
if (!lastState || !shallowEqual(lastState, currentState)) {
|
|
@@ -250,10 +252,6 @@ var QueryManager = class {
|
|
|
250
252
|
this.emit(key, state);
|
|
251
253
|
this.fetchQuery(key);
|
|
252
254
|
}
|
|
253
|
-
/**
|
|
254
|
-
* Subscribes to query state changes with automatic subscription management
|
|
255
|
-
* Handles mount logic to potentially start fetching
|
|
256
|
-
*/
|
|
257
255
|
subscribeQuery(key, cb, opts) {
|
|
258
256
|
const sk = serializeKey(key);
|
|
259
257
|
const state = this.ensureState(key, opts);
|
package/index.mjs
CHANGED
|
@@ -43,7 +43,47 @@ function createDefaultState(opts, refetch) {
|
|
|
43
43
|
usePlaceholderOnError: opts?.usePlaceholderOnError ?? false,
|
|
44
44
|
refetchOnSubscribe: opts?.refetchOnSubscribe ?? "stale",
|
|
45
45
|
enabled: opts?.enabled === false ? false : true,
|
|
46
|
-
refetch: refetch || (() => Promise.resolve(void 0))
|
|
46
|
+
refetch: refetch || (() => Promise.resolve(void 0)),
|
|
47
|
+
isSuccess: false,
|
|
48
|
+
isError: false
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
function createPublicState(state) {
|
|
52
|
+
const now = Date.now();
|
|
53
|
+
const isStale = state.updatedAt == null || now - (state.updatedAt || 0) > state.staleTime || state.isInvalidated;
|
|
54
|
+
let returnedData = state.data;
|
|
55
|
+
let isPlaceholderData = false;
|
|
56
|
+
switch (state.status) {
|
|
57
|
+
case "error":
|
|
58
|
+
if (state.usePlaceholderOnError && state.placeholderData !== void 0) {
|
|
59
|
+
returnedData = state.placeholderData;
|
|
60
|
+
isPlaceholderData = true;
|
|
61
|
+
}
|
|
62
|
+
break;
|
|
63
|
+
case "fetching":
|
|
64
|
+
if (!state.data && state.placeholderData) {
|
|
65
|
+
returnedData = state.placeholderData;
|
|
66
|
+
isPlaceholderData = true;
|
|
67
|
+
}
|
|
68
|
+
break;
|
|
69
|
+
case "success":
|
|
70
|
+
case "idle":
|
|
71
|
+
returnedData = state.data ?? state.placeholderData;
|
|
72
|
+
isPlaceholderData = state.data ? false : Boolean(state.placeholderData);
|
|
73
|
+
break;
|
|
74
|
+
}
|
|
75
|
+
return {
|
|
76
|
+
data: returnedData,
|
|
77
|
+
error: state.error,
|
|
78
|
+
status: state.status,
|
|
79
|
+
updatedAt: state.updatedAt,
|
|
80
|
+
isStale,
|
|
81
|
+
isPlaceholderData,
|
|
82
|
+
isLoading: state.status === "fetching" && !state.updatedAt,
|
|
83
|
+
isFetching: state.status === "fetching",
|
|
84
|
+
isError: state.isError,
|
|
85
|
+
isSuccess: state.isSuccess,
|
|
86
|
+
refetch: state.refetch
|
|
47
87
|
};
|
|
48
88
|
}
|
|
49
89
|
|
|
@@ -87,12 +127,14 @@ var QueryManager = class {
|
|
|
87
127
|
* Notifies all subscribers of a query state change
|
|
88
128
|
*/
|
|
89
129
|
emit(key, state) {
|
|
90
|
-
|
|
91
|
-
|
|
130
|
+
const stateKey = serializeKey(key);
|
|
131
|
+
this.cache.set(stateKey, state);
|
|
132
|
+
const set = this.subs.get(stateKey);
|
|
92
133
|
if (!set)
|
|
93
134
|
return;
|
|
135
|
+
const publicState = createPublicState(state);
|
|
94
136
|
for (const cb of Array.from(set))
|
|
95
|
-
cb();
|
|
137
|
+
cb(publicState);
|
|
96
138
|
}
|
|
97
139
|
registerFetcher(key, opts) {
|
|
98
140
|
this.ensureState(key, opts);
|
|
@@ -123,9 +165,13 @@ var QueryManager = class {
|
|
|
123
165
|
state.data = result2;
|
|
124
166
|
state.status = "success";
|
|
125
167
|
state.updatedAt = Date.now();
|
|
168
|
+
state.isError = false;
|
|
169
|
+
state.isSuccess = true;
|
|
126
170
|
}).catch((error) => {
|
|
127
171
|
state.error = error;
|
|
128
172
|
state.status = "error";
|
|
173
|
+
state.isError = true;
|
|
174
|
+
state.isSuccess = false;
|
|
129
175
|
}).finally(() => {
|
|
130
176
|
state.fetchPromise = void 0;
|
|
131
177
|
this.emit(key, state);
|
|
@@ -146,63 +192,19 @@ var QueryManager = class {
|
|
|
146
192
|
state.error = void 0;
|
|
147
193
|
state.status = "success";
|
|
148
194
|
state.isInvalidated = false;
|
|
195
|
+
state.isError = false;
|
|
196
|
+
state.isSuccess = true;
|
|
149
197
|
this.emit(key, state);
|
|
150
198
|
}
|
|
151
|
-
/**
|
|
152
|
-
* Gets query data
|
|
153
|
-
* Handles mount logic to potentially start fetching
|
|
154
|
-
*/
|
|
155
199
|
getQueryData(key, opts) {
|
|
156
200
|
const state = this.ensureState(key, opts);
|
|
157
201
|
this.handleMountLogic(key, state);
|
|
158
202
|
return state.data ?? state.placeholderData;
|
|
159
203
|
}
|
|
160
|
-
/**
|
|
161
|
-
* Gets comprehensive query state including computed flags
|
|
162
|
-
* Handles placeholder data and error states appropriately
|
|
163
|
-
* Handles mount logic to potentially start fetching
|
|
164
|
-
*/
|
|
165
204
|
getQueryState(key, opts) {
|
|
166
205
|
let state = this.ensureState(key, opts);
|
|
167
|
-
const now = Date.now();
|
|
168
|
-
const isStale = state.updatedAt == null || now - (state.updatedAt || 0) > state.staleTime || state.isInvalidated;
|
|
169
|
-
let returnedData = state.data;
|
|
170
|
-
let isPlaceholderData = false;
|
|
171
|
-
const status = state.status;
|
|
172
|
-
switch (status) {
|
|
173
|
-
case "error":
|
|
174
|
-
if (state.usePlaceholderOnError && state.placeholderData !== void 0) {
|
|
175
|
-
returnedData = state.placeholderData;
|
|
176
|
-
isPlaceholderData = true;
|
|
177
|
-
}
|
|
178
|
-
break;
|
|
179
|
-
case "fetching":
|
|
180
|
-
if (!state.data && state.placeholderData) {
|
|
181
|
-
returnedData = state.placeholderData;
|
|
182
|
-
isPlaceholderData = true;
|
|
183
|
-
}
|
|
184
|
-
break;
|
|
185
|
-
case "success":
|
|
186
|
-
case "idle":
|
|
187
|
-
returnedData = state.data ?? state.placeholderData;
|
|
188
|
-
isPlaceholderData = state.data ? false : Boolean(state.placeholderData);
|
|
189
|
-
break;
|
|
190
|
-
}
|
|
191
206
|
this.handleMountLogic(key, state);
|
|
192
|
-
const currentState =
|
|
193
|
-
data: returnedData,
|
|
194
|
-
error: state.error,
|
|
195
|
-
status: state.status,
|
|
196
|
-
updatedAt: state.updatedAt,
|
|
197
|
-
isStale,
|
|
198
|
-
isPlaceholderData,
|
|
199
|
-
isLoading: state.status === "fetching" && !state.updatedAt,
|
|
200
|
-
// true only for first fetch
|
|
201
|
-
isFetching: state.status === "fetching",
|
|
202
|
-
isError: state.status === "error",
|
|
203
|
-
isSuccess: state.status === "success",
|
|
204
|
-
refetch: state.refetch
|
|
205
|
-
};
|
|
207
|
+
const currentState = createPublicState(state);
|
|
206
208
|
const stateKey = serializeKey(key);
|
|
207
209
|
const lastState = this.lastReturnedState?.get(stateKey);
|
|
208
210
|
if (!lastState || !shallowEqual(lastState, currentState)) {
|
|
@@ -222,10 +224,6 @@ var QueryManager = class {
|
|
|
222
224
|
this.emit(key, state);
|
|
223
225
|
this.fetchQuery(key);
|
|
224
226
|
}
|
|
225
|
-
/**
|
|
226
|
-
* Subscribes to query state changes with automatic subscription management
|
|
227
|
-
* Handles mount logic to potentially start fetching
|
|
228
|
-
*/
|
|
229
227
|
subscribeQuery(key, cb, opts) {
|
|
230
228
|
const sk = serializeKey(key);
|
|
231
229
|
const state = this.ensureState(key, opts);
|