@katlux/providers 0.1.0-alpha.81
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 +200 -0
- package/README.md +21 -0
- package/dist/index.cjs +2763 -0
- package/dist/index.d.cts +482 -0
- package/dist/index.d.mts +482 -0
- package/dist/index.d.ts +482 -0
- package/dist/index.mjs +2742 -0
- package/dist/nuxtAppCompat.cjs +55 -0
- package/dist/nuxtAppCompat.d.cts +31 -0
- package/dist/nuxtAppCompat.d.mts +31 -0
- package/dist/nuxtAppCompat.d.ts +31 -0
- package/dist/nuxtAppCompat.mjs +47 -0
- package/dist/nuxtAppCompat.server.cjs +29 -0
- package/dist/nuxtAppCompat.server.d.cts +21 -0
- package/dist/nuxtAppCompat.server.d.mts +21 -0
- package/dist/nuxtAppCompat.server.d.ts +21 -0
- package/dist/nuxtAppCompat.server.mjs +21 -0
- package/package.json +47 -0
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,2742 @@
|
|
|
1
|
+
import { ref, watch, computed } from 'vue';
|
|
2
|
+
import { getNuxtApp, getRoute, getRouter, getNuxtData, clearNuxtDataKey, getAsyncData, onNuxtReadyCallback } from '@katlux/providers/nuxtAppCompat';
|
|
3
|
+
import { EDataFilterOperator as EDataFilterOperator$1 } from '@katlux/providers';
|
|
4
|
+
import { parseCookies, getCookie, setCookie, deleteCookie } from 'h3';
|
|
5
|
+
import { $fetch } from 'ofetch';
|
|
6
|
+
|
|
7
|
+
var EDataFilterOperator = /* @__PURE__ */ ((EDataFilterOperator2) => {
|
|
8
|
+
EDataFilterOperator2["Equal"] = "==";
|
|
9
|
+
EDataFilterOperator2["NotEqual"] = "!=";
|
|
10
|
+
EDataFilterOperator2["GreaterThan"] = ">";
|
|
11
|
+
EDataFilterOperator2["LessThan"] = "<";
|
|
12
|
+
EDataFilterOperator2["GreaterThanOrEqual"] = ">=";
|
|
13
|
+
EDataFilterOperator2["LessThanOrEqual"] = "<=";
|
|
14
|
+
EDataFilterOperator2["In"] = "in";
|
|
15
|
+
EDataFilterOperator2["NotIn"] = "nin";
|
|
16
|
+
EDataFilterOperator2["And"] = "and";
|
|
17
|
+
EDataFilterOperator2["Or"] = "or";
|
|
18
|
+
EDataFilterOperator2["Nand"] = "nand";
|
|
19
|
+
EDataFilterOperator2["Nor"] = "nor";
|
|
20
|
+
return EDataFilterOperator2;
|
|
21
|
+
})(EDataFilterOperator || {});
|
|
22
|
+
var ECacheStrategy = /* @__PURE__ */ ((ECacheStrategy2) => {
|
|
23
|
+
ECacheStrategy2["Application"] = "Application";
|
|
24
|
+
ECacheStrategy2["Session"] = "Session";
|
|
25
|
+
ECacheStrategy2["Memory"] = "Memory";
|
|
26
|
+
ECacheStrategy2["LocalStorage"] = "LocalStorage";
|
|
27
|
+
ECacheStrategy2["IndexedDB"] = "IndexedDB";
|
|
28
|
+
ECacheStrategy2["Cookie"] = "Cookie";
|
|
29
|
+
return ECacheStrategy2;
|
|
30
|
+
})(ECacheStrategy || {});
|
|
31
|
+
|
|
32
|
+
const useDebounce = (callback, delay) => {
|
|
33
|
+
let timeoutId = null;
|
|
34
|
+
return function(...args) {
|
|
35
|
+
if (timeoutId !== null) {
|
|
36
|
+
clearTimeout(timeoutId);
|
|
37
|
+
}
|
|
38
|
+
timeoutId = setTimeout(() => {
|
|
39
|
+
callback.apply(this, args);
|
|
40
|
+
}, delay);
|
|
41
|
+
};
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
class ADataProvider {
|
|
45
|
+
filter = ref(null);
|
|
46
|
+
sortList = ref([]);
|
|
47
|
+
currentPage = ref(1);
|
|
48
|
+
pageSize = ref(10);
|
|
49
|
+
pageData = ref([]);
|
|
50
|
+
rowCount = ref(0);
|
|
51
|
+
loading = ref(false);
|
|
52
|
+
SSR = ref(false);
|
|
53
|
+
deduplicate = ref(true);
|
|
54
|
+
nuxtApp = null;
|
|
55
|
+
urlPageParam = ref("");
|
|
56
|
+
selectedRows = ref([]);
|
|
57
|
+
selectAll = ref(false);
|
|
58
|
+
constructor(options) {
|
|
59
|
+
if (options?.nuxtApp) {
|
|
60
|
+
this.nuxtApp = options.nuxtApp;
|
|
61
|
+
} else if (import.meta.client) {
|
|
62
|
+
try {
|
|
63
|
+
this.nuxtApp = getNuxtApp();
|
|
64
|
+
} catch {
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
if (options?.filter) {
|
|
68
|
+
this.filter.value = options.filter;
|
|
69
|
+
}
|
|
70
|
+
if (options?.sortList) {
|
|
71
|
+
this.sortList.value = options.sortList;
|
|
72
|
+
}
|
|
73
|
+
if (options?.pageSize) {
|
|
74
|
+
this.pageSize.value = options.pageSize;
|
|
75
|
+
}
|
|
76
|
+
if (options?.currentPage) {
|
|
77
|
+
this.currentPage.value = options.currentPage;
|
|
78
|
+
}
|
|
79
|
+
if (options?.SSR) {
|
|
80
|
+
this.SSR.value = options.SSR;
|
|
81
|
+
}
|
|
82
|
+
if (options?.deduplicate !== void 0) {
|
|
83
|
+
this.deduplicate.value = options.deduplicate;
|
|
84
|
+
}
|
|
85
|
+
if (options?.urlPageParam) {
|
|
86
|
+
this.urlPageParam.value = options.urlPageParam;
|
|
87
|
+
if (import.meta.client) {
|
|
88
|
+
try {
|
|
89
|
+
const route = getRoute();
|
|
90
|
+
if (route) {
|
|
91
|
+
const pageFromUrl = route.query[options.urlPageParam];
|
|
92
|
+
if (pageFromUrl) {
|
|
93
|
+
const parsedPage = parseInt(pageFromUrl, 10);
|
|
94
|
+
if (!isNaN(parsedPage) && parsedPage > 0) {
|
|
95
|
+
this.currentPage.value = parsedPage;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
} catch (e) {
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
watch(this.currentPage, (newPage) => {
|
|
104
|
+
this.loadPageData();
|
|
105
|
+
if (import.meta.client && this.urlPageParam.value) {
|
|
106
|
+
try {
|
|
107
|
+
const router = getRouter();
|
|
108
|
+
if (router) {
|
|
109
|
+
const currentQuery = { ...router.currentRoute.value.query };
|
|
110
|
+
if (newPage === 1) {
|
|
111
|
+
delete currentQuery[this.urlPageParam.value];
|
|
112
|
+
} else {
|
|
113
|
+
currentQuery[this.urlPageParam.value] = String(newPage);
|
|
114
|
+
}
|
|
115
|
+
router.replace({ query: currentQuery });
|
|
116
|
+
}
|
|
117
|
+
} catch (e) {
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
});
|
|
121
|
+
watch(this.pageSize, () => {
|
|
122
|
+
this.currentPage.value = 1;
|
|
123
|
+
this.loadPageData();
|
|
124
|
+
});
|
|
125
|
+
watch(this.filter, useDebounce(() => {
|
|
126
|
+
this.currentPage.value = 1;
|
|
127
|
+
this.loadPageData();
|
|
128
|
+
}, 300));
|
|
129
|
+
watch(this.sortList, () => {
|
|
130
|
+
this.currentPage.value = 1;
|
|
131
|
+
this.loadPageData();
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
setFilter(filter) {
|
|
135
|
+
this.filter.value = filter;
|
|
136
|
+
}
|
|
137
|
+
setSortList(sortList) {
|
|
138
|
+
this.sortList.value = sortList;
|
|
139
|
+
}
|
|
140
|
+
setCurrentPage(currentPage) {
|
|
141
|
+
this.currentPage.value = currentPage;
|
|
142
|
+
}
|
|
143
|
+
setPageSize(pageSize) {
|
|
144
|
+
this.pageSize.value = pageSize;
|
|
145
|
+
}
|
|
146
|
+
async refresh(hardRefresh = false) {
|
|
147
|
+
this.loadPageData();
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
const useFilterLogic = () => {
|
|
152
|
+
const evaluateFilter = (filter, row) => {
|
|
153
|
+
if (filter.operator === EDataFilterOperator$1.And || filter.operator === EDataFilterOperator$1.Or || filter.operator === EDataFilterOperator$1.Nand || filter.operator === EDataFilterOperator$1.Nor) {
|
|
154
|
+
return !filter.active || applyOperator(filter.operator, row, filter.field);
|
|
155
|
+
}
|
|
156
|
+
if ("operator" in filter.field && "field" in filter.field) {
|
|
157
|
+
return !filter.active || evaluateFilter(filter.field, row);
|
|
158
|
+
}
|
|
159
|
+
const field = filter.field;
|
|
160
|
+
const fieldKeys = Object.keys(field);
|
|
161
|
+
return !filter.active || fieldKeys.every((key) => {
|
|
162
|
+
const filterValue = field[key];
|
|
163
|
+
const rowValue = row[key];
|
|
164
|
+
return applyOperator(filter.operator, rowValue, filterValue);
|
|
165
|
+
});
|
|
166
|
+
};
|
|
167
|
+
const applyOperator = (operator, rowValue, filterValue) => {
|
|
168
|
+
switch (operator) {
|
|
169
|
+
case EDataFilterOperator$1.And:
|
|
170
|
+
return compareAnd(rowValue, filterValue);
|
|
171
|
+
case EDataFilterOperator$1.Or:
|
|
172
|
+
return compareOr(rowValue, filterValue);
|
|
173
|
+
case EDataFilterOperator$1.Nand:
|
|
174
|
+
return !compareAnd(rowValue, filterValue);
|
|
175
|
+
case EDataFilterOperator$1.Nor:
|
|
176
|
+
return !compareOr(rowValue, filterValue);
|
|
177
|
+
case EDataFilterOperator$1.Equal:
|
|
178
|
+
return compareEqual(rowValue, filterValue);
|
|
179
|
+
case EDataFilterOperator$1.NotEqual:
|
|
180
|
+
return !compareEqual(rowValue, filterValue);
|
|
181
|
+
case EDataFilterOperator$1.GreaterThan:
|
|
182
|
+
return compareValues(rowValue, filterValue) > 0;
|
|
183
|
+
case EDataFilterOperator$1.LessThan:
|
|
184
|
+
return compareValues(rowValue, filterValue) < 0;
|
|
185
|
+
case EDataFilterOperator$1.GreaterThanOrEqual:
|
|
186
|
+
return compareValues(rowValue, filterValue) >= 0;
|
|
187
|
+
case EDataFilterOperator$1.LessThanOrEqual:
|
|
188
|
+
return compareValues(rowValue, filterValue) <= 0;
|
|
189
|
+
case EDataFilterOperator$1.In:
|
|
190
|
+
return compareIn(rowValue, filterValue);
|
|
191
|
+
case EDataFilterOperator$1.NotIn:
|
|
192
|
+
return !compareIn(rowValue, filterValue);
|
|
193
|
+
default:
|
|
194
|
+
return compareEqual(rowValue, filterValue);
|
|
195
|
+
}
|
|
196
|
+
};
|
|
197
|
+
const compareAnd = (row, nested) => {
|
|
198
|
+
const subFilters = Array.isArray(nested) ? nested : nested && typeof nested === "object" ? Object.values(nested) : [];
|
|
199
|
+
const validFilters = subFilters.filter((f) => f && typeof f === "object" && "operator" in f && "field" in f);
|
|
200
|
+
if (validFilters.length === 0) return true;
|
|
201
|
+
return validFilters.every((f) => {
|
|
202
|
+
const active = f.active !== false;
|
|
203
|
+
return active ? evaluateFilter(f, row) : true;
|
|
204
|
+
});
|
|
205
|
+
};
|
|
206
|
+
const compareOr = (row, nested) => {
|
|
207
|
+
const subFilters = Array.isArray(nested) ? nested : nested && typeof nested === "object" ? Object.values(nested) : [];
|
|
208
|
+
const validFilters = subFilters.filter((f) => f && typeof f === "object" && "operator" in f && "field" in f);
|
|
209
|
+
const activeFilters = validFilters.filter((f) => f.active !== false);
|
|
210
|
+
if (activeFilters.length === 0) return true;
|
|
211
|
+
return activeFilters.some((f) => {
|
|
212
|
+
return evaluateFilter(f, row);
|
|
213
|
+
});
|
|
214
|
+
};
|
|
215
|
+
const compareIn = (rowValue, filterValue) => {
|
|
216
|
+
if (typeof rowValue === "string" && typeof filterValue === "string") {
|
|
217
|
+
return rowValue.toLowerCase().includes(filterValue.toLowerCase());
|
|
218
|
+
}
|
|
219
|
+
return false;
|
|
220
|
+
};
|
|
221
|
+
const compareEqual = (rowValue, filterValue) => {
|
|
222
|
+
if (typeof rowValue === "string" && typeof filterValue === "string") {
|
|
223
|
+
return rowValue.toLowerCase() == filterValue.toLowerCase();
|
|
224
|
+
}
|
|
225
|
+
if (typeof rowValue === "number" && typeof filterValue === "number") {
|
|
226
|
+
return rowValue === filterValue;
|
|
227
|
+
}
|
|
228
|
+
if (typeof rowValue === "boolean" && typeof filterValue === "boolean") {
|
|
229
|
+
return rowValue === filterValue;
|
|
230
|
+
}
|
|
231
|
+
return rowValue === filterValue;
|
|
232
|
+
};
|
|
233
|
+
const compareValues = (rowValue, filterValue) => {
|
|
234
|
+
if (rowValue == null || filterValue == null) {
|
|
235
|
+
return rowValue == null ? -1 : 1;
|
|
236
|
+
}
|
|
237
|
+
if (typeof rowValue === "string" && typeof filterValue === "string") {
|
|
238
|
+
return rowValue.localeCompare(filterValue);
|
|
239
|
+
}
|
|
240
|
+
if (typeof rowValue === "number" && typeof filterValue === "number") {
|
|
241
|
+
return rowValue - filterValue;
|
|
242
|
+
}
|
|
243
|
+
return String(rowValue).localeCompare(String(filterValue));
|
|
244
|
+
};
|
|
245
|
+
const filterTreeData = (nodes, filter, options) => {
|
|
246
|
+
const { idKey, parentKey } = options;
|
|
247
|
+
const nodeMap = new Map(nodes.map((node) => [node[idKey], node]));
|
|
248
|
+
const childrenMap = /* @__PURE__ */ new Map();
|
|
249
|
+
nodes.forEach((node) => {
|
|
250
|
+
const pId = node[parentKey];
|
|
251
|
+
if (pId != null) {
|
|
252
|
+
if (!childrenMap.has(pId)) {
|
|
253
|
+
childrenMap.set(pId, []);
|
|
254
|
+
}
|
|
255
|
+
childrenMap.get(pId).push(node);
|
|
256
|
+
}
|
|
257
|
+
});
|
|
258
|
+
const matchingNodeIds = /* @__PURE__ */ new Set();
|
|
259
|
+
const expandedNodes = /* @__PURE__ */ new Set();
|
|
260
|
+
const visibleNodeIds = /* @__PURE__ */ new Set();
|
|
261
|
+
nodes.forEach((node) => {
|
|
262
|
+
const evalRow = node.data ? { ...node.data, ...node } : node;
|
|
263
|
+
if (evaluateFilter(filter, evalRow)) {
|
|
264
|
+
matchingNodeIds.add(node[idKey]);
|
|
265
|
+
}
|
|
266
|
+
});
|
|
267
|
+
const addDescendants = (nodeId) => {
|
|
268
|
+
const children = childrenMap.get(nodeId);
|
|
269
|
+
if (children && children.length > 0) {
|
|
270
|
+
expandedNodes.add(nodeId);
|
|
271
|
+
children.forEach((child) => {
|
|
272
|
+
visibleNodeIds.add(child[idKey]);
|
|
273
|
+
addDescendants(child[idKey]);
|
|
274
|
+
});
|
|
275
|
+
}
|
|
276
|
+
};
|
|
277
|
+
matchingNodeIds.forEach((id) => {
|
|
278
|
+
visibleNodeIds.add(id);
|
|
279
|
+
addDescendants(id);
|
|
280
|
+
let currentId = id;
|
|
281
|
+
while (currentId != null) {
|
|
282
|
+
visibleNodeIds.add(currentId);
|
|
283
|
+
const node = nodeMap.get(currentId);
|
|
284
|
+
if (node) {
|
|
285
|
+
if (node[parentKey] != null) {
|
|
286
|
+
expandedNodes.add(node[parentKey]);
|
|
287
|
+
currentId = node[parentKey];
|
|
288
|
+
} else {
|
|
289
|
+
currentId = null;
|
|
290
|
+
}
|
|
291
|
+
} else {
|
|
292
|
+
break;
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
});
|
|
296
|
+
const visibleNodes = nodes.filter((node) => visibleNodeIds.has(node[idKey]));
|
|
297
|
+
return {
|
|
298
|
+
visibleNodes,
|
|
299
|
+
expandedNodes
|
|
300
|
+
};
|
|
301
|
+
};
|
|
302
|
+
const filterData = (data, filter, options) => {
|
|
303
|
+
if (options?.treeOptions) {
|
|
304
|
+
const { visibleNodes, expandedNodes } = filterTreeData(
|
|
305
|
+
data,
|
|
306
|
+
filter,
|
|
307
|
+
options.treeOptions
|
|
308
|
+
);
|
|
309
|
+
return { results: visibleNodes, expandedNodes };
|
|
310
|
+
}
|
|
311
|
+
const results = data.filter((row) => evaluateFilter(filter, row));
|
|
312
|
+
return { results };
|
|
313
|
+
};
|
|
314
|
+
return {
|
|
315
|
+
evaluateFilter,
|
|
316
|
+
filterTreeData,
|
|
317
|
+
filterData
|
|
318
|
+
};
|
|
319
|
+
};
|
|
320
|
+
|
|
321
|
+
const useSortLogic = () => {
|
|
322
|
+
const sortData = (sortList, rows) => {
|
|
323
|
+
if (!sortList || sortList.length === 0 || !rows || rows.length === 0) {
|
|
324
|
+
return rows;
|
|
325
|
+
}
|
|
326
|
+
const sortedRows = [...rows];
|
|
327
|
+
const compare = (a, b) => {
|
|
328
|
+
for (const sort of sortList) {
|
|
329
|
+
const aVal = a[sort.field];
|
|
330
|
+
const bVal = b[sort.field];
|
|
331
|
+
if (aVal === null || aVal === void 0) {
|
|
332
|
+
if (bVal === null || bVal === void 0) continue;
|
|
333
|
+
return sort.direction === "asc" ? -1 : 1;
|
|
334
|
+
}
|
|
335
|
+
if (bVal === null || bVal === void 0) {
|
|
336
|
+
return sort.direction === "asc" ? 1 : -1;
|
|
337
|
+
}
|
|
338
|
+
if (aVal < bVal) {
|
|
339
|
+
return sort.direction === "asc" ? -1 : 1;
|
|
340
|
+
} else if (aVal > bVal) {
|
|
341
|
+
return sort.direction === "asc" ? 1 : -1;
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
return 0;
|
|
345
|
+
};
|
|
346
|
+
const merge = (left, right) => {
|
|
347
|
+
const result = [];
|
|
348
|
+
let leftIndex = 0;
|
|
349
|
+
let rightIndex = 0;
|
|
350
|
+
while (leftIndex < left.length && rightIndex < right.length) {
|
|
351
|
+
if (compare(left[leftIndex], right[rightIndex]) <= 0) {
|
|
352
|
+
result.push(left[leftIndex]);
|
|
353
|
+
leftIndex++;
|
|
354
|
+
} else {
|
|
355
|
+
result.push(right[rightIndex]);
|
|
356
|
+
rightIndex++;
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
return result.concat(left.slice(leftIndex)).concat(right.slice(rightIndex));
|
|
360
|
+
};
|
|
361
|
+
const mergeSort = (arr) => {
|
|
362
|
+
if (arr.length <= 1) {
|
|
363
|
+
return arr;
|
|
364
|
+
}
|
|
365
|
+
const mid = Math.floor(arr.length / 2);
|
|
366
|
+
const left = mergeSort(arr.slice(0, mid));
|
|
367
|
+
const right = mergeSort(arr.slice(mid));
|
|
368
|
+
return merge(left, right);
|
|
369
|
+
};
|
|
370
|
+
return mergeSort(sortedRows);
|
|
371
|
+
};
|
|
372
|
+
return {
|
|
373
|
+
sortData
|
|
374
|
+
};
|
|
375
|
+
};
|
|
376
|
+
|
|
377
|
+
const { filterData: filterData$1 } = useFilterLogic();
|
|
378
|
+
const { sortData } = useSortLogic();
|
|
379
|
+
class CFlatClientDataProvider extends ADataProvider {
|
|
380
|
+
allData = ref([]);
|
|
381
|
+
filteredData = ref([]);
|
|
382
|
+
constructor(options) {
|
|
383
|
+
super(options);
|
|
384
|
+
}
|
|
385
|
+
setData(data) {
|
|
386
|
+
this.allData.value = [...data];
|
|
387
|
+
this.loadPageData();
|
|
388
|
+
}
|
|
389
|
+
async loadPageData() {
|
|
390
|
+
if (!this.filter.value) {
|
|
391
|
+
this.filteredData.value = this.allData.value;
|
|
392
|
+
} else {
|
|
393
|
+
const { results } = filterData$1(this.allData.value, this.filter.value);
|
|
394
|
+
this.filteredData.value = results;
|
|
395
|
+
}
|
|
396
|
+
this.rowCount.value = this.filteredData.value.length;
|
|
397
|
+
if (this.sortList.value.length > 0)
|
|
398
|
+
this.filteredData.value = sortData(this.sortList.value, this.filteredData.value);
|
|
399
|
+
if (this.pageSize.value <= 0) {
|
|
400
|
+
this.pageData.value = this.filteredData.value;
|
|
401
|
+
} else {
|
|
402
|
+
const startIndex = (this.currentPage.value - 1) * this.pageSize.value;
|
|
403
|
+
const endIndex = startIndex + this.pageSize.value;
|
|
404
|
+
this.pageData.value = this.filteredData.value.slice(startIndex, endIndex);
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
class ACacheProvider {
|
|
410
|
+
constructor() {
|
|
411
|
+
this.cleanupExpired();
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
class CApplicationCache extends ACacheProvider {
|
|
416
|
+
static instance = null;
|
|
417
|
+
static _storage = null;
|
|
418
|
+
static get storage() {
|
|
419
|
+
if (!this._storage) {
|
|
420
|
+
this._storage = /* @__PURE__ */ new Map();
|
|
421
|
+
}
|
|
422
|
+
return this._storage;
|
|
423
|
+
}
|
|
424
|
+
static getInstance() {
|
|
425
|
+
if (!this.instance) {
|
|
426
|
+
this.instance = new CApplicationCache();
|
|
427
|
+
}
|
|
428
|
+
return this.instance;
|
|
429
|
+
}
|
|
430
|
+
static getSnapshot() {
|
|
431
|
+
return this.storage;
|
|
432
|
+
}
|
|
433
|
+
constructor() {
|
|
434
|
+
super();
|
|
435
|
+
}
|
|
436
|
+
async getKeyList(nuxtApp) {
|
|
437
|
+
const prefix = "cache:";
|
|
438
|
+
const storage = CApplicationCache.storage;
|
|
439
|
+
return Array.from(storage.keys()).filter((key) => key.startsWith(prefix)).map((key) => key.substring(prefix.length));
|
|
440
|
+
}
|
|
441
|
+
async get(key, nuxtApp) {
|
|
442
|
+
if (import.meta.server) {
|
|
443
|
+
const prefixedKey = "cache:" + key;
|
|
444
|
+
const storage = CApplicationCache.storage;
|
|
445
|
+
const entry = storage.get(prefixedKey);
|
|
446
|
+
if (!entry) return null;
|
|
447
|
+
if (Date.now() - entry.timestamp > entry.lifetime) {
|
|
448
|
+
storage.delete(prefixedKey);
|
|
449
|
+
return null;
|
|
450
|
+
}
|
|
451
|
+
return entry.data;
|
|
452
|
+
}
|
|
453
|
+
return null;
|
|
454
|
+
}
|
|
455
|
+
async set(key, data, lifetime, nuxtApp) {
|
|
456
|
+
if (import.meta.server) {
|
|
457
|
+
const prefixedKey = "cache:" + key;
|
|
458
|
+
const storage = CApplicationCache.storage;
|
|
459
|
+
storage.set(prefixedKey, {
|
|
460
|
+
data,
|
|
461
|
+
timestamp: Date.now(),
|
|
462
|
+
lifetime
|
|
463
|
+
});
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
async remove(key, nuxtApp) {
|
|
467
|
+
if (import.meta.server) {
|
|
468
|
+
const prefixedKey = "cache:" + key;
|
|
469
|
+
CApplicationCache.storage.delete(prefixedKey);
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
async removeByPrefix(prefix, nuxtApp) {
|
|
473
|
+
if (import.meta.server) {
|
|
474
|
+
const fullPrefix = "cache:" + prefix;
|
|
475
|
+
const storage = CApplicationCache.storage;
|
|
476
|
+
const keysToDelete = [];
|
|
477
|
+
for (const key of storage.keys()) {
|
|
478
|
+
if (key.startsWith(fullPrefix)) {
|
|
479
|
+
keysToDelete.push(key);
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
for (const key of keysToDelete) {
|
|
483
|
+
storage.delete(key);
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
async getRemainingTime(key, nuxtApp) {
|
|
488
|
+
if (import.meta.server) {
|
|
489
|
+
const prefixedKey = "cache:" + key;
|
|
490
|
+
const storage = CApplicationCache.storage;
|
|
491
|
+
const entry = storage.get(prefixedKey);
|
|
492
|
+
if (!entry) return null;
|
|
493
|
+
return Math.max(0, entry.timestamp + entry.lifetime - Date.now());
|
|
494
|
+
}
|
|
495
|
+
return null;
|
|
496
|
+
}
|
|
497
|
+
async cleanupExpired() {
|
|
498
|
+
if (import.meta.server) {
|
|
499
|
+
const prefix = "cache:";
|
|
500
|
+
const now = Date.now();
|
|
501
|
+
const storage = CApplicationCache.storage;
|
|
502
|
+
const keysToDelete = [];
|
|
503
|
+
for (const [key, entry] of storage.entries()) {
|
|
504
|
+
if (key.startsWith(prefix)) {
|
|
505
|
+
if (now - entry.timestamp > entry.lifetime) {
|
|
506
|
+
keysToDelete.push(key);
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
for (const key of keysToDelete) {
|
|
511
|
+
storage.delete(key);
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
class CMemoryCache extends ACacheProvider {
|
|
518
|
+
static instance = null;
|
|
519
|
+
static _storage = null;
|
|
520
|
+
static get storage() {
|
|
521
|
+
if (!this._storage) this._storage = /* @__PURE__ */ new Map();
|
|
522
|
+
return this._storage;
|
|
523
|
+
}
|
|
524
|
+
static getInstance() {
|
|
525
|
+
if (!this.instance) {
|
|
526
|
+
this.instance = new CMemoryCache();
|
|
527
|
+
}
|
|
528
|
+
return this.instance;
|
|
529
|
+
}
|
|
530
|
+
constructor() {
|
|
531
|
+
super();
|
|
532
|
+
if (import.meta.client && CMemoryCache.storage.size === 0) {
|
|
533
|
+
this._hydrateFromPayload();
|
|
534
|
+
}
|
|
535
|
+
}
|
|
536
|
+
async _hydrateFromPayload() {
|
|
537
|
+
try {
|
|
538
|
+
const nuxtApp = await getNuxtApp();
|
|
539
|
+
const payloadData = nuxtApp?.payload?.data || globalThis.__NUXT__?.payload?.data;
|
|
540
|
+
if (!payloadData) return;
|
|
541
|
+
for (const key in payloadData) {
|
|
542
|
+
const value = payloadData[key];
|
|
543
|
+
if (value && typeof value === "object" && "data" in value && "timestamp" in value && "lifetime" in value) {
|
|
544
|
+
if (typeof value.lifetime === "number") {
|
|
545
|
+
CMemoryCache.storage.set(key, value);
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
} catch (e) {
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
async getKeyList(nuxtApp) {
|
|
553
|
+
const prefix = "cache:";
|
|
554
|
+
return Array.from(CMemoryCache.storage.keys()).filter((key) => key.startsWith(prefix)).map((key) => key.substring(prefix.length));
|
|
555
|
+
}
|
|
556
|
+
async get(key, nuxtApp) {
|
|
557
|
+
const prefixedKey = "cache:" + key;
|
|
558
|
+
if (import.meta.client) {
|
|
559
|
+
const entry = CMemoryCache.storage.get(prefixedKey);
|
|
560
|
+
if (entry) {
|
|
561
|
+
if (Date.now() - entry.timestamp <= entry.lifetime) {
|
|
562
|
+
return entry.data;
|
|
563
|
+
} else {
|
|
564
|
+
CMemoryCache.storage.delete(prefixedKey);
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
try {
|
|
569
|
+
let payloadData = null;
|
|
570
|
+
if (import.meta.client) {
|
|
571
|
+
payloadData = globalThis.__NUXT__?.payload?.data;
|
|
572
|
+
} else if (nuxtApp) {
|
|
573
|
+
payloadData = nuxtApp.payload?.data || nuxtApp.ssrContext?.payload?.data;
|
|
574
|
+
}
|
|
575
|
+
if (payloadData && payloadData[prefixedKey]) {
|
|
576
|
+
const entry = payloadData[prefixedKey];
|
|
577
|
+
if (Date.now() - entry.timestamp <= entry.lifetime) {
|
|
578
|
+
if (import.meta.client) {
|
|
579
|
+
CMemoryCache.storage.set(prefixedKey, entry);
|
|
580
|
+
}
|
|
581
|
+
return entry.data;
|
|
582
|
+
}
|
|
583
|
+
}
|
|
584
|
+
} catch (e) {
|
|
585
|
+
}
|
|
586
|
+
return null;
|
|
587
|
+
}
|
|
588
|
+
async set(key, data, lifetime, nuxtApp) {
|
|
589
|
+
const prefixedKey = "cache:" + key;
|
|
590
|
+
const entry = {
|
|
591
|
+
data,
|
|
592
|
+
timestamp: Date.now(),
|
|
593
|
+
lifetime
|
|
594
|
+
};
|
|
595
|
+
if (import.meta.server && nuxtApp) {
|
|
596
|
+
try {
|
|
597
|
+
const payload = nuxtApp.payload?.data || nuxtApp.ssrContext?.payload?.data;
|
|
598
|
+
if (payload) {
|
|
599
|
+
payload[prefixedKey] = entry;
|
|
600
|
+
}
|
|
601
|
+
} catch (e) {
|
|
602
|
+
}
|
|
603
|
+
}
|
|
604
|
+
if (import.meta.client) {
|
|
605
|
+
CMemoryCache.storage.set(prefixedKey, entry);
|
|
606
|
+
}
|
|
607
|
+
}
|
|
608
|
+
async remove(key, nuxtApp) {
|
|
609
|
+
const prefixedKey = "cache:" + key;
|
|
610
|
+
CMemoryCache.storage.delete(prefixedKey);
|
|
611
|
+
if (import.meta.server && nuxtApp) {
|
|
612
|
+
try {
|
|
613
|
+
const payload = nuxtApp.payload?.data || nuxtApp.ssrContext?.payload?.data;
|
|
614
|
+
if (payload && payload[prefixedKey]) {
|
|
615
|
+
delete payload[prefixedKey];
|
|
616
|
+
}
|
|
617
|
+
} catch (e) {
|
|
618
|
+
}
|
|
619
|
+
}
|
|
620
|
+
}
|
|
621
|
+
async removeByPrefix(prefix, nuxtApp) {
|
|
622
|
+
const fullPrefix = "cache:" + prefix;
|
|
623
|
+
const keysToDelete = [];
|
|
624
|
+
for (const key of CMemoryCache.storage.keys()) {
|
|
625
|
+
if (key.startsWith(fullPrefix)) {
|
|
626
|
+
keysToDelete.push(key);
|
|
627
|
+
}
|
|
628
|
+
}
|
|
629
|
+
for (const key of keysToDelete) {
|
|
630
|
+
CMemoryCache.storage.delete(key);
|
|
631
|
+
}
|
|
632
|
+
if (import.meta.server && nuxtApp) {
|
|
633
|
+
try {
|
|
634
|
+
const payload = nuxtApp.payload?.data || nuxtApp.ssrContext?.payload?.data;
|
|
635
|
+
if (payload) {
|
|
636
|
+
for (const key in payload) {
|
|
637
|
+
if (key.startsWith(fullPrefix)) {
|
|
638
|
+
delete payload[key];
|
|
639
|
+
}
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
} catch (e) {
|
|
643
|
+
}
|
|
644
|
+
}
|
|
645
|
+
}
|
|
646
|
+
async getRemainingTime(key, nuxtApp) {
|
|
647
|
+
const prefixedKey = "cache:" + key;
|
|
648
|
+
const entry = CMemoryCache.storage.get(prefixedKey);
|
|
649
|
+
if (!entry) return null;
|
|
650
|
+
return Math.max(0, entry.timestamp + entry.lifetime - Date.now());
|
|
651
|
+
}
|
|
652
|
+
async cleanupExpired() {
|
|
653
|
+
const prefix = "cache:";
|
|
654
|
+
const now = Date.now();
|
|
655
|
+
const keysToDelete = [];
|
|
656
|
+
for (const [key, entry] of CMemoryCache.storage.entries()) {
|
|
657
|
+
if (key.startsWith(prefix)) {
|
|
658
|
+
if (now - entry.timestamp > entry.lifetime) {
|
|
659
|
+
keysToDelete.push(key);
|
|
660
|
+
}
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
for (const key of keysToDelete) {
|
|
664
|
+
CMemoryCache.storage.delete(key);
|
|
665
|
+
}
|
|
666
|
+
}
|
|
667
|
+
}
|
|
668
|
+
|
|
669
|
+
class CLocalStorageCache extends ACacheProvider {
|
|
670
|
+
static instance = null;
|
|
671
|
+
static getInstance() {
|
|
672
|
+
if (!this.instance) {
|
|
673
|
+
this.instance = new CLocalStorageCache();
|
|
674
|
+
}
|
|
675
|
+
return this.instance;
|
|
676
|
+
}
|
|
677
|
+
type = "LocalStorage";
|
|
678
|
+
constructor() {
|
|
679
|
+
super();
|
|
680
|
+
if (import.meta.client) {
|
|
681
|
+
this._hydrateFromPayload();
|
|
682
|
+
}
|
|
683
|
+
}
|
|
684
|
+
async _hydrateFromPayload() {
|
|
685
|
+
try {
|
|
686
|
+
const nuxtApp = await getNuxtApp();
|
|
687
|
+
const payloadData = nuxtApp?.payload?.data || window.__NUXT__?.payload?.data;
|
|
688
|
+
if (!payloadData) return;
|
|
689
|
+
const prefix = "cache:";
|
|
690
|
+
let count = 0;
|
|
691
|
+
for (const key in payloadData) {
|
|
692
|
+
if (key.startsWith(prefix)) {
|
|
693
|
+
const value = payloadData[key];
|
|
694
|
+
if (value && typeof value === "object" && "data" in value && "timestamp" in value && "lifetime" in value) {
|
|
695
|
+
try {
|
|
696
|
+
localStorage.setItem(key, JSON.stringify(value));
|
|
697
|
+
count++;
|
|
698
|
+
} catch (e) {
|
|
699
|
+
}
|
|
700
|
+
}
|
|
701
|
+
}
|
|
702
|
+
}
|
|
703
|
+
if (count > 0) console.log(`[CLocalStorageCache] Hydrated ${count} entries from payload`);
|
|
704
|
+
} catch (e) {
|
|
705
|
+
}
|
|
706
|
+
}
|
|
707
|
+
async getKeyList(nuxtApp) {
|
|
708
|
+
if (!import.meta.client) return [];
|
|
709
|
+
const prefix = "cache:";
|
|
710
|
+
return Object.keys(localStorage).filter((key) => key.startsWith(prefix)).map((key) => key.substring(prefix.length));
|
|
711
|
+
}
|
|
712
|
+
async get(key, nuxtApp) {
|
|
713
|
+
const prefixedKey = "cache:" + key;
|
|
714
|
+
if (import.meta.client) {
|
|
715
|
+
try {
|
|
716
|
+
const stored = localStorage.getItem(prefixedKey);
|
|
717
|
+
if (stored) {
|
|
718
|
+
const entry = JSON.parse(stored);
|
|
719
|
+
if (Date.now() - entry.timestamp <= entry.lifetime) {
|
|
720
|
+
console.log(`[CLocalStorageCache] GET SUCCESS: ${key}`);
|
|
721
|
+
return entry.data;
|
|
722
|
+
} else {
|
|
723
|
+
console.log(`[CLocalStorageCache] EXPIRED: ${key}`);
|
|
724
|
+
localStorage.removeItem(prefixedKey);
|
|
725
|
+
}
|
|
726
|
+
} else {
|
|
727
|
+
console.log(`[CLocalStorageCache] NOT IN STORAGE: ${key}`);
|
|
728
|
+
}
|
|
729
|
+
} catch (e) {
|
|
730
|
+
}
|
|
731
|
+
}
|
|
732
|
+
try {
|
|
733
|
+
let payloadData = null;
|
|
734
|
+
if (import.meta.client) {
|
|
735
|
+
payloadData = window.__NUXT__?.payload?.data;
|
|
736
|
+
} else if (nuxtApp) {
|
|
737
|
+
payloadData = nuxtApp.payload?.data || nuxtApp.ssrContext?.payload?.data;
|
|
738
|
+
}
|
|
739
|
+
if (payloadData && payloadData[prefixedKey]) {
|
|
740
|
+
const entry = payloadData[prefixedKey];
|
|
741
|
+
if (Date.now() - entry.timestamp <= entry.lifetime) {
|
|
742
|
+
if (import.meta.client) {
|
|
743
|
+
localStorage.setItem(prefixedKey, JSON.stringify(entry));
|
|
744
|
+
}
|
|
745
|
+
return entry.data;
|
|
746
|
+
}
|
|
747
|
+
}
|
|
748
|
+
} catch (e) {
|
|
749
|
+
}
|
|
750
|
+
return null;
|
|
751
|
+
}
|
|
752
|
+
async set(key, data, lifetime, nuxtApp) {
|
|
753
|
+
const prefixedKey = "cache:" + key;
|
|
754
|
+
const entry = {
|
|
755
|
+
data,
|
|
756
|
+
timestamp: Date.now(),
|
|
757
|
+
lifetime
|
|
758
|
+
};
|
|
759
|
+
if (import.meta.server && nuxtApp) {
|
|
760
|
+
try {
|
|
761
|
+
const payload = nuxtApp.payload?.data || nuxtApp.ssrContext?.payload?.data;
|
|
762
|
+
if (payload) {
|
|
763
|
+
payload[prefixedKey] = entry;
|
|
764
|
+
}
|
|
765
|
+
} catch (e) {
|
|
766
|
+
}
|
|
767
|
+
}
|
|
768
|
+
if (import.meta.client) {
|
|
769
|
+
try {
|
|
770
|
+
localStorage.setItem(prefixedKey, JSON.stringify(entry));
|
|
771
|
+
} catch (e) {
|
|
772
|
+
}
|
|
773
|
+
}
|
|
774
|
+
}
|
|
775
|
+
async remove(key, nuxtApp) {
|
|
776
|
+
const prefixedKey = "cache:" + key;
|
|
777
|
+
if (import.meta.client) {
|
|
778
|
+
localStorage.removeItem(prefixedKey);
|
|
779
|
+
}
|
|
780
|
+
if (import.meta.server && nuxtApp) {
|
|
781
|
+
try {
|
|
782
|
+
const payload = nuxtApp.payload?.data || nuxtApp.ssrContext?.payload?.data;
|
|
783
|
+
if (payload && payload[prefixedKey]) {
|
|
784
|
+
delete payload[prefixedKey];
|
|
785
|
+
}
|
|
786
|
+
} catch (e) {
|
|
787
|
+
}
|
|
788
|
+
}
|
|
789
|
+
}
|
|
790
|
+
async removeByPrefix(prefix, nuxtApp) {
|
|
791
|
+
const fullPrefix = "cache:" + prefix;
|
|
792
|
+
if (import.meta.client) {
|
|
793
|
+
const keysToDelete = [];
|
|
794
|
+
for (let i = 0; i < localStorage.length; i++) {
|
|
795
|
+
const key = localStorage.key(i);
|
|
796
|
+
if (key && key.startsWith(fullPrefix)) {
|
|
797
|
+
keysToDelete.push(key);
|
|
798
|
+
}
|
|
799
|
+
}
|
|
800
|
+
for (const key of keysToDelete) {
|
|
801
|
+
localStorage.removeItem(key);
|
|
802
|
+
}
|
|
803
|
+
}
|
|
804
|
+
if (import.meta.server && nuxtApp) {
|
|
805
|
+
try {
|
|
806
|
+
const payload = nuxtApp.payload?.data || nuxtApp.ssrContext?.payload?.data;
|
|
807
|
+
if (payload) {
|
|
808
|
+
for (const key in payload) {
|
|
809
|
+
if (key.startsWith(fullPrefix)) {
|
|
810
|
+
delete payload[key];
|
|
811
|
+
}
|
|
812
|
+
}
|
|
813
|
+
}
|
|
814
|
+
} catch (e) {
|
|
815
|
+
}
|
|
816
|
+
}
|
|
817
|
+
}
|
|
818
|
+
async getRemainingTime(key, nuxtApp) {
|
|
819
|
+
if (import.meta.client) {
|
|
820
|
+
const prefixedKey = "cache:" + key;
|
|
821
|
+
const entryStr = localStorage.getItem(prefixedKey);
|
|
822
|
+
if (!entryStr) return null;
|
|
823
|
+
try {
|
|
824
|
+
const entry = JSON.parse(entryStr);
|
|
825
|
+
return Math.max(0, entry.timestamp + entry.lifetime - Date.now());
|
|
826
|
+
} catch (e) {
|
|
827
|
+
return null;
|
|
828
|
+
}
|
|
829
|
+
}
|
|
830
|
+
return null;
|
|
831
|
+
}
|
|
832
|
+
async cleanupExpired() {
|
|
833
|
+
if (import.meta.client) {
|
|
834
|
+
try {
|
|
835
|
+
const prefix = "cache:";
|
|
836
|
+
const now = Date.now();
|
|
837
|
+
const keysToDelete = [];
|
|
838
|
+
for (let i = 0; i < localStorage.length; i++) {
|
|
839
|
+
const key = localStorage.key(i);
|
|
840
|
+
if (key && key.startsWith(prefix)) {
|
|
841
|
+
const stored = localStorage.getItem(key);
|
|
842
|
+
if (stored) {
|
|
843
|
+
try {
|
|
844
|
+
const entry = JSON.parse(stored);
|
|
845
|
+
if (now - entry.timestamp > entry.lifetime) {
|
|
846
|
+
keysToDelete.push(key);
|
|
847
|
+
}
|
|
848
|
+
} catch (e) {
|
|
849
|
+
keysToDelete.push(key);
|
|
850
|
+
}
|
|
851
|
+
}
|
|
852
|
+
}
|
|
853
|
+
}
|
|
854
|
+
for (const key of keysToDelete) {
|
|
855
|
+
localStorage.removeItem(key);
|
|
856
|
+
}
|
|
857
|
+
} catch (e) {
|
|
858
|
+
}
|
|
859
|
+
}
|
|
860
|
+
}
|
|
861
|
+
}
|
|
862
|
+
|
|
863
|
+
class CIndexedDBCache extends ACacheProvider {
|
|
864
|
+
static instance = null;
|
|
865
|
+
static getInstance() {
|
|
866
|
+
if (!this.instance) {
|
|
867
|
+
this.instance = new CIndexedDBCache();
|
|
868
|
+
}
|
|
869
|
+
return this.instance;
|
|
870
|
+
}
|
|
871
|
+
dbName = "KatluxDB";
|
|
872
|
+
storeName = "cache";
|
|
873
|
+
version = 2;
|
|
874
|
+
dbPromise = null;
|
|
875
|
+
setStore(storeName = "cache") {
|
|
876
|
+
this.storeName = storeName || "cache";
|
|
877
|
+
if (import.meta.client) {
|
|
878
|
+
this.dbPromise = this.openDB();
|
|
879
|
+
this._hydrateFromPayload();
|
|
880
|
+
}
|
|
881
|
+
}
|
|
882
|
+
constructor() {
|
|
883
|
+
super();
|
|
884
|
+
this.setStore();
|
|
885
|
+
}
|
|
886
|
+
async _hydrateFromPayload() {
|
|
887
|
+
try {
|
|
888
|
+
const nuxtApp = await getNuxtApp();
|
|
889
|
+
const payloadData = nuxtApp?.payload?.data || globalThis.__NUXT__?.payload?.data;
|
|
890
|
+
if (!payloadData) return;
|
|
891
|
+
const prefix = "cache:";
|
|
892
|
+
let count = 0;
|
|
893
|
+
for (const key in payloadData) {
|
|
894
|
+
if (key.startsWith(prefix)) {
|
|
895
|
+
const value = payloadData[key];
|
|
896
|
+
if (value && typeof value === "object" && "data" in value && "timestamp" in value && "lifetime" in value) {
|
|
897
|
+
this.dbPromise?.then(async (db) => {
|
|
898
|
+
try {
|
|
899
|
+
const tx = db.transaction(this.storeName, "readwrite");
|
|
900
|
+
const store = tx.objectStore(this.storeName);
|
|
901
|
+
store.put(value, key);
|
|
902
|
+
tx.commit?.();
|
|
903
|
+
} catch (e) {
|
|
904
|
+
}
|
|
905
|
+
});
|
|
906
|
+
count++;
|
|
907
|
+
}
|
|
908
|
+
}
|
|
909
|
+
}
|
|
910
|
+
if (count > 0) console.log(`[CIndexedDBCache] Hydrated ${count} entries from payload`);
|
|
911
|
+
} catch (e) {
|
|
912
|
+
}
|
|
913
|
+
}
|
|
914
|
+
openDB() {
|
|
915
|
+
return new Promise((resolve, reject) => {
|
|
916
|
+
const request = indexedDB.open(this.dbName, this.version);
|
|
917
|
+
request.onerror = () => reject(request.error);
|
|
918
|
+
request.onsuccess = () => resolve(request.result);
|
|
919
|
+
request.onupgradeneeded = (event) => {
|
|
920
|
+
const db = event.target.result;
|
|
921
|
+
if (!db.objectStoreNames.contains(this.storeName)) {
|
|
922
|
+
db.createObjectStore(this.storeName);
|
|
923
|
+
}
|
|
924
|
+
};
|
|
925
|
+
});
|
|
926
|
+
}
|
|
927
|
+
async getStore(mode) {
|
|
928
|
+
if (!this.dbPromise) return Promise.reject("IndexedDB not initialized");
|
|
929
|
+
const db = await this.dbPromise;
|
|
930
|
+
return db.transaction(this.storeName, mode).objectStore(this.storeName);
|
|
931
|
+
}
|
|
932
|
+
async getKeyList(nuxtApp) {
|
|
933
|
+
if (!import.meta.client || !this.dbPromise) return [];
|
|
934
|
+
const db = await this.dbPromise;
|
|
935
|
+
const store = db.transaction(this.storeName, "readonly").objectStore(this.storeName);
|
|
936
|
+
const keys = await new Promise((resolve, reject) => {
|
|
937
|
+
const req = store.getAllKeys();
|
|
938
|
+
req.onsuccess = () => resolve(req.result);
|
|
939
|
+
req.onerror = () => reject(req.error);
|
|
940
|
+
});
|
|
941
|
+
const prefix = "cache:";
|
|
942
|
+
return keys.filter((key) => key.startsWith(prefix)).map((key) => key.substring(prefix.length));
|
|
943
|
+
}
|
|
944
|
+
async get(key, nuxtApp) {
|
|
945
|
+
const prefixedKey = "cache:" + key;
|
|
946
|
+
if (import.meta.client) {
|
|
947
|
+
try {
|
|
948
|
+
const store = await this.getStore("readonly");
|
|
949
|
+
const data = await new Promise((resolve, reject) => {
|
|
950
|
+
const req = store.get(prefixedKey);
|
|
951
|
+
req.onsuccess = () => resolve(req.result);
|
|
952
|
+
req.onerror = () => reject(req.error);
|
|
953
|
+
});
|
|
954
|
+
if (data) {
|
|
955
|
+
if (Date.now() - data.timestamp <= data.lifetime) {
|
|
956
|
+
console.log(`[CIndexedDBCache] GET SUCCESS: ${key}`);
|
|
957
|
+
return data.data;
|
|
958
|
+
} else {
|
|
959
|
+
console.log(`[CIndexedDBCache] EXPIRED: ${key}`);
|
|
960
|
+
const writeStore = await this.getStore("readwrite");
|
|
961
|
+
writeStore.delete(prefixedKey);
|
|
962
|
+
}
|
|
963
|
+
} else {
|
|
964
|
+
console.log(`[CIndexedDBCache] NOT IN DB: ${key}`);
|
|
965
|
+
}
|
|
966
|
+
} catch (e) {
|
|
967
|
+
}
|
|
968
|
+
}
|
|
969
|
+
try {
|
|
970
|
+
let payloadData = null;
|
|
971
|
+
if (import.meta.client) {
|
|
972
|
+
payloadData = globalThis.__NUXT__?.payload?.data;
|
|
973
|
+
} else if (nuxtApp) {
|
|
974
|
+
payloadData = nuxtApp.payload?.data || nuxtApp.ssrContext?.payload?.data;
|
|
975
|
+
}
|
|
976
|
+
if (payloadData && payloadData[prefixedKey]) {
|
|
977
|
+
const entry = payloadData[prefixedKey];
|
|
978
|
+
if (Date.now() - entry.timestamp <= entry.lifetime) {
|
|
979
|
+
if (import.meta.client) {
|
|
980
|
+
this.set(key, entry.data, entry.lifetime, nuxtApp);
|
|
981
|
+
}
|
|
982
|
+
return entry.data;
|
|
983
|
+
}
|
|
984
|
+
}
|
|
985
|
+
} catch (e) {
|
|
986
|
+
}
|
|
987
|
+
return null;
|
|
988
|
+
}
|
|
989
|
+
async set(key, data, lifetime, nuxtApp) {
|
|
990
|
+
const prefixedKey = "cache:" + key;
|
|
991
|
+
const entry = {
|
|
992
|
+
data,
|
|
993
|
+
timestamp: Date.now(),
|
|
994
|
+
lifetime
|
|
995
|
+
};
|
|
996
|
+
if (import.meta.server && nuxtApp) {
|
|
997
|
+
try {
|
|
998
|
+
const payload = nuxtApp.payload?.data || nuxtApp.ssrContext?.payload?.data;
|
|
999
|
+
if (payload) {
|
|
1000
|
+
payload[prefixedKey] = entry;
|
|
1001
|
+
}
|
|
1002
|
+
} catch (e) {
|
|
1003
|
+
}
|
|
1004
|
+
}
|
|
1005
|
+
if (import.meta.client) {
|
|
1006
|
+
try {
|
|
1007
|
+
const store = await this.getStore("readwrite");
|
|
1008
|
+
await new Promise((resolve, reject) => {
|
|
1009
|
+
const req = store.put(entry, prefixedKey);
|
|
1010
|
+
req.onsuccess = () => resolve();
|
|
1011
|
+
req.onerror = () => reject(req.error);
|
|
1012
|
+
});
|
|
1013
|
+
} catch (e) {
|
|
1014
|
+
}
|
|
1015
|
+
}
|
|
1016
|
+
}
|
|
1017
|
+
async remove(key, nuxtApp) {
|
|
1018
|
+
const prefixedKey = "cache:" + key;
|
|
1019
|
+
if (import.meta.client) {
|
|
1020
|
+
try {
|
|
1021
|
+
const store = await this.getStore("readwrite");
|
|
1022
|
+
await new Promise((resolve, reject) => {
|
|
1023
|
+
const req = store.delete(prefixedKey);
|
|
1024
|
+
req.onsuccess = () => resolve();
|
|
1025
|
+
req.onerror = () => reject(req.error);
|
|
1026
|
+
});
|
|
1027
|
+
} catch (e) {
|
|
1028
|
+
}
|
|
1029
|
+
}
|
|
1030
|
+
if (import.meta.server && nuxtApp) {
|
|
1031
|
+
try {
|
|
1032
|
+
const payload = nuxtApp.payload?.data || nuxtApp.ssrContext?.payload?.data;
|
|
1033
|
+
if (payload && payload[prefixedKey]) {
|
|
1034
|
+
delete payload[prefixedKey];
|
|
1035
|
+
}
|
|
1036
|
+
} catch (e) {
|
|
1037
|
+
}
|
|
1038
|
+
}
|
|
1039
|
+
}
|
|
1040
|
+
async removeByPrefix(prefix, nuxtApp) {
|
|
1041
|
+
const fullPrefix = "cache:" + prefix;
|
|
1042
|
+
if (import.meta.client) {
|
|
1043
|
+
try {
|
|
1044
|
+
const store = await this.getStore("readwrite");
|
|
1045
|
+
const allKeys = await new Promise((resolve, reject) => {
|
|
1046
|
+
const req = store.getAllKeys();
|
|
1047
|
+
req.onsuccess = () => resolve(req.result);
|
|
1048
|
+
req.onerror = () => reject(req.error);
|
|
1049
|
+
});
|
|
1050
|
+
const keysToDelete = allKeys.filter((k) => k.startsWith(fullPrefix));
|
|
1051
|
+
for (const key of keysToDelete) {
|
|
1052
|
+
await new Promise((resolve, reject) => {
|
|
1053
|
+
const req = store.delete(key);
|
|
1054
|
+
req.onsuccess = () => resolve();
|
|
1055
|
+
req.onerror = () => reject(req.error);
|
|
1056
|
+
});
|
|
1057
|
+
}
|
|
1058
|
+
} catch (e) {
|
|
1059
|
+
}
|
|
1060
|
+
}
|
|
1061
|
+
if (import.meta.server && nuxtApp) {
|
|
1062
|
+
try {
|
|
1063
|
+
const payload = nuxtApp.payload?.data || nuxtApp.ssrContext?.payload?.data;
|
|
1064
|
+
if (payload) {
|
|
1065
|
+
for (const key in payload) {
|
|
1066
|
+
if (key.startsWith(fullPrefix)) {
|
|
1067
|
+
delete payload[key];
|
|
1068
|
+
}
|
|
1069
|
+
}
|
|
1070
|
+
}
|
|
1071
|
+
} catch (e) {
|
|
1072
|
+
}
|
|
1073
|
+
}
|
|
1074
|
+
}
|
|
1075
|
+
async getRemainingTime(key, nuxtApp) {
|
|
1076
|
+
if (import.meta.client) {
|
|
1077
|
+
try {
|
|
1078
|
+
const prefixedKey = "cache:" + key;
|
|
1079
|
+
const store = await this.getStore("readonly");
|
|
1080
|
+
const entry = await new Promise((resolve, reject) => {
|
|
1081
|
+
const req = store.get(prefixedKey);
|
|
1082
|
+
req.onsuccess = () => resolve(req.result);
|
|
1083
|
+
req.onerror = () => reject(req.error);
|
|
1084
|
+
});
|
|
1085
|
+
if (!entry) return null;
|
|
1086
|
+
return Math.max(0, entry.timestamp + entry.lifetime - Date.now());
|
|
1087
|
+
} catch (e) {
|
|
1088
|
+
return null;
|
|
1089
|
+
}
|
|
1090
|
+
}
|
|
1091
|
+
return null;
|
|
1092
|
+
}
|
|
1093
|
+
async cleanupExpired() {
|
|
1094
|
+
if (import.meta.client && this.dbPromise) {
|
|
1095
|
+
try {
|
|
1096
|
+
const prefix = "cache:";
|
|
1097
|
+
const now = Date.now();
|
|
1098
|
+
const keysToDelete = [];
|
|
1099
|
+
const store = await this.getStore("readwrite");
|
|
1100
|
+
const allKeys = await new Promise((resolve, reject) => {
|
|
1101
|
+
const req = store.getAllKeys();
|
|
1102
|
+
req.onsuccess = () => resolve(req.result);
|
|
1103
|
+
req.onerror = () => reject(req.error);
|
|
1104
|
+
});
|
|
1105
|
+
for (const key of allKeys) {
|
|
1106
|
+
if (key.startsWith(prefix)) {
|
|
1107
|
+
const entry = await new Promise((resolve, reject) => {
|
|
1108
|
+
const req = store.get(key);
|
|
1109
|
+
req.onsuccess = () => resolve(req.result);
|
|
1110
|
+
req.onerror = () => reject(req.error);
|
|
1111
|
+
});
|
|
1112
|
+
if (entry && now - entry.timestamp > entry.lifetime) {
|
|
1113
|
+
keysToDelete.push(key);
|
|
1114
|
+
}
|
|
1115
|
+
}
|
|
1116
|
+
}
|
|
1117
|
+
for (const key of keysToDelete) {
|
|
1118
|
+
await new Promise((resolve, reject) => {
|
|
1119
|
+
const req = store.delete(key);
|
|
1120
|
+
req.onsuccess = () => resolve();
|
|
1121
|
+
req.onerror = () => reject(req.error);
|
|
1122
|
+
});
|
|
1123
|
+
}
|
|
1124
|
+
} catch (e) {
|
|
1125
|
+
}
|
|
1126
|
+
}
|
|
1127
|
+
}
|
|
1128
|
+
}
|
|
1129
|
+
|
|
1130
|
+
class CCookieCache extends ACacheProvider {
|
|
1131
|
+
static instance = null;
|
|
1132
|
+
static getInstance() {
|
|
1133
|
+
if (!this.instance) {
|
|
1134
|
+
this.instance = new CCookieCache();
|
|
1135
|
+
}
|
|
1136
|
+
return this.instance;
|
|
1137
|
+
}
|
|
1138
|
+
type = "Cookie";
|
|
1139
|
+
constructor() {
|
|
1140
|
+
super();
|
|
1141
|
+
}
|
|
1142
|
+
async getKeyList(nuxtApp) {
|
|
1143
|
+
const prefix = "cache:";
|
|
1144
|
+
let cookieStr = "";
|
|
1145
|
+
if (import.meta.client) {
|
|
1146
|
+
cookieStr = document.cookie;
|
|
1147
|
+
} else if (nuxtApp) {
|
|
1148
|
+
const event = nuxtApp.ssrContext?.event;
|
|
1149
|
+
if (event) {
|
|
1150
|
+
const cookies2 = parseCookies(event);
|
|
1151
|
+
return Object.keys(cookies2).filter((k) => k.startsWith(prefix)).map((k) => k.substring(prefix.length));
|
|
1152
|
+
}
|
|
1153
|
+
}
|
|
1154
|
+
if (!cookieStr) return [];
|
|
1155
|
+
const keys = [];
|
|
1156
|
+
const cookies = cookieStr.split(";");
|
|
1157
|
+
for (let i = 0; i < cookies.length; i++) {
|
|
1158
|
+
const cookie = cookies[i].trim();
|
|
1159
|
+
const eqPos = cookie.indexOf("=");
|
|
1160
|
+
if (eqPos > 0) {
|
|
1161
|
+
const name = decodeURIComponent(cookie.substring(0, eqPos));
|
|
1162
|
+
if (name.startsWith(prefix)) {
|
|
1163
|
+
keys.push(name.substring(prefix.length));
|
|
1164
|
+
}
|
|
1165
|
+
}
|
|
1166
|
+
}
|
|
1167
|
+
return keys;
|
|
1168
|
+
}
|
|
1169
|
+
async get(key, nuxtApp) {
|
|
1170
|
+
const prefixedKey = "cache:" + key;
|
|
1171
|
+
let cookieValue = null;
|
|
1172
|
+
if (import.meta.client) {
|
|
1173
|
+
const name = prefixedKey + "=";
|
|
1174
|
+
const ca = document.cookie.split(";");
|
|
1175
|
+
for (let i = 0; i < ca.length; i++) {
|
|
1176
|
+
let c = ca[i].trim();
|
|
1177
|
+
if (c.indexOf(name) === 0) {
|
|
1178
|
+
cookieValue = c.substring(name.length, c.length);
|
|
1179
|
+
break;
|
|
1180
|
+
}
|
|
1181
|
+
}
|
|
1182
|
+
} else if (nuxtApp) {
|
|
1183
|
+
const event = nuxtApp.ssrContext?.event;
|
|
1184
|
+
if (event) {
|
|
1185
|
+
cookieValue = getCookie(event, prefixedKey) ?? null;
|
|
1186
|
+
}
|
|
1187
|
+
}
|
|
1188
|
+
if (!cookieValue) return null;
|
|
1189
|
+
try {
|
|
1190
|
+
const val = JSON.parse(cookieValue);
|
|
1191
|
+
if (val && val.timestamp && val.lifetime) {
|
|
1192
|
+
if (Date.now() - val.timestamp <= val.lifetime) {
|
|
1193
|
+
return val.data;
|
|
1194
|
+
} else {
|
|
1195
|
+
await this.set(key, null, 0, nuxtApp);
|
|
1196
|
+
}
|
|
1197
|
+
}
|
|
1198
|
+
return null;
|
|
1199
|
+
} catch (e) {
|
|
1200
|
+
return null;
|
|
1201
|
+
}
|
|
1202
|
+
}
|
|
1203
|
+
async set(key, data, lifetime, nuxtApp) {
|
|
1204
|
+
const prefixedKey = "cache:" + key;
|
|
1205
|
+
const entry = {
|
|
1206
|
+
data,
|
|
1207
|
+
timestamp: Date.now(),
|
|
1208
|
+
lifetime
|
|
1209
|
+
};
|
|
1210
|
+
const maxAge = Math.floor(lifetime / 1e3);
|
|
1211
|
+
if (import.meta.client) {
|
|
1212
|
+
const cookieValue = encodeURIComponent(JSON.stringify(entry));
|
|
1213
|
+
document.cookie = `${prefixedKey}=${cookieValue}; Max-Age=${maxAge}; Path=/; SameSite=Lax`;
|
|
1214
|
+
} else if (nuxtApp) {
|
|
1215
|
+
const event = nuxtApp.ssrContext?.event;
|
|
1216
|
+
if (event) {
|
|
1217
|
+
setCookie(event, prefixedKey, JSON.stringify(entry), {
|
|
1218
|
+
maxAge,
|
|
1219
|
+
path: "/",
|
|
1220
|
+
sameSite: "lax",
|
|
1221
|
+
httpOnly: true
|
|
1222
|
+
});
|
|
1223
|
+
}
|
|
1224
|
+
}
|
|
1225
|
+
}
|
|
1226
|
+
async remove(key, nuxtApp) {
|
|
1227
|
+
const prefixedKey = "cache:" + key;
|
|
1228
|
+
if (import.meta.client) {
|
|
1229
|
+
document.cookie = `${prefixedKey}=; Max-Age=0; Path=/; SameSite=Lax`;
|
|
1230
|
+
} else if (nuxtApp) {
|
|
1231
|
+
const event = nuxtApp.ssrContext?.event;
|
|
1232
|
+
if (event) {
|
|
1233
|
+
deleteCookie(event, prefixedKey, { path: "/", sameSite: "lax", httpOnly: true });
|
|
1234
|
+
}
|
|
1235
|
+
}
|
|
1236
|
+
}
|
|
1237
|
+
async getRemainingTime(key, nuxtApp) {
|
|
1238
|
+
const prefixedKey = "cache:" + key;
|
|
1239
|
+
let cookieValue = null;
|
|
1240
|
+
if (import.meta.client) {
|
|
1241
|
+
const name = prefixedKey + "=";
|
|
1242
|
+
const ca = document.cookie.split(";");
|
|
1243
|
+
for (let i = 0; i < ca.length; i++) {
|
|
1244
|
+
let c = ca[i].trim();
|
|
1245
|
+
if (c.indexOf(name) === 0) {
|
|
1246
|
+
cookieValue = c.substring(name.length, c.length);
|
|
1247
|
+
break;
|
|
1248
|
+
}
|
|
1249
|
+
}
|
|
1250
|
+
} else if (nuxtApp) {
|
|
1251
|
+
const event = nuxtApp.ssrContext?.event;
|
|
1252
|
+
if (event) {
|
|
1253
|
+
cookieValue = getCookie(event, prefixedKey) ?? null;
|
|
1254
|
+
}
|
|
1255
|
+
}
|
|
1256
|
+
if (!cookieValue) return null;
|
|
1257
|
+
try {
|
|
1258
|
+
const val = JSON.parse(cookieValue);
|
|
1259
|
+
if (val && val.timestamp && val.lifetime) {
|
|
1260
|
+
return Math.max(0, val.timestamp + val.lifetime - Date.now());
|
|
1261
|
+
}
|
|
1262
|
+
return null;
|
|
1263
|
+
} catch (e) {
|
|
1264
|
+
return null;
|
|
1265
|
+
}
|
|
1266
|
+
}
|
|
1267
|
+
async cleanupExpired() {
|
|
1268
|
+
if (import.meta.client) {
|
|
1269
|
+
const prefix = "cache:";
|
|
1270
|
+
const now = Date.now();
|
|
1271
|
+
const cookies = document.cookie.split(";");
|
|
1272
|
+
for (let i = 0; i < cookies.length; i++) {
|
|
1273
|
+
const cookie = cookies[i].trim();
|
|
1274
|
+
const eqPos = cookie.indexOf("=");
|
|
1275
|
+
if (eqPos > 0) {
|
|
1276
|
+
const name = decodeURIComponent(cookie.substring(0, eqPos));
|
|
1277
|
+
if (name.startsWith(prefix)) {
|
|
1278
|
+
const value = decodeURIComponent(cookie.substring(eqPos + 1));
|
|
1279
|
+
try {
|
|
1280
|
+
const entry = JSON.parse(value);
|
|
1281
|
+
if (now - entry.timestamp > entry.lifetime) {
|
|
1282
|
+
document.cookie = `${encodeURIComponent(name)}=; max-age=0; path=/`;
|
|
1283
|
+
}
|
|
1284
|
+
} catch (e) {
|
|
1285
|
+
document.cookie = `${encodeURIComponent(name)}=; max-age=0; path=/`;
|
|
1286
|
+
}
|
|
1287
|
+
}
|
|
1288
|
+
}
|
|
1289
|
+
}
|
|
1290
|
+
}
|
|
1291
|
+
}
|
|
1292
|
+
}
|
|
1293
|
+
|
|
1294
|
+
class CSessionCache extends ACacheProvider {
|
|
1295
|
+
static instance = null;
|
|
1296
|
+
static getInstance() {
|
|
1297
|
+
if (!this.instance) {
|
|
1298
|
+
this.instance = new CSessionCache();
|
|
1299
|
+
}
|
|
1300
|
+
return this.instance;
|
|
1301
|
+
}
|
|
1302
|
+
// Use global symbol to share storage across module instances (API vs App)
|
|
1303
|
+
static get storage() {
|
|
1304
|
+
const globalKey = Symbol.for("Katlux_CSessionCache_Storage");
|
|
1305
|
+
const _global = globalThis;
|
|
1306
|
+
if (!_global[globalKey]) {
|
|
1307
|
+
_global[globalKey] = /* @__PURE__ */ new Map();
|
|
1308
|
+
}
|
|
1309
|
+
return _global[globalKey];
|
|
1310
|
+
}
|
|
1311
|
+
static getSnapshot() {
|
|
1312
|
+
return this.storage;
|
|
1313
|
+
}
|
|
1314
|
+
sessionIdCache = null;
|
|
1315
|
+
sessionId = null;
|
|
1316
|
+
SESSION_ID_KEY = "_session_id";
|
|
1317
|
+
constructor() {
|
|
1318
|
+
super();
|
|
1319
|
+
this.sessionIdCache = CCookieCache.getInstance();
|
|
1320
|
+
}
|
|
1321
|
+
/**
|
|
1322
|
+
* Generate a UUID v4 sessionId
|
|
1323
|
+
*/
|
|
1324
|
+
generateSessionId() {
|
|
1325
|
+
return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => {
|
|
1326
|
+
const r = Math.random() * 16 | 0;
|
|
1327
|
+
const v = c === "x" ? r : r & 3 | 8;
|
|
1328
|
+
return v.toString(16);
|
|
1329
|
+
});
|
|
1330
|
+
}
|
|
1331
|
+
/**
|
|
1332
|
+
* Get or create sessionId
|
|
1333
|
+
*/
|
|
1334
|
+
async getSessionId(nuxtApp) {
|
|
1335
|
+
if (this.sessionId) {
|
|
1336
|
+
return this.sessionId;
|
|
1337
|
+
}
|
|
1338
|
+
if (!this.sessionIdCache) {
|
|
1339
|
+
return this.generateSessionId();
|
|
1340
|
+
}
|
|
1341
|
+
const existingId = await this.sessionIdCache.get(this.SESSION_ID_KEY, nuxtApp);
|
|
1342
|
+
if (existingId) {
|
|
1343
|
+
this.sessionId = existingId;
|
|
1344
|
+
return existingId;
|
|
1345
|
+
}
|
|
1346
|
+
const newId = this.generateSessionId();
|
|
1347
|
+
this.sessionId = newId;
|
|
1348
|
+
if (this.sessionIdCache) {
|
|
1349
|
+
await this.sessionIdCache.set(this.SESSION_ID_KEY, newId, 365 * 24 * 60 * 60 * 1e3, nuxtApp);
|
|
1350
|
+
}
|
|
1351
|
+
return newId;
|
|
1352
|
+
}
|
|
1353
|
+
async getKeyList(nuxtApp) {
|
|
1354
|
+
const prefix = "cache:";
|
|
1355
|
+
if (import.meta.client) {
|
|
1356
|
+
return Object.keys(sessionStorage).filter((key) => key.startsWith(prefix)).map((key) => key.substring(prefix.length));
|
|
1357
|
+
}
|
|
1358
|
+
const sessionId = await this.getSessionId(nuxtApp);
|
|
1359
|
+
const sessionData = CSessionCache.storage.get(sessionId);
|
|
1360
|
+
if (!sessionData) {
|
|
1361
|
+
return [];
|
|
1362
|
+
}
|
|
1363
|
+
return Array.from(sessionData.keys()).filter((key) => key.startsWith(prefix)).map((key) => key.substring(prefix.length));
|
|
1364
|
+
}
|
|
1365
|
+
async get(key, nuxtApp) {
|
|
1366
|
+
const prefixedKey = "cache:" + key;
|
|
1367
|
+
if (import.meta.client) {
|
|
1368
|
+
try {
|
|
1369
|
+
const stored = sessionStorage.getItem(prefixedKey);
|
|
1370
|
+
if (stored) {
|
|
1371
|
+
const entry = JSON.parse(stored);
|
|
1372
|
+
if (Date.now() - entry.timestamp <= entry.lifetime) {
|
|
1373
|
+
return entry.data;
|
|
1374
|
+
} else {
|
|
1375
|
+
sessionStorage.removeItem(prefixedKey);
|
|
1376
|
+
}
|
|
1377
|
+
}
|
|
1378
|
+
} catch (e) {
|
|
1379
|
+
}
|
|
1380
|
+
try {
|
|
1381
|
+
const payloadData = window.__NUXT__?.payload?.data;
|
|
1382
|
+
if (payloadData && payloadData[prefixedKey]) {
|
|
1383
|
+
const entry = payloadData[prefixedKey];
|
|
1384
|
+
if (Date.now() - entry.timestamp <= entry.lifetime) {
|
|
1385
|
+
window.sessionStorage.setItem(prefixedKey, JSON.stringify(entry));
|
|
1386
|
+
return entry.data;
|
|
1387
|
+
}
|
|
1388
|
+
}
|
|
1389
|
+
} catch (e) {
|
|
1390
|
+
}
|
|
1391
|
+
return null;
|
|
1392
|
+
}
|
|
1393
|
+
if (import.meta.server) {
|
|
1394
|
+
const sessionId = await this.getSessionId(nuxtApp);
|
|
1395
|
+
const sessionData = CSessionCache.storage.get(sessionId);
|
|
1396
|
+
if (!sessionData) {
|
|
1397
|
+
return null;
|
|
1398
|
+
}
|
|
1399
|
+
const entry = sessionData.get(prefixedKey);
|
|
1400
|
+
if (!entry) {
|
|
1401
|
+
return null;
|
|
1402
|
+
}
|
|
1403
|
+
if (Date.now() - entry.timestamp <= entry.lifetime) {
|
|
1404
|
+
return entry.data;
|
|
1405
|
+
} else {
|
|
1406
|
+
sessionData.delete(prefixedKey);
|
|
1407
|
+
return null;
|
|
1408
|
+
}
|
|
1409
|
+
}
|
|
1410
|
+
return null;
|
|
1411
|
+
}
|
|
1412
|
+
async set(key, data, lifetime, nuxtApp) {
|
|
1413
|
+
const prefixedKey = "cache:" + key;
|
|
1414
|
+
const entry = {
|
|
1415
|
+
data,
|
|
1416
|
+
timestamp: Date.now(),
|
|
1417
|
+
lifetime
|
|
1418
|
+
};
|
|
1419
|
+
if (import.meta.client) {
|
|
1420
|
+
try {
|
|
1421
|
+
sessionStorage.setItem(prefixedKey, JSON.stringify(entry));
|
|
1422
|
+
} catch (e) {
|
|
1423
|
+
}
|
|
1424
|
+
}
|
|
1425
|
+
if (import.meta.server) {
|
|
1426
|
+
try {
|
|
1427
|
+
const sessionId = await this.getSessionId(nuxtApp);
|
|
1428
|
+
let sessionData = CSessionCache.storage.get(sessionId);
|
|
1429
|
+
if (!sessionData) {
|
|
1430
|
+
sessionData = /* @__PURE__ */ new Map();
|
|
1431
|
+
CSessionCache.storage.set(sessionId, sessionData);
|
|
1432
|
+
}
|
|
1433
|
+
sessionData.set(prefixedKey, entry);
|
|
1434
|
+
if (nuxtApp) {
|
|
1435
|
+
const payload = nuxtApp.payload?.data || nuxtApp.ssrContext?.payload?.data;
|
|
1436
|
+
if (payload) {
|
|
1437
|
+
payload[prefixedKey] = entry;
|
|
1438
|
+
}
|
|
1439
|
+
}
|
|
1440
|
+
} catch (e) {
|
|
1441
|
+
}
|
|
1442
|
+
}
|
|
1443
|
+
}
|
|
1444
|
+
async remove(key, nuxtApp) {
|
|
1445
|
+
const prefixedKey = "cache:" + key;
|
|
1446
|
+
if (import.meta.client) {
|
|
1447
|
+
sessionStorage.removeItem(prefixedKey);
|
|
1448
|
+
}
|
|
1449
|
+
if (import.meta.server) {
|
|
1450
|
+
try {
|
|
1451
|
+
const sessionId = await this.getSessionId(nuxtApp);
|
|
1452
|
+
const sessionData = CSessionCache.storage.get(sessionId);
|
|
1453
|
+
if (sessionData) {
|
|
1454
|
+
sessionData.delete(prefixedKey);
|
|
1455
|
+
}
|
|
1456
|
+
if (nuxtApp) {
|
|
1457
|
+
const payload = nuxtApp.payload?.data || nuxtApp.ssrContext?.payload?.data;
|
|
1458
|
+
if (payload && payload[prefixedKey]) {
|
|
1459
|
+
delete payload[prefixedKey];
|
|
1460
|
+
}
|
|
1461
|
+
}
|
|
1462
|
+
} catch (e) {
|
|
1463
|
+
}
|
|
1464
|
+
}
|
|
1465
|
+
}
|
|
1466
|
+
async removeByPrefix(prefix, nuxtApp) {
|
|
1467
|
+
const fullPrefix = "cache:" + prefix;
|
|
1468
|
+
if (import.meta.client) {
|
|
1469
|
+
const keysToDelete = [];
|
|
1470
|
+
for (let i = 0; i < sessionStorage.length; i++) {
|
|
1471
|
+
const key = sessionStorage.key(i);
|
|
1472
|
+
if (key && key.startsWith(fullPrefix)) {
|
|
1473
|
+
keysToDelete.push(key);
|
|
1474
|
+
}
|
|
1475
|
+
}
|
|
1476
|
+
for (const key of keysToDelete) {
|
|
1477
|
+
sessionStorage.removeItem(key);
|
|
1478
|
+
}
|
|
1479
|
+
}
|
|
1480
|
+
if (import.meta.server) {
|
|
1481
|
+
try {
|
|
1482
|
+
const sessionId = await this.getSessionId(nuxtApp);
|
|
1483
|
+
const sessionData = CSessionCache.storage.get(sessionId);
|
|
1484
|
+
if (sessionData) {
|
|
1485
|
+
const keysToDelete = [];
|
|
1486
|
+
for (const key of sessionData.keys()) {
|
|
1487
|
+
if (key.startsWith(fullPrefix)) {
|
|
1488
|
+
keysToDelete.push(key);
|
|
1489
|
+
}
|
|
1490
|
+
}
|
|
1491
|
+
for (const key of keysToDelete) {
|
|
1492
|
+
sessionData.delete(key);
|
|
1493
|
+
}
|
|
1494
|
+
}
|
|
1495
|
+
if (nuxtApp) {
|
|
1496
|
+
const payload = nuxtApp.payload?.data || nuxtApp.ssrContext?.payload?.data;
|
|
1497
|
+
if (payload) {
|
|
1498
|
+
for (const key in payload) {
|
|
1499
|
+
if (key.startsWith(fullPrefix)) {
|
|
1500
|
+
delete payload[key];
|
|
1501
|
+
}
|
|
1502
|
+
}
|
|
1503
|
+
}
|
|
1504
|
+
}
|
|
1505
|
+
} catch (e) {
|
|
1506
|
+
}
|
|
1507
|
+
}
|
|
1508
|
+
}
|
|
1509
|
+
async getRemainingTime(key, nuxtApp) {
|
|
1510
|
+
const prefixedKey = "cache:" + key;
|
|
1511
|
+
if (import.meta.client) {
|
|
1512
|
+
const entryStr = sessionStorage.getItem(prefixedKey);
|
|
1513
|
+
if (!entryStr) return null;
|
|
1514
|
+
try {
|
|
1515
|
+
const entry = JSON.parse(entryStr);
|
|
1516
|
+
return Math.max(0, entry.timestamp + entry.lifetime - Date.now());
|
|
1517
|
+
} catch (e) {
|
|
1518
|
+
return null;
|
|
1519
|
+
}
|
|
1520
|
+
}
|
|
1521
|
+
if (import.meta.server) {
|
|
1522
|
+
const sessionId = await this.getSessionId(nuxtApp);
|
|
1523
|
+
const sessionData = CSessionCache.storage.get(sessionId);
|
|
1524
|
+
if (!sessionData) return null;
|
|
1525
|
+
const entry = sessionData.get(prefixedKey);
|
|
1526
|
+
if (!entry) return null;
|
|
1527
|
+
return Math.max(0, entry.timestamp + entry.lifetime - Date.now());
|
|
1528
|
+
}
|
|
1529
|
+
return null;
|
|
1530
|
+
}
|
|
1531
|
+
async cleanupExpired() {
|
|
1532
|
+
const prefix = "cache:";
|
|
1533
|
+
const now = Date.now();
|
|
1534
|
+
if (import.meta.client) {
|
|
1535
|
+
const keysToDelete = [];
|
|
1536
|
+
for (let i = 0; i < sessionStorage.length; i++) {
|
|
1537
|
+
const key = sessionStorage.key(i);
|
|
1538
|
+
if (key && key.startsWith(prefix)) {
|
|
1539
|
+
const stored = sessionStorage.getItem(key);
|
|
1540
|
+
if (stored) {
|
|
1541
|
+
try {
|
|
1542
|
+
const entry = JSON.parse(stored);
|
|
1543
|
+
if (now - entry.timestamp > entry.lifetime) {
|
|
1544
|
+
keysToDelete.push(key);
|
|
1545
|
+
}
|
|
1546
|
+
} catch (e) {
|
|
1547
|
+
keysToDelete.push(key);
|
|
1548
|
+
}
|
|
1549
|
+
}
|
|
1550
|
+
}
|
|
1551
|
+
}
|
|
1552
|
+
for (const key of keysToDelete) {
|
|
1553
|
+
sessionStorage.removeItem(key);
|
|
1554
|
+
}
|
|
1555
|
+
}
|
|
1556
|
+
if (import.meta.server) {
|
|
1557
|
+
const sessionsToDelete = [];
|
|
1558
|
+
for (const [sessionId, sessionData] of CSessionCache.storage.entries()) {
|
|
1559
|
+
const keysToDelete = [];
|
|
1560
|
+
for (const [key, entry] of sessionData.entries()) {
|
|
1561
|
+
if (key.startsWith(prefix)) {
|
|
1562
|
+
if (now - entry.timestamp > entry.lifetime) {
|
|
1563
|
+
keysToDelete.push(key);
|
|
1564
|
+
}
|
|
1565
|
+
}
|
|
1566
|
+
}
|
|
1567
|
+
for (const key of keysToDelete) {
|
|
1568
|
+
sessionData.delete(key);
|
|
1569
|
+
}
|
|
1570
|
+
if (sessionData.size === 0) {
|
|
1571
|
+
sessionsToDelete.push(sessionId);
|
|
1572
|
+
}
|
|
1573
|
+
}
|
|
1574
|
+
for (const sessionId of sessionsToDelete) {
|
|
1575
|
+
CSessionCache.storage.delete(sessionId);
|
|
1576
|
+
}
|
|
1577
|
+
}
|
|
1578
|
+
}
|
|
1579
|
+
}
|
|
1580
|
+
|
|
1581
|
+
class CacheProviderFactory {
|
|
1582
|
+
static getProvider(strategy) {
|
|
1583
|
+
switch (strategy) {
|
|
1584
|
+
case ECacheStrategy.Application:
|
|
1585
|
+
return CApplicationCache.getInstance();
|
|
1586
|
+
case ECacheStrategy.Session:
|
|
1587
|
+
return CSessionCache.getInstance();
|
|
1588
|
+
case ECacheStrategy.Memory:
|
|
1589
|
+
return CMemoryCache.getInstance();
|
|
1590
|
+
case ECacheStrategy.LocalStorage:
|
|
1591
|
+
return CLocalStorageCache.getInstance();
|
|
1592
|
+
case ECacheStrategy.IndexedDB:
|
|
1593
|
+
return CIndexedDBCache.getInstance();
|
|
1594
|
+
case ECacheStrategy.Cookie:
|
|
1595
|
+
return CCookieCache.getInstance();
|
|
1596
|
+
default:
|
|
1597
|
+
return null;
|
|
1598
|
+
}
|
|
1599
|
+
}
|
|
1600
|
+
}
|
|
1601
|
+
|
|
1602
|
+
class RequestProvider {
|
|
1603
|
+
cacheProvider = null;
|
|
1604
|
+
cacheLifetime = 60 * 60 * 1e3;
|
|
1605
|
+
deduplicate = true;
|
|
1606
|
+
cacheKey = "";
|
|
1607
|
+
static requestQueue = [];
|
|
1608
|
+
static executing = false;
|
|
1609
|
+
static requestsInFlight = /* @__PURE__ */ new Map();
|
|
1610
|
+
lastUrl;
|
|
1611
|
+
lastOptions;
|
|
1612
|
+
dataReceivedCallback;
|
|
1613
|
+
constructor(provider, lifetime, deduplicate) {
|
|
1614
|
+
if (provider) this.setCacheProvider(provider);
|
|
1615
|
+
if (lifetime) this.setCacheLifetime(lifetime);
|
|
1616
|
+
if (deduplicate !== void 0) this.setDeduplicate(deduplicate);
|
|
1617
|
+
}
|
|
1618
|
+
setCacheProvider(provider) {
|
|
1619
|
+
if (!provider) {
|
|
1620
|
+
console.warn("RequestProvider: provider is required");
|
|
1621
|
+
}
|
|
1622
|
+
if (provider instanceof ACacheProvider) this.cacheProvider = provider;
|
|
1623
|
+
else this.cacheProvider = CacheProviderFactory.getProvider(provider);
|
|
1624
|
+
}
|
|
1625
|
+
setCacheLifetime(lifetime) {
|
|
1626
|
+
this.cacheLifetime = lifetime;
|
|
1627
|
+
}
|
|
1628
|
+
setDeduplicate(deduplicate) {
|
|
1629
|
+
this.deduplicate = deduplicate;
|
|
1630
|
+
}
|
|
1631
|
+
onDataReceived(callback) {
|
|
1632
|
+
this.dataReceivedCallback = callback;
|
|
1633
|
+
}
|
|
1634
|
+
hasLastUrl() {
|
|
1635
|
+
return !!this.lastUrl;
|
|
1636
|
+
}
|
|
1637
|
+
async refresh(hardRefresh = false) {
|
|
1638
|
+
if (!this.dataReceivedCallback) {
|
|
1639
|
+
return null;
|
|
1640
|
+
}
|
|
1641
|
+
if (!this.lastUrl) {
|
|
1642
|
+
console.warn("[RequestProvider] refresh called before any request was made.");
|
|
1643
|
+
return null;
|
|
1644
|
+
}
|
|
1645
|
+
const options = { ...this.lastOptions };
|
|
1646
|
+
if (hardRefresh) {
|
|
1647
|
+
options.disableCache = true;
|
|
1648
|
+
}
|
|
1649
|
+
return this.request(this.lastUrl, options);
|
|
1650
|
+
}
|
|
1651
|
+
getUniqueKey(url, options) {
|
|
1652
|
+
if (options?.key) return options.key;
|
|
1653
|
+
const { query, body, headers, method } = options || {};
|
|
1654
|
+
const stableStringify = (val) => JSON.stringify(val === void 0 ? null : val);
|
|
1655
|
+
return [
|
|
1656
|
+
url,
|
|
1657
|
+
stableStringify(query || {}),
|
|
1658
|
+
stableStringify(body || null),
|
|
1659
|
+
stableStringify(headers || {}),
|
|
1660
|
+
method || "GET"
|
|
1661
|
+
].join("|");
|
|
1662
|
+
}
|
|
1663
|
+
registerRequest(url, options) {
|
|
1664
|
+
const uniqueKey = this.getUniqueKey(url, options);
|
|
1665
|
+
const shouldDeduplicate = options?.deduplicate ?? this.deduplicate;
|
|
1666
|
+
if (shouldDeduplicate && RequestProvider.requestsInFlight.has(uniqueKey)) {
|
|
1667
|
+
const inflightPromise = RequestProvider.requestsInFlight.get(uniqueKey);
|
|
1668
|
+
return inflightPromise.then((result) => {
|
|
1669
|
+
this.lastUrl = url;
|
|
1670
|
+
this.lastOptions = options;
|
|
1671
|
+
if (this.dataReceivedCallback) {
|
|
1672
|
+
this.dataReceivedCallback(result);
|
|
1673
|
+
}
|
|
1674
|
+
return result;
|
|
1675
|
+
});
|
|
1676
|
+
}
|
|
1677
|
+
const promise = new Promise((resolve, reject) => {
|
|
1678
|
+
RequestProvider.requestQueue.push({
|
|
1679
|
+
url,
|
|
1680
|
+
options,
|
|
1681
|
+
instance: this,
|
|
1682
|
+
resolve,
|
|
1683
|
+
reject
|
|
1684
|
+
});
|
|
1685
|
+
RequestProvider.executeAll();
|
|
1686
|
+
}).finally(() => {
|
|
1687
|
+
if (shouldDeduplicate) {
|
|
1688
|
+
RequestProvider.requestsInFlight.delete(uniqueKey);
|
|
1689
|
+
}
|
|
1690
|
+
});
|
|
1691
|
+
if (shouldDeduplicate) {
|
|
1692
|
+
RequestProvider.requestsInFlight.set(uniqueKey, promise);
|
|
1693
|
+
}
|
|
1694
|
+
return promise;
|
|
1695
|
+
}
|
|
1696
|
+
static executeAll() {
|
|
1697
|
+
if (RequestProvider.executing) return;
|
|
1698
|
+
if (RequestProvider.requestQueue.length === 0) return;
|
|
1699
|
+
RequestProvider.executing = true;
|
|
1700
|
+
const queue = [...RequestProvider.requestQueue];
|
|
1701
|
+
RequestProvider.requestQueue = [];
|
|
1702
|
+
queue.forEach((queuedRequest) => {
|
|
1703
|
+
queuedRequest.instance.request(queuedRequest.url, queuedRequest.options).then((result) => queuedRequest.resolve?.(result)).catch((error) => queuedRequest.reject?.(error instanceof Error ? error : new Error(String(error))));
|
|
1704
|
+
});
|
|
1705
|
+
Promise.resolve().then(() => {
|
|
1706
|
+
RequestProvider.executing = false;
|
|
1707
|
+
if (RequestProvider.requestQueue.length > 0) {
|
|
1708
|
+
RequestProvider.executeAll();
|
|
1709
|
+
}
|
|
1710
|
+
});
|
|
1711
|
+
}
|
|
1712
|
+
async request(url, options) {
|
|
1713
|
+
const { cacheStrategy, lifetime, query, body, headers, method } = options || {};
|
|
1714
|
+
const uniqueKey = this.getUniqueKey(url, options);
|
|
1715
|
+
const nuxtApp = options?.nuxtApp;
|
|
1716
|
+
let serverHeaders = {};
|
|
1717
|
+
if (nuxtApp && import.meta.server) {
|
|
1718
|
+
const event = nuxtApp.ssrContext?.event;
|
|
1719
|
+
if (event) {
|
|
1720
|
+
const { getRequestHeader } = await import('h3');
|
|
1721
|
+
const cookieHeader = getRequestHeader(event, "cookie");
|
|
1722
|
+
if (cookieHeader) {
|
|
1723
|
+
serverHeaders = { cookie: cookieHeader };
|
|
1724
|
+
}
|
|
1725
|
+
}
|
|
1726
|
+
}
|
|
1727
|
+
const provider = cacheStrategy ? CacheProviderFactory.getProvider(cacheStrategy) : this.cacheProvider;
|
|
1728
|
+
const cacheLifetime = lifetime || this.cacheLifetime;
|
|
1729
|
+
const requestMethod = method || "GET";
|
|
1730
|
+
const isGetRequest = requestMethod === "GET";
|
|
1731
|
+
if (provider && isGetRequest && !options?.disableCache) {
|
|
1732
|
+
const cached = await provider.get(uniqueKey, nuxtApp);
|
|
1733
|
+
if (cached) {
|
|
1734
|
+
console.log(`[RequestProvider] CACHE HIT: ${url}`);
|
|
1735
|
+
this.lastUrl = url;
|
|
1736
|
+
this.lastOptions = options;
|
|
1737
|
+
if (this.dataReceivedCallback) {
|
|
1738
|
+
this.dataReceivedCallback(cached);
|
|
1739
|
+
}
|
|
1740
|
+
return cached;
|
|
1741
|
+
}
|
|
1742
|
+
console.log(`[RequestProvider] CACHE MISS: ${url}`);
|
|
1743
|
+
}
|
|
1744
|
+
const fetchOptions = {
|
|
1745
|
+
method: requestMethod,
|
|
1746
|
+
body,
|
|
1747
|
+
headers: { ...headers, ...serverHeaders },
|
|
1748
|
+
query
|
|
1749
|
+
};
|
|
1750
|
+
const responseData = await $fetch(url, fetchOptions);
|
|
1751
|
+
if (provider && cacheLifetime && responseData && isGetRequest) {
|
|
1752
|
+
await provider.set(uniqueKey, responseData, cacheLifetime, nuxtApp);
|
|
1753
|
+
}
|
|
1754
|
+
this.lastUrl = url;
|
|
1755
|
+
this.lastOptions = options;
|
|
1756
|
+
if (this.dataReceivedCallback) {
|
|
1757
|
+
this.dataReceivedCallback(responseData);
|
|
1758
|
+
}
|
|
1759
|
+
return responseData;
|
|
1760
|
+
}
|
|
1761
|
+
}
|
|
1762
|
+
|
|
1763
|
+
class CAPIFlatClientDataProvider extends CFlatClientDataProvider {
|
|
1764
|
+
apiUrl = ref("");
|
|
1765
|
+
contextKey = ref("");
|
|
1766
|
+
initialLoad = ref(true);
|
|
1767
|
+
requestProvider = new RequestProvider();
|
|
1768
|
+
cacheStrategy = ref(null);
|
|
1769
|
+
cacheLifetime = ref(0);
|
|
1770
|
+
refreshOnMutation = ref(void 0);
|
|
1771
|
+
constructor(options) {
|
|
1772
|
+
super(options);
|
|
1773
|
+
if (options?.cacheStrategy) this.cacheStrategy.value = options.cacheStrategy;
|
|
1774
|
+
if (options?.cacheLifetime) this.cacheLifetime.value = options.cacheLifetime;
|
|
1775
|
+
if (options?.refreshOnMutation !== void 0) this.refreshOnMutation.value = options.refreshOnMutation;
|
|
1776
|
+
this.requestProvider.onDataReceived((data) => {
|
|
1777
|
+
if (data) {
|
|
1778
|
+
this.setData(data.rows || data);
|
|
1779
|
+
}
|
|
1780
|
+
});
|
|
1781
|
+
}
|
|
1782
|
+
setContextKey(key) {
|
|
1783
|
+
this.contextKey.value = key;
|
|
1784
|
+
this.requestProvider.cacheKey = key;
|
|
1785
|
+
if (this.cacheStrategy.value) this.requestProvider.setCacheProvider(this.cacheStrategy.value);
|
|
1786
|
+
if (this.cacheLifetime.value) this.requestProvider.setCacheLifetime(this.cacheLifetime.value);
|
|
1787
|
+
}
|
|
1788
|
+
async refresh(hardRefresh = false) {
|
|
1789
|
+
await this.refreshData({ disableCache: hardRefresh });
|
|
1790
|
+
}
|
|
1791
|
+
async refreshData(options) {
|
|
1792
|
+
if (!this.requestProvider.hasLastUrl()) {
|
|
1793
|
+
await this._initialFetch(options?.disableCache ?? false);
|
|
1794
|
+
return;
|
|
1795
|
+
}
|
|
1796
|
+
this.loading.value = true;
|
|
1797
|
+
try {
|
|
1798
|
+
await this.requestProvider.refresh(options?.disableCache ?? false);
|
|
1799
|
+
} finally {
|
|
1800
|
+
this.loading.value = false;
|
|
1801
|
+
}
|
|
1802
|
+
}
|
|
1803
|
+
async _initialFetch(disableCache = false) {
|
|
1804
|
+
if (!this.SSR.value && import.meta.server) return;
|
|
1805
|
+
const fetcher = async () => {
|
|
1806
|
+
const promise = this.requestProvider.registerRequest(this.apiUrl.value, {
|
|
1807
|
+
deduplicate: this.deduplicate.value,
|
|
1808
|
+
nuxtApp: this.nuxtApp,
|
|
1809
|
+
disableCache
|
|
1810
|
+
});
|
|
1811
|
+
if (this.SSR.value && import.meta.server) return await promise;
|
|
1812
|
+
return promise;
|
|
1813
|
+
};
|
|
1814
|
+
const key = `${this.contextKey.value}`;
|
|
1815
|
+
if (this.contextKey.value && this.initialLoad.value && !disableCache) {
|
|
1816
|
+
const { data } = getNuxtData(key, this.nuxtApp);
|
|
1817
|
+
if (data.value) {
|
|
1818
|
+
const result = data.value;
|
|
1819
|
+
this.setData(result.rows);
|
|
1820
|
+
this.initialLoad.value = false;
|
|
1821
|
+
this.loading.value = false;
|
|
1822
|
+
return;
|
|
1823
|
+
}
|
|
1824
|
+
}
|
|
1825
|
+
if (import.meta.server && this.contextKey.value) {
|
|
1826
|
+
if (disableCache) {
|
|
1827
|
+
clearNuxtDataKey(key, this.nuxtApp);
|
|
1828
|
+
}
|
|
1829
|
+
const { data } = await getAsyncData(key, fetcher, this.nuxtApp);
|
|
1830
|
+
if (data.value) {
|
|
1831
|
+
const result = data.value;
|
|
1832
|
+
this.setData(result.rows);
|
|
1833
|
+
this.initialLoad.value = false;
|
|
1834
|
+
this.loading.value = false;
|
|
1835
|
+
return;
|
|
1836
|
+
}
|
|
1837
|
+
}
|
|
1838
|
+
if (!this.SSR.value) {
|
|
1839
|
+
const promise = this.requestProvider.registerRequest(this.apiUrl.value, {
|
|
1840
|
+
deduplicate: this.deduplicate.value,
|
|
1841
|
+
nuxtApp: this.nuxtApp,
|
|
1842
|
+
disableCache
|
|
1843
|
+
});
|
|
1844
|
+
promise.then(() => {
|
|
1845
|
+
this.initialLoad.value = false;
|
|
1846
|
+
this.loading.value = false;
|
|
1847
|
+
}).catch(() => {
|
|
1848
|
+
this.initialLoad.value = false;
|
|
1849
|
+
this.loading.value = false;
|
|
1850
|
+
});
|
|
1851
|
+
return;
|
|
1852
|
+
}
|
|
1853
|
+
await fetcher();
|
|
1854
|
+
this.initialLoad.value = false;
|
|
1855
|
+
this.loading.value = false;
|
|
1856
|
+
}
|
|
1857
|
+
async setAPIUrl(url) {
|
|
1858
|
+
this.loading.value = true;
|
|
1859
|
+
this.apiUrl.value = url;
|
|
1860
|
+
this.setContextKey(url);
|
|
1861
|
+
if (this.allData.value.length == 0)
|
|
1862
|
+
await this.refreshData();
|
|
1863
|
+
}
|
|
1864
|
+
async create(item) {
|
|
1865
|
+
if (!this.apiUrl.value) return;
|
|
1866
|
+
const result = await this.requestProvider.registerRequest(this.apiUrl.value, {
|
|
1867
|
+
method: "POST",
|
|
1868
|
+
body: item,
|
|
1869
|
+
nuxtApp: this.nuxtApp
|
|
1870
|
+
});
|
|
1871
|
+
if (this.refreshOnMutation.value) {
|
|
1872
|
+
await this.refresh(true);
|
|
1873
|
+
} else {
|
|
1874
|
+
if (result && result.item) {
|
|
1875
|
+
this.allData.value.push(result.item);
|
|
1876
|
+
this.loadPageData();
|
|
1877
|
+
await this.refresh(true);
|
|
1878
|
+
}
|
|
1879
|
+
if (this.requestProvider.cacheProvider) {
|
|
1880
|
+
await this.requestProvider.cacheProvider.removeByPrefix(this.apiUrl.value);
|
|
1881
|
+
}
|
|
1882
|
+
if (this.contextKey.value) {
|
|
1883
|
+
clearNuxtDataKey(this.contextKey.value, this.nuxtApp);
|
|
1884
|
+
}
|
|
1885
|
+
}
|
|
1886
|
+
}
|
|
1887
|
+
async update(item) {
|
|
1888
|
+
if (!this.apiUrl.value) return;
|
|
1889
|
+
const result = await this.requestProvider.registerRequest(this.apiUrl.value, {
|
|
1890
|
+
method: "PUT",
|
|
1891
|
+
body: item,
|
|
1892
|
+
nuxtApp: this.nuxtApp
|
|
1893
|
+
});
|
|
1894
|
+
if (this.refreshOnMutation.value) {
|
|
1895
|
+
await this.refresh(true);
|
|
1896
|
+
} else {
|
|
1897
|
+
const index = this.allData.value.findIndex((row) => row["id"] === item["id"]);
|
|
1898
|
+
if (index !== -1) {
|
|
1899
|
+
if (result && result.item) {
|
|
1900
|
+
this.allData.value[index] = result.item;
|
|
1901
|
+
} else {
|
|
1902
|
+
this.allData.value[index] = { ...this.allData.value[index], ...item };
|
|
1903
|
+
}
|
|
1904
|
+
this.loadPageData();
|
|
1905
|
+
}
|
|
1906
|
+
if (this.requestProvider.cacheProvider) {
|
|
1907
|
+
await this.requestProvider.cacheProvider.removeByPrefix(this.apiUrl.value);
|
|
1908
|
+
}
|
|
1909
|
+
if (this.contextKey.value) {
|
|
1910
|
+
clearNuxtDataKey(this.contextKey.value, this.nuxtApp);
|
|
1911
|
+
}
|
|
1912
|
+
}
|
|
1913
|
+
}
|
|
1914
|
+
async delete(items) {
|
|
1915
|
+
if (!this.apiUrl.value) return;
|
|
1916
|
+
if (!items || items.length === 0) return;
|
|
1917
|
+
const ids = items.map((i) => i.id);
|
|
1918
|
+
await this.requestProvider.registerRequest(this.apiUrl.value, {
|
|
1919
|
+
method: "DELETE",
|
|
1920
|
+
body: { id: ids },
|
|
1921
|
+
nuxtApp: this.nuxtApp
|
|
1922
|
+
});
|
|
1923
|
+
if (this.refreshOnMutation.value) {
|
|
1924
|
+
await this.refresh(true);
|
|
1925
|
+
} else {
|
|
1926
|
+
const idsToDelete = new Set(ids);
|
|
1927
|
+
this.allData.value = this.allData.value.filter((row) => !idsToDelete.has(row["id"]));
|
|
1928
|
+
if (this.requestProvider.cacheProvider) {
|
|
1929
|
+
await this.requestProvider.cacheProvider.removeByPrefix(this.apiUrl.value);
|
|
1930
|
+
}
|
|
1931
|
+
if (this.contextKey.value) {
|
|
1932
|
+
clearNuxtDataKey(this.contextKey.value, this.nuxtApp);
|
|
1933
|
+
}
|
|
1934
|
+
}
|
|
1935
|
+
}
|
|
1936
|
+
}
|
|
1937
|
+
|
|
1938
|
+
class CFlatServerDataProvider extends ADataProvider {
|
|
1939
|
+
pageDataHandler = ref((currentPage, pageSize, filter, sortList) => {
|
|
1940
|
+
return {
|
|
1941
|
+
rows: [],
|
|
1942
|
+
rowCount: 0
|
|
1943
|
+
};
|
|
1944
|
+
});
|
|
1945
|
+
contextKey = ref("");
|
|
1946
|
+
initialLoad = ref(true);
|
|
1947
|
+
constructor(options) {
|
|
1948
|
+
super(options);
|
|
1949
|
+
}
|
|
1950
|
+
setContextKey(key) {
|
|
1951
|
+
this.contextKey.value = key;
|
|
1952
|
+
}
|
|
1953
|
+
async setPageDataHandler(handler) {
|
|
1954
|
+
this.pageDataHandler.value = handler;
|
|
1955
|
+
await this.loadPageData();
|
|
1956
|
+
}
|
|
1957
|
+
async loadPageData(options) {
|
|
1958
|
+
if (!this.pageDataHandler.value || !this.SSR.value && import.meta.server) return;
|
|
1959
|
+
const stableStringify = (val) => JSON.stringify(val === void 0 ? "" : val);
|
|
1960
|
+
const key = [
|
|
1961
|
+
this.contextKey.value,
|
|
1962
|
+
this.currentPage.value,
|
|
1963
|
+
this.pageSize.value,
|
|
1964
|
+
stableStringify(this.filter.value),
|
|
1965
|
+
stableStringify(this.sortList.value)
|
|
1966
|
+
].join("-");
|
|
1967
|
+
const fetcher = async () => await this.pageDataHandler.value(this.currentPage.value, this.pageSize.value, this.filter.value, this.sortList.value, options);
|
|
1968
|
+
if (!options?.disableCache && this.SSR.value && this.contextKey.value && this.initialLoad.value) {
|
|
1969
|
+
const { data } = getNuxtData(key, this.nuxtApp);
|
|
1970
|
+
if (data.value) {
|
|
1971
|
+
const result = data.value;
|
|
1972
|
+
this.pageData.value = result.rows;
|
|
1973
|
+
this.rowCount.value = result.rowCount;
|
|
1974
|
+
this.initialLoad.value = false;
|
|
1975
|
+
this.loading.value = false;
|
|
1976
|
+
return;
|
|
1977
|
+
}
|
|
1978
|
+
}
|
|
1979
|
+
if (this.SSR.value && this.contextKey.value && !options?.disableCache && (import.meta.server || this.initialLoad.value)) {
|
|
1980
|
+
this.loading.value = true;
|
|
1981
|
+
const { data } = await getAsyncData(key, fetcher, this.nuxtApp);
|
|
1982
|
+
if (data.value) {
|
|
1983
|
+
const result = data.value;
|
|
1984
|
+
this.pageData.value = result.rows;
|
|
1985
|
+
this.rowCount.value = result.rowCount;
|
|
1986
|
+
this.initialLoad.value = false;
|
|
1987
|
+
this.loading.value = false;
|
|
1988
|
+
return;
|
|
1989
|
+
}
|
|
1990
|
+
}
|
|
1991
|
+
if (!this.SSR.value) {
|
|
1992
|
+
onNuxtReadyCallback(() => {
|
|
1993
|
+
this.loading.value = true;
|
|
1994
|
+
fetcher().then((returnedData2) => {
|
|
1995
|
+
this.pageData.value = returnedData2.rows;
|
|
1996
|
+
this.rowCount.value = returnedData2.rowCount;
|
|
1997
|
+
this.initialLoad.value = false;
|
|
1998
|
+
this.loading.value = false;
|
|
1999
|
+
}).catch(() => {
|
|
2000
|
+
this.initialLoad.value = false;
|
|
2001
|
+
this.loading.value = false;
|
|
2002
|
+
});
|
|
2003
|
+
});
|
|
2004
|
+
return;
|
|
2005
|
+
}
|
|
2006
|
+
this.loading.value = true;
|
|
2007
|
+
const returnedData = await fetcher();
|
|
2008
|
+
this.pageData.value = returnedData.rows;
|
|
2009
|
+
this.rowCount.value = returnedData.rowCount;
|
|
2010
|
+
this.initialLoad.value = false;
|
|
2011
|
+
this.loading.value = false;
|
|
2012
|
+
}
|
|
2013
|
+
async refresh(hardRefresh = false) {
|
|
2014
|
+
await this.loadPageData(hardRefresh ? { disableCache: true } : void 0);
|
|
2015
|
+
}
|
|
2016
|
+
}
|
|
2017
|
+
|
|
2018
|
+
class CAPIFlatServerDataProvider extends CFlatServerDataProvider {
|
|
2019
|
+
apiUrl = ref("");
|
|
2020
|
+
requestProvider = new RequestProvider();
|
|
2021
|
+
cacheStrategy = ref(null);
|
|
2022
|
+
cacheLifetime = ref(0);
|
|
2023
|
+
refreshOnMutation = ref(true);
|
|
2024
|
+
// Default true for server
|
|
2025
|
+
constructor(options) {
|
|
2026
|
+
super(options);
|
|
2027
|
+
if (options?.cacheStrategy) this.cacheStrategy.value = options.cacheStrategy;
|
|
2028
|
+
if (options?.cacheLifetime) this.cacheLifetime.value = options.cacheLifetime;
|
|
2029
|
+
if (options?.refreshOnMutation !== void 0) this.refreshOnMutation.value = options.refreshOnMutation;
|
|
2030
|
+
this.requestProvider.onDataReceived((data) => {
|
|
2031
|
+
if (data) {
|
|
2032
|
+
this.pageData.value = data.rows || data;
|
|
2033
|
+
if (data.rowCount !== void 0) {
|
|
2034
|
+
this.rowCount.value = data.rowCount;
|
|
2035
|
+
}
|
|
2036
|
+
}
|
|
2037
|
+
});
|
|
2038
|
+
}
|
|
2039
|
+
async refresh(hardRefresh = false) {
|
|
2040
|
+
if (hardRefresh && this.requestProvider.cacheProvider) {
|
|
2041
|
+
await this.requestProvider.cacheProvider.removeByPrefix(this.apiUrl.value);
|
|
2042
|
+
}
|
|
2043
|
+
this.loading.value = true;
|
|
2044
|
+
try {
|
|
2045
|
+
await this.loadPageData(hardRefresh ? { disableCache: true } : void 0);
|
|
2046
|
+
} finally {
|
|
2047
|
+
this.loading.value = false;
|
|
2048
|
+
}
|
|
2049
|
+
}
|
|
2050
|
+
async refreshData(options) {
|
|
2051
|
+
await this.refresh(options?.disableCache ?? false);
|
|
2052
|
+
}
|
|
2053
|
+
async setAPIUrl(url) {
|
|
2054
|
+
this.apiUrl.value = url;
|
|
2055
|
+
this.setContextKey(url);
|
|
2056
|
+
if (this.cacheStrategy.value) this.requestProvider.setCacheProvider(this.cacheStrategy.value);
|
|
2057
|
+
if (this.cacheLifetime.value) this.requestProvider.setCacheLifetime(this.cacheLifetime.value);
|
|
2058
|
+
await this.setPageDataHandler(
|
|
2059
|
+
async (currentPage, pageSize, filter, sortList, options) => {
|
|
2060
|
+
return await this.requestProvider.registerRequest(this.apiUrl.value, {
|
|
2061
|
+
query: {
|
|
2062
|
+
pageNumber: currentPage,
|
|
2063
|
+
pageSize,
|
|
2064
|
+
filter,
|
|
2065
|
+
sortList
|
|
2066
|
+
},
|
|
2067
|
+
deduplicate: this.deduplicate.value,
|
|
2068
|
+
nuxtApp: this.nuxtApp,
|
|
2069
|
+
disableCache: options?.disableCache
|
|
2070
|
+
});
|
|
2071
|
+
}
|
|
2072
|
+
);
|
|
2073
|
+
}
|
|
2074
|
+
async delete(items) {
|
|
2075
|
+
if (!this.apiUrl.value) return;
|
|
2076
|
+
if (!items || items.length === 0) return;
|
|
2077
|
+
const ids = items.map((i) => i.id);
|
|
2078
|
+
await this.requestProvider.registerRequest(this.apiUrl.value, {
|
|
2079
|
+
method: "DELETE",
|
|
2080
|
+
body: { id: ids },
|
|
2081
|
+
nuxtApp: this.nuxtApp
|
|
2082
|
+
});
|
|
2083
|
+
if (this.refreshOnMutation.value !== false) {
|
|
2084
|
+
if (this.requestProvider.cacheProvider) {
|
|
2085
|
+
await this.requestProvider.cacheProvider.removeByPrefix(this.apiUrl.value);
|
|
2086
|
+
}
|
|
2087
|
+
await this.refresh(true);
|
|
2088
|
+
}
|
|
2089
|
+
}
|
|
2090
|
+
}
|
|
2091
|
+
|
|
2092
|
+
class AAPIDataProvider {
|
|
2093
|
+
apiUrl = ref("");
|
|
2094
|
+
cacheStrategy = ref(null);
|
|
2095
|
+
cacheLifetime = ref(60 * 1e3);
|
|
2096
|
+
requestProvider = new RequestProvider();
|
|
2097
|
+
refreshOnMutation = ref(void 0);
|
|
2098
|
+
constructor(options) {
|
|
2099
|
+
if (options?.cacheStrategy) this.cacheStrategy.value = options.cacheStrategy;
|
|
2100
|
+
if (options?.cacheLifetime) this.cacheLifetime.value = options.cacheLifetime;
|
|
2101
|
+
if (options?.refreshOnMutation !== void 0) this.refreshOnMutation.value = options.refreshOnMutation;
|
|
2102
|
+
}
|
|
2103
|
+
}
|
|
2104
|
+
|
|
2105
|
+
const { filterData } = useFilterLogic();
|
|
2106
|
+
class CTreeClientDataProvider extends CFlatClientDataProvider {
|
|
2107
|
+
// Tree configuration
|
|
2108
|
+
parentKey = "parentId";
|
|
2109
|
+
idKey = "id";
|
|
2110
|
+
expandedByDefault = false;
|
|
2111
|
+
paginateBy = "all";
|
|
2112
|
+
// Tree state
|
|
2113
|
+
expandedNodes = ref(/* @__PURE__ */ new Set());
|
|
2114
|
+
// Internal: static tree structure (only rebuilds when data changes)
|
|
2115
|
+
_staticNodes;
|
|
2116
|
+
_nodeMap;
|
|
2117
|
+
_sortedNodeIds;
|
|
2118
|
+
constructor(options) {
|
|
2119
|
+
super(options);
|
|
2120
|
+
if (options?.parentKey) this.parentKey = options.parentKey;
|
|
2121
|
+
if (options?.idKey) this.idKey = options.idKey;
|
|
2122
|
+
if (options?.expandedByDefault) this.expandedByDefault = options.expandedByDefault;
|
|
2123
|
+
if (options?.paginateBy) this.paginateBy = options.paginateBy;
|
|
2124
|
+
this._staticNodes = computed(() => this.buildStaticNodes());
|
|
2125
|
+
this._nodeMap = computed(() => new Map(this._staticNodes.value.map((n) => [n.id, n])));
|
|
2126
|
+
this._sortedNodeIds = computed(() => this.computeSortedIds());
|
|
2127
|
+
watch([this.expandedNodes, this._staticNodes], () => {
|
|
2128
|
+
this.updatePageData();
|
|
2129
|
+
}, { immediate: true });
|
|
2130
|
+
}
|
|
2131
|
+
buildStaticNodes() {
|
|
2132
|
+
const allData = this.allData.value || [];
|
|
2133
|
+
const nodeMap = /* @__PURE__ */ new Map();
|
|
2134
|
+
const childrenMap = /* @__PURE__ */ new Map();
|
|
2135
|
+
allData.forEach((item) => {
|
|
2136
|
+
const id = item[this.idKey];
|
|
2137
|
+
const parentId = item[this.parentKey] || null;
|
|
2138
|
+
nodeMap.set(id, {
|
|
2139
|
+
data: item,
|
|
2140
|
+
id,
|
|
2141
|
+
parentId,
|
|
2142
|
+
depth: 0,
|
|
2143
|
+
hasChildren: false
|
|
2144
|
+
});
|
|
2145
|
+
if (parentId !== null) {
|
|
2146
|
+
if (!childrenMap.has(parentId)) {
|
|
2147
|
+
childrenMap.set(parentId, []);
|
|
2148
|
+
}
|
|
2149
|
+
childrenMap.get(parentId).push(item);
|
|
2150
|
+
}
|
|
2151
|
+
});
|
|
2152
|
+
const calculateDepth = (nodeId, depth = 0) => {
|
|
2153
|
+
const node = nodeMap.get(nodeId);
|
|
2154
|
+
if (!node) return;
|
|
2155
|
+
node.depth = depth;
|
|
2156
|
+
const children = childrenMap.get(nodeId);
|
|
2157
|
+
if (children && children.length > 0) {
|
|
2158
|
+
node.hasChildren = true;
|
|
2159
|
+
children.forEach((child) => {
|
|
2160
|
+
calculateDepth(child[this.idKey], depth + 1);
|
|
2161
|
+
});
|
|
2162
|
+
}
|
|
2163
|
+
};
|
|
2164
|
+
nodeMap.forEach((node) => {
|
|
2165
|
+
if (node.parentId === null) {
|
|
2166
|
+
calculateDepth(node.id, 0);
|
|
2167
|
+
}
|
|
2168
|
+
});
|
|
2169
|
+
return Array.from(nodeMap.values());
|
|
2170
|
+
}
|
|
2171
|
+
// Pre-compute sorted order once (only when data changes)
|
|
2172
|
+
computeSortedIds() {
|
|
2173
|
+
const nodes = this._staticNodes.value;
|
|
2174
|
+
new Map(nodes.map((n) => [n.id, n]));
|
|
2175
|
+
const sortedIds = [];
|
|
2176
|
+
const rootNodes = nodes.filter((n) => n.parentId === null);
|
|
2177
|
+
const childrenMap = /* @__PURE__ */ new Map();
|
|
2178
|
+
nodes.forEach((n) => {
|
|
2179
|
+
if (n.parentId !== null) {
|
|
2180
|
+
if (!childrenMap.has(n.parentId)) {
|
|
2181
|
+
childrenMap.set(n.parentId, []);
|
|
2182
|
+
}
|
|
2183
|
+
childrenMap.get(n.parentId).push(n);
|
|
2184
|
+
}
|
|
2185
|
+
});
|
|
2186
|
+
const collectNodes = (node) => {
|
|
2187
|
+
sortedIds.push(node.id);
|
|
2188
|
+
const children = childrenMap.get(node.id) || [];
|
|
2189
|
+
children.forEach((child) => collectNodes(child));
|
|
2190
|
+
};
|
|
2191
|
+
rootNodes.forEach((root) => collectNodes(root));
|
|
2192
|
+
return sortedIds;
|
|
2193
|
+
}
|
|
2194
|
+
// Fast visibility check and page data update
|
|
2195
|
+
updatePageData() {
|
|
2196
|
+
const nodeMap = this._nodeMap.value;
|
|
2197
|
+
const sortedIds = this._sortedNodeIds.value;
|
|
2198
|
+
const visibleNodes = [];
|
|
2199
|
+
if (this.filter.value && this.filter.value.active) {
|
|
2200
|
+
const { results: filtered, expandedNodes: expandedResults } = filterData(
|
|
2201
|
+
this._staticNodes.value,
|
|
2202
|
+
this.filter.value,
|
|
2203
|
+
{
|
|
2204
|
+
treeOptions: {
|
|
2205
|
+
idKey: this.idKey,
|
|
2206
|
+
parentKey: this.parentKey
|
|
2207
|
+
}
|
|
2208
|
+
}
|
|
2209
|
+
);
|
|
2210
|
+
const expandedSet = expandedResults || /* @__PURE__ */ new Set();
|
|
2211
|
+
for (const node of filtered) {
|
|
2212
|
+
visibleNodes.push({
|
|
2213
|
+
...node,
|
|
2214
|
+
isExpanded: expandedSet.has(node.id)
|
|
2215
|
+
});
|
|
2216
|
+
}
|
|
2217
|
+
} else {
|
|
2218
|
+
for (const id of sortedIds) {
|
|
2219
|
+
const staticNode = nodeMap.get(id);
|
|
2220
|
+
if (!staticNode) continue;
|
|
2221
|
+
if (this.isNodeVisible(staticNode, nodeMap)) {
|
|
2222
|
+
const isExpanded = this.expandedByDefault ? !this.expandedNodes.value.has(id) : this.expandedNodes.value.has(id);
|
|
2223
|
+
visibleNodes.push({
|
|
2224
|
+
...staticNode,
|
|
2225
|
+
isExpanded
|
|
2226
|
+
});
|
|
2227
|
+
}
|
|
2228
|
+
}
|
|
2229
|
+
}
|
|
2230
|
+
const paginatedNodes = this.paginateNodes(visibleNodes);
|
|
2231
|
+
this.pageData.value = paginatedNodes.map((node) => ({
|
|
2232
|
+
...node.data,
|
|
2233
|
+
__treeNode: node
|
|
2234
|
+
}));
|
|
2235
|
+
}
|
|
2236
|
+
isNodeVisible(node, nodeMap) {
|
|
2237
|
+
if (node.parentId === null) return true;
|
|
2238
|
+
let currentId = node.parentId;
|
|
2239
|
+
while (currentId !== null) {
|
|
2240
|
+
const parent = nodeMap.get(currentId);
|
|
2241
|
+
if (!parent) return false;
|
|
2242
|
+
const parentExpanded = this.expandedByDefault ? !this.expandedNodes.value.has(currentId) : this.expandedNodes.value.has(currentId);
|
|
2243
|
+
if (!parentExpanded) return false;
|
|
2244
|
+
currentId = parent.parentId;
|
|
2245
|
+
}
|
|
2246
|
+
return true;
|
|
2247
|
+
}
|
|
2248
|
+
paginateNodes(visible) {
|
|
2249
|
+
const pageSize = this.pageSize.value;
|
|
2250
|
+
const currentPage = this.currentPage.value;
|
|
2251
|
+
if (pageSize <= 0) {
|
|
2252
|
+
this.rowCount.value = visible.length;
|
|
2253
|
+
return visible;
|
|
2254
|
+
}
|
|
2255
|
+
if (this.paginateBy === "root") {
|
|
2256
|
+
const rootNodes = visible.filter((n) => n.parentId === null);
|
|
2257
|
+
const startIndex = (currentPage - 1) * pageSize;
|
|
2258
|
+
const endIndex = startIndex + pageSize;
|
|
2259
|
+
const paginatedRoots = rootNodes.slice(startIndex, endIndex);
|
|
2260
|
+
const paginatedRootIds = new Set(paginatedRoots.map((n) => n.id));
|
|
2261
|
+
const nodeMap = new Map(visible.map((n) => [n.id, n]));
|
|
2262
|
+
const getRootId = (node) => {
|
|
2263
|
+
let current = node;
|
|
2264
|
+
while (current.parentId !== null) {
|
|
2265
|
+
const parent = nodeMap.get(current.parentId);
|
|
2266
|
+
if (!parent) break;
|
|
2267
|
+
current = parent;
|
|
2268
|
+
}
|
|
2269
|
+
return current.id;
|
|
2270
|
+
};
|
|
2271
|
+
const result = visible.filter((node) => paginatedRootIds.has(getRootId(node)));
|
|
2272
|
+
this.rowCount.value = rootNodes.length;
|
|
2273
|
+
return result;
|
|
2274
|
+
} else {
|
|
2275
|
+
const startIndex = (currentPage - 1) * pageSize;
|
|
2276
|
+
const endIndex = startIndex + pageSize;
|
|
2277
|
+
this.rowCount.value = visible.length;
|
|
2278
|
+
return visible.slice(startIndex, endIndex);
|
|
2279
|
+
}
|
|
2280
|
+
}
|
|
2281
|
+
// Override loadPageData
|
|
2282
|
+
async loadPageData() {
|
|
2283
|
+
this.updatePageData();
|
|
2284
|
+
}
|
|
2285
|
+
// Public API
|
|
2286
|
+
get treeNodes() {
|
|
2287
|
+
return this._staticNodes.value.map((node) => ({
|
|
2288
|
+
...node,
|
|
2289
|
+
isExpanded: this.expandedByDefault ? !this.expandedNodes.value.has(node.id) : this.expandedNodes.value.has(node.id)
|
|
2290
|
+
}));
|
|
2291
|
+
}
|
|
2292
|
+
get visibleRows() {
|
|
2293
|
+
const nodeMap = this._nodeMap.value;
|
|
2294
|
+
const sortedIds = this._sortedNodeIds.value;
|
|
2295
|
+
const visibleNodes = [];
|
|
2296
|
+
for (const id of sortedIds) {
|
|
2297
|
+
const staticNode = nodeMap.get(id);
|
|
2298
|
+
if (!staticNode) continue;
|
|
2299
|
+
if (this.isNodeVisible(staticNode, nodeMap)) {
|
|
2300
|
+
visibleNodes.push({
|
|
2301
|
+
...staticNode,
|
|
2302
|
+
isExpanded: this.expandedByDefault ? !this.expandedNodes.value.has(id) : this.expandedNodes.value.has(id)
|
|
2303
|
+
});
|
|
2304
|
+
}
|
|
2305
|
+
}
|
|
2306
|
+
return this.paginateNodes(visibleNodes);
|
|
2307
|
+
}
|
|
2308
|
+
toggleNode(nodeId) {
|
|
2309
|
+
if (this.expandedNodes.value.has(nodeId)) {
|
|
2310
|
+
this.expandedNodes.value.delete(nodeId);
|
|
2311
|
+
} else {
|
|
2312
|
+
this.expandedNodes.value.add(nodeId);
|
|
2313
|
+
}
|
|
2314
|
+
this.expandedNodes.value = new Set(this.expandedNodes.value);
|
|
2315
|
+
}
|
|
2316
|
+
expand(nodeId) {
|
|
2317
|
+
this.expandedNodes.value.add(nodeId);
|
|
2318
|
+
this.expandedNodes.value = new Set(this.expandedNodes.value);
|
|
2319
|
+
}
|
|
2320
|
+
collapse(nodeId) {
|
|
2321
|
+
this.expandedNodes.value.delete(nodeId);
|
|
2322
|
+
this.expandedNodes.value = new Set(this.expandedNodes.value);
|
|
2323
|
+
}
|
|
2324
|
+
expandAll() {
|
|
2325
|
+
const allIds = this._staticNodes.value.filter((n) => n.hasChildren).map((n) => n.id);
|
|
2326
|
+
this.expandedNodes.value = new Set(allIds);
|
|
2327
|
+
}
|
|
2328
|
+
collapseAll() {
|
|
2329
|
+
this.expandedNodes.value = /* @__PURE__ */ new Set();
|
|
2330
|
+
}
|
|
2331
|
+
getNode(nodeId) {
|
|
2332
|
+
const staticNode = this._nodeMap.value.get(nodeId);
|
|
2333
|
+
if (!staticNode) return void 0;
|
|
2334
|
+
return {
|
|
2335
|
+
...staticNode,
|
|
2336
|
+
isExpanded: this.expandedByDefault ? !this.expandedNodes.value.has(nodeId) : this.expandedNodes.value.has(nodeId)
|
|
2337
|
+
};
|
|
2338
|
+
}
|
|
2339
|
+
getChildren(nodeId) {
|
|
2340
|
+
return this.treeNodes.filter((n) => n.parentId === nodeId);
|
|
2341
|
+
}
|
|
2342
|
+
getParent(nodeId) {
|
|
2343
|
+
const node = this.getNode(nodeId);
|
|
2344
|
+
if (!node || node.parentId === null) return void 0;
|
|
2345
|
+
return this.getNode(node.parentId);
|
|
2346
|
+
}
|
|
2347
|
+
}
|
|
2348
|
+
|
|
2349
|
+
class CAPITreeClientDataProvider extends CTreeClientDataProvider {
|
|
2350
|
+
apiUrl = ref("");
|
|
2351
|
+
contextKey = ref("");
|
|
2352
|
+
initialLoad = ref(true);
|
|
2353
|
+
requestProvider = new RequestProvider();
|
|
2354
|
+
cacheStrategy = ref(null);
|
|
2355
|
+
cacheLifetime = ref(0);
|
|
2356
|
+
refreshOnMutation = ref(void 0);
|
|
2357
|
+
constructor(options) {
|
|
2358
|
+
super(options);
|
|
2359
|
+
if (options?.cacheStrategy) this.cacheStrategy.value = options.cacheStrategy;
|
|
2360
|
+
if (options?.cacheLifetime) this.cacheLifetime.value = options.cacheLifetime;
|
|
2361
|
+
if (options?.refreshOnMutation !== void 0) this.refreshOnMutation.value = options.refreshOnMutation;
|
|
2362
|
+
this.requestProvider.onDataReceived((data) => {
|
|
2363
|
+
if (data) {
|
|
2364
|
+
this.setData(data.rows || data);
|
|
2365
|
+
}
|
|
2366
|
+
});
|
|
2367
|
+
}
|
|
2368
|
+
setContextKey(key) {
|
|
2369
|
+
this.contextKey.value = key;
|
|
2370
|
+
this.requestProvider.cacheKey = key;
|
|
2371
|
+
if (this.cacheStrategy.value) this.requestProvider.setCacheProvider(this.cacheStrategy.value);
|
|
2372
|
+
if (this.cacheLifetime.value) this.requestProvider.setCacheLifetime(this.cacheLifetime.value);
|
|
2373
|
+
}
|
|
2374
|
+
async refresh(hardRefresh = false) {
|
|
2375
|
+
await this.refreshData({ disableCache: hardRefresh });
|
|
2376
|
+
}
|
|
2377
|
+
async refreshData(options) {
|
|
2378
|
+
if (!this.requestProvider.hasLastUrl()) {
|
|
2379
|
+
await this._initialFetch(options?.disableCache ?? false);
|
|
2380
|
+
return;
|
|
2381
|
+
}
|
|
2382
|
+
this.loading.value = true;
|
|
2383
|
+
try {
|
|
2384
|
+
await this.requestProvider.refresh(options?.disableCache ?? false);
|
|
2385
|
+
} finally {
|
|
2386
|
+
this.loading.value = false;
|
|
2387
|
+
}
|
|
2388
|
+
}
|
|
2389
|
+
async _initialFetch(disableCache = false) {
|
|
2390
|
+
if (!this.SSR.value && import.meta.server) return;
|
|
2391
|
+
const fetcher = async () => {
|
|
2392
|
+
const promise = this.requestProvider.registerRequest(this.apiUrl.value, {
|
|
2393
|
+
deduplicate: this.deduplicate.value,
|
|
2394
|
+
nuxtApp: this.nuxtApp,
|
|
2395
|
+
disableCache
|
|
2396
|
+
});
|
|
2397
|
+
if (this.SSR.value && import.meta.server) return await promise;
|
|
2398
|
+
return promise;
|
|
2399
|
+
};
|
|
2400
|
+
const key = `${this.contextKey.value}`;
|
|
2401
|
+
if (this.contextKey.value && this.initialLoad.value && !disableCache) {
|
|
2402
|
+
const { data } = getNuxtData(key, this.nuxtApp);
|
|
2403
|
+
if (data.value) {
|
|
2404
|
+
const result = data.value;
|
|
2405
|
+
this.setData(result.rows);
|
|
2406
|
+
this.initialLoad.value = false;
|
|
2407
|
+
this.loading.value = false;
|
|
2408
|
+
return;
|
|
2409
|
+
}
|
|
2410
|
+
}
|
|
2411
|
+
if (import.meta.server && this.contextKey.value) {
|
|
2412
|
+
if (disableCache) {
|
|
2413
|
+
clearNuxtDataKey(key, this.nuxtApp);
|
|
2414
|
+
}
|
|
2415
|
+
const { data } = await getAsyncData(key, fetcher, this.nuxtApp);
|
|
2416
|
+
if (data.value) {
|
|
2417
|
+
const result = data.value;
|
|
2418
|
+
this.setData(result.rows);
|
|
2419
|
+
this.initialLoad.value = false;
|
|
2420
|
+
this.loading.value = false;
|
|
2421
|
+
return;
|
|
2422
|
+
}
|
|
2423
|
+
}
|
|
2424
|
+
if (!this.SSR.value) {
|
|
2425
|
+
const promise = this.requestProvider.registerRequest(this.apiUrl.value, {
|
|
2426
|
+
deduplicate: this.deduplicate.value,
|
|
2427
|
+
nuxtApp: this.nuxtApp,
|
|
2428
|
+
disableCache
|
|
2429
|
+
});
|
|
2430
|
+
promise.then(() => {
|
|
2431
|
+
this.initialLoad.value = false;
|
|
2432
|
+
this.loading.value = false;
|
|
2433
|
+
}).catch(() => {
|
|
2434
|
+
this.initialLoad.value = false;
|
|
2435
|
+
this.loading.value = false;
|
|
2436
|
+
});
|
|
2437
|
+
return;
|
|
2438
|
+
}
|
|
2439
|
+
await fetcher();
|
|
2440
|
+
this.initialLoad.value = false;
|
|
2441
|
+
this.loading.value = false;
|
|
2442
|
+
}
|
|
2443
|
+
async setAPIUrl(url) {
|
|
2444
|
+
this.loading.value = true;
|
|
2445
|
+
this.apiUrl.value = url;
|
|
2446
|
+
this.setContextKey(url);
|
|
2447
|
+
if (this.allData.value.length == 0)
|
|
2448
|
+
await this.refreshData();
|
|
2449
|
+
}
|
|
2450
|
+
async create(item) {
|
|
2451
|
+
if (!this.apiUrl.value) return;
|
|
2452
|
+
const result = await this.requestProvider.registerRequest(this.apiUrl.value, {
|
|
2453
|
+
method: "POST",
|
|
2454
|
+
body: item,
|
|
2455
|
+
nuxtApp: this.nuxtApp
|
|
2456
|
+
});
|
|
2457
|
+
if (this.refreshOnMutation.value) {
|
|
2458
|
+
await this.refresh(true);
|
|
2459
|
+
} else {
|
|
2460
|
+
if (result && result.item) {
|
|
2461
|
+
this.allData.value.push(result.item);
|
|
2462
|
+
} else {
|
|
2463
|
+
await this.refresh(true);
|
|
2464
|
+
}
|
|
2465
|
+
if (this.requestProvider.cacheProvider) {
|
|
2466
|
+
await this.requestProvider.cacheProvider.removeByPrefix(this.apiUrl.value);
|
|
2467
|
+
}
|
|
2468
|
+
if (this.contextKey.value) {
|
|
2469
|
+
clearNuxtDataKey(this.contextKey.value, this.nuxtApp);
|
|
2470
|
+
}
|
|
2471
|
+
}
|
|
2472
|
+
}
|
|
2473
|
+
async update(item) {
|
|
2474
|
+
if (!this.apiUrl.value) return;
|
|
2475
|
+
const result = await this.requestProvider.registerRequest(this.apiUrl.value, {
|
|
2476
|
+
method: "PUT",
|
|
2477
|
+
body: item,
|
|
2478
|
+
nuxtApp: this.nuxtApp
|
|
2479
|
+
});
|
|
2480
|
+
if (this.refreshOnMutation.value) {
|
|
2481
|
+
await this.refresh(true);
|
|
2482
|
+
} else {
|
|
2483
|
+
const index = this.allData.value.findIndex((row) => row[this.idKey] === item[this.idKey]);
|
|
2484
|
+
if (index !== -1) {
|
|
2485
|
+
if (result && result.item) {
|
|
2486
|
+
this.allData.value[index] = result.item;
|
|
2487
|
+
} else {
|
|
2488
|
+
this.allData.value[index] = { ...this.allData.value[index], ...item };
|
|
2489
|
+
}
|
|
2490
|
+
this.allData.value = [...this.allData.value];
|
|
2491
|
+
}
|
|
2492
|
+
if (this.requestProvider.cacheProvider) {
|
|
2493
|
+
await this.requestProvider.cacheProvider.removeByPrefix(this.apiUrl.value);
|
|
2494
|
+
}
|
|
2495
|
+
if (this.contextKey.value) {
|
|
2496
|
+
clearNuxtDataKey(this.contextKey.value, this.nuxtApp);
|
|
2497
|
+
}
|
|
2498
|
+
}
|
|
2499
|
+
}
|
|
2500
|
+
async delete(items) {
|
|
2501
|
+
if (!this.apiUrl.value) return;
|
|
2502
|
+
if (!items || items.length === 0) return;
|
|
2503
|
+
const ids = items.map((i) => i.id);
|
|
2504
|
+
await this.requestProvider.registerRequest(this.apiUrl.value, {
|
|
2505
|
+
method: "DELETE",
|
|
2506
|
+
body: { id: ids },
|
|
2507
|
+
nuxtApp: this.nuxtApp
|
|
2508
|
+
});
|
|
2509
|
+
if (this.refreshOnMutation.value) {
|
|
2510
|
+
await this.refresh(true);
|
|
2511
|
+
} else {
|
|
2512
|
+
const idsToDelete = new Set(ids);
|
|
2513
|
+
this.allData.value = this.allData.value.filter((row) => !idsToDelete.has(row[this.idKey]));
|
|
2514
|
+
if (this.requestProvider.cacheProvider) {
|
|
2515
|
+
await this.requestProvider.cacheProvider.removeByPrefix(this.apiUrl.value);
|
|
2516
|
+
}
|
|
2517
|
+
if (this.contextKey.value) {
|
|
2518
|
+
clearNuxtDataKey(this.contextKey.value, this.nuxtApp);
|
|
2519
|
+
}
|
|
2520
|
+
}
|
|
2521
|
+
}
|
|
2522
|
+
}
|
|
2523
|
+
|
|
2524
|
+
class CTreeServerDataProvider extends ADataProvider {
|
|
2525
|
+
// Tree configuration (sent to server)
|
|
2526
|
+
parentKey = "parentId";
|
|
2527
|
+
idKey = "id";
|
|
2528
|
+
expandedByDefault = false;
|
|
2529
|
+
paginateBy = "all";
|
|
2530
|
+
// Tree state - toggled nodes (sent to server for visibility calculation)
|
|
2531
|
+
expandedNodes = ref(/* @__PURE__ */ new Set());
|
|
2532
|
+
// Server-side data handler
|
|
2533
|
+
pageDataHandler = ref(null);
|
|
2534
|
+
contextKey = ref("");
|
|
2535
|
+
initialLoad = ref(true);
|
|
2536
|
+
constructor(options) {
|
|
2537
|
+
super(options);
|
|
2538
|
+
if (options?.parentKey) this.parentKey = options.parentKey;
|
|
2539
|
+
if (options?.idKey) this.idKey = options.idKey;
|
|
2540
|
+
if (options?.expandedByDefault) this.expandedByDefault = options.expandedByDefault;
|
|
2541
|
+
if (options?.paginateBy) this.paginateBy = options.paginateBy;
|
|
2542
|
+
watch([this.expandedNodes, this.currentPage, this.pageSize], () => {
|
|
2543
|
+
if (this.pageDataHandler.value && !this.initialLoad.value) {
|
|
2544
|
+
this.loadPageData();
|
|
2545
|
+
}
|
|
2546
|
+
});
|
|
2547
|
+
}
|
|
2548
|
+
setContextKey(key) {
|
|
2549
|
+
this.contextKey.value = key;
|
|
2550
|
+
}
|
|
2551
|
+
async setPageDataHandler(handler) {
|
|
2552
|
+
this.pageDataHandler.value = handler;
|
|
2553
|
+
await this.loadPageData();
|
|
2554
|
+
}
|
|
2555
|
+
/**
|
|
2556
|
+
* Load page data from server
|
|
2557
|
+
* Server handles tree building, visibility, and pagination
|
|
2558
|
+
*/
|
|
2559
|
+
async loadPageData(options) {
|
|
2560
|
+
if (!this.pageDataHandler.value || !this.SSR.value && import.meta.server) return;
|
|
2561
|
+
const expandedArray = Array.from(this.expandedNodes.value);
|
|
2562
|
+
const stableStringify = (val) => JSON.stringify(val === void 0 ? "" : val);
|
|
2563
|
+
const key = [
|
|
2564
|
+
this.contextKey.value,
|
|
2565
|
+
this.currentPage.value,
|
|
2566
|
+
this.pageSize.value,
|
|
2567
|
+
stableStringify(this.filter.value),
|
|
2568
|
+
stableStringify(this.sortList.value),
|
|
2569
|
+
stableStringify(expandedArray)
|
|
2570
|
+
].join("-");
|
|
2571
|
+
const treeParams = {
|
|
2572
|
+
expandedNodes: expandedArray,
|
|
2573
|
+
parentKey: this.parentKey,
|
|
2574
|
+
idKey: this.idKey,
|
|
2575
|
+
paginateBy: this.paginateBy,
|
|
2576
|
+
expandedByDefault: this.expandedByDefault
|
|
2577
|
+
};
|
|
2578
|
+
const fetcher = async () => await this.pageDataHandler.value(
|
|
2579
|
+
this.currentPage.value,
|
|
2580
|
+
this.pageSize.value,
|
|
2581
|
+
this.filter.value,
|
|
2582
|
+
this.sortList.value,
|
|
2583
|
+
treeParams,
|
|
2584
|
+
options
|
|
2585
|
+
);
|
|
2586
|
+
if (!options?.disableCache && this.SSR.value && this.contextKey.value && this.initialLoad.value) {
|
|
2587
|
+
const { data } = getNuxtData(key, this.nuxtApp);
|
|
2588
|
+
if (data.value) {
|
|
2589
|
+
const result = data.value;
|
|
2590
|
+
this.pageData.value = result.rows;
|
|
2591
|
+
this.rowCount.value = result.rowCount;
|
|
2592
|
+
this.initialLoad.value = false;
|
|
2593
|
+
this.loading.value = false;
|
|
2594
|
+
return;
|
|
2595
|
+
}
|
|
2596
|
+
}
|
|
2597
|
+
if (this.SSR.value && this.contextKey.value && !options?.disableCache && (import.meta.server || this.initialLoad.value)) {
|
|
2598
|
+
this.loading.value = true;
|
|
2599
|
+
const { data } = await getAsyncData(key, fetcher, this.nuxtApp);
|
|
2600
|
+
if (data.value) {
|
|
2601
|
+
const result = data.value;
|
|
2602
|
+
this.pageData.value = result.rows;
|
|
2603
|
+
this.rowCount.value = result.rowCount;
|
|
2604
|
+
this.initialLoad.value = false;
|
|
2605
|
+
this.loading.value = false;
|
|
2606
|
+
return;
|
|
2607
|
+
}
|
|
2608
|
+
}
|
|
2609
|
+
if (!this.SSR.value) {
|
|
2610
|
+
onNuxtReadyCallback(() => {
|
|
2611
|
+
this.loading.value = true;
|
|
2612
|
+
fetcher().then((returnedData2) => {
|
|
2613
|
+
this.pageData.value = returnedData2.rows;
|
|
2614
|
+
this.rowCount.value = returnedData2.rowCount;
|
|
2615
|
+
this.initialLoad.value = false;
|
|
2616
|
+
this.loading.value = false;
|
|
2617
|
+
}).catch(() => {
|
|
2618
|
+
this.initialLoad.value = false;
|
|
2619
|
+
this.loading.value = false;
|
|
2620
|
+
});
|
|
2621
|
+
});
|
|
2622
|
+
return;
|
|
2623
|
+
}
|
|
2624
|
+
this.loading.value = true;
|
|
2625
|
+
const returnedData = await fetcher();
|
|
2626
|
+
this.pageData.value = returnedData.rows;
|
|
2627
|
+
this.rowCount.value = returnedData.rowCount;
|
|
2628
|
+
this.initialLoad.value = false;
|
|
2629
|
+
this.loading.value = false;
|
|
2630
|
+
}
|
|
2631
|
+
async refresh(hardRefresh = false) {
|
|
2632
|
+
await this.loadPageData(hardRefresh ? { disableCache: true } : void 0);
|
|
2633
|
+
}
|
|
2634
|
+
// ============================================
|
|
2635
|
+
// Expand/Collapse API
|
|
2636
|
+
// ============================================
|
|
2637
|
+
toggleNode(nodeId) {
|
|
2638
|
+
if (this.expandedNodes.value.has(nodeId)) {
|
|
2639
|
+
this.expandedNodes.value.delete(nodeId);
|
|
2640
|
+
} else {
|
|
2641
|
+
this.expandedNodes.value.add(nodeId);
|
|
2642
|
+
}
|
|
2643
|
+
this.expandedNodes.value = new Set(this.expandedNodes.value);
|
|
2644
|
+
}
|
|
2645
|
+
expand(nodeId) {
|
|
2646
|
+
this.expandedNodes.value.add(nodeId);
|
|
2647
|
+
this.expandedNodes.value = new Set(this.expandedNodes.value);
|
|
2648
|
+
}
|
|
2649
|
+
collapse(nodeId) {
|
|
2650
|
+
this.expandedNodes.value.delete(nodeId);
|
|
2651
|
+
this.expandedNodes.value = new Set(this.expandedNodes.value);
|
|
2652
|
+
}
|
|
2653
|
+
collapseAll() {
|
|
2654
|
+
this.expandedNodes.value = /* @__PURE__ */ new Set();
|
|
2655
|
+
}
|
|
2656
|
+
isExpanded(nodeId) {
|
|
2657
|
+
const isToggled = this.expandedNodes.value.has(nodeId);
|
|
2658
|
+
return this.expandedByDefault ? !isToggled : isToggled;
|
|
2659
|
+
}
|
|
2660
|
+
}
|
|
2661
|
+
|
|
2662
|
+
class CAPITreeServerDataProvider extends CTreeServerDataProvider {
|
|
2663
|
+
apiUrl = ref("");
|
|
2664
|
+
requestProvider = new RequestProvider();
|
|
2665
|
+
cacheStrategy = ref(null);
|
|
2666
|
+
cacheLifetime = ref(0);
|
|
2667
|
+
refreshOnMutation = ref(true);
|
|
2668
|
+
// Default true for server
|
|
2669
|
+
constructor(options) {
|
|
2670
|
+
super(options);
|
|
2671
|
+
if (options?.cacheStrategy) this.cacheStrategy.value = options.cacheStrategy;
|
|
2672
|
+
if (options?.cacheLifetime) this.cacheLifetime.value = options.cacheLifetime;
|
|
2673
|
+
if (options?.refreshOnMutation !== void 0) this.refreshOnMutation.value = options.refreshOnMutation;
|
|
2674
|
+
this.requestProvider.onDataReceived((data) => {
|
|
2675
|
+
if (data) {
|
|
2676
|
+
this.pageData.value = data.rows || data;
|
|
2677
|
+
if (data.rowCount !== void 0) {
|
|
2678
|
+
this.rowCount.value = data.rowCount;
|
|
2679
|
+
}
|
|
2680
|
+
}
|
|
2681
|
+
});
|
|
2682
|
+
}
|
|
2683
|
+
async refresh(hardRefresh = false) {
|
|
2684
|
+
if (hardRefresh && this.requestProvider.cacheProvider) {
|
|
2685
|
+
await this.requestProvider.cacheProvider.removeByPrefix(this.apiUrl.value);
|
|
2686
|
+
}
|
|
2687
|
+
this.loading.value = true;
|
|
2688
|
+
try {
|
|
2689
|
+
await this.loadPageData(hardRefresh ? { disableCache: true } : void 0);
|
|
2690
|
+
} finally {
|
|
2691
|
+
this.loading.value = false;
|
|
2692
|
+
}
|
|
2693
|
+
}
|
|
2694
|
+
async refreshData(options) {
|
|
2695
|
+
await this.refresh(options?.disableCache ?? false);
|
|
2696
|
+
}
|
|
2697
|
+
async setAPIUrl(url) {
|
|
2698
|
+
this.apiUrl.value = url;
|
|
2699
|
+
this.setContextKey(url);
|
|
2700
|
+
if (this.cacheStrategy.value) this.requestProvider.setCacheProvider(this.cacheStrategy.value);
|
|
2701
|
+
if (this.cacheLifetime.value) this.requestProvider.setCacheLifetime(this.cacheLifetime.value);
|
|
2702
|
+
await this.setPageDataHandler(
|
|
2703
|
+
async (currentPage, pageSize, filter, sortList, treeParams, options) => {
|
|
2704
|
+
return await this.requestProvider.registerRequest(this.apiUrl.value, {
|
|
2705
|
+
query: {
|
|
2706
|
+
pageNumber: currentPage,
|
|
2707
|
+
pageSize,
|
|
2708
|
+
filter,
|
|
2709
|
+
sortList,
|
|
2710
|
+
// Tree-specific params for server-side processing
|
|
2711
|
+
expandedNodes: JSON.stringify(treeParams.expandedNodes),
|
|
2712
|
+
parentKey: treeParams.parentKey,
|
|
2713
|
+
idKey: treeParams.idKey,
|
|
2714
|
+
paginateBy: treeParams.paginateBy,
|
|
2715
|
+
expandedByDefault: treeParams.expandedByDefault
|
|
2716
|
+
},
|
|
2717
|
+
deduplicate: this.deduplicate.value,
|
|
2718
|
+
nuxtApp: this.nuxtApp,
|
|
2719
|
+
disableCache: options?.disableCache
|
|
2720
|
+
});
|
|
2721
|
+
}
|
|
2722
|
+
);
|
|
2723
|
+
}
|
|
2724
|
+
async delete(items) {
|
|
2725
|
+
if (!this.apiUrl.value) return;
|
|
2726
|
+
if (!items || items.length === 0) return;
|
|
2727
|
+
const ids = items.map((i) => i.id);
|
|
2728
|
+
await this.requestProvider.registerRequest(this.apiUrl.value, {
|
|
2729
|
+
method: "DELETE",
|
|
2730
|
+
body: { id: ids },
|
|
2731
|
+
nuxtApp: this.nuxtApp
|
|
2732
|
+
});
|
|
2733
|
+
if (this.refreshOnMutation.value !== false) {
|
|
2734
|
+
if (this.requestProvider.cacheProvider) {
|
|
2735
|
+
await this.requestProvider.cacheProvider.removeByPrefix(this.apiUrl.value);
|
|
2736
|
+
}
|
|
2737
|
+
await this.refresh(true);
|
|
2738
|
+
}
|
|
2739
|
+
}
|
|
2740
|
+
}
|
|
2741
|
+
|
|
2742
|
+
export { AAPIDataProvider, ADataProvider, CAPIFlatClientDataProvider, CAPIFlatServerDataProvider, CAPITreeClientDataProvider, CAPITreeServerDataProvider, CApplicationCache, CCookieCache, CFlatClientDataProvider, CFlatServerDataProvider, CIndexedDBCache, CLocalStorageCache, CMemoryCache, CSessionCache, CTreeClientDataProvider, CTreeServerDataProvider, CacheProviderFactory, ECacheStrategy, EDataFilterOperator, RequestProvider };
|