@void-snippets/react 0.3.0 → 0.6.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/dist/index.d.mts +452 -51
- package/dist/index.d.ts +452 -51
- package/dist/index.js +590 -49
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +584 -47
- package/dist/index.mjs.map +1 -1
- package/package.json +24 -3
- package/README.md +0 -192
package/dist/index.js
CHANGED
|
@@ -21,30 +21,227 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
21
21
|
var index_exports = {};
|
|
22
22
|
__export(index_exports, {
|
|
23
23
|
createResourceHooks: () => createResourceHooks,
|
|
24
|
+
createRouteContract: () => createRouteContract,
|
|
25
|
+
createSocketHooks: () => createSocketHooks,
|
|
26
|
+
defineRoute: () => defineRoute,
|
|
24
27
|
useAlertMessage: () => useAlertMessage,
|
|
25
28
|
useAsyncState: () => useAsyncState,
|
|
26
29
|
useCallTimer: () => useCallTimer,
|
|
27
30
|
useModal: () => useModal,
|
|
28
|
-
usePagination: () => usePagination
|
|
31
|
+
usePagination: () => usePagination,
|
|
32
|
+
useTypedSearchParams: () => useTypedSearchParams
|
|
29
33
|
});
|
|
30
34
|
module.exports = __toCommonJS(index_exports);
|
|
31
35
|
|
|
32
36
|
// src/hooks/createResourceHooks.ts
|
|
33
37
|
var import_react_query = require("@tanstack/react-query");
|
|
34
38
|
var import_core = require("@void-snippets/core");
|
|
35
|
-
var DEFAULT_PAGINATION = {
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
};
|
|
39
|
+
var DEFAULT_PAGINATION = { page: 1, limit: 10 };
|
|
40
|
+
function toOperation(op) {
|
|
41
|
+
if (op.kind === "create") return { kind: "create", payload: op.payload, tempId: op.tempId };
|
|
42
|
+
if (op.kind === "update") return { kind: "update", _id: op._id, payload: op.payload };
|
|
43
|
+
return { kind: "remove", _id: op._id };
|
|
44
|
+
}
|
|
45
|
+
var _stacks = /* @__PURE__ */ new WeakMap();
|
|
46
|
+
function getStack(client, prefix) {
|
|
47
|
+
if (!_stacks.has(client)) _stacks.set(client, /* @__PURE__ */ new Map());
|
|
48
|
+
const map = _stacks.get(client);
|
|
49
|
+
if (!map.has(prefix)) {
|
|
50
|
+
map.set(prefix, {
|
|
51
|
+
pendingOps: [],
|
|
52
|
+
effectiveBaseListSnapshots: [],
|
|
53
|
+
effectiveBaseInfiniteSnapshots: [],
|
|
54
|
+
effectiveBaseGet: /* @__PURE__ */ new Map()
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
return map.get(prefix);
|
|
58
|
+
}
|
|
59
|
+
function isListQueryKey(query) {
|
|
60
|
+
const key = query.queryKey;
|
|
61
|
+
return key.length === 2 && key[1] !== null && typeof key[1] === "object" && !Array.isArray(key[1]);
|
|
62
|
+
}
|
|
63
|
+
function generateTempId() {
|
|
64
|
+
if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
|
|
65
|
+
return crypto.randomUUID();
|
|
66
|
+
}
|
|
67
|
+
return `${Date.now()}-${Math.random().toString(36).slice(2, 9)}`;
|
|
68
|
+
}
|
|
69
|
+
function patchPagination(pagination, delta) {
|
|
70
|
+
if (delta === 0) return pagination;
|
|
71
|
+
const newTotal = Math.max(0, pagination.totalDocuments + delta);
|
|
72
|
+
return {
|
|
73
|
+
...pagination,
|
|
74
|
+
totalDocuments: newTotal,
|
|
75
|
+
totalPages: Math.ceil(newTotal / pagination.limit)
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
function applyUpdateToAllCaches(client, prefix, _id, payload, handler) {
|
|
79
|
+
client.setQueriesData(
|
|
80
|
+
{ queryKey: [prefix], predicate: isListQueryKey },
|
|
81
|
+
(old) => old ? { ...old, items: handler(old.items, { _id, payload }) } : old
|
|
82
|
+
);
|
|
83
|
+
client.setQueriesData(
|
|
84
|
+
{ queryKey: [prefix, "INFINITE"] },
|
|
85
|
+
(old) => old ? { ...old, pages: old.pages.map((p) => ({ ...p, items: handler(p.items, { _id, payload }) })) } : old
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
function applyRemoveFromAllCaches(client, prefix, _id, handler) {
|
|
89
|
+
client.setQueriesData(
|
|
90
|
+
{ queryKey: [prefix], predicate: isListQueryKey },
|
|
91
|
+
(old) => {
|
|
92
|
+
if (!old) return old;
|
|
93
|
+
const newItems = handler(old.items, _id);
|
|
94
|
+
return { ...old, items: newItems, pagination: patchPagination(old.pagination, newItems.length - old.items.length) };
|
|
95
|
+
}
|
|
96
|
+
);
|
|
97
|
+
client.setQueriesData(
|
|
98
|
+
{ queryKey: [prefix, "INFINITE"] },
|
|
99
|
+
(old) => old ? {
|
|
100
|
+
...old,
|
|
101
|
+
pages: old.pages.map((p) => {
|
|
102
|
+
const newItems = handler(p.items, _id);
|
|
103
|
+
return { ...p, items: newItems, pagination: patchPagination(p.pagination, newItems.length - p.items.length) };
|
|
104
|
+
})
|
|
105
|
+
} : old
|
|
106
|
+
);
|
|
107
|
+
}
|
|
108
|
+
function applyCreateToAllCaches(client, prefix, payload, tempId, handler) {
|
|
109
|
+
client.setQueriesData(
|
|
110
|
+
{ queryKey: [prefix], predicate: isListQueryKey },
|
|
111
|
+
(old) => {
|
|
112
|
+
if (!old) return old;
|
|
113
|
+
const newItems = handler(old.items, { payload, tempId });
|
|
114
|
+
return { ...old, items: newItems, pagination: patchPagination(old.pagination, newItems.length - old.items.length) };
|
|
115
|
+
}
|
|
116
|
+
);
|
|
117
|
+
client.setQueriesData(
|
|
118
|
+
{ queryKey: [prefix, "INFINITE"] },
|
|
119
|
+
(old) => {
|
|
120
|
+
if (!old) return old;
|
|
121
|
+
return {
|
|
122
|
+
...old,
|
|
123
|
+
pages: old.pages.map((p, i) => {
|
|
124
|
+
if (i !== 0) return p;
|
|
125
|
+
const newItems = handler(p.items, { payload, tempId });
|
|
126
|
+
return { ...p, items: newItems, pagination: patchPagination(p.pagination, newItems.length - p.items.length) };
|
|
127
|
+
})
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
);
|
|
131
|
+
}
|
|
132
|
+
function restoreEffectiveBase(client, prefix, stack) {
|
|
133
|
+
stack.effectiveBaseListSnapshots.forEach(([key, data]) => client.setQueryData(key, data));
|
|
134
|
+
stack.effectiveBaseInfiniteSnapshots.forEach(([key, data]) => client.setQueryData(key, data));
|
|
135
|
+
stack.effectiveBaseGet.forEach((data, idStr) => client.setQueryData([prefix, idStr], data));
|
|
136
|
+
}
|
|
137
|
+
function advanceEffectiveBase(stack, op, optimistic) {
|
|
138
|
+
if (op.kind === "update" && optimistic.update) {
|
|
139
|
+
stack.effectiveBaseListSnapshots = stack.effectiveBaseListSnapshots.map(
|
|
140
|
+
([key, data]) => data ? [key, { ...data, items: optimistic.update(data.items, { _id: op._id, payload: op.payload }) }] : [key, data]
|
|
141
|
+
);
|
|
142
|
+
stack.effectiveBaseInfiniteSnapshots = stack.effectiveBaseInfiniteSnapshots.map(
|
|
143
|
+
([key, data]) => data ? [key, { ...data, pages: data.pages.map((p) => ({ ...p, items: optimistic.update(p.items, { _id: op._id, payload: op.payload }) })) }] : [key, data]
|
|
144
|
+
);
|
|
145
|
+
const baseEntry = stack.effectiveBaseGet.get(String(op._id));
|
|
146
|
+
if (baseEntry !== void 0) {
|
|
147
|
+
const advanced = optimistic.updateSingle ? optimistic.updateSingle(baseEntry, op.payload) : { ...baseEntry, ...op.payload };
|
|
148
|
+
stack.effectiveBaseGet.set(String(op._id), advanced);
|
|
149
|
+
}
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
if (op.kind === "remove" && optimistic.remove) {
|
|
153
|
+
stack.effectiveBaseListSnapshots = stack.effectiveBaseListSnapshots.map(([key, data]) => {
|
|
154
|
+
if (!data) return [key, data];
|
|
155
|
+
const newItems = optimistic.remove(data.items, op._id);
|
|
156
|
+
return [key, { ...data, items: newItems, pagination: patchPagination(data.pagination, newItems.length - data.items.length) }];
|
|
157
|
+
});
|
|
158
|
+
stack.effectiveBaseInfiniteSnapshots = stack.effectiveBaseInfiniteSnapshots.map(
|
|
159
|
+
([key, data]) => data ? [
|
|
160
|
+
key,
|
|
161
|
+
{
|
|
162
|
+
...data,
|
|
163
|
+
pages: data.pages.map((p) => {
|
|
164
|
+
const newItems = optimistic.remove(p.items, op._id);
|
|
165
|
+
return { ...p, items: newItems, pagination: patchPagination(p.pagination, newItems.length - p.items.length) };
|
|
166
|
+
})
|
|
167
|
+
}
|
|
168
|
+
] : [key, data]
|
|
169
|
+
);
|
|
170
|
+
stack.effectiveBaseGet.delete(String(op._id));
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
function replayPendingOps(client, prefix, stack, optimistic) {
|
|
175
|
+
for (const op of stack.pendingOps) {
|
|
176
|
+
if (op.kind === "update" && optimistic.update) {
|
|
177
|
+
applyUpdateToAllCaches(client, prefix, op._id, op.payload, optimistic.update);
|
|
178
|
+
const current = client.getQueryData([prefix, String(op._id)]);
|
|
179
|
+
if (current !== void 0) {
|
|
180
|
+
const updated = optimistic.updateSingle ? optimistic.updateSingle(current, op.payload) : { ...current, ...op.payload };
|
|
181
|
+
client.setQueryData([prefix, String(op._id)], updated);
|
|
182
|
+
}
|
|
183
|
+
} else if (op.kind === "remove" && optimistic.remove) {
|
|
184
|
+
applyRemoveFromAllCaches(client, prefix, op._id, optimistic.remove);
|
|
185
|
+
client.invalidateQueries({ queryKey: [prefix, String(op._id)], refetchType: "none" });
|
|
186
|
+
} else if (op.kind === "create" && optimistic.create) {
|
|
187
|
+
applyCreateToAllCaches(client, prefix, op.payload, op.tempId, optimistic.create);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
function flushStack(client, prefix, stack) {
|
|
192
|
+
stack.pendingOps = [];
|
|
193
|
+
stack.effectiveBaseListSnapshots = [];
|
|
194
|
+
stack.effectiveBaseInfiniteSnapshots = [];
|
|
195
|
+
stack.effectiveBaseGet.clear();
|
|
196
|
+
client.invalidateQueries({ queryKey: [prefix] });
|
|
197
|
+
}
|
|
198
|
+
function handleOptimisticError(client, prefix, error, context, optimistic) {
|
|
199
|
+
if (!context) return;
|
|
200
|
+
const stack = getStack(client, prefix);
|
|
201
|
+
const failedOp = stack.pendingOps.find((op) => op.id === context.operationId);
|
|
202
|
+
stack.pendingOps = stack.pendingOps.filter((op) => op.id !== context.operationId);
|
|
203
|
+
restoreEffectiveBase(client, prefix, stack);
|
|
204
|
+
replayPendingOps(client, prefix, stack, optimistic);
|
|
205
|
+
if (failedOp && optimistic.onError) {
|
|
206
|
+
try {
|
|
207
|
+
optimistic.onError(error, toOperation(failedOp));
|
|
208
|
+
} catch {
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
function handleOptimisticSettled(client, prefix, error, context, optimistic) {
|
|
213
|
+
if (!context) {
|
|
214
|
+
client.invalidateQueries({ queryKey: [prefix] });
|
|
215
|
+
return;
|
|
216
|
+
}
|
|
217
|
+
const stack = getStack(client, prefix);
|
|
218
|
+
if (!error) {
|
|
219
|
+
const settledOp = stack.pendingOps.find((op) => op.id === context.operationId);
|
|
220
|
+
if (settledOp) {
|
|
221
|
+
advanceEffectiveBase(stack, settledOp, optimistic);
|
|
222
|
+
if (optimistic.onSuccess) {
|
|
223
|
+
try {
|
|
224
|
+
optimistic.onSuccess(toOperation(settledOp));
|
|
225
|
+
} catch {
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
stack.pendingOps = stack.pendingOps.filter((op) => op.id !== context.operationId);
|
|
231
|
+
if (stack.pendingOps.length === 0) {
|
|
232
|
+
flushStack(client, prefix, stack);
|
|
233
|
+
}
|
|
234
|
+
}
|
|
39
235
|
function createResourceHooks(queryKeyPrefix, apiService, options = {}) {
|
|
40
236
|
const service = apiService;
|
|
41
237
|
const {
|
|
42
238
|
adapters = (0, import_core.createDefaultAdapters)(),
|
|
43
|
-
defaultParams = DEFAULT_PAGINATION
|
|
239
|
+
defaultParams = DEFAULT_PAGINATION,
|
|
240
|
+
optimistic
|
|
44
241
|
} = options;
|
|
45
242
|
return {
|
|
46
243
|
// -------------------------------------------------------------------------
|
|
47
|
-
// useList
|
|
244
|
+
// useList
|
|
48
245
|
// -------------------------------------------------------------------------
|
|
49
246
|
useList: (params = defaultParams) => {
|
|
50
247
|
var _a, _b, _c, _d, _e;
|
|
@@ -64,13 +261,17 @@ function createResourceHooks(queryKeyPrefix, apiService, options = {}) {
|
|
|
64
261
|
totalPages: 0,
|
|
65
262
|
totalDocuments: 0
|
|
66
263
|
},
|
|
67
|
-
isLoading: query.isLoading
|
|
264
|
+
isLoading: query.isLoading,
|
|
265
|
+
isFetching: query.isFetching,
|
|
266
|
+
isRefetching: query.isRefetching,
|
|
267
|
+
isError: query.isError,
|
|
68
268
|
error: query.error,
|
|
269
|
+
refetch: query.refetch,
|
|
69
270
|
invalidate: () => queryClient.invalidateQueries({ queryKey: [queryKeyPrefix] })
|
|
70
271
|
};
|
|
71
272
|
},
|
|
72
273
|
// -------------------------------------------------------------------------
|
|
73
|
-
// useGet
|
|
274
|
+
// useGet
|
|
74
275
|
// -------------------------------------------------------------------------
|
|
75
276
|
useGet: (id, staleTime = 3e4) => {
|
|
76
277
|
const query = (0, import_react_query.useQuery)({
|
|
@@ -84,46 +285,173 @@ function createResourceHooks(queryKeyPrefix, apiService, options = {}) {
|
|
|
84
285
|
});
|
|
85
286
|
return {
|
|
86
287
|
item: query.data,
|
|
87
|
-
isLoading: query.isLoading
|
|
288
|
+
isLoading: query.isLoading,
|
|
289
|
+
isFetching: query.isFetching,
|
|
290
|
+
isRefetching: query.isRefetching,
|
|
291
|
+
isError: query.isError,
|
|
88
292
|
error: query.error,
|
|
89
293
|
refetch: query.refetch
|
|
90
294
|
};
|
|
91
295
|
},
|
|
92
296
|
// -------------------------------------------------------------------------
|
|
93
|
-
// useMutations
|
|
297
|
+
// useMutations
|
|
94
298
|
// -------------------------------------------------------------------------
|
|
95
299
|
useMutations: () => {
|
|
96
300
|
const queryClient = (0, import_react_query.useQueryClient)();
|
|
97
301
|
const invalidate = () => queryClient.invalidateQueries({ queryKey: [queryKeyPrefix] });
|
|
302
|
+
function captureBaseIfFirstOp(stack) {
|
|
303
|
+
if (stack.pendingOps.length === 0) {
|
|
304
|
+
stack.effectiveBaseListSnapshots = queryClient.getQueriesData({
|
|
305
|
+
queryKey: [queryKeyPrefix],
|
|
306
|
+
predicate: isListQueryKey
|
|
307
|
+
});
|
|
308
|
+
stack.effectiveBaseInfiniteSnapshots = queryClient.getQueriesData({
|
|
309
|
+
queryKey: [queryKeyPrefix, "INFINITE"]
|
|
310
|
+
});
|
|
311
|
+
}
|
|
312
|
+
}
|
|
98
313
|
const createMutation = (0, import_react_query.useMutation)({
|
|
99
314
|
mutationFn: async (payload) => {
|
|
100
315
|
const raw = await service.create(payload);
|
|
101
316
|
return adapters.fromSingle(raw);
|
|
102
317
|
},
|
|
103
|
-
|
|
318
|
+
onMutate: async (payload) => {
|
|
319
|
+
if (!(optimistic == null ? void 0 : optimistic.create)) return void 0;
|
|
320
|
+
await queryClient.cancelQueries({ queryKey: [queryKeyPrefix] });
|
|
321
|
+
const stack = getStack(
|
|
322
|
+
queryClient,
|
|
323
|
+
queryKeyPrefix
|
|
324
|
+
);
|
|
325
|
+
captureBaseIfFirstOp(stack);
|
|
326
|
+
const tempId = generateTempId();
|
|
327
|
+
const op = {
|
|
328
|
+
id: /* @__PURE__ */ Symbol(),
|
|
329
|
+
kind: "create",
|
|
330
|
+
payload,
|
|
331
|
+
tempId
|
|
332
|
+
};
|
|
333
|
+
stack.pendingOps.push(op);
|
|
334
|
+
try {
|
|
335
|
+
applyCreateToAllCaches(queryClient, queryKeyPrefix, payload, tempId, optimistic.create);
|
|
336
|
+
} catch {
|
|
337
|
+
stack.pendingOps = stack.pendingOps.filter((o) => o.id !== op.id);
|
|
338
|
+
throw new Error("[@void-snippets/react] Optimistic create setup failed.");
|
|
339
|
+
}
|
|
340
|
+
return { operationId: op.id };
|
|
341
|
+
},
|
|
342
|
+
onError: (_err, _vars, context) => {
|
|
343
|
+
if (!(optimistic == null ? void 0 : optimistic.create)) return;
|
|
344
|
+
handleOptimisticError(queryClient, queryKeyPrefix, _err, context, optimistic);
|
|
345
|
+
},
|
|
346
|
+
onSettled: (_data, error, _vars, context) => {
|
|
347
|
+
if (!(optimistic == null ? void 0 : optimistic.create)) {
|
|
348
|
+
invalidate();
|
|
349
|
+
return;
|
|
350
|
+
}
|
|
351
|
+
handleOptimisticSettled(queryClient, queryKeyPrefix, error != null ? error : null, context, optimistic);
|
|
352
|
+
}
|
|
104
353
|
});
|
|
105
354
|
const updateMutation = (0, import_react_query.useMutation)({
|
|
106
355
|
mutationFn: async ({ _id, payload }) => {
|
|
107
356
|
const raw = await service.update(_id, payload);
|
|
108
357
|
return adapters.fromSingle(raw);
|
|
109
358
|
},
|
|
110
|
-
|
|
359
|
+
onMutate: async ({ _id, payload }) => {
|
|
360
|
+
if (!(optimistic == null ? void 0 : optimistic.update)) return void 0;
|
|
361
|
+
await queryClient.cancelQueries({ queryKey: [queryKeyPrefix] });
|
|
362
|
+
const stack = getStack(
|
|
363
|
+
queryClient,
|
|
364
|
+
queryKeyPrefix
|
|
365
|
+
);
|
|
366
|
+
captureBaseIfFirstOp(stack);
|
|
367
|
+
const currentSingle = queryClient.getQueryData([queryKeyPrefix, String(_id)]);
|
|
368
|
+
if (currentSingle !== void 0) {
|
|
369
|
+
stack.effectiveBaseGet.set(String(_id), currentSingle);
|
|
370
|
+
}
|
|
371
|
+
const op = {
|
|
372
|
+
id: /* @__PURE__ */ Symbol(),
|
|
373
|
+
kind: "update",
|
|
374
|
+
_id,
|
|
375
|
+
payload
|
|
376
|
+
};
|
|
377
|
+
stack.pendingOps.push(op);
|
|
378
|
+
try {
|
|
379
|
+
applyUpdateToAllCaches(queryClient, queryKeyPrefix, _id, payload, optimistic.update);
|
|
380
|
+
if (currentSingle !== void 0) {
|
|
381
|
+
const updated = optimistic.updateSingle ? optimistic.updateSingle(currentSingle, payload) : { ...currentSingle, ...payload };
|
|
382
|
+
queryClient.setQueryData([queryKeyPrefix, String(_id)], updated);
|
|
383
|
+
}
|
|
384
|
+
} catch {
|
|
385
|
+
stack.pendingOps = stack.pendingOps.filter((o) => o.id !== op.id);
|
|
386
|
+
throw new Error("[@void-snippets/react] Optimistic update setup failed.");
|
|
387
|
+
}
|
|
388
|
+
return { operationId: op.id };
|
|
389
|
+
},
|
|
390
|
+
onError: (_err, _vars, context) => {
|
|
391
|
+
if (!(optimistic == null ? void 0 : optimistic.update)) return;
|
|
392
|
+
handleOptimisticError(queryClient, queryKeyPrefix, _err, context, optimistic);
|
|
393
|
+
},
|
|
394
|
+
onSettled: (_data, error, _vars, context) => {
|
|
395
|
+
if (!(optimistic == null ? void 0 : optimistic.update)) {
|
|
396
|
+
invalidate();
|
|
397
|
+
return;
|
|
398
|
+
}
|
|
399
|
+
handleOptimisticSettled(queryClient, queryKeyPrefix, error != null ? error : null, context, optimistic);
|
|
400
|
+
}
|
|
111
401
|
});
|
|
112
402
|
const removeMutation = (0, import_react_query.useMutation)({
|
|
113
403
|
mutationFn: async (_id) => {
|
|
114
404
|
const raw = await service.delete(_id);
|
|
115
405
|
return adapters.fromSingle(raw);
|
|
116
406
|
},
|
|
117
|
-
|
|
407
|
+
onMutate: async (_id) => {
|
|
408
|
+
if (!(optimistic == null ? void 0 : optimistic.remove)) return void 0;
|
|
409
|
+
await queryClient.cancelQueries({ queryKey: [queryKeyPrefix] });
|
|
410
|
+
const stack = getStack(
|
|
411
|
+
queryClient,
|
|
412
|
+
queryKeyPrefix
|
|
413
|
+
);
|
|
414
|
+
captureBaseIfFirstOp(stack);
|
|
415
|
+
const currentSingle = queryClient.getQueryData([queryKeyPrefix, String(_id)]);
|
|
416
|
+
if (currentSingle !== void 0) {
|
|
417
|
+
stack.effectiveBaseGet.set(String(_id), currentSingle);
|
|
418
|
+
}
|
|
419
|
+
const op = {
|
|
420
|
+
id: /* @__PURE__ */ Symbol(),
|
|
421
|
+
kind: "remove",
|
|
422
|
+
_id
|
|
423
|
+
};
|
|
424
|
+
stack.pendingOps.push(op);
|
|
425
|
+
try {
|
|
426
|
+
applyRemoveFromAllCaches(queryClient, queryKeyPrefix, _id, optimistic.remove);
|
|
427
|
+
if (currentSingle !== void 0) {
|
|
428
|
+
queryClient.invalidateQueries({
|
|
429
|
+
queryKey: [queryKeyPrefix, String(_id)],
|
|
430
|
+
refetchType: "none"
|
|
431
|
+
});
|
|
432
|
+
}
|
|
433
|
+
} catch {
|
|
434
|
+
stack.pendingOps = stack.pendingOps.filter((o) => o.id !== op.id);
|
|
435
|
+
throw new Error("[@void-snippets/react] Optimistic remove setup failed.");
|
|
436
|
+
}
|
|
437
|
+
return { operationId: op.id };
|
|
438
|
+
},
|
|
439
|
+
onError: (_err, _vars, context) => {
|
|
440
|
+
if (!(optimistic == null ? void 0 : optimistic.remove)) return;
|
|
441
|
+
handleOptimisticError(queryClient, queryKeyPrefix, _err, context, optimistic);
|
|
442
|
+
},
|
|
443
|
+
onSettled: (_data, error, _vars, context) => {
|
|
444
|
+
if (!(optimistic == null ? void 0 : optimistic.remove)) {
|
|
445
|
+
invalidate();
|
|
446
|
+
return;
|
|
447
|
+
}
|
|
448
|
+
handleOptimisticSettled(queryClient, queryKeyPrefix, error != null ? error : null, context, optimistic);
|
|
449
|
+
}
|
|
118
450
|
});
|
|
119
|
-
return {
|
|
120
|
-
create: createMutation,
|
|
121
|
-
update: updateMutation,
|
|
122
|
-
remove: removeMutation
|
|
123
|
-
};
|
|
451
|
+
return { create: createMutation, update: updateMutation, remove: removeMutation };
|
|
124
452
|
},
|
|
125
453
|
// -------------------------------------------------------------------------
|
|
126
|
-
// useInfinite
|
|
454
|
+
// useInfinite
|
|
127
455
|
// -------------------------------------------------------------------------
|
|
128
456
|
useInfinite: (params = defaultParams) => {
|
|
129
457
|
return (0, import_react_query.useInfiniteQuery)({
|
|
@@ -147,15 +475,224 @@ function createResourceHooks(queryKeyPrefix, apiService, options = {}) {
|
|
|
147
475
|
};
|
|
148
476
|
}
|
|
149
477
|
|
|
150
|
-
// src/
|
|
478
|
+
// src/socket/createSocketHooks.ts
|
|
151
479
|
var import_react = require("react");
|
|
480
|
+
function createSocketHooks(socket) {
|
|
481
|
+
function useSocketEmit() {
|
|
482
|
+
const emit = (0, import_react.useCallback)(
|
|
483
|
+
(event, ...args) => {
|
|
484
|
+
if (!socket.connected) {
|
|
485
|
+
throw new Error(
|
|
486
|
+
`[@void-snippets/react] Cannot emit "${String(event)}" \u2014 socket is not connected.`
|
|
487
|
+
);
|
|
488
|
+
}
|
|
489
|
+
socket.emit(event, ...args);
|
|
490
|
+
},
|
|
491
|
+
[]
|
|
492
|
+
);
|
|
493
|
+
const emitWithAck = (0, import_react.useCallback)(
|
|
494
|
+
(event, ...args) => {
|
|
495
|
+
if (!socket.connected) {
|
|
496
|
+
return Promise.reject(
|
|
497
|
+
new Error(
|
|
498
|
+
`[@void-snippets/react] Cannot emit "${String(event)}" \u2014 socket is not connected.`
|
|
499
|
+
)
|
|
500
|
+
);
|
|
501
|
+
}
|
|
502
|
+
return socket.emitWithAck(
|
|
503
|
+
event,
|
|
504
|
+
...args
|
|
505
|
+
);
|
|
506
|
+
},
|
|
507
|
+
[]
|
|
508
|
+
);
|
|
509
|
+
return { emit, emitWithAck };
|
|
510
|
+
}
|
|
511
|
+
function useSocketListener(event, handler, options) {
|
|
512
|
+
var _a;
|
|
513
|
+
const enabled = (_a = options == null ? void 0 : options.enabled) != null ? _a : true;
|
|
514
|
+
const savedHandler = (0, import_react.useRef)(handler);
|
|
515
|
+
(0, import_react.useEffect)(() => {
|
|
516
|
+
savedHandler.current = handler;
|
|
517
|
+
}, [handler]);
|
|
518
|
+
(0, import_react.useEffect)(() => {
|
|
519
|
+
if (!enabled) return;
|
|
520
|
+
const listener = ((...args) => {
|
|
521
|
+
savedHandler.current(...args);
|
|
522
|
+
});
|
|
523
|
+
socket.on(event, listener);
|
|
524
|
+
return () => {
|
|
525
|
+
socket.off(event, listener);
|
|
526
|
+
};
|
|
527
|
+
}, [event, enabled]);
|
|
528
|
+
}
|
|
529
|
+
function useSocketConnection() {
|
|
530
|
+
const [isConnected, setIsConnected] = (0, import_react.useState)(socket.connected);
|
|
531
|
+
const [isConnecting, setIsConnecting] = (0, import_react.useState)(false);
|
|
532
|
+
const [socketId, setSocketId] = (0, import_react.useState)(socket.id);
|
|
533
|
+
const [error, setError] = (0, import_react.useState)(null);
|
|
534
|
+
(0, import_react.useEffect)(() => {
|
|
535
|
+
function onConnect() {
|
|
536
|
+
setIsConnected(true);
|
|
537
|
+
setIsConnecting(false);
|
|
538
|
+
setSocketId(socket.id);
|
|
539
|
+
setError(null);
|
|
540
|
+
}
|
|
541
|
+
function onDisconnect() {
|
|
542
|
+
setIsConnected(false);
|
|
543
|
+
setIsConnecting(false);
|
|
544
|
+
setSocketId(void 0);
|
|
545
|
+
}
|
|
546
|
+
function onConnectError(err) {
|
|
547
|
+
setIsConnected(false);
|
|
548
|
+
setIsConnecting(false);
|
|
549
|
+
setError(err);
|
|
550
|
+
}
|
|
551
|
+
function onReconnectAttempt() {
|
|
552
|
+
setIsConnecting(true);
|
|
553
|
+
}
|
|
554
|
+
function onReconnectFailed() {
|
|
555
|
+
setIsConnecting(false);
|
|
556
|
+
setError(
|
|
557
|
+
new Error(
|
|
558
|
+
"[@void-snippets/react] Socket reconnection failed \u2014 maximum attempts exceeded."
|
|
559
|
+
)
|
|
560
|
+
);
|
|
561
|
+
}
|
|
562
|
+
socket.on("connect", onConnect);
|
|
563
|
+
socket.on("disconnect", onDisconnect);
|
|
564
|
+
socket.on("connect_error", onConnectError);
|
|
565
|
+
socket.io.on("reconnect_attempt", onReconnectAttempt);
|
|
566
|
+
socket.io.on("reconnect_failed", onReconnectFailed);
|
|
567
|
+
return () => {
|
|
568
|
+
socket.off("connect", onConnect);
|
|
569
|
+
socket.off("disconnect", onDisconnect);
|
|
570
|
+
socket.off("connect_error", onConnectError);
|
|
571
|
+
socket.io.off("reconnect_attempt", onReconnectAttempt);
|
|
572
|
+
socket.io.off("reconnect_failed", onReconnectFailed);
|
|
573
|
+
};
|
|
574
|
+
}, []);
|
|
575
|
+
const connect = (0, import_react.useCallback)(() => {
|
|
576
|
+
if (!socket.connected) {
|
|
577
|
+
setIsConnecting(true);
|
|
578
|
+
socket.connect();
|
|
579
|
+
}
|
|
580
|
+
}, []);
|
|
581
|
+
const disconnect = (0, import_react.useCallback)(() => {
|
|
582
|
+
socket.disconnect();
|
|
583
|
+
}, []);
|
|
584
|
+
return {
|
|
585
|
+
isConnected,
|
|
586
|
+
isConnecting,
|
|
587
|
+
socketId,
|
|
588
|
+
error,
|
|
589
|
+
connect,
|
|
590
|
+
disconnect
|
|
591
|
+
};
|
|
592
|
+
}
|
|
593
|
+
return {
|
|
594
|
+
useSocketEmit,
|
|
595
|
+
useSocketListener,
|
|
596
|
+
useSocketConnection
|
|
597
|
+
};
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
// src/routing/createRouteContract.ts
|
|
601
|
+
var import_react_router = require("react-router");
|
|
602
|
+
var import_react_router2 = require("react-router");
|
|
603
|
+
function isRouteDefinition(node) {
|
|
604
|
+
if (node === null || typeof node !== "object") return false;
|
|
605
|
+
const n = node;
|
|
606
|
+
return typeof n["path"] === "string" && "_search" in n && typeof n["search"] === "function";
|
|
607
|
+
}
|
|
608
|
+
function defineRoute(path, config) {
|
|
609
|
+
const definition = {
|
|
610
|
+
...config,
|
|
611
|
+
path,
|
|
612
|
+
// Phantom anchor — undefined at runtime, typed as `never` for the base definition.
|
|
613
|
+
// The search<S>() method changes this to `S` at the TypeScript level only.
|
|
614
|
+
_search: void 0,
|
|
615
|
+
search() {
|
|
616
|
+
return definition;
|
|
617
|
+
}
|
|
618
|
+
};
|
|
619
|
+
return definition;
|
|
620
|
+
}
|
|
621
|
+
function createRouteContract(tree) {
|
|
622
|
+
const result = {};
|
|
623
|
+
for (const key in tree) {
|
|
624
|
+
const node = tree[key];
|
|
625
|
+
if (isRouteDefinition(node)) {
|
|
626
|
+
const {
|
|
627
|
+
_search: _phantom,
|
|
628
|
+
search: _searchFn,
|
|
629
|
+
...metadata
|
|
630
|
+
} = node;
|
|
631
|
+
result[key] = {
|
|
632
|
+
...metadata,
|
|
633
|
+
// Preserve the phantom anchor on the ProcessedRoute for useTypedSearchParams.
|
|
634
|
+
_search: void 0,
|
|
635
|
+
build(options = {}) {
|
|
636
|
+
const { params, search } = options;
|
|
637
|
+
const pathname = params ? (0, import_react_router.generatePath)(
|
|
638
|
+
node.path,
|
|
639
|
+
Object.fromEntries(
|
|
640
|
+
Object.entries(params).map(([k, v]) => [k, String(v)])
|
|
641
|
+
)
|
|
642
|
+
) : node.path;
|
|
643
|
+
if (search) {
|
|
644
|
+
const defined = Object.entries(search).filter(
|
|
645
|
+
([, v]) => v !== void 0 && v !== null
|
|
646
|
+
);
|
|
647
|
+
if (defined.length > 0) {
|
|
648
|
+
const qs = new URLSearchParams(
|
|
649
|
+
defined.map(([k, v]) => [k, String(v)])
|
|
650
|
+
).toString();
|
|
651
|
+
return `${pathname}?${qs}`;
|
|
652
|
+
}
|
|
653
|
+
}
|
|
654
|
+
return pathname;
|
|
655
|
+
}
|
|
656
|
+
};
|
|
657
|
+
} else {
|
|
658
|
+
result[key] = createRouteContract(node);
|
|
659
|
+
}
|
|
660
|
+
}
|
|
661
|
+
return result;
|
|
662
|
+
}
|
|
663
|
+
function useTypedSearchParams(_route) {
|
|
664
|
+
const [searchParams, setSearchParams] = (0, import_react_router2.useSearchParams)();
|
|
665
|
+
const search = Object.fromEntries(searchParams.entries());
|
|
666
|
+
function setSearch(update) {
|
|
667
|
+
setSearchParams((prev) => {
|
|
668
|
+
const next = Object.fromEntries(prev.entries());
|
|
669
|
+
for (const [k, v] of Object.entries(
|
|
670
|
+
update
|
|
671
|
+
)) {
|
|
672
|
+
if (v === void 0 || v === null) {
|
|
673
|
+
delete next[k];
|
|
674
|
+
} else {
|
|
675
|
+
next[k] = String(v);
|
|
676
|
+
}
|
|
677
|
+
}
|
|
678
|
+
return next;
|
|
679
|
+
});
|
|
680
|
+
}
|
|
681
|
+
function clearSearch() {
|
|
682
|
+
setSearchParams({});
|
|
683
|
+
}
|
|
684
|
+
return { search, setSearch, clearSearch };
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
// src/hooks/useAlertMessage.ts
|
|
688
|
+
var import_react2 = require("react");
|
|
152
689
|
function useAlertMessage(autoHideDuration = 3e3) {
|
|
153
|
-
const [alert, setAlert] = (0,
|
|
690
|
+
const [alert, setAlert] = (0, import_react2.useState)({
|
|
154
691
|
message: null,
|
|
155
692
|
type: "info",
|
|
156
693
|
isVisible: false
|
|
157
694
|
});
|
|
158
|
-
const showAlert = (0,
|
|
695
|
+
const showAlert = (0, import_react2.useCallback)(
|
|
159
696
|
(message, type = "info") => {
|
|
160
697
|
setAlert({ message, type, isVisible: true });
|
|
161
698
|
if (autoHideDuration) {
|
|
@@ -166,31 +703,31 @@ function useAlertMessage(autoHideDuration = 3e3) {
|
|
|
166
703
|
},
|
|
167
704
|
[autoHideDuration]
|
|
168
705
|
);
|
|
169
|
-
const hideAlert = (0,
|
|
706
|
+
const hideAlert = (0, import_react2.useCallback)(() => {
|
|
170
707
|
setAlert((prev) => ({ ...prev, isVisible: false }));
|
|
171
708
|
}, []);
|
|
172
709
|
return { alert, showAlert, hideAlert };
|
|
173
710
|
}
|
|
174
711
|
|
|
175
712
|
// src/hooks/useAsyncState.ts
|
|
176
|
-
var
|
|
713
|
+
var import_react3 = require("react");
|
|
177
714
|
var import_core2 = require("@void-snippets/core");
|
|
178
715
|
function useAsyncState(initialData = null) {
|
|
179
|
-
const [state, setState] = (0,
|
|
716
|
+
const [state, setState] = (0, import_react3.useState)({
|
|
180
717
|
data: initialData,
|
|
181
718
|
status: "idle",
|
|
182
719
|
error: null
|
|
183
720
|
});
|
|
184
|
-
const setData = (0,
|
|
721
|
+
const setData = (0, import_react3.useCallback)((data) => {
|
|
185
722
|
setState({ data, status: "success", error: null });
|
|
186
723
|
}, []);
|
|
187
|
-
const setError = (0,
|
|
724
|
+
const setError = (0, import_react3.useCallback)((error) => {
|
|
188
725
|
setState((prev) => ({ ...prev, error, status: "error" }));
|
|
189
726
|
}, []);
|
|
190
|
-
const reset = (0,
|
|
727
|
+
const reset = (0, import_react3.useCallback)(() => {
|
|
191
728
|
setState({ data: initialData, status: "idle", error: null });
|
|
192
729
|
}, [initialData]);
|
|
193
|
-
const execute = (0,
|
|
730
|
+
const execute = (0, import_react3.useCallback)(
|
|
194
731
|
async (asyncFn, options) => {
|
|
195
732
|
var _a, _b;
|
|
196
733
|
setState((prev) => ({ ...prev, status: "pending", error: null }));
|
|
@@ -206,7 +743,7 @@ function useAsyncState(initialData = null) {
|
|
|
206
743
|
},
|
|
207
744
|
[]
|
|
208
745
|
);
|
|
209
|
-
const flags = (0,
|
|
746
|
+
const flags = (0, import_react3.useMemo)(
|
|
210
747
|
() => ({
|
|
211
748
|
isLoading: state.status === "pending",
|
|
212
749
|
isSuccess: state.status === "success",
|
|
@@ -218,10 +755,10 @@ function useAsyncState(initialData = null) {
|
|
|
218
755
|
}
|
|
219
756
|
|
|
220
757
|
// src/hooks/useCallTimer.ts
|
|
221
|
-
var
|
|
758
|
+
var import_react4 = require("react");
|
|
222
759
|
function useCallTimer(startedAt) {
|
|
223
|
-
const [duration, setDuration] = (0,
|
|
224
|
-
(0,
|
|
760
|
+
const [duration, setDuration] = (0, import_react4.useState)("00:00");
|
|
761
|
+
(0, import_react4.useEffect)(() => {
|
|
225
762
|
if (!startedAt) {
|
|
226
763
|
setDuration("00:00");
|
|
227
764
|
return;
|
|
@@ -238,27 +775,27 @@ function useCallTimer(startedAt) {
|
|
|
238
775
|
}
|
|
239
776
|
|
|
240
777
|
// src/hooks/useModal.ts
|
|
241
|
-
var
|
|
778
|
+
var import_react5 = require("react");
|
|
242
779
|
function useModal() {
|
|
243
|
-
const [isOpen, setIsOpen] = (0,
|
|
244
|
-
const [data, setData] = (0,
|
|
245
|
-
const [isLoading, setIsLoading] = (0,
|
|
246
|
-
const openCreateModal = (0,
|
|
780
|
+
const [isOpen, setIsOpen] = (0, import_react5.useState)(false);
|
|
781
|
+
const [data, setData] = (0, import_react5.useState)(null);
|
|
782
|
+
const [isLoading, setIsLoading] = (0, import_react5.useState)(false);
|
|
783
|
+
const openCreateModal = (0, import_react5.useCallback)(() => {
|
|
247
784
|
setIsOpen(true);
|
|
248
785
|
setData(null);
|
|
249
786
|
}, []);
|
|
250
|
-
const openEditModal = (0,
|
|
787
|
+
const openEditModal = (0, import_react5.useCallback)((editData) => {
|
|
251
788
|
setIsOpen(true);
|
|
252
789
|
setData(editData);
|
|
253
790
|
}, []);
|
|
254
|
-
const setLoading = (0,
|
|
791
|
+
const setLoading = (0, import_react5.useCallback)((loading) => {
|
|
255
792
|
setIsLoading(loading);
|
|
256
793
|
}, []);
|
|
257
|
-
const closeModal = (0,
|
|
794
|
+
const closeModal = (0, import_react5.useCallback)(() => {
|
|
258
795
|
setIsOpen(false);
|
|
259
796
|
setData(null);
|
|
260
797
|
}, []);
|
|
261
|
-
const setModal = (0,
|
|
798
|
+
const setModal = (0, import_react5.useCallback)((open, editData) => {
|
|
262
799
|
setIsOpen(open);
|
|
263
800
|
setData(editData != null ? editData : null);
|
|
264
801
|
}, []);
|
|
@@ -275,18 +812,18 @@ function useModal() {
|
|
|
275
812
|
}
|
|
276
813
|
|
|
277
814
|
// src/hooks/usePagination.ts
|
|
278
|
-
var
|
|
815
|
+
var import_react6 = require("react");
|
|
279
816
|
function usePagination(initialPage = 1, initialLimit = 10) {
|
|
280
|
-
const [page, setPage] = (0,
|
|
281
|
-
const [limit, setLimit] = (0,
|
|
282
|
-
const onPaginationChange = (0,
|
|
817
|
+
const [page, setPage] = (0, import_react6.useState)(initialPage);
|
|
818
|
+
const [limit, setLimit] = (0, import_react6.useState)(initialLimit);
|
|
819
|
+
const onPaginationChange = (0, import_react6.useCallback)(
|
|
283
820
|
(newPage, newLimit) => {
|
|
284
821
|
setPage(newPage);
|
|
285
822
|
setLimit(newLimit);
|
|
286
823
|
},
|
|
287
824
|
[]
|
|
288
825
|
);
|
|
289
|
-
const resetPagination = (0,
|
|
826
|
+
const resetPagination = (0, import_react6.useCallback)(() => {
|
|
290
827
|
setPage(1);
|
|
291
828
|
}, []);
|
|
292
829
|
return {
|
|
@@ -302,10 +839,14 @@ function usePagination(initialPage = 1, initialLimit = 10) {
|
|
|
302
839
|
// Annotate the CommonJS export names for ESM import in node:
|
|
303
840
|
0 && (module.exports = {
|
|
304
841
|
createResourceHooks,
|
|
842
|
+
createRouteContract,
|
|
843
|
+
createSocketHooks,
|
|
844
|
+
defineRoute,
|
|
305
845
|
useAlertMessage,
|
|
306
846
|
useAsyncState,
|
|
307
847
|
useCallTimer,
|
|
308
848
|
useModal,
|
|
309
|
-
usePagination
|
|
849
|
+
usePagination,
|
|
850
|
+
useTypedSearchParams
|
|
310
851
|
});
|
|
311
852
|
//# sourceMappingURL=index.js.map
|