@structyl/api-client 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +150 -0
- package/dist/devtools.cjs +181 -0
- package/dist/devtools.cjs.map +1 -0
- package/dist/devtools.d.cts +8 -0
- package/dist/devtools.d.ts +8 -0
- package/dist/devtools.mjs +179 -0
- package/dist/devtools.mjs.map +1 -0
- package/dist/index.cjs +905 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +48 -0
- package/dist/index.d.ts +48 -0
- package/dist/index.mjs +887 -0
- package/dist/index.mjs.map +1 -0
- package/dist/server-BdrIj1E3.d.cts +208 -0
- package/dist/server-BdrIj1E3.d.ts +208 -0
- package/dist/server.cjs +230 -0
- package/dist/server.cjs.map +1 -0
- package/dist/server.d.cts +2 -0
- package/dist/server.d.ts +2 -0
- package/dist/server.mjs +225 -0
- package/dist/server.mjs.map +1 -0
- package/package.json +72 -0
package/dist/server.cjs
ADDED
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// src/cache.ts
|
|
4
|
+
function serializeKey(key) {
|
|
5
|
+
return JSON.stringify(key);
|
|
6
|
+
}
|
|
7
|
+
var QueryCache = class {
|
|
8
|
+
constructor(gcTime = 5 * 6e4) {
|
|
9
|
+
this.entries = /* @__PURE__ */ new Map();
|
|
10
|
+
this.subscribers = /* @__PURE__ */ new Map();
|
|
11
|
+
this.inFlight = /* @__PURE__ */ new Map();
|
|
12
|
+
// Discards responses from requests that were superseded (e.g. after cancelQueries)
|
|
13
|
+
this.generations = /* @__PURE__ */ new Map();
|
|
14
|
+
// Evicts entries when no subscriber remains for longer than gcTime
|
|
15
|
+
this.gcTimers = /* @__PURE__ */ new Map();
|
|
16
|
+
// AbortControllers for in-flight requests
|
|
17
|
+
this.abortControllers = /* @__PURE__ */ new Map();
|
|
18
|
+
// Global subscribers (for persistence and devtools)
|
|
19
|
+
this.globalSubscribers = /* @__PURE__ */ new Set();
|
|
20
|
+
this.gcTime = gcTime;
|
|
21
|
+
}
|
|
22
|
+
get(key) {
|
|
23
|
+
return this.entries.get(key);
|
|
24
|
+
}
|
|
25
|
+
subscribe(key, fn) {
|
|
26
|
+
const pending = this.gcTimers.get(key);
|
|
27
|
+
if (pending !== void 0) {
|
|
28
|
+
clearTimeout(pending);
|
|
29
|
+
this.gcTimers.delete(key);
|
|
30
|
+
}
|
|
31
|
+
if (!this.subscribers.has(key)) this.subscribers.set(key, /* @__PURE__ */ new Set());
|
|
32
|
+
this.subscribers.get(key).add(fn);
|
|
33
|
+
return () => {
|
|
34
|
+
const set = this.subscribers.get(key);
|
|
35
|
+
if (!set) return;
|
|
36
|
+
set.delete(fn);
|
|
37
|
+
if (set.size === 0) {
|
|
38
|
+
this.subscribers.delete(key);
|
|
39
|
+
const timer = setTimeout(() => {
|
|
40
|
+
this.entries.delete(key);
|
|
41
|
+
this.generations.delete(key);
|
|
42
|
+
this.gcTimers.delete(key);
|
|
43
|
+
}, this.gcTime);
|
|
44
|
+
this.gcTimers.set(key, timer);
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
subscribeGlobal(fn) {
|
|
49
|
+
this.globalSubscribers.add(fn);
|
|
50
|
+
return () => this.globalSubscribers.delete(fn);
|
|
51
|
+
}
|
|
52
|
+
notify(key) {
|
|
53
|
+
this.subscribers.get(key)?.forEach((fn) => fn());
|
|
54
|
+
this.globalSubscribers.forEach((fn) => fn());
|
|
55
|
+
}
|
|
56
|
+
setData(key, data, staleTime) {
|
|
57
|
+
this.entries.set(key, {
|
|
58
|
+
data,
|
|
59
|
+
error: void 0,
|
|
60
|
+
status: "success",
|
|
61
|
+
updatedAt: Date.now(),
|
|
62
|
+
staleTime
|
|
63
|
+
});
|
|
64
|
+
this.inFlight.delete(key);
|
|
65
|
+
this.notify(key);
|
|
66
|
+
}
|
|
67
|
+
setError(key, error) {
|
|
68
|
+
const existing = this.entries.get(key);
|
|
69
|
+
this.entries.set(key, {
|
|
70
|
+
data: existing?.data,
|
|
71
|
+
error,
|
|
72
|
+
status: "error",
|
|
73
|
+
updatedAt: Date.now(),
|
|
74
|
+
staleTime: 0
|
|
75
|
+
});
|
|
76
|
+
this.inFlight.delete(key);
|
|
77
|
+
this.notify(key);
|
|
78
|
+
}
|
|
79
|
+
setLoading(key) {
|
|
80
|
+
const existing = this.entries.get(key);
|
|
81
|
+
if (existing?.status === "loading") return;
|
|
82
|
+
this.entries.set(key, {
|
|
83
|
+
data: existing?.data,
|
|
84
|
+
error: void 0,
|
|
85
|
+
status: "loading",
|
|
86
|
+
updatedAt: existing?.updatedAt ?? 0,
|
|
87
|
+
staleTime: existing?.staleTime ?? 0
|
|
88
|
+
});
|
|
89
|
+
this.notify(key);
|
|
90
|
+
}
|
|
91
|
+
isStale(key) {
|
|
92
|
+
const e = this.entries.get(key);
|
|
93
|
+
if (!e || e.status === "idle" || e.status === "error") return true;
|
|
94
|
+
if (e.status === "loading") return false;
|
|
95
|
+
return e.updatedAt === 0 || Date.now() - e.updatedAt > e.staleTime;
|
|
96
|
+
}
|
|
97
|
+
// True only when markStale() was explicitly called on a successful entry.
|
|
98
|
+
// Used to detect *external* invalidation (e.g. after a mutation) vs time-based
|
|
99
|
+
// staleness, so the re-fetch effect doesn't loop when staleTime is 0.
|
|
100
|
+
isExternallyInvalidated(key) {
|
|
101
|
+
const e = this.entries.get(key);
|
|
102
|
+
return !!e && e.status === "success" && e.updatedAt === 0;
|
|
103
|
+
}
|
|
104
|
+
getInFlight(key) {
|
|
105
|
+
return this.inFlight.get(key);
|
|
106
|
+
}
|
|
107
|
+
setInFlight(key, p) {
|
|
108
|
+
this.inFlight.set(key, p);
|
|
109
|
+
}
|
|
110
|
+
clearInFlight(key) {
|
|
111
|
+
this.inFlight.delete(key);
|
|
112
|
+
}
|
|
113
|
+
// Returns the new generation. Does NOT touch inFlight — call clearInFlight separately.
|
|
114
|
+
bumpGeneration(key) {
|
|
115
|
+
const g = (this.generations.get(key) ?? 0) + 1;
|
|
116
|
+
this.generations.set(key, g);
|
|
117
|
+
return g;
|
|
118
|
+
}
|
|
119
|
+
getGeneration(key) {
|
|
120
|
+
return this.generations.get(key) ?? 0;
|
|
121
|
+
}
|
|
122
|
+
// Sets updatedAt = 0 as the sentinel for "externally invalidated"
|
|
123
|
+
markStale(key) {
|
|
124
|
+
const e = this.entries.get(key);
|
|
125
|
+
if (e) {
|
|
126
|
+
this.entries.set(key, { ...e, updatedAt: 0 });
|
|
127
|
+
this.notify(key);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
// AbortController management
|
|
131
|
+
setAbortController(key, ctrl) {
|
|
132
|
+
this.abortControllers.set(key, ctrl);
|
|
133
|
+
}
|
|
134
|
+
getAbortController(key) {
|
|
135
|
+
return this.abortControllers.get(key);
|
|
136
|
+
}
|
|
137
|
+
clearAbortController(key) {
|
|
138
|
+
this.abortControllers.delete(key);
|
|
139
|
+
}
|
|
140
|
+
clear() {
|
|
141
|
+
for (const timer of this.gcTimers.values()) clearTimeout(timer);
|
|
142
|
+
this.gcTimers.clear();
|
|
143
|
+
for (const ctrl of this.abortControllers.values()) ctrl.abort();
|
|
144
|
+
this.abortControllers.clear();
|
|
145
|
+
this.entries.clear();
|
|
146
|
+
this.inFlight.clear();
|
|
147
|
+
this.generations.clear();
|
|
148
|
+
this.subscribers.clear();
|
|
149
|
+
}
|
|
150
|
+
snapshot() {
|
|
151
|
+
const result = {};
|
|
152
|
+
for (const [key, entry] of this.entries) {
|
|
153
|
+
if (entry.status === "success") result[key] = entry;
|
|
154
|
+
}
|
|
155
|
+
return result;
|
|
156
|
+
}
|
|
157
|
+
restore(state) {
|
|
158
|
+
for (const [key, entry] of Object.entries(state)) {
|
|
159
|
+
if (!this.entries.has(key)) this.entries.set(key, entry);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
};
|
|
163
|
+
var QueryClient = class {
|
|
164
|
+
constructor(config) {
|
|
165
|
+
this.config = config ?? {};
|
|
166
|
+
this.cache = new QueryCache(config?.gcTime);
|
|
167
|
+
}
|
|
168
|
+
getQueryData(key) {
|
|
169
|
+
return this.cache.get(serializeKey(key))?.data;
|
|
170
|
+
}
|
|
171
|
+
setQueryData(key, updater) {
|
|
172
|
+
const k = serializeKey(key);
|
|
173
|
+
const existing = this.cache.get(k);
|
|
174
|
+
const newData = typeof updater === "function" ? updater(existing?.data) : updater;
|
|
175
|
+
this.cache.setData(k, newData, existing?.staleTime ?? 6e4);
|
|
176
|
+
this.config.onSuccess?.(newData, k);
|
|
177
|
+
}
|
|
178
|
+
invalidateQueries(options) {
|
|
179
|
+
this.cache.markStale(serializeKey(options.queryKey));
|
|
180
|
+
}
|
|
181
|
+
async cancelQueries(options) {
|
|
182
|
+
const k = serializeKey(options.queryKey);
|
|
183
|
+
this.cache.getAbortController(k)?.abort();
|
|
184
|
+
this.cache.clearAbortController(k);
|
|
185
|
+
this.cache.bumpGeneration(k);
|
|
186
|
+
this.cache.clearInFlight(k);
|
|
187
|
+
this.cache.markStale(k);
|
|
188
|
+
}
|
|
189
|
+
async prefetchQuery(options) {
|
|
190
|
+
const k = serializeKey(options.queryKey);
|
|
191
|
+
if (!this.cache.isStale(k)) return;
|
|
192
|
+
try {
|
|
193
|
+
const data = await options.queryFn();
|
|
194
|
+
this.cache.setData(k, data, options.staleTime ?? 6e4);
|
|
195
|
+
this.config.onSuccess?.(data, k);
|
|
196
|
+
} catch {
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
// Called internally after setData / setError to fire global callbacks
|
|
200
|
+
notifySuccess(data, key) {
|
|
201
|
+
this.config.onSuccess?.(data, key);
|
|
202
|
+
}
|
|
203
|
+
notifyError(error, key) {
|
|
204
|
+
this.config.onError?.(error, key);
|
|
205
|
+
}
|
|
206
|
+
};
|
|
207
|
+
|
|
208
|
+
// src/server.ts
|
|
209
|
+
function dehydrate(queryClient) {
|
|
210
|
+
return { entries: queryClient.cache.snapshot() };
|
|
211
|
+
}
|
|
212
|
+
function hydrate(queryClient, state) {
|
|
213
|
+
queryClient.cache.restore(state.entries);
|
|
214
|
+
}
|
|
215
|
+
async function prefetchApiQuery(queryClient, apiClient, keyOrUrl, urlOrFn, options) {
|
|
216
|
+
const queryKey = typeof keyOrUrl === "string" ? [keyOrUrl] : keyOrUrl;
|
|
217
|
+
const queryFn = typeof urlOrFn === "function" ? () => urlOrFn(apiClient.instance) : typeof urlOrFn === "string" ? () => apiClient.instance.get(urlOrFn).then((r) => r.data) : () => apiClient.instance.get(keyOrUrl).then((r) => r.data);
|
|
218
|
+
await queryClient.prefetchQuery({
|
|
219
|
+
queryKey,
|
|
220
|
+
queryFn,
|
|
221
|
+
staleTime: options?.staleTime ?? 6e4
|
|
222
|
+
});
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
exports.QueryClient = QueryClient;
|
|
226
|
+
exports.dehydrate = dehydrate;
|
|
227
|
+
exports.hydrate = hydrate;
|
|
228
|
+
exports.prefetchApiQuery = prefetchApiQuery;
|
|
229
|
+
//# sourceMappingURL=server.cjs.map
|
|
230
|
+
//# sourceMappingURL=server.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/cache.ts","../src/server.ts"],"names":[],"mappings":"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","file":"server.cjs","sourcesContent":["import type { ApiError, QueryStatus, QueryClientConfig } from './types';\n\nexport type { QueryStatus };\n\nexport interface CacheEntry<TData = unknown> {\n data: TData | undefined;\n error: ApiError | undefined;\n status: QueryStatus;\n updatedAt: number;\n staleTime: number;\n}\n\ntype Subscriber = () => void;\n\nexport function serializeKey(key: unknown[]): string {\n return JSON.stringify(key);\n}\n\nexport class QueryCache {\n private entries = new Map<string, CacheEntry>();\n private subscribers = new Map<string, Set<Subscriber>>();\n private inFlight = new Map<string, Promise<unknown>>();\n // Discards responses from requests that were superseded (e.g. after cancelQueries)\n private generations = new Map<string, number>();\n // Evicts entries when no subscriber remains for longer than gcTime\n private gcTimers = new Map<string, ReturnType<typeof setTimeout>>();\n // AbortControllers for in-flight requests\n private abortControllers = new Map<string, AbortController>();\n // Global subscribers (for persistence and devtools)\n private globalSubscribers = new Set<() => void>();\n\n readonly gcTime: number;\n\n constructor(gcTime = 5 * 60_000) {\n this.gcTime = gcTime;\n }\n\n get<TData>(key: string): CacheEntry<TData> | undefined {\n return this.entries.get(key) as CacheEntry<TData> | undefined;\n }\n\n subscribe(key: string, fn: Subscriber): () => void {\n // A new subscriber cancels any pending GC eviction for this key\n const pending = this.gcTimers.get(key);\n if (pending !== undefined) {\n clearTimeout(pending);\n this.gcTimers.delete(key);\n }\n\n if (!this.subscribers.has(key)) this.subscribers.set(key, new Set());\n this.subscribers.get(key)!.add(fn);\n\n return () => {\n const set = this.subscribers.get(key);\n if (!set) return;\n set.delete(fn);\n if (set.size === 0) {\n this.subscribers.delete(key);\n // Schedule eviction after the last subscriber leaves\n const timer = setTimeout(() => {\n this.entries.delete(key);\n this.generations.delete(key);\n this.gcTimers.delete(key);\n }, this.gcTime);\n this.gcTimers.set(key, timer);\n }\n };\n }\n\n subscribeGlobal(fn: () => void): () => void {\n this.globalSubscribers.add(fn);\n return () => this.globalSubscribers.delete(fn);\n }\n\n private notify(key: string): void {\n this.subscribers.get(key)?.forEach((fn) => fn());\n this.globalSubscribers.forEach((fn) => fn());\n }\n\n setData<TData>(key: string, data: TData, staleTime: number): void {\n this.entries.set(key, {\n data,\n error: undefined,\n status: 'success',\n updatedAt: Date.now(),\n staleTime,\n });\n this.inFlight.delete(key);\n this.notify(key);\n }\n\n setError(key: string, error: ApiError): void {\n const existing = this.entries.get(key);\n this.entries.set(key, {\n data: existing?.data,\n error,\n status: 'error',\n updatedAt: Date.now(),\n staleTime: 0,\n });\n this.inFlight.delete(key);\n this.notify(key);\n }\n\n setLoading(key: string): void {\n const existing = this.entries.get(key);\n if (existing?.status === 'loading') return;\n this.entries.set(key, {\n data: existing?.data,\n error: undefined,\n status: 'loading',\n updatedAt: existing?.updatedAt ?? 0,\n staleTime: existing?.staleTime ?? 0,\n });\n this.notify(key);\n }\n\n isStale(key: string): boolean {\n const e = this.entries.get(key);\n if (!e || e.status === 'idle' || e.status === 'error') return true;\n if (e.status === 'loading') return false;\n // updatedAt === 0 is the sentinel written by markStale()\n return e.updatedAt === 0 || Date.now() - e.updatedAt > e.staleTime;\n }\n\n // True only when markStale() was explicitly called on a successful entry.\n // Used to detect *external* invalidation (e.g. after a mutation) vs time-based\n // staleness, so the re-fetch effect doesn't loop when staleTime is 0.\n isExternallyInvalidated(key: string): boolean {\n const e = this.entries.get(key);\n return !!e && e.status === 'success' && e.updatedAt === 0;\n }\n\n getInFlight(key: string): Promise<unknown> | undefined {\n return this.inFlight.get(key);\n }\n\n setInFlight(key: string, p: Promise<unknown>): void {\n this.inFlight.set(key, p);\n }\n\n clearInFlight(key: string): void {\n this.inFlight.delete(key);\n }\n\n // Returns the new generation. Does NOT touch inFlight — call clearInFlight separately.\n bumpGeneration(key: string): number {\n const g = (this.generations.get(key) ?? 0) + 1;\n this.generations.set(key, g);\n return g;\n }\n\n getGeneration(key: string): number {\n return this.generations.get(key) ?? 0;\n }\n\n // Sets updatedAt = 0 as the sentinel for \"externally invalidated\"\n markStale(key: string): void {\n const e = this.entries.get(key);\n if (e) {\n this.entries.set(key, { ...e, updatedAt: 0 });\n this.notify(key);\n }\n }\n\n // AbortController management\n setAbortController(key: string, ctrl: AbortController): void {\n this.abortControllers.set(key, ctrl);\n }\n\n getAbortController(key: string): AbortController | undefined {\n return this.abortControllers.get(key);\n }\n\n clearAbortController(key: string): void {\n this.abortControllers.delete(key);\n }\n\n clear(): void {\n for (const timer of this.gcTimers.values()) clearTimeout(timer);\n this.gcTimers.clear();\n // Abort all in-flight requests\n for (const ctrl of this.abortControllers.values()) ctrl.abort();\n this.abortControllers.clear();\n this.entries.clear();\n this.inFlight.clear();\n this.generations.clear();\n this.subscribers.clear();\n // globalSubscribers intentionally NOT cleared — they survive cache clears\n }\n\n snapshot(): Record<string, CacheEntry> {\n const result: Record<string, CacheEntry> = {};\n for (const [key, entry] of this.entries) {\n if (entry.status === 'success') result[key] = entry;\n }\n return result;\n }\n\n restore(state: Record<string, CacheEntry>): void {\n for (const [key, entry] of Object.entries(state)) {\n if (!this.entries.has(key)) this.entries.set(key, entry);\n }\n }\n}\n\nexport class QueryClient {\n readonly cache: QueryCache;\n private readonly config: QueryClientConfig;\n\n constructor(config?: QueryClientConfig) {\n this.config = config ?? {};\n this.cache = new QueryCache(config?.gcTime);\n }\n\n getQueryData<TData>(key: unknown[]): TData | undefined {\n return this.cache.get<TData>(serializeKey(key))?.data;\n }\n\n setQueryData<TData>(\n key: unknown[],\n updater: TData | ((old: TData | undefined) => TData),\n ): void {\n const k = serializeKey(key);\n const existing = this.cache.get<TData>(k);\n const newData =\n typeof updater === 'function'\n ? (updater as (old: TData | undefined) => TData)(existing?.data)\n : updater;\n this.cache.setData(k, newData, existing?.staleTime ?? 60_000);\n this.config.onSuccess?.(newData, k);\n }\n\n invalidateQueries(options: { queryKey: unknown[] }): void {\n this.cache.markStale(serializeKey(options.queryKey));\n }\n\n async cancelQueries(options: { queryKey: unknown[] }): Promise<void> {\n const k = serializeKey(options.queryKey);\n this.cache.getAbortController(k)?.abort();\n this.cache.clearAbortController(k);\n this.cache.bumpGeneration(k);\n this.cache.clearInFlight(k);\n this.cache.markStale(k);\n }\n\n async prefetchQuery<TData>(options: {\n queryKey: unknown[];\n queryFn: () => Promise<TData>;\n staleTime?: number;\n }): Promise<void> {\n const k = serializeKey(options.queryKey);\n if (!this.cache.isStale(k)) return;\n try {\n const data = await options.queryFn();\n this.cache.setData(k, data, options.staleTime ?? 60_000);\n this.config.onSuccess?.(data, k);\n } catch {\n // Prefetch failures are silent; the client will re-fetch\n }\n }\n\n // Called internally after setData / setError to fire global callbacks\n notifySuccess(data: unknown, key: string): void {\n this.config.onSuccess?.(data, key);\n }\n\n notifyError(error: ApiError, key: string): void {\n this.config.onError?.(error, key);\n }\n}\n","import type { AxiosInstance } from 'axios';\nimport { QueryClient } from './cache';\nimport type { CacheEntry } from './cache';\nimport type { ApiClient } from './client';\n\nexport interface DehydratedState {\n entries: Record<string, CacheEntry>;\n}\n\nexport interface PrefetchApiQueryOptions {\n staleTime?: number;\n}\n\n/** Serialize successful cache entries for SSR hydration. */\nexport function dehydrate(queryClient: QueryClient): DehydratedState {\n return { entries: queryClient.cache.snapshot() };\n}\n\n/** Restore a dehydrated state into a QueryClient. */\nexport function hydrate(queryClient: QueryClient, state: DehydratedState): void {\n queryClient.cache.restore(state.entries);\n}\n\n/**\n * Prefetch a query on the server (Next.js App Router, Pages Router, Remix loaders).\n * After prefetching, call `dehydrate(queryClient)` and pass the result to\n * `<ApiProvider hydratedState={...}>` on the client to avoid a loading flicker.\n */\nexport async function prefetchApiQuery<TData = unknown>(\n queryClient: QueryClient,\n apiClient: ApiClient,\n keyOrUrl: string | unknown[],\n urlOrFn?: string | ((instance: AxiosInstance) => Promise<TData>),\n options?: PrefetchApiQueryOptions,\n): Promise<void> {\n const queryKey = typeof keyOrUrl === 'string' ? [keyOrUrl] : keyOrUrl;\n\n const queryFn =\n typeof urlOrFn === 'function'\n ? () => urlOrFn(apiClient.instance)\n : typeof urlOrFn === 'string'\n ? () => apiClient.instance.get<TData>(urlOrFn).then((r) => r.data)\n : () => apiClient.instance.get<TData>(keyOrUrl as string).then((r) => r.data);\n\n await queryClient.prefetchQuery({\n queryKey,\n queryFn,\n staleTime: options?.staleTime ?? 60_000,\n });\n}\n\n// Re-exported so server files only need one import\nexport { QueryClient };\n"]}
|
package/dist/server.d.ts
ADDED
package/dist/server.mjs
ADDED
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
// src/cache.ts
|
|
2
|
+
function serializeKey(key) {
|
|
3
|
+
return JSON.stringify(key);
|
|
4
|
+
}
|
|
5
|
+
var QueryCache = class {
|
|
6
|
+
constructor(gcTime = 5 * 6e4) {
|
|
7
|
+
this.entries = /* @__PURE__ */ new Map();
|
|
8
|
+
this.subscribers = /* @__PURE__ */ new Map();
|
|
9
|
+
this.inFlight = /* @__PURE__ */ new Map();
|
|
10
|
+
// Discards responses from requests that were superseded (e.g. after cancelQueries)
|
|
11
|
+
this.generations = /* @__PURE__ */ new Map();
|
|
12
|
+
// Evicts entries when no subscriber remains for longer than gcTime
|
|
13
|
+
this.gcTimers = /* @__PURE__ */ new Map();
|
|
14
|
+
// AbortControllers for in-flight requests
|
|
15
|
+
this.abortControllers = /* @__PURE__ */ new Map();
|
|
16
|
+
// Global subscribers (for persistence and devtools)
|
|
17
|
+
this.globalSubscribers = /* @__PURE__ */ new Set();
|
|
18
|
+
this.gcTime = gcTime;
|
|
19
|
+
}
|
|
20
|
+
get(key) {
|
|
21
|
+
return this.entries.get(key);
|
|
22
|
+
}
|
|
23
|
+
subscribe(key, fn) {
|
|
24
|
+
const pending = this.gcTimers.get(key);
|
|
25
|
+
if (pending !== void 0) {
|
|
26
|
+
clearTimeout(pending);
|
|
27
|
+
this.gcTimers.delete(key);
|
|
28
|
+
}
|
|
29
|
+
if (!this.subscribers.has(key)) this.subscribers.set(key, /* @__PURE__ */ new Set());
|
|
30
|
+
this.subscribers.get(key).add(fn);
|
|
31
|
+
return () => {
|
|
32
|
+
const set = this.subscribers.get(key);
|
|
33
|
+
if (!set) return;
|
|
34
|
+
set.delete(fn);
|
|
35
|
+
if (set.size === 0) {
|
|
36
|
+
this.subscribers.delete(key);
|
|
37
|
+
const timer = setTimeout(() => {
|
|
38
|
+
this.entries.delete(key);
|
|
39
|
+
this.generations.delete(key);
|
|
40
|
+
this.gcTimers.delete(key);
|
|
41
|
+
}, this.gcTime);
|
|
42
|
+
this.gcTimers.set(key, timer);
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
subscribeGlobal(fn) {
|
|
47
|
+
this.globalSubscribers.add(fn);
|
|
48
|
+
return () => this.globalSubscribers.delete(fn);
|
|
49
|
+
}
|
|
50
|
+
notify(key) {
|
|
51
|
+
this.subscribers.get(key)?.forEach((fn) => fn());
|
|
52
|
+
this.globalSubscribers.forEach((fn) => fn());
|
|
53
|
+
}
|
|
54
|
+
setData(key, data, staleTime) {
|
|
55
|
+
this.entries.set(key, {
|
|
56
|
+
data,
|
|
57
|
+
error: void 0,
|
|
58
|
+
status: "success",
|
|
59
|
+
updatedAt: Date.now(),
|
|
60
|
+
staleTime
|
|
61
|
+
});
|
|
62
|
+
this.inFlight.delete(key);
|
|
63
|
+
this.notify(key);
|
|
64
|
+
}
|
|
65
|
+
setError(key, error) {
|
|
66
|
+
const existing = this.entries.get(key);
|
|
67
|
+
this.entries.set(key, {
|
|
68
|
+
data: existing?.data,
|
|
69
|
+
error,
|
|
70
|
+
status: "error",
|
|
71
|
+
updatedAt: Date.now(),
|
|
72
|
+
staleTime: 0
|
|
73
|
+
});
|
|
74
|
+
this.inFlight.delete(key);
|
|
75
|
+
this.notify(key);
|
|
76
|
+
}
|
|
77
|
+
setLoading(key) {
|
|
78
|
+
const existing = this.entries.get(key);
|
|
79
|
+
if (existing?.status === "loading") return;
|
|
80
|
+
this.entries.set(key, {
|
|
81
|
+
data: existing?.data,
|
|
82
|
+
error: void 0,
|
|
83
|
+
status: "loading",
|
|
84
|
+
updatedAt: existing?.updatedAt ?? 0,
|
|
85
|
+
staleTime: existing?.staleTime ?? 0
|
|
86
|
+
});
|
|
87
|
+
this.notify(key);
|
|
88
|
+
}
|
|
89
|
+
isStale(key) {
|
|
90
|
+
const e = this.entries.get(key);
|
|
91
|
+
if (!e || e.status === "idle" || e.status === "error") return true;
|
|
92
|
+
if (e.status === "loading") return false;
|
|
93
|
+
return e.updatedAt === 0 || Date.now() - e.updatedAt > e.staleTime;
|
|
94
|
+
}
|
|
95
|
+
// True only when markStale() was explicitly called on a successful entry.
|
|
96
|
+
// Used to detect *external* invalidation (e.g. after a mutation) vs time-based
|
|
97
|
+
// staleness, so the re-fetch effect doesn't loop when staleTime is 0.
|
|
98
|
+
isExternallyInvalidated(key) {
|
|
99
|
+
const e = this.entries.get(key);
|
|
100
|
+
return !!e && e.status === "success" && e.updatedAt === 0;
|
|
101
|
+
}
|
|
102
|
+
getInFlight(key) {
|
|
103
|
+
return this.inFlight.get(key);
|
|
104
|
+
}
|
|
105
|
+
setInFlight(key, p) {
|
|
106
|
+
this.inFlight.set(key, p);
|
|
107
|
+
}
|
|
108
|
+
clearInFlight(key) {
|
|
109
|
+
this.inFlight.delete(key);
|
|
110
|
+
}
|
|
111
|
+
// Returns the new generation. Does NOT touch inFlight — call clearInFlight separately.
|
|
112
|
+
bumpGeneration(key) {
|
|
113
|
+
const g = (this.generations.get(key) ?? 0) + 1;
|
|
114
|
+
this.generations.set(key, g);
|
|
115
|
+
return g;
|
|
116
|
+
}
|
|
117
|
+
getGeneration(key) {
|
|
118
|
+
return this.generations.get(key) ?? 0;
|
|
119
|
+
}
|
|
120
|
+
// Sets updatedAt = 0 as the sentinel for "externally invalidated"
|
|
121
|
+
markStale(key) {
|
|
122
|
+
const e = this.entries.get(key);
|
|
123
|
+
if (e) {
|
|
124
|
+
this.entries.set(key, { ...e, updatedAt: 0 });
|
|
125
|
+
this.notify(key);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
// AbortController management
|
|
129
|
+
setAbortController(key, ctrl) {
|
|
130
|
+
this.abortControllers.set(key, ctrl);
|
|
131
|
+
}
|
|
132
|
+
getAbortController(key) {
|
|
133
|
+
return this.abortControllers.get(key);
|
|
134
|
+
}
|
|
135
|
+
clearAbortController(key) {
|
|
136
|
+
this.abortControllers.delete(key);
|
|
137
|
+
}
|
|
138
|
+
clear() {
|
|
139
|
+
for (const timer of this.gcTimers.values()) clearTimeout(timer);
|
|
140
|
+
this.gcTimers.clear();
|
|
141
|
+
for (const ctrl of this.abortControllers.values()) ctrl.abort();
|
|
142
|
+
this.abortControllers.clear();
|
|
143
|
+
this.entries.clear();
|
|
144
|
+
this.inFlight.clear();
|
|
145
|
+
this.generations.clear();
|
|
146
|
+
this.subscribers.clear();
|
|
147
|
+
}
|
|
148
|
+
snapshot() {
|
|
149
|
+
const result = {};
|
|
150
|
+
for (const [key, entry] of this.entries) {
|
|
151
|
+
if (entry.status === "success") result[key] = entry;
|
|
152
|
+
}
|
|
153
|
+
return result;
|
|
154
|
+
}
|
|
155
|
+
restore(state) {
|
|
156
|
+
for (const [key, entry] of Object.entries(state)) {
|
|
157
|
+
if (!this.entries.has(key)) this.entries.set(key, entry);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
};
|
|
161
|
+
var QueryClient = class {
|
|
162
|
+
constructor(config) {
|
|
163
|
+
this.config = config ?? {};
|
|
164
|
+
this.cache = new QueryCache(config?.gcTime);
|
|
165
|
+
}
|
|
166
|
+
getQueryData(key) {
|
|
167
|
+
return this.cache.get(serializeKey(key))?.data;
|
|
168
|
+
}
|
|
169
|
+
setQueryData(key, updater) {
|
|
170
|
+
const k = serializeKey(key);
|
|
171
|
+
const existing = this.cache.get(k);
|
|
172
|
+
const newData = typeof updater === "function" ? updater(existing?.data) : updater;
|
|
173
|
+
this.cache.setData(k, newData, existing?.staleTime ?? 6e4);
|
|
174
|
+
this.config.onSuccess?.(newData, k);
|
|
175
|
+
}
|
|
176
|
+
invalidateQueries(options) {
|
|
177
|
+
this.cache.markStale(serializeKey(options.queryKey));
|
|
178
|
+
}
|
|
179
|
+
async cancelQueries(options) {
|
|
180
|
+
const k = serializeKey(options.queryKey);
|
|
181
|
+
this.cache.getAbortController(k)?.abort();
|
|
182
|
+
this.cache.clearAbortController(k);
|
|
183
|
+
this.cache.bumpGeneration(k);
|
|
184
|
+
this.cache.clearInFlight(k);
|
|
185
|
+
this.cache.markStale(k);
|
|
186
|
+
}
|
|
187
|
+
async prefetchQuery(options) {
|
|
188
|
+
const k = serializeKey(options.queryKey);
|
|
189
|
+
if (!this.cache.isStale(k)) return;
|
|
190
|
+
try {
|
|
191
|
+
const data = await options.queryFn();
|
|
192
|
+
this.cache.setData(k, data, options.staleTime ?? 6e4);
|
|
193
|
+
this.config.onSuccess?.(data, k);
|
|
194
|
+
} catch {
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
// Called internally after setData / setError to fire global callbacks
|
|
198
|
+
notifySuccess(data, key) {
|
|
199
|
+
this.config.onSuccess?.(data, key);
|
|
200
|
+
}
|
|
201
|
+
notifyError(error, key) {
|
|
202
|
+
this.config.onError?.(error, key);
|
|
203
|
+
}
|
|
204
|
+
};
|
|
205
|
+
|
|
206
|
+
// src/server.ts
|
|
207
|
+
function dehydrate(queryClient) {
|
|
208
|
+
return { entries: queryClient.cache.snapshot() };
|
|
209
|
+
}
|
|
210
|
+
function hydrate(queryClient, state) {
|
|
211
|
+
queryClient.cache.restore(state.entries);
|
|
212
|
+
}
|
|
213
|
+
async function prefetchApiQuery(queryClient, apiClient, keyOrUrl, urlOrFn, options) {
|
|
214
|
+
const queryKey = typeof keyOrUrl === "string" ? [keyOrUrl] : keyOrUrl;
|
|
215
|
+
const queryFn = typeof urlOrFn === "function" ? () => urlOrFn(apiClient.instance) : typeof urlOrFn === "string" ? () => apiClient.instance.get(urlOrFn).then((r) => r.data) : () => apiClient.instance.get(keyOrUrl).then((r) => r.data);
|
|
216
|
+
await queryClient.prefetchQuery({
|
|
217
|
+
queryKey,
|
|
218
|
+
queryFn,
|
|
219
|
+
staleTime: options?.staleTime ?? 6e4
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
export { QueryClient, dehydrate, hydrate, prefetchApiQuery };
|
|
224
|
+
//# sourceMappingURL=server.mjs.map
|
|
225
|
+
//# sourceMappingURL=server.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/cache.ts","../src/server.ts"],"names":[],"mappings":"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","file":"server.mjs","sourcesContent":["import type { ApiError, QueryStatus, QueryClientConfig } from './types';\n\nexport type { QueryStatus };\n\nexport interface CacheEntry<TData = unknown> {\n data: TData | undefined;\n error: ApiError | undefined;\n status: QueryStatus;\n updatedAt: number;\n staleTime: number;\n}\n\ntype Subscriber = () => void;\n\nexport function serializeKey(key: unknown[]): string {\n return JSON.stringify(key);\n}\n\nexport class QueryCache {\n private entries = new Map<string, CacheEntry>();\n private subscribers = new Map<string, Set<Subscriber>>();\n private inFlight = new Map<string, Promise<unknown>>();\n // Discards responses from requests that were superseded (e.g. after cancelQueries)\n private generations = new Map<string, number>();\n // Evicts entries when no subscriber remains for longer than gcTime\n private gcTimers = new Map<string, ReturnType<typeof setTimeout>>();\n // AbortControllers for in-flight requests\n private abortControllers = new Map<string, AbortController>();\n // Global subscribers (for persistence and devtools)\n private globalSubscribers = new Set<() => void>();\n\n readonly gcTime: number;\n\n constructor(gcTime = 5 * 60_000) {\n this.gcTime = gcTime;\n }\n\n get<TData>(key: string): CacheEntry<TData> | undefined {\n return this.entries.get(key) as CacheEntry<TData> | undefined;\n }\n\n subscribe(key: string, fn: Subscriber): () => void {\n // A new subscriber cancels any pending GC eviction for this key\n const pending = this.gcTimers.get(key);\n if (pending !== undefined) {\n clearTimeout(pending);\n this.gcTimers.delete(key);\n }\n\n if (!this.subscribers.has(key)) this.subscribers.set(key, new Set());\n this.subscribers.get(key)!.add(fn);\n\n return () => {\n const set = this.subscribers.get(key);\n if (!set) return;\n set.delete(fn);\n if (set.size === 0) {\n this.subscribers.delete(key);\n // Schedule eviction after the last subscriber leaves\n const timer = setTimeout(() => {\n this.entries.delete(key);\n this.generations.delete(key);\n this.gcTimers.delete(key);\n }, this.gcTime);\n this.gcTimers.set(key, timer);\n }\n };\n }\n\n subscribeGlobal(fn: () => void): () => void {\n this.globalSubscribers.add(fn);\n return () => this.globalSubscribers.delete(fn);\n }\n\n private notify(key: string): void {\n this.subscribers.get(key)?.forEach((fn) => fn());\n this.globalSubscribers.forEach((fn) => fn());\n }\n\n setData<TData>(key: string, data: TData, staleTime: number): void {\n this.entries.set(key, {\n data,\n error: undefined,\n status: 'success',\n updatedAt: Date.now(),\n staleTime,\n });\n this.inFlight.delete(key);\n this.notify(key);\n }\n\n setError(key: string, error: ApiError): void {\n const existing = this.entries.get(key);\n this.entries.set(key, {\n data: existing?.data,\n error,\n status: 'error',\n updatedAt: Date.now(),\n staleTime: 0,\n });\n this.inFlight.delete(key);\n this.notify(key);\n }\n\n setLoading(key: string): void {\n const existing = this.entries.get(key);\n if (existing?.status === 'loading') return;\n this.entries.set(key, {\n data: existing?.data,\n error: undefined,\n status: 'loading',\n updatedAt: existing?.updatedAt ?? 0,\n staleTime: existing?.staleTime ?? 0,\n });\n this.notify(key);\n }\n\n isStale(key: string): boolean {\n const e = this.entries.get(key);\n if (!e || e.status === 'idle' || e.status === 'error') return true;\n if (e.status === 'loading') return false;\n // updatedAt === 0 is the sentinel written by markStale()\n return e.updatedAt === 0 || Date.now() - e.updatedAt > e.staleTime;\n }\n\n // True only when markStale() was explicitly called on a successful entry.\n // Used to detect *external* invalidation (e.g. after a mutation) vs time-based\n // staleness, so the re-fetch effect doesn't loop when staleTime is 0.\n isExternallyInvalidated(key: string): boolean {\n const e = this.entries.get(key);\n return !!e && e.status === 'success' && e.updatedAt === 0;\n }\n\n getInFlight(key: string): Promise<unknown> | undefined {\n return this.inFlight.get(key);\n }\n\n setInFlight(key: string, p: Promise<unknown>): void {\n this.inFlight.set(key, p);\n }\n\n clearInFlight(key: string): void {\n this.inFlight.delete(key);\n }\n\n // Returns the new generation. Does NOT touch inFlight — call clearInFlight separately.\n bumpGeneration(key: string): number {\n const g = (this.generations.get(key) ?? 0) + 1;\n this.generations.set(key, g);\n return g;\n }\n\n getGeneration(key: string): number {\n return this.generations.get(key) ?? 0;\n }\n\n // Sets updatedAt = 0 as the sentinel for \"externally invalidated\"\n markStale(key: string): void {\n const e = this.entries.get(key);\n if (e) {\n this.entries.set(key, { ...e, updatedAt: 0 });\n this.notify(key);\n }\n }\n\n // AbortController management\n setAbortController(key: string, ctrl: AbortController): void {\n this.abortControllers.set(key, ctrl);\n }\n\n getAbortController(key: string): AbortController | undefined {\n return this.abortControllers.get(key);\n }\n\n clearAbortController(key: string): void {\n this.abortControllers.delete(key);\n }\n\n clear(): void {\n for (const timer of this.gcTimers.values()) clearTimeout(timer);\n this.gcTimers.clear();\n // Abort all in-flight requests\n for (const ctrl of this.abortControllers.values()) ctrl.abort();\n this.abortControllers.clear();\n this.entries.clear();\n this.inFlight.clear();\n this.generations.clear();\n this.subscribers.clear();\n // globalSubscribers intentionally NOT cleared — they survive cache clears\n }\n\n snapshot(): Record<string, CacheEntry> {\n const result: Record<string, CacheEntry> = {};\n for (const [key, entry] of this.entries) {\n if (entry.status === 'success') result[key] = entry;\n }\n return result;\n }\n\n restore(state: Record<string, CacheEntry>): void {\n for (const [key, entry] of Object.entries(state)) {\n if (!this.entries.has(key)) this.entries.set(key, entry);\n }\n }\n}\n\nexport class QueryClient {\n readonly cache: QueryCache;\n private readonly config: QueryClientConfig;\n\n constructor(config?: QueryClientConfig) {\n this.config = config ?? {};\n this.cache = new QueryCache(config?.gcTime);\n }\n\n getQueryData<TData>(key: unknown[]): TData | undefined {\n return this.cache.get<TData>(serializeKey(key))?.data;\n }\n\n setQueryData<TData>(\n key: unknown[],\n updater: TData | ((old: TData | undefined) => TData),\n ): void {\n const k = serializeKey(key);\n const existing = this.cache.get<TData>(k);\n const newData =\n typeof updater === 'function'\n ? (updater as (old: TData | undefined) => TData)(existing?.data)\n : updater;\n this.cache.setData(k, newData, existing?.staleTime ?? 60_000);\n this.config.onSuccess?.(newData, k);\n }\n\n invalidateQueries(options: { queryKey: unknown[] }): void {\n this.cache.markStale(serializeKey(options.queryKey));\n }\n\n async cancelQueries(options: { queryKey: unknown[] }): Promise<void> {\n const k = serializeKey(options.queryKey);\n this.cache.getAbortController(k)?.abort();\n this.cache.clearAbortController(k);\n this.cache.bumpGeneration(k);\n this.cache.clearInFlight(k);\n this.cache.markStale(k);\n }\n\n async prefetchQuery<TData>(options: {\n queryKey: unknown[];\n queryFn: () => Promise<TData>;\n staleTime?: number;\n }): Promise<void> {\n const k = serializeKey(options.queryKey);\n if (!this.cache.isStale(k)) return;\n try {\n const data = await options.queryFn();\n this.cache.setData(k, data, options.staleTime ?? 60_000);\n this.config.onSuccess?.(data, k);\n } catch {\n // Prefetch failures are silent; the client will re-fetch\n }\n }\n\n // Called internally after setData / setError to fire global callbacks\n notifySuccess(data: unknown, key: string): void {\n this.config.onSuccess?.(data, key);\n }\n\n notifyError(error: ApiError, key: string): void {\n this.config.onError?.(error, key);\n }\n}\n","import type { AxiosInstance } from 'axios';\nimport { QueryClient } from './cache';\nimport type { CacheEntry } from './cache';\nimport type { ApiClient } from './client';\n\nexport interface DehydratedState {\n entries: Record<string, CacheEntry>;\n}\n\nexport interface PrefetchApiQueryOptions {\n staleTime?: number;\n}\n\n/** Serialize successful cache entries for SSR hydration. */\nexport function dehydrate(queryClient: QueryClient): DehydratedState {\n return { entries: queryClient.cache.snapshot() };\n}\n\n/** Restore a dehydrated state into a QueryClient. */\nexport function hydrate(queryClient: QueryClient, state: DehydratedState): void {\n queryClient.cache.restore(state.entries);\n}\n\n/**\n * Prefetch a query on the server (Next.js App Router, Pages Router, Remix loaders).\n * After prefetching, call `dehydrate(queryClient)` and pass the result to\n * `<ApiProvider hydratedState={...}>` on the client to avoid a loading flicker.\n */\nexport async function prefetchApiQuery<TData = unknown>(\n queryClient: QueryClient,\n apiClient: ApiClient,\n keyOrUrl: string | unknown[],\n urlOrFn?: string | ((instance: AxiosInstance) => Promise<TData>),\n options?: PrefetchApiQueryOptions,\n): Promise<void> {\n const queryKey = typeof keyOrUrl === 'string' ? [keyOrUrl] : keyOrUrl;\n\n const queryFn =\n typeof urlOrFn === 'function'\n ? () => urlOrFn(apiClient.instance)\n : typeof urlOrFn === 'string'\n ? () => apiClient.instance.get<TData>(urlOrFn).then((r) => r.data)\n : () => apiClient.instance.get<TData>(keyOrUrl as string).then((r) => r.data);\n\n await queryClient.prefetchQuery({\n queryKey,\n queryFn,\n staleTime: options?.staleTime ?? 60_000,\n });\n}\n\n// Re-exported so server files only need one import\nexport { QueryClient };\n"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@structyl/api-client",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"publishConfig": {
|
|
5
|
+
"access": "public"
|
|
6
|
+
},
|
|
7
|
+
"description": "React data-fetching for any framework: Axios client with a built-in query cache, hooks for queries, mutations, infinite & suspense, plus SSR.",
|
|
8
|
+
"keywords": [
|
|
9
|
+
"react",
|
|
10
|
+
"typescript",
|
|
11
|
+
"structyl",
|
|
12
|
+
"axios",
|
|
13
|
+
"data-fetching",
|
|
14
|
+
"react-query",
|
|
15
|
+
"cache",
|
|
16
|
+
"hooks",
|
|
17
|
+
"mutations",
|
|
18
|
+
"infinite-query",
|
|
19
|
+
"suspense",
|
|
20
|
+
"ssr"
|
|
21
|
+
],
|
|
22
|
+
"license": "MIT",
|
|
23
|
+
"type": "module",
|
|
24
|
+
"sideEffects": false,
|
|
25
|
+
"main": "./dist/index.cjs",
|
|
26
|
+
"module": "./dist/index.mjs",
|
|
27
|
+
"types": "./dist/index.d.ts",
|
|
28
|
+
"exports": {
|
|
29
|
+
".": {
|
|
30
|
+
"types": "./dist/index.d.ts",
|
|
31
|
+
"import": "./dist/index.mjs",
|
|
32
|
+
"require": "./dist/index.cjs"
|
|
33
|
+
},
|
|
34
|
+
"./server": {
|
|
35
|
+
"types": "./dist/server.d.ts",
|
|
36
|
+
"import": "./dist/server.mjs",
|
|
37
|
+
"require": "./dist/server.cjs"
|
|
38
|
+
},
|
|
39
|
+
"./devtools": {
|
|
40
|
+
"types": "./dist/devtools.d.ts",
|
|
41
|
+
"import": "./dist/devtools.mjs",
|
|
42
|
+
"require": "./dist/devtools.cjs"
|
|
43
|
+
}
|
|
44
|
+
},
|
|
45
|
+
"files": [
|
|
46
|
+
"dist"
|
|
47
|
+
],
|
|
48
|
+
"peerDependencies": {
|
|
49
|
+
"axios": "^1.0.0",
|
|
50
|
+
"react": "^18.0.0 || ^19.0.0"
|
|
51
|
+
},
|
|
52
|
+
"devDependencies": {
|
|
53
|
+
"@testing-library/react": "^16.0.0",
|
|
54
|
+
"@types/react": "^19.0.0",
|
|
55
|
+
"axios": "^1.7.7",
|
|
56
|
+
"axios-mock-adapter": "^2.1.0",
|
|
57
|
+
"react": "^19.0.0",
|
|
58
|
+
"react-dom": "^19.0.0",
|
|
59
|
+
"tsup": "^8.3.0",
|
|
60
|
+
"typescript": "^5.6.3",
|
|
61
|
+
"vitest": "^3.2.4"
|
|
62
|
+
},
|
|
63
|
+
"scripts": {
|
|
64
|
+
"build": "tsup",
|
|
65
|
+
"dev": "tsup --watch",
|
|
66
|
+
"lint": "eslint src",
|
|
67
|
+
"test": "vitest run",
|
|
68
|
+
"test:watch": "vitest",
|
|
69
|
+
"typecheck": "tsc --noEmit",
|
|
70
|
+
"clean": "rm -rf dist .turbo"
|
|
71
|
+
}
|
|
72
|
+
}
|