@recats/cdeebee 3.0.0-beta.12 → 3.0.0-beta.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +78 -8
- package/dist/index.cjs +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +45 -6
- package/dist/index.js +169 -145
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -40,14 +40,14 @@ After fetching data from the API (which returns data in the format `{ data: [...
|
|
|
40
40
|
|
|
41
41
|
```typescript
|
|
42
42
|
{
|
|
43
|
-
forumList: {
|
|
44
|
-
1: { id: 1, title: 'Milky Way Galaxy' }
|
|
43
|
+
forumList: {
|
|
44
|
+
1: { id: 1, title: 'Milky Way Galaxy' }
|
|
45
45
|
},
|
|
46
|
-
threadList: {
|
|
47
|
-
10001: { id: 10001, title: 'Solar system', forumID: 1 }
|
|
46
|
+
threadList: {
|
|
47
|
+
10001: { id: 10001, title: 'Solar system', forumID: 1 }
|
|
48
48
|
},
|
|
49
|
-
postList: {
|
|
50
|
-
2: { id: 2, title: 'Earth', threadID: 10001 }
|
|
49
|
+
postList: {
|
|
50
|
+
2: { id: 2, title: 'Earth', threadID: 10001 }
|
|
51
51
|
}
|
|
52
52
|
}
|
|
53
53
|
```
|
|
@@ -171,6 +171,7 @@ function ForumsList() {
|
|
|
171
171
|
- `useStorage()` - Get the entire storage
|
|
172
172
|
- `useRequestHistory(api)` - Get successful request history for an API
|
|
173
173
|
- `useRequestErrors(api)` - Get error history for an API
|
|
174
|
+
- `useLastResultIdList(api)` - Get the IDs returned by the last request to an API (for filtering storage)
|
|
174
175
|
|
|
175
176
|
See the [React Hooks](#react-hooks) section for detailed documentation.
|
|
176
177
|
|
|
@@ -186,8 +187,8 @@ interface CdeebeeSettings<T> {
|
|
|
186
187
|
fileKey: string; // Key name for file uploads in FormData
|
|
187
188
|
bodyKey: string; // Key name for request body in FormData
|
|
188
189
|
listStrategy?: CdeebeeListStrategy<T>; // Merge strategy per list: 'merge' | 'replace' | 'skip'
|
|
189
|
-
mergeWithData?: unknown;
|
|
190
|
-
mergeWithHeaders?: Record<string, string
|
|
190
|
+
mergeWithData?: Record<string, unknown> | (() => Record<string, unknown>); // Data to merge with every request body (static or dynamic)
|
|
191
|
+
mergeWithHeaders?: Record<string, string> | (() => Record<string, string>); // Headers to merge with every request (static or dynamic)
|
|
191
192
|
normalize?: (storage, result, strategyList) => T; // Custom normalization function
|
|
192
193
|
}
|
|
193
194
|
```
|
|
@@ -228,6 +229,32 @@ listStrategy: {
|
|
|
228
229
|
}
|
|
229
230
|
```
|
|
230
231
|
|
|
232
|
+
## Dynamic Headers and Data
|
|
233
|
+
|
|
234
|
+
`mergeWithHeaders` and `mergeWithData` support both static objects and dynamic functions. Functions are called on each request, making them ideal for auth tokens:
|
|
235
|
+
|
|
236
|
+
```typescript
|
|
237
|
+
const cdeebeeSlice = factory<Storage>({
|
|
238
|
+
modules: ['storage', 'history', 'listener'],
|
|
239
|
+
|
|
240
|
+
// Static headers (evaluated once at factory creation)
|
|
241
|
+
mergeWithHeaders: { 'X-App': 'myapp' },
|
|
242
|
+
|
|
243
|
+
// OR Dynamic headers (evaluated on each request)
|
|
244
|
+
mergeWithHeaders: () => ({
|
|
245
|
+
'Authorization': `Bearer ${getSessionToken()}`,
|
|
246
|
+
}),
|
|
247
|
+
|
|
248
|
+
// Same for mergeWithData
|
|
249
|
+
mergeWithData: () => ({
|
|
250
|
+
timestamp: Date.now(),
|
|
251
|
+
clientVersion: APP_VERSION,
|
|
252
|
+
}),
|
|
253
|
+
});
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
**Note**: When using functions, Redux will warn about non-serializable values in state. Configure your store's `serializableCheck.ignoredPaths` to include `cdeebee.settings.mergeWithHeaders` and `cdeebee.settings.mergeWithData`.
|
|
257
|
+
|
|
231
258
|
## API Response Format
|
|
232
259
|
|
|
233
260
|
cdeebee expects API responses in a format where list data is provided as arrays with a `primaryKey` field. The library automatically normalizes this data into the storage structure.
|
|
@@ -621,6 +648,46 @@ function ErrorDisplay({ api }: { api: string }) {
|
|
|
621
648
|
}
|
|
622
649
|
```
|
|
623
650
|
|
|
651
|
+
### Result ID List Hook
|
|
652
|
+
|
|
653
|
+
#### `useLastResultIdList(api: string)`
|
|
654
|
+
|
|
655
|
+
Get the list of IDs returned by the last successful request to an API. This is useful for filtering storage data when using `merge` strategy, so you can display only the results from the current search/request.
|
|
656
|
+
|
|
657
|
+
```typescript
|
|
658
|
+
import { useStorageList, useLastResultIdList } from '@recats/cdeebee';
|
|
659
|
+
|
|
660
|
+
interface MyStorage {
|
|
661
|
+
productList: Record<string, { id: string; name: string; price: number }>;
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
function SearchResults() {
|
|
665
|
+
// Get all products from storage (accumulated via merge strategy)
|
|
666
|
+
const products = useStorageList<MyStorage, 'productList'>('productList');
|
|
667
|
+
|
|
668
|
+
// Get only the IDs from the last search request
|
|
669
|
+
const lastSearchIds = useLastResultIdList('/api/search');
|
|
670
|
+
|
|
671
|
+
// Filter to show only results from current search
|
|
672
|
+
const displayResults = lastSearchIds
|
|
673
|
+
.map(id => products[id])
|
|
674
|
+
.filter(Boolean);
|
|
675
|
+
|
|
676
|
+
return (
|
|
677
|
+
<div>
|
|
678
|
+
{displayResults.map(product => (
|
|
679
|
+
<div key={product.id}>{product.name} - ${product.price}</div>
|
|
680
|
+
))}
|
|
681
|
+
</div>
|
|
682
|
+
);
|
|
683
|
+
}
|
|
684
|
+
```
|
|
685
|
+
|
|
686
|
+
**Why use this?** When using `replace` strategy with search/filter pages, navigating away and using browser back loses the previous results. With `merge` strategy + `useLastResultIdList`:
|
|
687
|
+
- Data accumulates in storage (never lost on navigation)
|
|
688
|
+
- `lastResultIdList` tracks which IDs belong to the current request
|
|
689
|
+
- Filter storage by those IDs to display the correct results
|
|
690
|
+
|
|
624
691
|
### Advanced: Custom State Path
|
|
625
692
|
|
|
626
693
|
If you're **not** using `combineSlices` or have cdeebee at a custom path in your state (not `state.cdeebee`), use `createCdeebeeHooks`:
|
|
@@ -638,6 +705,7 @@ export const {
|
|
|
638
705
|
useRequestHistory,
|
|
639
706
|
useRequestErrors,
|
|
640
707
|
useIsLoading,
|
|
708
|
+
useLastResultIdList,
|
|
641
709
|
} = createCdeebeeHooks<RootState, MyStorage>(
|
|
642
710
|
state => state.myCustomPath // Your custom path
|
|
643
711
|
);
|
|
@@ -669,6 +737,7 @@ const users = useSelector(state => state.cdeebee.storage.userList);
|
|
|
669
737
|
export { factory } from '@recats/cdeebee'; // Create cdeebee slice
|
|
670
738
|
export { request } from '@recats/cdeebee'; // Request thunk
|
|
671
739
|
export { batchingUpdate } from '@recats/cdeebee'; // Batch update helper
|
|
740
|
+
export { defaultNormalize } from '@recats/cdeebee'; // Default normalization function
|
|
672
741
|
|
|
673
742
|
// React hooks
|
|
674
743
|
export {
|
|
@@ -679,6 +748,7 @@ export {
|
|
|
679
748
|
useStorage, // Get entire storage
|
|
680
749
|
useRequestHistory, // Get successful request history
|
|
681
750
|
useRequestErrors, // Get error history
|
|
751
|
+
useLastResultIdList, // Get IDs from last request (for filtering storage)
|
|
682
752
|
} from '@recats/cdeebee';
|
|
683
753
|
|
|
684
754
|
// Types
|
package/dist/index.cjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const R=require("@reduxjs/toolkit"),d=require("react-redux");function
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const R=require("@reduxjs/toolkit"),d=require("react-redux");function y(e,r,n){e.modules.includes(r)&&n()}function f(e){return e!==null&&typeof e=="object"&&!Array.isArray(e)}function p(e,r){if(!f(e)||!f(r))return r;const n={...e},s=r;for(const t in s)if(Object.prototype.hasOwnProperty.call(s,t)){const i=n[t],o=s[t];f(i)&&f(o)&&!Array.isArray(i)&&!Array.isArray(o)?n[t]=p(i,o):n[t]=o}return n}function x(e,r){const n={...r};for(const s of e)delete n[s];return n}function N(e){if(!f(e))return[];const r=[];for(const n of Object.keys(e)){const s=e[n];if(f(s)&&Array.isArray(s.data)&&typeof s.primaryKey=="string"){const t=s.primaryKey;for(const i of s.data)f(i)&&t in i&&r.push(String(i[t]))}}return r}function K(e,r){for(let n=0;n<r.length;n++){const s=r[n],t=s.key,i=s.value;if(t.length===0)continue;let o=e;for(let u=0;u<t.length-1;u++){const a=t[u];if(Array.isArray(o)){const c=typeof a=="number"?a:Number(a);(!(c in o)||!f(o[c]))&&(o[c]={}),o=o[c]}else{const c=String(a);if(!(c in o)){const g=typeof t[u+1]=="number"||!isNaN(Number(t[u+1]))&&String(Number(t[u+1]))===String(t[u+1]);o[c]=g?[]:{}}const l=o[c];o=Array.isArray(l)||f(l)?l:{}}}Array.isArray(o)||(o[String(t[t.length-1])]=i)}}class T{constructor(){this.byRequestId=new Map,this.byApi=new Map}add(r,n,s){const t={requestId:n,controller:s,api:r};this.byRequestId.set(n,t),this.byApi.has(r)||this.byApi.set(r,new Set),this.byApi.get(r).add(n)}delete(r){const n=this.byRequestId.get(r);if(!n)return;this.byRequestId.delete(r);const s=this.byApi.get(n.api);s&&(s.delete(r),s.size===0&&this.byApi.delete(n.api))}abortAllForApi(r,n){const s=this.byApi.get(r);s&&s.forEach(t=>{if(t!==n){const i=this.byRequestId.get(t);i&&(i.controller.abort(),this.delete(t))}})}}const L=new T;function j(e,r){L.abortAllForApi(e,r)}function C(e,r,n){const s=new AbortController,t=()=>{L.delete(n)};return e.addEventListener("abort",()=>{s.abort(),t()}),{controller:s,init:()=>L.add(r,n,s),drop:t}}class E{constructor(){this.currentPromise=Promise.resolve(),this.queueLength=0}async enqueue(r){this.queueLength++;const n=this.currentPromise;return this.currentPromise=n.then(()=>r(),()=>r()).finally(()=>{this.queueLength--}),this.currentPromise}getQueueLength(){return this.queueLength}clear(){this.queueLength=0}}const O=new E,h=R.createAsyncThunk("cdeebee/request",async(e,{rejectWithValue:r,getState:n,requestId:s,signal:t})=>{const i=new Date().toUTCString(),{cdeebee:{settings:o}}=n(),u=C(t,e.api,s),a=e.onResult&&typeof e.onResult=="function";y(o,"cancelation",u.init);const c=async()=>{try{const{method:l="POST",body:g,headers:H={}}=e,z={...typeof o.mergeWithHeaders=="function"?o.mergeWithHeaders():o.mergeWithHeaders??{},...H},P={...typeof o.mergeWithData=="function"?o.mergeWithData():o.mergeWithData??{},...g??{}};let q=JSON.stringify(P);if(e.files){const S=new FormData,w=e.fileKey||o.fileKey,I=e.bodyKey||o.bodyKey;for(let A=0;A<e.files.length;A+=1)w&&S.append(w,e.files[A]);I&&S.append(I,q),q=S}const m=await fetch(e.api,{method:l,headers:{"ui-request-id":s,"Content-Type":"application/json",...z},signal:u.controller.signal,body:q});y(o,"cancelation",u.drop);let b;const k=e.responseType||"json";return k==="text"?b=await m.text():k==="blob"?b=await m.blob():b=await m.json(),m.ok?(a&&e.onResult(b),{result:b,startedAt:i,endedAt:new Date().toUTCString()}):(a&&e.onResult(b),r(m))}catch(l){return y(o,"cancelation",u.drop),a&&e.onResult(l),l instanceof Error&&l.name==="AbortError"?r({message:"Request was cancelled",cancelled:!0}):r({message:l instanceof Error?l.message:"Unknown error occurred"})}};return o.modules.includes("queryQueue")?O.enqueue(c):c()});function W(e){return f(e)&&Array.isArray(e.data)&&typeof e.primaryKey=="string"}function Q(e,r){const n={};for(const s of e)if(f(s)&&r in s){const t=String(s[r]);n[t]=s}return n}function D(e,r,n,s){return n==="replace"?r:n==="merge"?p(e,r):n==="skip"?e:(console.warn(`Cdeebee: Unknown strategy "${n}" for key "${s}". Skipping normalization.`),p(e,r))}function v(e,r,n){const s=Object.keys(r),t=f(e.storage)?e.storage:{},i={...t},o=new Set;for(const u of s){const a=r[u];if(a==null||typeof a=="string"){o.add(u);continue}const c=n[u]??"merge";if(c==="skip"&&!(u in t))continue;const l=u in t?t[u]:{};if(W(a)){const g=Q(a.data,a.primaryKey);i[u]=D(l,g,c,u);continue}f(a)?i[u]=D(l,a,c,u):i[u]=a}return o.size>0?x(Array.from(o),i):i}const U={settings:{modules:["history","listener","storage","cancelation"],fileKey:"file",bodyKey:"value",listStrategy:{},mergeWithData:{},mergeWithHeaders:{}},storage:{},request:{active:[],errors:{},done:{},lastResultIdList:{}}},M=(e,r)=>R.createSlice({name:"cdeebee",initialState:p(U,{settings:e,storage:r??{}}),reducers:{set(s,t){K(s.storage,t.payload)},historyClear(s,t){const i=t.payload;i?(delete s.request.done[i],delete s.request.errors[i]):(s.request.done={},s.request.errors={})}},extraReducers:s=>{s.addCase(h.pending,(t,i)=>{const o=i.meta.arg.api,u=i.meta.requestId;i.meta.arg.historyClear&&y(t.settings,"history",()=>{delete t.request.done[o],delete t.request.errors[o]}),y(t.settings,"cancelation",()=>{j(o,u)}),y(t.settings,"listener",()=>{t.request.active.push({api:o,requestId:u})})}).addCase(h.fulfilled,(t,i)=>{const o=i.meta.requestId,u=i.meta.arg.api;y(t.settings,"listener",()=>{t.request.active=t.request.active.filter(a=>!(a.api===u&&a.requestId===o))}),y(t.settings,"history",()=>{t.request.done[u]||(t.request.done[u]=[]),t.request.done[u].push({api:u,request:i.payload,requestId:o})}),y(t.settings,"storage",()=>{if(i.meta.arg.ignore)return;const a=i.meta.arg.listStrategy??t.settings.listStrategy??{},c=i.meta.arg.normalize??t.settings.normalize??v,l=R.current(t),g=c(l,i.payload.result,a);t.storage=g,t.request.lastResultIdList[u]=N(i.payload.result)})}).addCase(h.rejected,(t,i)=>{const o=i.meta.requestId,u=i.meta.arg.api;y(t.settings,"listener",()=>{t.request.active=t.request.active.filter(a=>!(a.api===u&&a.requestId===o))}),y(t.settings,"history",()=>{t.request.errors[u]||(t.request.errors[u]=[]),t.request.errors[u].push({requestId:o,api:u,request:i.error})})})}});function F(e){function r(a){return d.useSelector(c=>e(c).request.active.some(g=>a.includes(g.api)))}function n(a){return d.useSelector(c=>e(c).request.done[a]??[])}function s(a){return d.useSelector(c=>e(c).request.errors[a]??[])}function t(a){return d.useSelector(c=>e(c).storage[a])}function i(){return d.useSelector(a=>e(a).storage)}function o(){return d.useSelector(a=>e(a).request.active.length>0)}function u(a){return d.useSelector(c=>e(c).request.lastResultIdList[a]??[])}return{useLoading:r,useRequestHistory:n,useRequestErrors:s,useStorageList:t,useStorage:i,useIsLoading:o,useLastResultIdList:u}}function $(e){return d.useSelector(r=>r.cdeebee.request.active.some(n=>e.includes(n.api)))}function J(e){return d.useSelector(r=>r.cdeebee.request.done[e]??[])}function B(e){return d.useSelector(r=>r.cdeebee.request.errors[e]??[])}function G(e){return d.useSelector(r=>r.cdeebee.storage[e])}function X(){return d.useSelector(e=>e.cdeebee.storage)}function Y(){return d.useSelector(e=>e.cdeebee.request.active.length>0)}function Z(e){return d.useSelector(r=>r.cdeebee.request.lastResultIdList[e]??[])}exports.batchingUpdate=K;exports.createCdeebeeHooks=F;exports.defaultNormalize=v;exports.factory=M;exports.request=h;exports.useIsLoading=Y;exports.useLastResultIdList=Z;exports.useLoading=$;exports.useRequestErrors=B;exports.useRequestHistory=J;exports.useStorage=X;exports.useStorageList=G;
|
|
2
2
|
//# sourceMappingURL=index.cjs.map
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","sources":["../lib/reducer/helpers.ts","../lib/reducer/abortController.ts","../lib/reducer/queryQueue.ts","../lib/reducer/request.ts","../lib/reducer/storage.ts","../lib/reducer/index.ts","../lib/hooks.ts"],"sourcesContent":["import { type WritableDraft } from '@reduxjs/toolkit';\nimport { type CdeebeeSettings, type CdeebeeModule, CdeebeeValueList } from './types';\n\nexport function checkModule(settings: CdeebeeSettings<unknown> | WritableDraft<CdeebeeSettings<unknown>>, module: CdeebeeModule, result: () => void) {\n if (settings.modules.includes(module)) {\n result();\n }\n}\nexport function isRecord(value: unknown): value is Record<string, unknown> {\n return value !== null && typeof value === 'object' && !Array.isArray(value);\n}\n\nexport function hasDataProperty(value: unknown): value is Record<string, unknown> & { data: unknown[] } {\n return isRecord(value) && Array.isArray(value.data);\n}\n\nexport function hasProperty(value: unknown, prop: string): boolean {\n return isRecord(value) && Object.prototype.hasOwnProperty.call(value, prop);\n}\n\nexport function mergeDeepRight<T>(\n left: T,\n right: Partial<T> | Record<string, unknown>\n): T {\n if (!isRecord(left) || !isRecord(right)) {\n return right as T;\n }\n\n const result = { ...left } as Record<string, unknown>;\n const rightRecord = right as Record<string, unknown>;\n\n for (const key in rightRecord) {\n if (Object.prototype.hasOwnProperty.call(rightRecord, key)) {\n const leftValue = result[key];\n const rightValue = rightRecord[key];\n\n if (\n isRecord(leftValue) &&\n isRecord(rightValue) &&\n !Array.isArray(leftValue) &&\n !Array.isArray(rightValue)\n ) {\n result[key] = mergeDeepRight(leftValue, rightValue);\n } else {\n result[key] = rightValue;\n }\n }\n }\n\n return result as T;\n}\n\nexport function omit<T extends Record<string, unknown>>(keys: string[], obj: T): Omit<T, keyof T> {\n const result = { ...obj };\n for (const key of keys) {\n delete result[key];\n }\n return result as Omit<T, keyof T>;\n}\n\nexport function assocPath<T>(path: (string | number)[], value: unknown, obj: T): T {\n if (path.length === 0) {\n return value as T;\n }\n\n const [first, ...rest] = path;\n const firstKey = String(first);\n const result = Array.isArray(obj) ? [...obj] : { ...obj } as Record<string, unknown>;\n\n if (rest.length === 0) {\n (result as Record<string, unknown>)[firstKey] = value;\n } else {\n const currentValue = (result as Record<string, unknown>)[firstKey];\n (result as Record<string, unknown>)[firstKey] = assocPath(rest, value, currentValue ?? {});\n }\n\n return result as T;\n}\n\nexport function batchingUpdate<T extends Record<string, unknown>>(\n state: T,\n valueList: CdeebeeValueList<T>\n): void {\n for (let i = 0; i < valueList.length; i++) {\n const item = valueList[i] as { key: readonly (string | number)[]; value: unknown };\n const path = item.key;\n const value = item.value;\n \n if (path.length === 0) {\n continue;\n }\n\n let current: Record<string, unknown> | unknown[] = state as Record<string, unknown>;\n \n for (let j = 0; j < path.length - 1; j++) {\n const pathKey = path[j];\n \n if (Array.isArray(current)) {\n const index = typeof pathKey === 'number' ? pathKey : Number(pathKey);\n if (!(index in current) || !isRecord(current[index])) {\n current[index] = {};\n }\n current = current[index] as Record<string, unknown>;\n } else {\n const key = String(pathKey);\n if (!(key in current)) {\n const nextIsNumeric = typeof path[j + 1] === 'number' || (!isNaN(Number(path[j + 1])) && String(Number(path[j + 1])) === String(path[j + 1]));\n current[key] = nextIsNumeric ? [] : {};\n }\n const next = current[key];\n current = (Array.isArray(next) ? next : (isRecord(next) ? next : {})) as Record<string, unknown> | unknown[];\n }\n }\n \n if (Array.isArray(current)) {\n continue; // Can't update array element directly\n }\n current[String(path[path.length - 1])] = value;\n }\n}\n","interface RequestController {\n requestId: string;\n controller: AbortController;\n api: string;\n}\n\nclass AbortControllerStore {\n private byRequestId = new Map<string, RequestController>();\n private byApi = new Map<string, Set<string>>();\n\n add(api: string, requestId: string, controller: AbortController): void {\n const item: RequestController = { requestId, controller, api };\n this.byRequestId.set(requestId, item);\n\n if (!this.byApi.has(api)) {\n this.byApi.set(api, new Set());\n }\n this.byApi.get(api)!.add(requestId);\n }\n\n delete(requestId: string): void {\n const item = this.byRequestId.get(requestId);\n if (!item) return;\n\n this.byRequestId.delete(requestId);\n const apiSet = this.byApi.get(item.api);\n if (apiSet) {\n apiSet.delete(requestId);\n if (apiSet.size === 0) {\n this.byApi.delete(item.api);\n }\n }\n }\n\n abortAllForApi(api: string, excludeRequestId: string): void {\n const requestIds = this.byApi.get(api);\n if (!requestIds) return;\n\n requestIds.forEach(requestId => {\n if (requestId !== excludeRequestId) {\n const item = this.byRequestId.get(requestId);\n if (item) {\n item.controller.abort();\n this.delete(requestId);\n }\n }\n });\n }\n}\n\nconst abortStore = new AbortControllerStore();\n\nexport function abortQuery(api: string, currentRequestId: string): void {\n abortStore.abortAllForApi(api, currentRequestId);\n}\n\nexport function abortManager(signal: AbortSignal, api: string, requestId: string) {\n const controller = new AbortController();\n\n const cleanup = () => {\n abortStore.delete(requestId);\n };\n\n signal.addEventListener('abort', () => {\n controller.abort();\n cleanup();\n });\n\n return {\n controller,\n init: () => abortStore.add(api, requestId, controller),\n drop: cleanup,\n };\n}\n","class QueryQueue {\n private currentPromise: Promise<unknown> = Promise.resolve();\n private queueLength = 0;\n\n async enqueue<T>(task: () => Promise<T>): Promise<T> {\n this.queueLength++;\n \n const previousPromise = this.currentPromise;\n \n this.currentPromise = previousPromise\n .then(() => task(), () => task())\n .finally(() => {\n this.queueLength--;\n });\n\n return this.currentPromise as Promise<T>;\n }\n\n getQueueLength(): number {\n return this.queueLength;\n }\n\n clear(): void {\n this.queueLength = 0;\n }\n}\n\nexport const queryQueue = new QueryQueue();\n\n","import { createAsyncThunk } from '@reduxjs/toolkit';\nimport { checkModule } from './helpers';\nimport { abortManager } from './abortController';\nimport { queryQueue } from './queryQueue';\nimport { type CdeebeeState, type CdeebeeRequestOptions } from './types';\n\nexport const request = createAsyncThunk(\n 'cdeebee/request',\n async (options: CdeebeeRequestOptions<unknown>, { rejectWithValue, getState, requestId, signal }) => {\n const startedAt = new Date().toUTCString();\n const { cdeebee: { settings } } = getState() as { cdeebee: CdeebeeState<unknown> };\n\n const abort = abortManager(signal, options.api, requestId);\n const withCallback = options.onResult && typeof options.onResult === 'function';\n\n checkModule(settings, 'cancelation', abort.init);\n\n const executeRequest = async () => {\n try {\n const { method = 'POST', body, headers = {} } = options;\n const extraHeaders: Record<string, string> = { ...(settings.mergeWithHeaders ?? {}), ...headers };\n\n const b = { ...(settings.mergeWithData ?? {}), ...(body ?? {}) };\n let requestData: FormData | string = JSON.stringify(b);\n\n // handling files\n if (options.files) {\n const formData = new FormData();\n const fileKey = options.fileKey || settings.fileKey;\n const bodyKey = options.bodyKey || settings.bodyKey;\n\n for (let i = 0; i < options.files.length; i += 1) {\n if (fileKey) {\n formData.append(fileKey, options.files[i]);\n }\n }\n\n if (bodyKey) {\n formData.append(bodyKey, requestData);\n }\n requestData = formData;\n }\n // [end] handling files\n \n const response = await fetch(options.api, {\n method,\n headers: {\n 'ui-request-id': requestId,\n 'Content-Type': 'application/json',\n ...extraHeaders,\n },\n signal: abort.controller.signal,\n body: requestData,\n });\n\n checkModule(settings, 'cancelation', abort.drop);\n\n let result: unknown;\n const responseType = options.responseType || 'json';\n \n if (responseType === 'text') {\n result = await response.text();\n } else if (responseType === 'blob') {\n result = await response.blob();\n } else {\n // default: json\n result = await response.json();\n }\n\n if (!response.ok) {\n if (withCallback) options.onResult!(result);\n return rejectWithValue(response);\n }\n\n if (withCallback) options.onResult!(result);\n return { result, startedAt, endedAt: new Date().toUTCString() };\n } catch (error) {\n checkModule(settings, 'cancelation', abort.drop);\n\n if (withCallback) options.onResult!(error); \n\n if (error instanceof Error && error.name === 'AbortError') {\n return rejectWithValue({ message: 'Request was cancelled', cancelled: true });\n }\n\n return rejectWithValue({ message: error instanceof Error ? error.message : 'Unknown error occurred' });\n }\n };\n\n if (settings.modules.includes('queryQueue')) {\n return queryQueue.enqueue(executeRequest);\n }\n\n return executeRequest();\n },\n);\n\n","import { type CdeebeeListStrategy, type CdeebeeState } from './types';\nimport { isRecord, mergeDeepRight, omit } from './helpers';\n\ntype ResponseValue = Record<string, unknown>;\n\ntype IResponse = Record<string, ResponseValue>;\n\ntype StorageData = Record<string, unknown>;\n\nfunction isDataWithPrimaryKey(value: unknown): value is { data: unknown[]; primaryKey: string } {\n return (\n isRecord(value) &&\n Array.isArray(value.data) &&\n typeof value.primaryKey === 'string'\n );\n}\nfunction normalizeDataWithPrimaryKey(data: unknown[], primaryKey: string): Record<string, unknown> {\n const result: Record<string, unknown> = {};\n \n for (const item of data) {\n if (isRecord(item) && primaryKey in item) {\n const key = String(item[primaryKey]);\n result[key] = item;\n }\n }\n \n return result;\n}\n\nfunction applyStrategy(\n existingValue: StorageData,\n newValue: StorageData | ResponseValue,\n strategy: string,\n key: string\n): ResponseValue {\n if (strategy === 'replace') {\n return newValue as ResponseValue;\n } else if (strategy === 'merge') {\n return mergeDeepRight(existingValue, newValue as StorageData) as ResponseValue;\n } else if (strategy === 'skip') {\n return existingValue as ResponseValue;\n } else {\n console.warn(`Cdeebee: Unknown strategy \"${strategy}\" for key \"${key}\". Skipping normalization.`);\n return mergeDeepRight(existingValue, newValue as StorageData) as ResponseValue;\n }\n}\n\nexport function defaultNormalize<T>(\n cdeebee: CdeebeeState<T>,\n response: IResponse,\n strategyList: CdeebeeListStrategy<T> \n): Record<string, ResponseValue> {\n const keyList = Object.keys(response);\n const currentStorage = isRecord(cdeebee.storage) ? (cdeebee.storage as Record<string, unknown>) : {};\n \n const result = { ...currentStorage } as Record<string, ResponseValue>;\n const keyListToOmit = new Set<string>();\n\n for (const key of keyList) {\n const responseValue = response[key];\n\n if (responseValue === null || responseValue === undefined || typeof responseValue === 'string') {\n keyListToOmit.add(key);\n continue;\n }\n\n const strategy = strategyList[key as keyof T] ?? 'merge';\n \n // For 'skip' strategy, if key doesn't exist in storage, skip it entirely\n if (strategy === 'skip' && !(key in currentStorage)) {\n continue;\n }\n \n const existingValue = key in currentStorage ? (currentStorage[key] as StorageData) : {};\n\n if (isDataWithPrimaryKey(responseValue)) {\n const normalizedValue = normalizeDataWithPrimaryKey(responseValue.data, responseValue.primaryKey);\n result[key] = applyStrategy(existingValue, normalizedValue, strategy, key);\n continue;\n }\n\n if (isRecord(responseValue)) {\n result[key] = applyStrategy(existingValue, responseValue as StorageData, strategy, key);\n } else {\n result[key] = responseValue;\n }\n }\n\n return keyListToOmit.size > 0 ? omit(Array.from(keyListToOmit), result) : result;\n}\n","import { createSlice, current, type PayloadAction } from '@reduxjs/toolkit';\n\nimport { type CdeebeeSettings, type CdeebeeState, type CdeebeeValueList, type CdeebeeListStrategy } from './types';\nimport { checkModule, mergeDeepRight, batchingUpdate } from './helpers';\nimport { abortQuery } from './abortController';\nimport { request } from './request';\nimport { defaultNormalize } from './storage';\n\nconst initialState: CdeebeeState<unknown> = {\n settings: {\n modules: ['history', 'listener', 'storage', 'cancelation'],\n fileKey: 'file',\n bodyKey: 'value',\n listStrategy: {},\n mergeWithData: {},\n mergeWithHeaders: {},\n },\n storage: {},\n request: {\n active: [],\n errors: {},\n done: {}\n },\n};\n\nexport const factory = <T>(settings: CdeebeeSettings<T>, storage?: T) => {\n const slice = createSlice({\n name: 'cdeebee',\n initialState: mergeDeepRight(initialState, { settings, storage: storage ?? {} }) as CdeebeeState<T>,\n reducers: {\n set(state, action: { payload: CdeebeeValueList<T> }) {\n // Directly mutate state.storage using Immer Draft\n // This is more performant than creating a new object\n // Immer will track changes and create minimal updates\n batchingUpdate(state.storage as Record<string, unknown>, action.payload);\n },\n historyClear(state, action: PayloadAction<string | undefined>) {\n const api = action.payload;\n\n if (api) {\n delete state.request.done[api];\n delete state.request.errors[api];\n } else {\n state.request.done = {};\n state.request.errors = {};\n }\n }\n },\n extraReducers: builder => {\n builder\n .addCase(request.pending, (state, action) => {\n const api = action.meta.arg.api;\n const requestId = action.meta.requestId;\n\n if (action.meta.arg.historyClear) {\n checkModule(state.settings, 'history', () => {\n delete state.request.done[api];\n delete state.request.errors[api];\n });\n }\n\n checkModule(state.settings, 'cancelation', () => {\n abortQuery(api, requestId);\n });\n checkModule(state.settings, 'listener', () => {\n state.request.active.push({ api, requestId });\n });\n })\n .addCase(request.fulfilled, (state, action) => {\n const requestId = action.meta.requestId;\n const api = action.meta.arg.api;\n\n checkModule(state.settings, 'listener', () => {\n state.request.active = state.request.active.filter(q => !(q.api === api && q.requestId === requestId));\n });\n checkModule(state.settings, 'history', () => {\n if (!state.request.done[api]) state.request.done[api] = [];\n state.request.done[api].push({ api, request: action.payload, requestId });\n });\n checkModule(state.settings, 'storage', () => {\n if (action.meta.arg.ignore) {\n return;\n }\n \n const strategyList = (action.meta.arg.listStrategy ?? state.settings.listStrategy ?? {}) as CdeebeeListStrategy<T>;\n const normalize = action.meta.arg.normalize ?? state.settings.normalize ?? defaultNormalize;\n\n const currentState = current(state) as CdeebeeState<T>;\n // Type assertion is safe here because we've already checked isRecord\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const normalizedData = normalize(currentState, action.payload.result as any, strategyList);\n\n // Normalize already handles merge/replace/skip and preserves keys not in response\n // Simply apply the result\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n (state.storage as any) = normalizedData;\n });\n })\n .addCase(request.rejected, (state, action) => {\n const requestId = action.meta.requestId;\n const api = action.meta.arg.api;\n\n checkModule(state.settings, 'listener', () => {\n state.request.active = state.request.active.filter(q => !(q.api === api && q.requestId === requestId));\n });\n checkModule(state.settings, 'history', () => {\n if (!state.request.errors[api]) state.request.errors[api] = [];\n state.request.errors[api].push({ requestId: requestId, api, request: action.error });\n });\n });\n },\n });\n\n return slice;\n};\n","import { useSelector } from 'react-redux';\nimport { type CdeebeeState } from './reducer/types';\n\n/**\n * Generic hook factory that creates a selector hook for cdeebee state.\n * This allows the hooks to work with any Redux root state structure.\n *\n * @template RootState - The shape of the Redux root state\n * @template Storage - The shape of the cdeebee storage\n * @param selectCdeebee - Function to select the cdeebee slice from root state\n * @returns An object containing all cdeebee hooks\n */\nexport function createCdeebeeHooks<RootState, Storage>(\n selectCdeebee: (state: RootState) => CdeebeeState<Storage>\n) {\n /**\n * Check if any of the specified APIs are currently loading.\n *\n * @param apiList - Array of API endpoints to check\n * @returns true if any of the APIs are currently active/loading\n *\n * @example\n * const isLoading = useLoading(['/api/forums', '/api/threads']);\n * if (isLoading) return <Spinner />;\n */\n function useLoading(apiList: string[]): boolean {\n return useSelector((state: RootState) => {\n const cdeebee = selectCdeebee(state);\n return cdeebee.request.active.some(q => apiList.includes(q.api));\n });\n }\n\n /**\n * Get the successful request history for a specific API endpoint.\n *\n * @param api - The API endpoint\n * @returns Array of successful request history entries\n *\n * @example\n * const history = useRequestHistory('/api/forums');\n * console.log(`Made ${history.length} successful requests`);\n */\n function useRequestHistory(api: string) {\n return useSelector((state: RootState) => {\n const cdeebee = selectCdeebee(state);\n return cdeebee.request.done[api] ?? [];\n });\n }\n\n /**\n * Get the error history for a specific API endpoint.\n *\n * @param api - The API endpoint\n * @returns Array of error history entries\n *\n * @example\n * const errors = useRequestErrors('/api/forums');\n * if (errors.length > 0) {\n * console.error('Last error:', errors[errors.length - 1]);\n * }\n */\n function useRequestErrors(api: string) {\n return useSelector((state: RootState) => {\n const cdeebee = selectCdeebee(state);\n return cdeebee.request.errors[api] ?? [];\n });\n }\n\n /**\n * Get a specific list from storage with full type safety.\n *\n * @param listName - The name of the list in storage\n * @returns The list data\n *\n * @example\n * const forums = useStorageList('forumList');\n * const forumArray = Object.values(forums);\n */\n function useStorageList<K extends keyof Storage>(listName: K): Storage[K] {\n return useSelector((state: RootState) => {\n const cdeebee = selectCdeebee(state);\n return cdeebee.storage[listName];\n });\n }\n\n /**\n * Get the entire cdeebee storage.\n *\n * @returns The complete storage object\n *\n * @example\n * const storage = useStorage();\n * console.log(Object.keys(storage)); // ['forumList', 'threadList', ...]\n */\n function useStorage(): Storage {\n return useSelector((state: RootState) => {\n const cdeebee = selectCdeebee(state);\n return cdeebee.storage;\n });\n }\n\n /**\n * Check if any request is currently loading (across all APIs).\n *\n * @returns true if any request is active\n *\n * @example\n * const isAnythingLoading = useIsLoading();\n * if (isAnythingLoading) return <GlobalSpinner />;\n */\n function useIsLoading(): boolean {\n return useSelector((state: RootState) => {\n const cdeebee = selectCdeebee(state);\n return cdeebee.request.active.length > 0;\n });\n }\n\n return {\n useLoading,\n useRequestHistory,\n useRequestErrors,\n useStorageList,\n useStorage,\n useIsLoading,\n };\n}\n\n/**\n * Standalone hook that can be used without createCdeebeeHooks.\n * Assumes the cdeebee slice is at state.cdeebee.\n *\n * @param apiList - Array of API endpoints to check\n * @returns true if any of the APIs are currently active/loading\n *\n * @example\n * const isLoading = useLoading(['/api/forums', '/api/threads']);\n */\nexport function useLoading<Storage = unknown>(apiList: string[]): boolean {\n return useSelector((state: { cdeebee: CdeebeeState<Storage> }) => {\n return state.cdeebee.request.active.some(q => apiList.includes(q.api));\n });\n}\n\n/**\n * Standalone hook that can be used without createCdeebeeHooks.\n * Assumes the cdeebee slice is at state.cdeebee.\n *\n * @param api - The API endpoint\n * @returns Array of successful request history entries\n */\nexport function useRequestHistory<Storage = unknown>(api: string) {\n return useSelector((state: { cdeebee: CdeebeeState<Storage> }) => {\n return state.cdeebee.request.done[api] ?? [];\n });\n}\n\n/**\n * Standalone hook that can be used without createCdeebeeHooks.\n * Assumes the cdeebee slice is at state.cdeebee.\n *\n * @param api - The API endpoint\n * @returns Array of error history entries\n */\nexport function useRequestErrors<Storage = unknown>(api: string) {\n return useSelector((state: { cdeebee: CdeebeeState<Storage> }) => {\n return state.cdeebee.request.errors[api] ?? [];\n });\n}\n\n/**\n * Standalone hook that can be used without createCdeebeeHooks.\n * Assumes the cdeebee slice is at state.cdeebee.\n *\n * @param listName - The name of the list in storage\n * @returns The list data\n */\nexport function useStorageList<Storage, K extends keyof Storage>(listName: K): Storage[K] {\n return useSelector((state: { cdeebee: CdeebeeState<Storage> }) => {\n return state.cdeebee.storage[listName];\n });\n}\n\n/**\n * Standalone hook that can be used without createCdeebeeHooks.\n * Assumes the cdeebee slice is at state.cdeebee.\n *\n * @returns The complete storage object\n */\nexport function useStorage<Storage>(): Storage {\n return useSelector((state: { cdeebee: CdeebeeState<Storage> }) => {\n return state.cdeebee.storage;\n });\n}\n\n/**\n * Standalone hook that can be used without createCdeebeeHooks.\n * Assumes the cdeebee slice is at state.cdeebee.\n *\n * @returns true if any request is active\n */\nexport function useIsLoading<Storage = unknown>(): boolean {\n return useSelector((state: { cdeebee: CdeebeeState<Storage> }) => {\n return state.cdeebee.request.active.length > 0;\n });\n}\n"],"names":["checkModule","settings","module","result","isRecord","value","mergeDeepRight","left","right","rightRecord","key","leftValue","rightValue","omit","keys","obj","batchingUpdate","state","valueList","i","item","path","current","j","pathKey","index","nextIsNumeric","next","AbortControllerStore","api","requestId","controller","apiSet","excludeRequestId","requestIds","abortStore","abortQuery","currentRequestId","abortManager","signal","cleanup","QueryQueue","task","previousPromise","queryQueue","request","createAsyncThunk","options","rejectWithValue","getState","startedAt","abort","withCallback","executeRequest","method","body","headers","extraHeaders","b","requestData","formData","fileKey","bodyKey","response","responseType","error","isDataWithPrimaryKey","normalizeDataWithPrimaryKey","data","primaryKey","applyStrategy","existingValue","newValue","strategy","defaultNormalize","cdeebee","strategyList","keyList","currentStorage","keyListToOmit","responseValue","normalizedValue","initialState","factory","storage","createSlice","action","builder","q","normalize","currentState","normalizedData","createCdeebeeHooks","selectCdeebee","useLoading","apiList","useSelector","useRequestHistory","useRequestErrors","useStorageList","listName","useStorage","useIsLoading"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.cjs","sources":["../lib/reducer/helpers.ts","../lib/reducer/abortController.ts","../lib/reducer/queryQueue.ts","../lib/reducer/request.ts","../lib/reducer/storage.ts","../lib/reducer/index.ts","../lib/hooks/createCdeebeeHooks.ts","../lib/hooks/selectors.ts"],"sourcesContent":["import { type WritableDraft } from '@reduxjs/toolkit';\nimport { type CdeebeeSettings, type CdeebeeModule, CdeebeeValueList } from './types';\n\nexport function checkModule(settings: CdeebeeSettings<unknown> | WritableDraft<CdeebeeSettings<unknown>>, module: CdeebeeModule, result: () => void) {\n if (settings.modules.includes(module)) {\n result();\n }\n}\n\nexport function isRecord(value: unknown): value is Record<string, unknown> {\n return value !== null && typeof value === 'object' && !Array.isArray(value);\n}\n\nexport function mergeDeepRight<T>(\n left: T,\n right: Partial<T> | Record<string, unknown>\n): T {\n if (!isRecord(left) || !isRecord(right)) {\n return right as T;\n }\n\n const result = { ...left } as Record<string, unknown>;\n const rightRecord = right as Record<string, unknown>;\n\n for (const key in rightRecord) {\n if (Object.prototype.hasOwnProperty.call(rightRecord, key)) {\n const leftValue = result[key];\n const rightValue = rightRecord[key];\n\n if (\n isRecord(leftValue) &&\n isRecord(rightValue) &&\n !Array.isArray(leftValue) &&\n !Array.isArray(rightValue)\n ) {\n result[key] = mergeDeepRight(leftValue, rightValue);\n } else {\n result[key] = rightValue;\n }\n }\n }\n\n return result as T;\n}\n\nexport function omit<T extends Record<string, unknown>>(keys: string[], obj: T): Omit<T, keyof T> {\n const result = { ...obj };\n for (const key of keys) {\n delete result[key];\n }\n return result as Omit<T, keyof T>;\n}\n\n/**\n * Extract primary key values from API response data.\n * Handles responses with format: { listName: { data: [...], primaryKey: 'id' } }\n * Returns a flat array of all extracted IDs from all lists.\n */\nexport function extractResultIdList(response: unknown): string[] {\n if (!isRecord(response)) {\n return [];\n }\n\n const ids: string[] = [];\n\n for (const key of Object.keys(response)) {\n const value = response[key];\n\n if (\n isRecord(value) &&\n Array.isArray(value.data) &&\n typeof value.primaryKey === 'string'\n ) {\n const primaryKey = value.primaryKey;\n for (const item of value.data) {\n if (isRecord(item) && primaryKey in item) {\n ids.push(String(item[primaryKey]));\n }\n }\n }\n }\n\n return ids;\n}\n\nexport function batchingUpdate<T extends Record<string, unknown>>(\n state: T,\n valueList: CdeebeeValueList<T>\n): void {\n for (let i = 0; i < valueList.length; i++) {\n const item = valueList[i] as { key: readonly (string | number)[]; value: unknown };\n const path = item.key;\n const value = item.value;\n\n if (path.length === 0) {\n continue;\n }\n\n let current: Record<string, unknown> | unknown[] = state as Record<string, unknown>;\n\n for (let j = 0; j < path.length - 1; j++) {\n const pathKey = path[j];\n\n if (Array.isArray(current)) {\n const index = typeof pathKey === 'number' ? pathKey : Number(pathKey);\n if (!(index in current) || !isRecord(current[index])) {\n current[index] = {};\n }\n current = current[index] as Record<string, unknown>;\n } else {\n const key = String(pathKey);\n if (!(key in current)) {\n const nextIsNumeric = typeof path[j + 1] === 'number' || (!isNaN(Number(path[j + 1])) && String(Number(path[j + 1])) === String(path[j + 1]));\n current[key] = nextIsNumeric ? [] : {};\n }\n const next = current[key];\n current = (Array.isArray(next) ? next : (isRecord(next) ? next : {})) as Record<string, unknown> | unknown[];\n }\n }\n\n if (Array.isArray(current)) {\n continue; // Can't update array element directly\n }\n current[String(path[path.length - 1])] = value;\n }\n}\n","interface RequestController {\n requestId: string;\n controller: AbortController;\n api: string;\n}\n\nclass AbortControllerStore {\n private byRequestId = new Map<string, RequestController>();\n private byApi = new Map<string, Set<string>>();\n\n add(api: string, requestId: string, controller: AbortController): void {\n const item: RequestController = { requestId, controller, api };\n this.byRequestId.set(requestId, item);\n\n if (!this.byApi.has(api)) {\n this.byApi.set(api, new Set());\n }\n this.byApi.get(api)!.add(requestId);\n }\n\n delete(requestId: string): void {\n const item = this.byRequestId.get(requestId);\n if (!item) return;\n\n this.byRequestId.delete(requestId);\n const apiSet = this.byApi.get(item.api);\n if (apiSet) {\n apiSet.delete(requestId);\n if (apiSet.size === 0) {\n this.byApi.delete(item.api);\n }\n }\n }\n\n abortAllForApi(api: string, excludeRequestId: string): void {\n const requestIds = this.byApi.get(api);\n if (!requestIds) return;\n\n requestIds.forEach(requestId => {\n if (requestId !== excludeRequestId) {\n const item = this.byRequestId.get(requestId);\n if (item) {\n item.controller.abort();\n this.delete(requestId);\n }\n }\n });\n }\n}\n\nconst abortStore = new AbortControllerStore();\n\nexport function abortQuery(api: string, currentRequestId: string): void {\n abortStore.abortAllForApi(api, currentRequestId);\n}\n\nexport function abortManager(signal: AbortSignal, api: string, requestId: string) {\n const controller = new AbortController();\n\n const cleanup = () => {\n abortStore.delete(requestId);\n };\n\n signal.addEventListener('abort', () => {\n controller.abort();\n cleanup();\n });\n\n return {\n controller,\n init: () => abortStore.add(api, requestId, controller),\n drop: cleanup,\n };\n}\n","class QueryQueue {\n private currentPromise: Promise<unknown> = Promise.resolve();\n private queueLength = 0;\n\n async enqueue<T>(task: () => Promise<T>): Promise<T> {\n this.queueLength++;\n\n const previousPromise = this.currentPromise;\n\n this.currentPromise = previousPromise\n .then(() => task(), () => task())\n .finally(() => {\n this.queueLength--;\n });\n\n return this.currentPromise as Promise<T>;\n }\n\n getQueueLength(): number {\n return this.queueLength;\n }\n\n clear(): void {\n this.queueLength = 0;\n }\n}\n\nexport const queryQueue = new QueryQueue();\n\n","import { createAsyncThunk } from '@reduxjs/toolkit';\nimport { checkModule } from './helpers';\nimport { abortManager } from './abortController';\nimport { queryQueue } from './queryQueue';\nimport { type CdeebeeState, type CdeebeeRequestOptions } from './types';\n\nexport const request = createAsyncThunk(\n 'cdeebee/request',\n async (options: CdeebeeRequestOptions<unknown>, { rejectWithValue, getState, requestId, signal }) => {\n const startedAt = new Date().toUTCString();\n const { cdeebee: { settings } } = getState() as { cdeebee: CdeebeeState<unknown> };\n\n const abort = abortManager(signal, options.api, requestId);\n const withCallback = options.onResult && typeof options.onResult === 'function';\n\n checkModule(settings, 'cancelation', abort.init);\n\n const executeRequest = async () => {\n try {\n const { method = 'POST', body, headers = {} } = options;\n const baseHeaders = typeof settings.mergeWithHeaders === 'function'\n ? settings.mergeWithHeaders()\n : (settings.mergeWithHeaders ?? {});\n\n const extraHeaders: Record<string, string> = { ...baseHeaders, ...headers };\n\n const baseData = typeof settings.mergeWithData === 'function'\n ? settings.mergeWithData()\n : (settings.mergeWithData ?? {});\n\n const b = { ...baseData, ...(body ?? {}) };\n let requestData: FormData | string = JSON.stringify(b);\n\n // handling files\n if (options.files) {\n const formData = new FormData();\n const fileKey = options.fileKey || settings.fileKey;\n const bodyKey = options.bodyKey || settings.bodyKey;\n\n for (let i = 0; i < options.files.length; i += 1) {\n if (fileKey) {\n formData.append(fileKey, options.files[i]);\n }\n }\n\n if (bodyKey) {\n formData.append(bodyKey, requestData);\n }\n requestData = formData;\n }\n // [end] handling files\n\n const response = await fetch(options.api, {\n method,\n headers: {\n 'ui-request-id': requestId,\n 'Content-Type': 'application/json',\n ...extraHeaders,\n },\n signal: abort.controller.signal,\n body: requestData,\n });\n\n checkModule(settings, 'cancelation', abort.drop);\n\n let result: unknown;\n const responseType = options.responseType || 'json';\n\n if (responseType === 'text') {\n result = await response.text();\n } else if (responseType === 'blob') {\n result = await response.blob();\n } else {\n // default: json\n result = await response.json();\n }\n\n if (!response.ok) {\n if (withCallback) options.onResult!(result);\n return rejectWithValue(response);\n }\n\n if (withCallback) options.onResult!(result);\n return { result, startedAt, endedAt: new Date().toUTCString() };\n } catch (error) {\n checkModule(settings, 'cancelation', abort.drop);\n\n if (withCallback) options.onResult!(error);\n\n if (error instanceof Error && error.name === 'AbortError') {\n return rejectWithValue({ message: 'Request was cancelled', cancelled: true });\n }\n\n return rejectWithValue({ message: error instanceof Error ? error.message : 'Unknown error occurred' });\n }\n };\n\n if (settings.modules.includes('queryQueue')) {\n return queryQueue.enqueue(executeRequest);\n }\n\n return executeRequest();\n },\n);\n\n","import { type CdeebeeListStrategy, type CdeebeeState } from './types';\nimport { isRecord, mergeDeepRight, omit } from './helpers';\n\ntype ResponseValue = Record<string, unknown>;\n\ntype IResponse = Record<string, ResponseValue>;\n\ntype StorageData = Record<string, unknown>;\n\nfunction isDataWithPrimaryKey(value: unknown): value is { data: unknown[]; primaryKey: string } {\n return (\n isRecord(value) &&\n Array.isArray(value.data) &&\n typeof value.primaryKey === 'string'\n );\n}\nfunction normalizeDataWithPrimaryKey(data: unknown[], primaryKey: string): Record<string, unknown> {\n const result: Record<string, unknown> = {};\n \n for (const item of data) {\n if (isRecord(item) && primaryKey in item) {\n const key = String(item[primaryKey]);\n result[key] = item;\n }\n }\n \n return result;\n}\n\nfunction applyStrategy(\n existingValue: StorageData,\n newValue: StorageData | ResponseValue,\n strategy: string,\n key: string\n): ResponseValue {\n if (strategy === 'replace') {\n return newValue as ResponseValue;\n } else if (strategy === 'merge') {\n return mergeDeepRight(existingValue, newValue as StorageData) as ResponseValue;\n } else if (strategy === 'skip') {\n return existingValue as ResponseValue;\n } else {\n console.warn(`Cdeebee: Unknown strategy \"${strategy}\" for key \"${key}\". Skipping normalization.`);\n return mergeDeepRight(existingValue, newValue as StorageData) as ResponseValue;\n }\n}\n\nexport function defaultNormalize<T>(\n cdeebee: CdeebeeState<T>,\n response: IResponse,\n strategyList: CdeebeeListStrategy<T> \n): Record<string, ResponseValue> {\n const keyList = Object.keys(response);\n const currentStorage = isRecord(cdeebee.storage) ? (cdeebee.storage as Record<string, unknown>) : {};\n \n const result = { ...currentStorage } as Record<string, ResponseValue>;\n const keyListToOmit = new Set<string>();\n\n for (const key of keyList) {\n const responseValue = response[key];\n\n if (responseValue === null || responseValue === undefined || typeof responseValue === 'string') {\n keyListToOmit.add(key);\n continue;\n }\n\n const strategy = strategyList[key as keyof T] ?? 'merge';\n \n // For 'skip' strategy, if key doesn't exist in storage, skip it entirely\n if (strategy === 'skip' && !(key in currentStorage)) {\n continue;\n }\n \n const existingValue = key in currentStorage ? (currentStorage[key] as StorageData) : {};\n\n if (isDataWithPrimaryKey(responseValue)) {\n const normalizedValue = normalizeDataWithPrimaryKey(responseValue.data, responseValue.primaryKey);\n result[key] = applyStrategy(existingValue, normalizedValue, strategy, key);\n continue;\n }\n\n if (isRecord(responseValue)) {\n result[key] = applyStrategy(existingValue, responseValue as StorageData, strategy, key);\n } else {\n result[key] = responseValue;\n }\n }\n\n return keyListToOmit.size > 0 ? omit(Array.from(keyListToOmit), result) : result;\n}\n","import { createSlice, current, type PayloadAction } from '@reduxjs/toolkit';\n\nimport { type CdeebeeSettings, type CdeebeeState, type CdeebeeValueList, type CdeebeeListStrategy } from './types';\nimport { checkModule, mergeDeepRight, batchingUpdate, extractResultIdList } from './helpers';\nimport { abortQuery } from './abortController';\nimport { request } from './request';\nimport { defaultNormalize } from './storage';\n\nconst initialState: CdeebeeState<unknown> = {\n settings: {\n modules: ['history', 'listener', 'storage', 'cancelation'],\n fileKey: 'file',\n bodyKey: 'value',\n listStrategy: {},\n mergeWithData: {},\n mergeWithHeaders: {},\n },\n storage: {},\n request: {\n active: [],\n errors: {},\n done: {},\n lastResultIdList: {},\n },\n};\n\nexport const factory = <T>(settings: CdeebeeSettings<T>, storage?: T) => {\n const slice = createSlice({\n name: 'cdeebee',\n initialState: mergeDeepRight(initialState, { settings, storage: storage ?? {} }) as CdeebeeState<T>,\n reducers: {\n set(state, action: { payload: CdeebeeValueList<T> }) {\n // Directly mutate state.storage using Immer Draft\n // This is more performant than creating a new object\n // Immer will track changes and create minimal updates\n batchingUpdate(state.storage as Record<string, unknown>, action.payload);\n },\n historyClear(state, action: PayloadAction<string | undefined>) {\n const api = action.payload;\n\n if (api) {\n delete state.request.done[api];\n delete state.request.errors[api];\n } else {\n state.request.done = {};\n state.request.errors = {};\n }\n }\n },\n extraReducers: builder => {\n builder\n .addCase(request.pending, (state, action) => {\n const api = action.meta.arg.api;\n const requestId = action.meta.requestId;\n\n if (action.meta.arg.historyClear) {\n checkModule(state.settings, 'history', () => {\n delete state.request.done[api];\n delete state.request.errors[api];\n });\n }\n\n checkModule(state.settings, 'cancelation', () => {\n abortQuery(api, requestId);\n });\n checkModule(state.settings, 'listener', () => {\n state.request.active.push({ api, requestId });\n });\n })\n .addCase(request.fulfilled, (state, action) => {\n const requestId = action.meta.requestId;\n const api = action.meta.arg.api;\n\n checkModule(state.settings, 'listener', () => {\n state.request.active = state.request.active.filter(q => !(q.api === api && q.requestId === requestId));\n });\n checkModule(state.settings, 'history', () => {\n if (!state.request.done[api]) state.request.done[api] = [];\n state.request.done[api].push({ api, request: action.payload, requestId });\n });\n checkModule(state.settings, 'storage', () => {\n if (action.meta.arg.ignore) {\n return;\n }\n\n const strategyList = (action.meta.arg.listStrategy ?? state.settings.listStrategy ?? {}) as CdeebeeListStrategy<T>;\n const normalize = action.meta.arg.normalize ?? state.settings.normalize ?? defaultNormalize;\n\n const currentState = current(state) as CdeebeeState<T>;\n // Type assertion is safe here because we've already checked isRecord\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const normalizedData = normalize(currentState, action.payload.result as any, strategyList);\n\n // Normalize already handles merge/replace/skip and preserves keys not in response\n // Simply apply the result\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n (state.storage as any) = normalizedData;\n\n // Extract and store result IDs for filtering\n state.request.lastResultIdList[api] = extractResultIdList(action.payload.result);\n });\n })\n .addCase(request.rejected, (state, action) => {\n const requestId = action.meta.requestId;\n const api = action.meta.arg.api;\n\n checkModule(state.settings, 'listener', () => {\n state.request.active = state.request.active.filter(q => !(q.api === api && q.requestId === requestId));\n });\n checkModule(state.settings, 'history', () => {\n if (!state.request.errors[api]) state.request.errors[api] = [];\n state.request.errors[api].push({ requestId: requestId, api, request: action.error });\n });\n });\n },\n });\n\n return slice;\n};\n","import { useSelector } from 'react-redux';\nimport { type CdeebeeState } from '../reducer/types';\n\n/**\n * Generic hook factory that creates a selector hook for cdeebee state.\n * This allows the hooks to work with any Redux root state structure.\n *\n * @template RootState - The shape of the Redux root state\n * @template Storage - The shape of the cdeebee storage\n * @param selectCdeebee - Function to select the cdeebee slice from root state\n * @returns An object containing all cdeebee hooks\n */\nexport function createCdeebeeHooks<RootState, Storage>(\n selectCdeebee: (state: RootState) => CdeebeeState<Storage>\n) {\n /**\n * Check if any of the specified APIs are currently loading.\n *\n * @param apiList - Array of API endpoints to check\n * @returns true if any of the APIs are currently active/loading\n *\n * @example\n * const isLoading = useLoading(['/api/forums', '/api/threads']);\n * if (isLoading) return <Spinner />;\n */\n function useLoading(apiList: string[]): boolean {\n return useSelector((state: RootState) => {\n const cdeebee = selectCdeebee(state);\n return cdeebee.request.active.some(q => apiList.includes(q.api));\n });\n }\n\n /**\n * Get the successful request history for a specific API endpoint.\n *\n * @param api - The API endpoint\n * @returns Array of successful request history entries\n *\n * @example\n * const history = useRequestHistory('/api/forums');\n * console.log(`Made ${history.length} successful requests`);\n */\n function useRequestHistory(api: string) {\n return useSelector((state: RootState) => {\n const cdeebee = selectCdeebee(state);\n return cdeebee.request.done[api] ?? [];\n });\n }\n\n /**\n * Get the error history for a specific API endpoint.\n *\n * @param api - The API endpoint\n * @returns Array of error history entries\n *\n * @example\n * const errors = useRequestErrors('/api/forums');\n * if (errors.length > 0) {\n * console.error('Last error:', errors[errors.length - 1]);\n * }\n */\n function useRequestErrors(api: string) {\n return useSelector((state: RootState) => {\n const cdeebee = selectCdeebee(state);\n return cdeebee.request.errors[api] ?? [];\n });\n }\n\n /**\n * Get a specific list from storage with full type safety.\n *\n * @param listName - The name of the list in storage\n * @returns The list data\n *\n * @example\n * const forums = useStorageList('forumList');\n * const forumArray = Object.values(forums);\n */\n function useStorageList<K extends keyof Storage>(listName: K): Storage[K] {\n return useSelector((state: RootState) => {\n const cdeebee = selectCdeebee(state);\n return cdeebee.storage[listName];\n });\n }\n\n /**\n * Get the entire cdeebee storage.\n *\n * @returns The complete storage object\n *\n * @example\n * const storage = useStorage();\n * console.log(Object.keys(storage)); // ['forumList', 'threadList', ...]\n */\n function useStorage(): Storage {\n return useSelector((state: RootState) => {\n const cdeebee = selectCdeebee(state);\n return cdeebee.storage;\n });\n }\n\n /**\n * Check if any request is currently loading (across all APIs).\n *\n * @returns true if any request is active\n *\n * @example\n * const isAnythingLoading = useIsLoading();\n * if (isAnythingLoading) return <GlobalSpinner />;\n */\n function useIsLoading(): boolean {\n return useSelector((state: RootState) => {\n const cdeebee = selectCdeebee(state);\n return cdeebee.request.active.length > 0;\n });\n }\n\n /**\n * Get the list of IDs returned by the last successful request to an API.\n * Useful for filtering storage data to show only results from a specific request.\n *\n * @param api - The API endpoint\n * @returns Array of primary key IDs from the last response\n *\n * @example\n * const productList = useStorageList('productList');\n * const lastIds = useLastResultIdList('/api/search');\n * const displayResults = lastIds.map(id => productList[id]).filter(Boolean);\n */\n function useLastResultIdList(api: string): string[] {\n return useSelector((state: RootState) => {\n const cdeebee = selectCdeebee(state);\n return cdeebee.request.lastResultIdList[api] ?? [];\n });\n }\n\n return {\n useLoading,\n useRequestHistory,\n useRequestErrors,\n useStorageList,\n useStorage,\n useIsLoading,\n useLastResultIdList,\n };\n}\n","import { useSelector } from 'react-redux';\nimport { type CdeebeeState } from '../reducer/types';\n\n/**\n * Standalone hook that can be used without createCdeebeeHooks.\n * Assumes the cdeebee slice is at state.cdeebee.\n *\n * @param apiList - Array of API endpoints to check\n * @returns true if any of the APIs are currently active/loading\n *\n * @example\n * const isLoading = useLoading(['/api/forums', '/api/threads']);\n */\nexport function useLoading<Storage = unknown>(apiList: string[]): boolean {\n return useSelector((state: { cdeebee: CdeebeeState<Storage> }) => {\n return state.cdeebee.request.active.some(q => apiList.includes(q.api));\n });\n}\n\n/**\n * Standalone hook that can be used without createCdeebeeHooks.\n * Assumes the cdeebee slice is at state.cdeebee.\n *\n * @param api - The API endpoint\n * @returns Array of successful request history entries\n */\nexport function useRequestHistory<Storage = unknown>(api: string) {\n return useSelector((state: { cdeebee: CdeebeeState<Storage> }) => {\n return state.cdeebee.request.done[api] ?? [];\n });\n}\n\n/**\n * Standalone hook that can be used without createCdeebeeHooks.\n * Assumes the cdeebee slice is at state.cdeebee.\n *\n * @param api - The API endpoint\n * @returns Array of error history entries\n */\nexport function useRequestErrors<Storage = unknown>(api: string) {\n return useSelector((state: { cdeebee: CdeebeeState<Storage> }) => {\n return state.cdeebee.request.errors[api] ?? [];\n });\n}\n\n/**\n * Standalone hook that can be used without createCdeebeeHooks.\n * Assumes the cdeebee slice is at state.cdeebee.\n *\n * @param listName - The name of the list in storage\n * @returns The list data\n */\nexport function useStorageList<Storage, K extends keyof Storage>(listName: K): Storage[K] {\n return useSelector((state: { cdeebee: CdeebeeState<Storage> }) => {\n return state.cdeebee.storage[listName];\n });\n}\n\n/**\n * Standalone hook that can be used without createCdeebeeHooks.\n * Assumes the cdeebee slice is at state.cdeebee.\n *\n * @returns The complete storage object\n */\nexport function useStorage<Storage>(): Storage {\n return useSelector((state: { cdeebee: CdeebeeState<Storage> }) => {\n return state.cdeebee.storage;\n });\n}\n\n/**\n * Standalone hook that can be used without createCdeebeeHooks.\n * Assumes the cdeebee slice is at state.cdeebee.\n *\n * @returns true if any request is active\n */\nexport function useIsLoading<Storage = unknown>(): boolean {\n return useSelector((state: { cdeebee: CdeebeeState<Storage> }) => {\n return state.cdeebee.request.active.length > 0;\n });\n}\n\n/**\n * Standalone hook that can be used without createCdeebeeHooks.\n * Assumes the cdeebee slice is at state.cdeebee.\n *\n * Get the list of IDs returned by the last successful request to an API.\n * Useful for filtering storage data to show only results from a specific request.\n *\n * @param api - The API endpoint\n * @returns Array of primary key IDs from the last response\n *\n * @example\n * const productList = useStorageList('productList');\n * const lastIds = useLastResultIdList('/api/search');\n * const displayResults = lastIds.map(id => productList[id]).filter(Boolean);\n */\nexport function useLastResultIdList<Storage = unknown>(api: string): string[] {\n return useSelector((state: { cdeebee: CdeebeeState<Storage> }) => {\n return state.cdeebee.request.lastResultIdList[api] ?? [];\n });\n}\n"],"names":["checkModule","settings","module","result","isRecord","value","mergeDeepRight","left","right","rightRecord","key","leftValue","rightValue","omit","keys","obj","extractResultIdList","response","ids","primaryKey","item","batchingUpdate","state","valueList","i","path","current","j","pathKey","index","nextIsNumeric","next","AbortControllerStore","api","requestId","controller","apiSet","excludeRequestId","requestIds","abortStore","abortQuery","currentRequestId","abortManager","signal","cleanup","QueryQueue","task","previousPromise","queryQueue","request","createAsyncThunk","options","rejectWithValue","getState","startedAt","abort","withCallback","executeRequest","method","body","headers","extraHeaders","b","requestData","formData","fileKey","bodyKey","responseType","error","isDataWithPrimaryKey","normalizeDataWithPrimaryKey","data","applyStrategy","existingValue","newValue","strategy","defaultNormalize","cdeebee","strategyList","keyList","currentStorage","keyListToOmit","responseValue","normalizedValue","initialState","factory","storage","createSlice","action","builder","q","normalize","currentState","normalizedData","createCdeebeeHooks","selectCdeebee","useLoading","apiList","useSelector","useRequestHistory","useRequestErrors","useStorageList","listName","useStorage","useIsLoading","useLastResultIdList"],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -43,14 +43,15 @@ declare interface CdeebeeRequestState {
|
|
|
43
43
|
active: CdeebeeActiveRequest[];
|
|
44
44
|
errors: Record<string, CdeebeeHistoryState[]>;
|
|
45
45
|
done: Record<string, CdeebeeHistoryState[]>;
|
|
46
|
+
lastResultIdList: Record<string, string[]>;
|
|
46
47
|
}
|
|
47
48
|
|
|
48
49
|
declare interface CdeebeeSettings<T> {
|
|
49
50
|
modules: CdeebeeModule[];
|
|
50
51
|
fileKey: string;
|
|
51
52
|
bodyKey: string;
|
|
52
|
-
mergeWithData: unknown;
|
|
53
|
-
mergeWithHeaders:
|
|
53
|
+
mergeWithData: Record<string, unknown> | (() => Record<string, unknown>);
|
|
54
|
+
mergeWithHeaders: Record<string, string> | (() => Record<string, string>);
|
|
54
55
|
listStrategy?: CdeebeeListStrategy<T>;
|
|
55
56
|
normalize?: <T>(storage: CdeebeeState<T>, result: T, strategyList: CdeebeeListStrategy<T>) => T;
|
|
56
57
|
}
|
|
@@ -86,16 +87,23 @@ export declare function createCdeebeeHooks<RootState, Storage>(selectCdeebee: (s
|
|
|
86
87
|
useStorageList: <K extends keyof Storage>(listName: K) => Storage[K];
|
|
87
88
|
useStorage: () => Storage;
|
|
88
89
|
useIsLoading: () => boolean;
|
|
90
|
+
useLastResultIdList: (api: string) => string[];
|
|
89
91
|
};
|
|
90
92
|
|
|
93
|
+
export declare function defaultNormalize<T>(cdeebee: CdeebeeState<T>, response: IResponse, strategyList: CdeebeeListStrategy<T>): Record<string, ResponseValue>;
|
|
94
|
+
|
|
91
95
|
export declare const factory: <T>(settings: CdeebeeSettings<T>, storage?: T) => Slice<CdeebeeState<T>, {
|
|
92
96
|
set(state: {
|
|
93
97
|
settings: {
|
|
94
98
|
modules: CdeebeeModule[];
|
|
95
99
|
fileKey: string;
|
|
96
100
|
bodyKey: string;
|
|
97
|
-
mergeWithData: unknown
|
|
98
|
-
|
|
101
|
+
mergeWithData: (() => Record<string, unknown>) | {
|
|
102
|
+
[x: string]: unknown;
|
|
103
|
+
};
|
|
104
|
+
mergeWithHeaders: (() => Record<string, string>) | {
|
|
105
|
+
[x: string]: string;
|
|
106
|
+
};
|
|
99
107
|
listStrategy?: (CdeebeeListStrategy<T> | undefined extends infer V ? V extends object ? Draft<V> : V : never) | undefined;
|
|
100
108
|
normalize?: (<T_1>(storage: CdeebeeState<T_1>, result: T_1, strategyList: CdeebeeListStrategy<T_1>) => T_1) | undefined;
|
|
101
109
|
};
|
|
@@ -119,6 +127,9 @@ api: string;
|
|
|
119
127
|
request: unknown;
|
|
120
128
|
}[];
|
|
121
129
|
};
|
|
130
|
+
lastResultIdList: {
|
|
131
|
+
[x: string]: string[];
|
|
132
|
+
};
|
|
122
133
|
};
|
|
123
134
|
}, action: {
|
|
124
135
|
payload: CdeebeeValueList<T>;
|
|
@@ -128,8 +139,12 @@ settings: {
|
|
|
128
139
|
modules: CdeebeeModule[];
|
|
129
140
|
fileKey: string;
|
|
130
141
|
bodyKey: string;
|
|
131
|
-
mergeWithData: unknown
|
|
132
|
-
|
|
142
|
+
mergeWithData: (() => Record<string, unknown>) | {
|
|
143
|
+
[x: string]: unknown;
|
|
144
|
+
};
|
|
145
|
+
mergeWithHeaders: (() => Record<string, string>) | {
|
|
146
|
+
[x: string]: string;
|
|
147
|
+
};
|
|
133
148
|
listStrategy?: (CdeebeeListStrategy<T> | undefined extends infer V ? V extends object ? Draft<V> : V : never) | undefined;
|
|
134
149
|
normalize?: (<T_1>(storage: CdeebeeState<T_1>, result: T_1, strategyList: CdeebeeListStrategy<T_1>) => T_1) | undefined;
|
|
135
150
|
};
|
|
@@ -153,10 +168,15 @@ api: string;
|
|
|
153
168
|
request: unknown;
|
|
154
169
|
}[];
|
|
155
170
|
};
|
|
171
|
+
lastResultIdList: {
|
|
172
|
+
[x: string]: string[];
|
|
173
|
+
};
|
|
156
174
|
};
|
|
157
175
|
}, action: PayloadAction<string | undefined>): void;
|
|
158
176
|
}, "cdeebee", "cdeebee", SliceSelectors<CdeebeeState<T>>>;
|
|
159
177
|
|
|
178
|
+
declare type IResponse = Record<string, ResponseValue>;
|
|
179
|
+
|
|
160
180
|
declare type IsArray<T> = T extends readonly unknown[] ? true : T extends unknown[] ? true : false;
|
|
161
181
|
|
|
162
182
|
declare type KeyOf<T> = Extract<keyof T, string | number>;
|
|
@@ -173,6 +193,8 @@ startedAt: string;
|
|
|
173
193
|
endedAt: string;
|
|
174
194
|
}, CdeebeeRequestOptions<unknown>, AsyncThunkConfig>;
|
|
175
195
|
|
|
196
|
+
declare type ResponseValue = Record<string, unknown>;
|
|
197
|
+
|
|
176
198
|
/**
|
|
177
199
|
* Standalone hook that can be used without createCdeebeeHooks.
|
|
178
200
|
* Assumes the cdeebee slice is at state.cdeebee.
|
|
@@ -181,6 +203,23 @@ endedAt: string;
|
|
|
181
203
|
*/
|
|
182
204
|
export declare function useIsLoading<Storage = unknown>(): boolean;
|
|
183
205
|
|
|
206
|
+
/**
|
|
207
|
+
* Standalone hook that can be used without createCdeebeeHooks.
|
|
208
|
+
* Assumes the cdeebee slice is at state.cdeebee.
|
|
209
|
+
*
|
|
210
|
+
* Get the list of IDs returned by the last successful request to an API.
|
|
211
|
+
* Useful for filtering storage data to show only results from a specific request.
|
|
212
|
+
*
|
|
213
|
+
* @param api - The API endpoint
|
|
214
|
+
* @returns Array of primary key IDs from the last response
|
|
215
|
+
*
|
|
216
|
+
* @example
|
|
217
|
+
* const productList = useStorageList('productList');
|
|
218
|
+
* const lastIds = useLastResultIdList('/api/search');
|
|
219
|
+
* const displayResults = lastIds.map(id => productList[id]).filter(Boolean);
|
|
220
|
+
*/
|
|
221
|
+
export declare function useLastResultIdList<Storage = unknown>(api: string): string[];
|
|
222
|
+
|
|
184
223
|
/**
|
|
185
224
|
* Standalone hook that can be used without createCdeebeeHooks.
|
|
186
225
|
* Assumes the cdeebee slice is at state.cdeebee.
|
package/dist/index.js
CHANGED
|
@@ -1,94 +1,108 @@
|
|
|
1
|
-
import { createAsyncThunk as
|
|
1
|
+
import { createAsyncThunk as z, createSlice as H, current as P } from "@reduxjs/toolkit";
|
|
2
2
|
import { useSelector as d } from "react-redux";
|
|
3
|
-
function
|
|
3
|
+
function y(e, r, s) {
|
|
4
4
|
e.modules.includes(r) && s();
|
|
5
5
|
}
|
|
6
|
-
function
|
|
6
|
+
function f(e) {
|
|
7
7
|
return e !== null && typeof e == "object" && !Array.isArray(e);
|
|
8
8
|
}
|
|
9
|
-
function
|
|
10
|
-
if (!
|
|
9
|
+
function h(e, r) {
|
|
10
|
+
if (!f(e) || !f(r))
|
|
11
11
|
return r;
|
|
12
|
-
const s = { ...e },
|
|
13
|
-
for (const t in
|
|
14
|
-
if (Object.prototype.hasOwnProperty.call(
|
|
15
|
-
const
|
|
16
|
-
|
|
12
|
+
const s = { ...e }, n = r;
|
|
13
|
+
for (const t in n)
|
|
14
|
+
if (Object.prototype.hasOwnProperty.call(n, t)) {
|
|
15
|
+
const o = s[t], i = n[t];
|
|
16
|
+
f(o) && f(i) && !Array.isArray(o) && !Array.isArray(i) ? s[t] = h(o, i) : s[t] = i;
|
|
17
17
|
}
|
|
18
18
|
return s;
|
|
19
19
|
}
|
|
20
|
-
function
|
|
20
|
+
function x(e, r) {
|
|
21
21
|
const s = { ...r };
|
|
22
|
-
for (const
|
|
23
|
-
delete s[
|
|
22
|
+
for (const n of e)
|
|
23
|
+
delete s[n];
|
|
24
24
|
return s;
|
|
25
25
|
}
|
|
26
|
-
function
|
|
26
|
+
function N(e) {
|
|
27
|
+
if (!f(e))
|
|
28
|
+
return [];
|
|
29
|
+
const r = [];
|
|
30
|
+
for (const s of Object.keys(e)) {
|
|
31
|
+
const n = e[s];
|
|
32
|
+
if (f(n) && Array.isArray(n.data) && typeof n.primaryKey == "string") {
|
|
33
|
+
const t = n.primaryKey;
|
|
34
|
+
for (const o of n.data)
|
|
35
|
+
f(o) && t in o && r.push(String(o[t]));
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return r;
|
|
39
|
+
}
|
|
40
|
+
function T(e, r) {
|
|
27
41
|
for (let s = 0; s < r.length; s++) {
|
|
28
|
-
const
|
|
42
|
+
const n = r[s], t = n.key, o = n.value;
|
|
29
43
|
if (t.length === 0)
|
|
30
44
|
continue;
|
|
31
45
|
let i = e;
|
|
32
|
-
for (let
|
|
33
|
-
const
|
|
46
|
+
for (let u = 0; u < t.length - 1; u++) {
|
|
47
|
+
const a = t[u];
|
|
34
48
|
if (Array.isArray(i)) {
|
|
35
|
-
const
|
|
36
|
-
(!(
|
|
49
|
+
const c = typeof a == "number" ? a : Number(a);
|
|
50
|
+
(!(c in i) || !f(i[c])) && (i[c] = {}), i = i[c];
|
|
37
51
|
} else {
|
|
38
|
-
const
|
|
39
|
-
if (!(
|
|
40
|
-
const g = typeof t[
|
|
41
|
-
i[
|
|
52
|
+
const c = String(a);
|
|
53
|
+
if (!(c in i)) {
|
|
54
|
+
const g = typeof t[u + 1] == "number" || !isNaN(Number(t[u + 1])) && String(Number(t[u + 1])) === String(t[u + 1]);
|
|
55
|
+
i[c] = g ? [] : {};
|
|
42
56
|
}
|
|
43
|
-
const l = i[
|
|
44
|
-
i = Array.isArray(l) ||
|
|
57
|
+
const l = i[c];
|
|
58
|
+
i = Array.isArray(l) || f(l) ? l : {};
|
|
45
59
|
}
|
|
46
60
|
}
|
|
47
|
-
Array.isArray(i) || (i[String(t[t.length - 1])] =
|
|
61
|
+
Array.isArray(i) || (i[String(t[t.length - 1])] = o);
|
|
48
62
|
}
|
|
49
63
|
}
|
|
50
|
-
class
|
|
64
|
+
class W {
|
|
51
65
|
constructor() {
|
|
52
66
|
this.byRequestId = /* @__PURE__ */ new Map(), this.byApi = /* @__PURE__ */ new Map();
|
|
53
67
|
}
|
|
54
|
-
add(r, s,
|
|
55
|
-
const t = { requestId: s, controller:
|
|
68
|
+
add(r, s, n) {
|
|
69
|
+
const t = { requestId: s, controller: n, api: r };
|
|
56
70
|
this.byRequestId.set(s, t), this.byApi.has(r) || this.byApi.set(r, /* @__PURE__ */ new Set()), this.byApi.get(r).add(s);
|
|
57
71
|
}
|
|
58
72
|
delete(r) {
|
|
59
73
|
const s = this.byRequestId.get(r);
|
|
60
74
|
if (!s) return;
|
|
61
75
|
this.byRequestId.delete(r);
|
|
62
|
-
const
|
|
63
|
-
|
|
76
|
+
const n = this.byApi.get(s.api);
|
|
77
|
+
n && (n.delete(r), n.size === 0 && this.byApi.delete(s.api));
|
|
64
78
|
}
|
|
65
79
|
abortAllForApi(r, s) {
|
|
66
|
-
const
|
|
67
|
-
|
|
80
|
+
const n = this.byApi.get(r);
|
|
81
|
+
n && n.forEach((t) => {
|
|
68
82
|
if (t !== s) {
|
|
69
|
-
const
|
|
70
|
-
|
|
83
|
+
const o = this.byRequestId.get(t);
|
|
84
|
+
o && (o.controller.abort(), this.delete(t));
|
|
71
85
|
}
|
|
72
86
|
});
|
|
73
87
|
}
|
|
74
88
|
}
|
|
75
|
-
const R = new
|
|
76
|
-
function
|
|
89
|
+
const R = new W();
|
|
90
|
+
function j(e, r) {
|
|
77
91
|
R.abortAllForApi(e, r);
|
|
78
92
|
}
|
|
79
|
-
function
|
|
80
|
-
const
|
|
93
|
+
function C(e, r, s) {
|
|
94
|
+
const n = new AbortController(), t = () => {
|
|
81
95
|
R.delete(s);
|
|
82
96
|
};
|
|
83
97
|
return e.addEventListener("abort", () => {
|
|
84
|
-
|
|
98
|
+
n.abort(), t();
|
|
85
99
|
}), {
|
|
86
|
-
controller:
|
|
87
|
-
init: () => R.add(r, s,
|
|
100
|
+
controller: n,
|
|
101
|
+
init: () => R.add(r, s, n),
|
|
88
102
|
drop: t
|
|
89
103
|
};
|
|
90
104
|
}
|
|
91
|
-
class
|
|
105
|
+
class E {
|
|
92
106
|
constructor() {
|
|
93
107
|
this.currentPromise = Promise.resolve(), this.queueLength = 0;
|
|
94
108
|
}
|
|
@@ -106,79 +120,79 @@ class j {
|
|
|
106
120
|
this.queueLength = 0;
|
|
107
121
|
}
|
|
108
122
|
}
|
|
109
|
-
const O = new
|
|
123
|
+
const O = new E(), S = z(
|
|
110
124
|
"cdeebee/request",
|
|
111
|
-
async (e, { rejectWithValue: r, getState: s, requestId:
|
|
112
|
-
const
|
|
113
|
-
|
|
114
|
-
const
|
|
125
|
+
async (e, { rejectWithValue: r, getState: s, requestId: n, signal: t }) => {
|
|
126
|
+
const o = (/* @__PURE__ */ new Date()).toUTCString(), { cdeebee: { settings: i } } = s(), u = C(t, e.api, n), a = e.onResult && typeof e.onResult == "function";
|
|
127
|
+
y(i, "cancelation", u.init);
|
|
128
|
+
const c = async () => {
|
|
115
129
|
try {
|
|
116
|
-
const { method: l = "POST", body: g, headers:
|
|
117
|
-
let p = JSON.stringify(
|
|
130
|
+
const { method: l = "POST", body: g, headers: D = {} } = e, K = { ...typeof i.mergeWithHeaders == "function" ? i.mergeWithHeaders() : i.mergeWithHeaders ?? {}, ...D }, v = { ...typeof i.mergeWithData == "function" ? i.mergeWithData() : i.mergeWithData ?? {}, ...g ?? {} };
|
|
131
|
+
let p = JSON.stringify(v);
|
|
118
132
|
if (e.files) {
|
|
119
|
-
const q = new FormData(),
|
|
133
|
+
const q = new FormData(), k = e.fileKey || i.fileKey, w = e.bodyKey || i.bodyKey;
|
|
120
134
|
for (let A = 0; A < e.files.length; A += 1)
|
|
121
|
-
|
|
122
|
-
|
|
135
|
+
k && q.append(k, e.files[A]);
|
|
136
|
+
w && q.append(w, p), p = q;
|
|
123
137
|
}
|
|
124
|
-
const
|
|
138
|
+
const b = await fetch(e.api, {
|
|
125
139
|
method: l,
|
|
126
140
|
headers: {
|
|
127
|
-
"ui-request-id":
|
|
141
|
+
"ui-request-id": n,
|
|
128
142
|
"Content-Type": "application/json",
|
|
129
|
-
...
|
|
143
|
+
...K
|
|
130
144
|
},
|
|
131
|
-
signal:
|
|
145
|
+
signal: u.controller.signal,
|
|
132
146
|
body: p
|
|
133
147
|
});
|
|
134
|
-
|
|
148
|
+
y(i, "cancelation", u.drop);
|
|
135
149
|
let m;
|
|
136
|
-
const
|
|
137
|
-
return
|
|
150
|
+
const L = e.responseType || "json";
|
|
151
|
+
return L === "text" ? m = await b.text() : L === "blob" ? m = await b.blob() : m = await b.json(), b.ok ? (a && e.onResult(m), { result: m, startedAt: o, endedAt: (/* @__PURE__ */ new Date()).toUTCString() }) : (a && e.onResult(m), r(b));
|
|
138
152
|
} catch (l) {
|
|
139
|
-
return
|
|
153
|
+
return y(i, "cancelation", u.drop), a && e.onResult(l), l instanceof Error && l.name === "AbortError" ? r({ message: "Request was cancelled", cancelled: !0 }) : r({ message: l instanceof Error ? l.message : "Unknown error occurred" });
|
|
140
154
|
}
|
|
141
155
|
};
|
|
142
|
-
return i.modules.includes("queryQueue") ? O.enqueue(
|
|
156
|
+
return i.modules.includes("queryQueue") ? O.enqueue(c) : c();
|
|
143
157
|
}
|
|
144
158
|
);
|
|
145
159
|
function Q(e) {
|
|
146
|
-
return
|
|
160
|
+
return f(e) && Array.isArray(e.data) && typeof e.primaryKey == "string";
|
|
147
161
|
}
|
|
148
162
|
function U(e, r) {
|
|
149
163
|
const s = {};
|
|
150
|
-
for (const
|
|
151
|
-
if (
|
|
152
|
-
const t = String(
|
|
153
|
-
s[t] =
|
|
164
|
+
for (const n of e)
|
|
165
|
+
if (f(n) && r in n) {
|
|
166
|
+
const t = String(n[r]);
|
|
167
|
+
s[t] = n;
|
|
154
168
|
}
|
|
155
169
|
return s;
|
|
156
170
|
}
|
|
157
|
-
function
|
|
158
|
-
return s === "replace" ? r : s === "merge" ?
|
|
171
|
+
function I(e, r, s, n) {
|
|
172
|
+
return s === "replace" ? r : s === "merge" ? h(e, r) : s === "skip" ? e : (console.warn(`Cdeebee: Unknown strategy "${s}" for key "${n}". Skipping normalization.`), h(e, r));
|
|
159
173
|
}
|
|
160
174
|
function M(e, r, s) {
|
|
161
|
-
const
|
|
162
|
-
for (const
|
|
163
|
-
const
|
|
164
|
-
if (
|
|
165
|
-
i.add(
|
|
175
|
+
const n = Object.keys(r), t = f(e.storage) ? e.storage : {}, o = { ...t }, i = /* @__PURE__ */ new Set();
|
|
176
|
+
for (const u of n) {
|
|
177
|
+
const a = r[u];
|
|
178
|
+
if (a == null || typeof a == "string") {
|
|
179
|
+
i.add(u);
|
|
166
180
|
continue;
|
|
167
181
|
}
|
|
168
|
-
const
|
|
169
|
-
if (
|
|
182
|
+
const c = s[u] ?? "merge";
|
|
183
|
+
if (c === "skip" && !(u in t))
|
|
170
184
|
continue;
|
|
171
|
-
const l =
|
|
172
|
-
if (Q(
|
|
173
|
-
const g = U(
|
|
174
|
-
u
|
|
185
|
+
const l = u in t ? t[u] : {};
|
|
186
|
+
if (Q(a)) {
|
|
187
|
+
const g = U(a.data, a.primaryKey);
|
|
188
|
+
o[u] = I(l, g, c, u);
|
|
175
189
|
continue;
|
|
176
190
|
}
|
|
177
|
-
|
|
191
|
+
f(a) ? o[u] = I(l, a, c, u) : o[u] = a;
|
|
178
192
|
}
|
|
179
|
-
return i.size > 0 ?
|
|
193
|
+
return i.size > 0 ? x(Array.from(i), o) : o;
|
|
180
194
|
}
|
|
181
|
-
const
|
|
195
|
+
const F = {
|
|
182
196
|
settings: {
|
|
183
197
|
modules: ["history", "listener", "storage", "cancelation"],
|
|
184
198
|
fileKey: "file",
|
|
@@ -191,108 +205,118 @@ const W = {
|
|
|
191
205
|
request: {
|
|
192
206
|
active: [],
|
|
193
207
|
errors: {},
|
|
194
|
-
done: {}
|
|
208
|
+
done: {},
|
|
209
|
+
lastResultIdList: {}
|
|
195
210
|
}
|
|
196
|
-
},
|
|
211
|
+
}, X = (e, r) => H({
|
|
197
212
|
name: "cdeebee",
|
|
198
|
-
initialState:
|
|
213
|
+
initialState: h(F, { settings: e, storage: r ?? {} }),
|
|
199
214
|
reducers: {
|
|
200
|
-
set(
|
|
201
|
-
|
|
215
|
+
set(n, t) {
|
|
216
|
+
T(n.storage, t.payload);
|
|
202
217
|
},
|
|
203
|
-
historyClear(
|
|
204
|
-
const
|
|
205
|
-
|
|
218
|
+
historyClear(n, t) {
|
|
219
|
+
const o = t.payload;
|
|
220
|
+
o ? (delete n.request.done[o], delete n.request.errors[o]) : (n.request.done = {}, n.request.errors = {});
|
|
206
221
|
}
|
|
207
222
|
},
|
|
208
|
-
extraReducers: (
|
|
209
|
-
|
|
210
|
-
const i =
|
|
211
|
-
|
|
223
|
+
extraReducers: (n) => {
|
|
224
|
+
n.addCase(S.pending, (t, o) => {
|
|
225
|
+
const i = o.meta.arg.api, u = o.meta.requestId;
|
|
226
|
+
o.meta.arg.historyClear && y(t.settings, "history", () => {
|
|
212
227
|
delete t.request.done[i], delete t.request.errors[i];
|
|
213
|
-
}),
|
|
214
|
-
|
|
215
|
-
}),
|
|
216
|
-
t.request.active.push({ api: i, requestId:
|
|
228
|
+
}), y(t.settings, "cancelation", () => {
|
|
229
|
+
j(i, u);
|
|
230
|
+
}), y(t.settings, "listener", () => {
|
|
231
|
+
t.request.active.push({ api: i, requestId: u });
|
|
217
232
|
});
|
|
218
|
-
}).addCase(S.fulfilled, (t,
|
|
219
|
-
const i =
|
|
220
|
-
|
|
221
|
-
t.request.active = t.request.active.filter((
|
|
222
|
-
}),
|
|
223
|
-
t.request.done[
|
|
224
|
-
}),
|
|
225
|
-
if (
|
|
233
|
+
}).addCase(S.fulfilled, (t, o) => {
|
|
234
|
+
const i = o.meta.requestId, u = o.meta.arg.api;
|
|
235
|
+
y(t.settings, "listener", () => {
|
|
236
|
+
t.request.active = t.request.active.filter((a) => !(a.api === u && a.requestId === i));
|
|
237
|
+
}), y(t.settings, "history", () => {
|
|
238
|
+
t.request.done[u] || (t.request.done[u] = []), t.request.done[u].push({ api: u, request: o.payload, requestId: i });
|
|
239
|
+
}), y(t.settings, "storage", () => {
|
|
240
|
+
if (o.meta.arg.ignore)
|
|
226
241
|
return;
|
|
227
|
-
const
|
|
228
|
-
t.storage = g;
|
|
242
|
+
const a = o.meta.arg.listStrategy ?? t.settings.listStrategy ?? {}, c = o.meta.arg.normalize ?? t.settings.normalize ?? M, l = P(t), g = c(l, o.payload.result, a);
|
|
243
|
+
t.storage = g, t.request.lastResultIdList[u] = N(o.payload.result);
|
|
229
244
|
});
|
|
230
|
-
}).addCase(S.rejected, (t,
|
|
231
|
-
const i =
|
|
232
|
-
|
|
233
|
-
t.request.active = t.request.active.filter((
|
|
234
|
-
}),
|
|
235
|
-
t.request.errors[
|
|
245
|
+
}).addCase(S.rejected, (t, o) => {
|
|
246
|
+
const i = o.meta.requestId, u = o.meta.arg.api;
|
|
247
|
+
y(t.settings, "listener", () => {
|
|
248
|
+
t.request.active = t.request.active.filter((a) => !(a.api === u && a.requestId === i));
|
|
249
|
+
}), y(t.settings, "history", () => {
|
|
250
|
+
t.request.errors[u] || (t.request.errors[u] = []), t.request.errors[u].push({ requestId: i, api: u, request: o.error });
|
|
236
251
|
});
|
|
237
252
|
});
|
|
238
253
|
}
|
|
239
254
|
});
|
|
240
|
-
function
|
|
241
|
-
function r(
|
|
242
|
-
return d((c) => e(c).request.active.some((
|
|
255
|
+
function Y(e) {
|
|
256
|
+
function r(a) {
|
|
257
|
+
return d((c) => e(c).request.active.some((g) => a.includes(g.api)));
|
|
243
258
|
}
|
|
244
|
-
function s(
|
|
245
|
-
return d((c) => e(c).request.done[
|
|
259
|
+
function s(a) {
|
|
260
|
+
return d((c) => e(c).request.done[a] ?? []);
|
|
246
261
|
}
|
|
247
|
-
function
|
|
248
|
-
return d((c) => e(c).request.errors[
|
|
262
|
+
function n(a) {
|
|
263
|
+
return d((c) => e(c).request.errors[a] ?? []);
|
|
249
264
|
}
|
|
250
|
-
function t(
|
|
251
|
-
return d((c) => e(c).storage[
|
|
265
|
+
function t(a) {
|
|
266
|
+
return d((c) => e(c).storage[a]);
|
|
252
267
|
}
|
|
253
|
-
function
|
|
254
|
-
return d((
|
|
268
|
+
function o() {
|
|
269
|
+
return d((a) => e(a).storage);
|
|
255
270
|
}
|
|
256
271
|
function i() {
|
|
257
|
-
return d((
|
|
272
|
+
return d((a) => e(a).request.active.length > 0);
|
|
273
|
+
}
|
|
274
|
+
function u(a) {
|
|
275
|
+
return d((c) => e(c).request.lastResultIdList[a] ?? []);
|
|
258
276
|
}
|
|
259
277
|
return {
|
|
260
278
|
useLoading: r,
|
|
261
279
|
useRequestHistory: s,
|
|
262
|
-
useRequestErrors:
|
|
280
|
+
useRequestErrors: n,
|
|
263
281
|
useStorageList: t,
|
|
264
|
-
useStorage:
|
|
265
|
-
useIsLoading: i
|
|
282
|
+
useStorage: o,
|
|
283
|
+
useIsLoading: i,
|
|
284
|
+
useLastResultIdList: u
|
|
266
285
|
};
|
|
267
286
|
}
|
|
268
|
-
function
|
|
287
|
+
function Z(e) {
|
|
269
288
|
return d((r) => r.cdeebee.request.active.some((s) => e.includes(s.api)));
|
|
270
289
|
}
|
|
271
|
-
function
|
|
290
|
+
function _(e) {
|
|
272
291
|
return d((r) => r.cdeebee.request.done[e] ?? []);
|
|
273
292
|
}
|
|
274
|
-
function
|
|
293
|
+
function V(e) {
|
|
275
294
|
return d((r) => r.cdeebee.request.errors[e] ?? []);
|
|
276
295
|
}
|
|
277
|
-
function
|
|
296
|
+
function ee(e) {
|
|
278
297
|
return d((r) => r.cdeebee.storage[e]);
|
|
279
298
|
}
|
|
280
|
-
function
|
|
299
|
+
function te() {
|
|
281
300
|
return d((e) => e.cdeebee.storage);
|
|
282
301
|
}
|
|
283
|
-
function
|
|
302
|
+
function re() {
|
|
284
303
|
return d((e) => e.cdeebee.request.active.length > 0);
|
|
285
304
|
}
|
|
305
|
+
function ne(e) {
|
|
306
|
+
return d((r) => r.cdeebee.request.lastResultIdList[e] ?? []);
|
|
307
|
+
}
|
|
286
308
|
export {
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
309
|
+
T as batchingUpdate,
|
|
310
|
+
Y as createCdeebeeHooks,
|
|
311
|
+
M as defaultNormalize,
|
|
312
|
+
X as factory,
|
|
290
313
|
S as request,
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
_ as
|
|
296
|
-
|
|
314
|
+
re as useIsLoading,
|
|
315
|
+
ne as useLastResultIdList,
|
|
316
|
+
Z as useLoading,
|
|
317
|
+
V as useRequestErrors,
|
|
318
|
+
_ as useRequestHistory,
|
|
319
|
+
te as useStorage,
|
|
320
|
+
ee as useStorageList
|
|
297
321
|
};
|
|
298
322
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":["../lib/reducer/helpers.ts","../lib/reducer/abortController.ts","../lib/reducer/queryQueue.ts","../lib/reducer/request.ts","../lib/reducer/storage.ts","../lib/reducer/index.ts","../lib/hooks.ts"],"sourcesContent":["import { type WritableDraft } from '@reduxjs/toolkit';\nimport { type CdeebeeSettings, type CdeebeeModule, CdeebeeValueList } from './types';\n\nexport function checkModule(settings: CdeebeeSettings<unknown> | WritableDraft<CdeebeeSettings<unknown>>, module: CdeebeeModule, result: () => void) {\n if (settings.modules.includes(module)) {\n result();\n }\n}\nexport function isRecord(value: unknown): value is Record<string, unknown> {\n return value !== null && typeof value === 'object' && !Array.isArray(value);\n}\n\nexport function hasDataProperty(value: unknown): value is Record<string, unknown> & { data: unknown[] } {\n return isRecord(value) && Array.isArray(value.data);\n}\n\nexport function hasProperty(value: unknown, prop: string): boolean {\n return isRecord(value) && Object.prototype.hasOwnProperty.call(value, prop);\n}\n\nexport function mergeDeepRight<T>(\n left: T,\n right: Partial<T> | Record<string, unknown>\n): T {\n if (!isRecord(left) || !isRecord(right)) {\n return right as T;\n }\n\n const result = { ...left } as Record<string, unknown>;\n const rightRecord = right as Record<string, unknown>;\n\n for (const key in rightRecord) {\n if (Object.prototype.hasOwnProperty.call(rightRecord, key)) {\n const leftValue = result[key];\n const rightValue = rightRecord[key];\n\n if (\n isRecord(leftValue) &&\n isRecord(rightValue) &&\n !Array.isArray(leftValue) &&\n !Array.isArray(rightValue)\n ) {\n result[key] = mergeDeepRight(leftValue, rightValue);\n } else {\n result[key] = rightValue;\n }\n }\n }\n\n return result as T;\n}\n\nexport function omit<T extends Record<string, unknown>>(keys: string[], obj: T): Omit<T, keyof T> {\n const result = { ...obj };\n for (const key of keys) {\n delete result[key];\n }\n return result as Omit<T, keyof T>;\n}\n\nexport function assocPath<T>(path: (string | number)[], value: unknown, obj: T): T {\n if (path.length === 0) {\n return value as T;\n }\n\n const [first, ...rest] = path;\n const firstKey = String(first);\n const result = Array.isArray(obj) ? [...obj] : { ...obj } as Record<string, unknown>;\n\n if (rest.length === 0) {\n (result as Record<string, unknown>)[firstKey] = value;\n } else {\n const currentValue = (result as Record<string, unknown>)[firstKey];\n (result as Record<string, unknown>)[firstKey] = assocPath(rest, value, currentValue ?? {});\n }\n\n return result as T;\n}\n\nexport function batchingUpdate<T extends Record<string, unknown>>(\n state: T,\n valueList: CdeebeeValueList<T>\n): void {\n for (let i = 0; i < valueList.length; i++) {\n const item = valueList[i] as { key: readonly (string | number)[]; value: unknown };\n const path = item.key;\n const value = item.value;\n \n if (path.length === 0) {\n continue;\n }\n\n let current: Record<string, unknown> | unknown[] = state as Record<string, unknown>;\n \n for (let j = 0; j < path.length - 1; j++) {\n const pathKey = path[j];\n \n if (Array.isArray(current)) {\n const index = typeof pathKey === 'number' ? pathKey : Number(pathKey);\n if (!(index in current) || !isRecord(current[index])) {\n current[index] = {};\n }\n current = current[index] as Record<string, unknown>;\n } else {\n const key = String(pathKey);\n if (!(key in current)) {\n const nextIsNumeric = typeof path[j + 1] === 'number' || (!isNaN(Number(path[j + 1])) && String(Number(path[j + 1])) === String(path[j + 1]));\n current[key] = nextIsNumeric ? [] : {};\n }\n const next = current[key];\n current = (Array.isArray(next) ? next : (isRecord(next) ? next : {})) as Record<string, unknown> | unknown[];\n }\n }\n \n if (Array.isArray(current)) {\n continue; // Can't update array element directly\n }\n current[String(path[path.length - 1])] = value;\n }\n}\n","interface RequestController {\n requestId: string;\n controller: AbortController;\n api: string;\n}\n\nclass AbortControllerStore {\n private byRequestId = new Map<string, RequestController>();\n private byApi = new Map<string, Set<string>>();\n\n add(api: string, requestId: string, controller: AbortController): void {\n const item: RequestController = { requestId, controller, api };\n this.byRequestId.set(requestId, item);\n\n if (!this.byApi.has(api)) {\n this.byApi.set(api, new Set());\n }\n this.byApi.get(api)!.add(requestId);\n }\n\n delete(requestId: string): void {\n const item = this.byRequestId.get(requestId);\n if (!item) return;\n\n this.byRequestId.delete(requestId);\n const apiSet = this.byApi.get(item.api);\n if (apiSet) {\n apiSet.delete(requestId);\n if (apiSet.size === 0) {\n this.byApi.delete(item.api);\n }\n }\n }\n\n abortAllForApi(api: string, excludeRequestId: string): void {\n const requestIds = this.byApi.get(api);\n if (!requestIds) return;\n\n requestIds.forEach(requestId => {\n if (requestId !== excludeRequestId) {\n const item = this.byRequestId.get(requestId);\n if (item) {\n item.controller.abort();\n this.delete(requestId);\n }\n }\n });\n }\n}\n\nconst abortStore = new AbortControllerStore();\n\nexport function abortQuery(api: string, currentRequestId: string): void {\n abortStore.abortAllForApi(api, currentRequestId);\n}\n\nexport function abortManager(signal: AbortSignal, api: string, requestId: string) {\n const controller = new AbortController();\n\n const cleanup = () => {\n abortStore.delete(requestId);\n };\n\n signal.addEventListener('abort', () => {\n controller.abort();\n cleanup();\n });\n\n return {\n controller,\n init: () => abortStore.add(api, requestId, controller),\n drop: cleanup,\n };\n}\n","class QueryQueue {\n private currentPromise: Promise<unknown> = Promise.resolve();\n private queueLength = 0;\n\n async enqueue<T>(task: () => Promise<T>): Promise<T> {\n this.queueLength++;\n \n const previousPromise = this.currentPromise;\n \n this.currentPromise = previousPromise\n .then(() => task(), () => task())\n .finally(() => {\n this.queueLength--;\n });\n\n return this.currentPromise as Promise<T>;\n }\n\n getQueueLength(): number {\n return this.queueLength;\n }\n\n clear(): void {\n this.queueLength = 0;\n }\n}\n\nexport const queryQueue = new QueryQueue();\n\n","import { createAsyncThunk } from '@reduxjs/toolkit';\nimport { checkModule } from './helpers';\nimport { abortManager } from './abortController';\nimport { queryQueue } from './queryQueue';\nimport { type CdeebeeState, type CdeebeeRequestOptions } from './types';\n\nexport const request = createAsyncThunk(\n 'cdeebee/request',\n async (options: CdeebeeRequestOptions<unknown>, { rejectWithValue, getState, requestId, signal }) => {\n const startedAt = new Date().toUTCString();\n const { cdeebee: { settings } } = getState() as { cdeebee: CdeebeeState<unknown> };\n\n const abort = abortManager(signal, options.api, requestId);\n const withCallback = options.onResult && typeof options.onResult === 'function';\n\n checkModule(settings, 'cancelation', abort.init);\n\n const executeRequest = async () => {\n try {\n const { method = 'POST', body, headers = {} } = options;\n const extraHeaders: Record<string, string> = { ...(settings.mergeWithHeaders ?? {}), ...headers };\n\n const b = { ...(settings.mergeWithData ?? {}), ...(body ?? {}) };\n let requestData: FormData | string = JSON.stringify(b);\n\n // handling files\n if (options.files) {\n const formData = new FormData();\n const fileKey = options.fileKey || settings.fileKey;\n const bodyKey = options.bodyKey || settings.bodyKey;\n\n for (let i = 0; i < options.files.length; i += 1) {\n if (fileKey) {\n formData.append(fileKey, options.files[i]);\n }\n }\n\n if (bodyKey) {\n formData.append(bodyKey, requestData);\n }\n requestData = formData;\n }\n // [end] handling files\n \n const response = await fetch(options.api, {\n method,\n headers: {\n 'ui-request-id': requestId,\n 'Content-Type': 'application/json',\n ...extraHeaders,\n },\n signal: abort.controller.signal,\n body: requestData,\n });\n\n checkModule(settings, 'cancelation', abort.drop);\n\n let result: unknown;\n const responseType = options.responseType || 'json';\n \n if (responseType === 'text') {\n result = await response.text();\n } else if (responseType === 'blob') {\n result = await response.blob();\n } else {\n // default: json\n result = await response.json();\n }\n\n if (!response.ok) {\n if (withCallback) options.onResult!(result);\n return rejectWithValue(response);\n }\n\n if (withCallback) options.onResult!(result);\n return { result, startedAt, endedAt: new Date().toUTCString() };\n } catch (error) {\n checkModule(settings, 'cancelation', abort.drop);\n\n if (withCallback) options.onResult!(error); \n\n if (error instanceof Error && error.name === 'AbortError') {\n return rejectWithValue({ message: 'Request was cancelled', cancelled: true });\n }\n\n return rejectWithValue({ message: error instanceof Error ? error.message : 'Unknown error occurred' });\n }\n };\n\n if (settings.modules.includes('queryQueue')) {\n return queryQueue.enqueue(executeRequest);\n }\n\n return executeRequest();\n },\n);\n\n","import { type CdeebeeListStrategy, type CdeebeeState } from './types';\nimport { isRecord, mergeDeepRight, omit } from './helpers';\n\ntype ResponseValue = Record<string, unknown>;\n\ntype IResponse = Record<string, ResponseValue>;\n\ntype StorageData = Record<string, unknown>;\n\nfunction isDataWithPrimaryKey(value: unknown): value is { data: unknown[]; primaryKey: string } {\n return (\n isRecord(value) &&\n Array.isArray(value.data) &&\n typeof value.primaryKey === 'string'\n );\n}\nfunction normalizeDataWithPrimaryKey(data: unknown[], primaryKey: string): Record<string, unknown> {\n const result: Record<string, unknown> = {};\n \n for (const item of data) {\n if (isRecord(item) && primaryKey in item) {\n const key = String(item[primaryKey]);\n result[key] = item;\n }\n }\n \n return result;\n}\n\nfunction applyStrategy(\n existingValue: StorageData,\n newValue: StorageData | ResponseValue,\n strategy: string,\n key: string\n): ResponseValue {\n if (strategy === 'replace') {\n return newValue as ResponseValue;\n } else if (strategy === 'merge') {\n return mergeDeepRight(existingValue, newValue as StorageData) as ResponseValue;\n } else if (strategy === 'skip') {\n return existingValue as ResponseValue;\n } else {\n console.warn(`Cdeebee: Unknown strategy \"${strategy}\" for key \"${key}\". Skipping normalization.`);\n return mergeDeepRight(existingValue, newValue as StorageData) as ResponseValue;\n }\n}\n\nexport function defaultNormalize<T>(\n cdeebee: CdeebeeState<T>,\n response: IResponse,\n strategyList: CdeebeeListStrategy<T> \n): Record<string, ResponseValue> {\n const keyList = Object.keys(response);\n const currentStorage = isRecord(cdeebee.storage) ? (cdeebee.storage as Record<string, unknown>) : {};\n \n const result = { ...currentStorage } as Record<string, ResponseValue>;\n const keyListToOmit = new Set<string>();\n\n for (const key of keyList) {\n const responseValue = response[key];\n\n if (responseValue === null || responseValue === undefined || typeof responseValue === 'string') {\n keyListToOmit.add(key);\n continue;\n }\n\n const strategy = strategyList[key as keyof T] ?? 'merge';\n \n // For 'skip' strategy, if key doesn't exist in storage, skip it entirely\n if (strategy === 'skip' && !(key in currentStorage)) {\n continue;\n }\n \n const existingValue = key in currentStorage ? (currentStorage[key] as StorageData) : {};\n\n if (isDataWithPrimaryKey(responseValue)) {\n const normalizedValue = normalizeDataWithPrimaryKey(responseValue.data, responseValue.primaryKey);\n result[key] = applyStrategy(existingValue, normalizedValue, strategy, key);\n continue;\n }\n\n if (isRecord(responseValue)) {\n result[key] = applyStrategy(existingValue, responseValue as StorageData, strategy, key);\n } else {\n result[key] = responseValue;\n }\n }\n\n return keyListToOmit.size > 0 ? omit(Array.from(keyListToOmit), result) : result;\n}\n","import { createSlice, current, type PayloadAction } from '@reduxjs/toolkit';\n\nimport { type CdeebeeSettings, type CdeebeeState, type CdeebeeValueList, type CdeebeeListStrategy } from './types';\nimport { checkModule, mergeDeepRight, batchingUpdate } from './helpers';\nimport { abortQuery } from './abortController';\nimport { request } from './request';\nimport { defaultNormalize } from './storage';\n\nconst initialState: CdeebeeState<unknown> = {\n settings: {\n modules: ['history', 'listener', 'storage', 'cancelation'],\n fileKey: 'file',\n bodyKey: 'value',\n listStrategy: {},\n mergeWithData: {},\n mergeWithHeaders: {},\n },\n storage: {},\n request: {\n active: [],\n errors: {},\n done: {}\n },\n};\n\nexport const factory = <T>(settings: CdeebeeSettings<T>, storage?: T) => {\n const slice = createSlice({\n name: 'cdeebee',\n initialState: mergeDeepRight(initialState, { settings, storage: storage ?? {} }) as CdeebeeState<T>,\n reducers: {\n set(state, action: { payload: CdeebeeValueList<T> }) {\n // Directly mutate state.storage using Immer Draft\n // This is more performant than creating a new object\n // Immer will track changes and create minimal updates\n batchingUpdate(state.storage as Record<string, unknown>, action.payload);\n },\n historyClear(state, action: PayloadAction<string | undefined>) {\n const api = action.payload;\n\n if (api) {\n delete state.request.done[api];\n delete state.request.errors[api];\n } else {\n state.request.done = {};\n state.request.errors = {};\n }\n }\n },\n extraReducers: builder => {\n builder\n .addCase(request.pending, (state, action) => {\n const api = action.meta.arg.api;\n const requestId = action.meta.requestId;\n\n if (action.meta.arg.historyClear) {\n checkModule(state.settings, 'history', () => {\n delete state.request.done[api];\n delete state.request.errors[api];\n });\n }\n\n checkModule(state.settings, 'cancelation', () => {\n abortQuery(api, requestId);\n });\n checkModule(state.settings, 'listener', () => {\n state.request.active.push({ api, requestId });\n });\n })\n .addCase(request.fulfilled, (state, action) => {\n const requestId = action.meta.requestId;\n const api = action.meta.arg.api;\n\n checkModule(state.settings, 'listener', () => {\n state.request.active = state.request.active.filter(q => !(q.api === api && q.requestId === requestId));\n });\n checkModule(state.settings, 'history', () => {\n if (!state.request.done[api]) state.request.done[api] = [];\n state.request.done[api].push({ api, request: action.payload, requestId });\n });\n checkModule(state.settings, 'storage', () => {\n if (action.meta.arg.ignore) {\n return;\n }\n \n const strategyList = (action.meta.arg.listStrategy ?? state.settings.listStrategy ?? {}) as CdeebeeListStrategy<T>;\n const normalize = action.meta.arg.normalize ?? state.settings.normalize ?? defaultNormalize;\n\n const currentState = current(state) as CdeebeeState<T>;\n // Type assertion is safe here because we've already checked isRecord\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const normalizedData = normalize(currentState, action.payload.result as any, strategyList);\n\n // Normalize already handles merge/replace/skip and preserves keys not in response\n // Simply apply the result\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n (state.storage as any) = normalizedData;\n });\n })\n .addCase(request.rejected, (state, action) => {\n const requestId = action.meta.requestId;\n const api = action.meta.arg.api;\n\n checkModule(state.settings, 'listener', () => {\n state.request.active = state.request.active.filter(q => !(q.api === api && q.requestId === requestId));\n });\n checkModule(state.settings, 'history', () => {\n if (!state.request.errors[api]) state.request.errors[api] = [];\n state.request.errors[api].push({ requestId: requestId, api, request: action.error });\n });\n });\n },\n });\n\n return slice;\n};\n","import { useSelector } from 'react-redux';\nimport { type CdeebeeState } from './reducer/types';\n\n/**\n * Generic hook factory that creates a selector hook for cdeebee state.\n * This allows the hooks to work with any Redux root state structure.\n *\n * @template RootState - The shape of the Redux root state\n * @template Storage - The shape of the cdeebee storage\n * @param selectCdeebee - Function to select the cdeebee slice from root state\n * @returns An object containing all cdeebee hooks\n */\nexport function createCdeebeeHooks<RootState, Storage>(\n selectCdeebee: (state: RootState) => CdeebeeState<Storage>\n) {\n /**\n * Check if any of the specified APIs are currently loading.\n *\n * @param apiList - Array of API endpoints to check\n * @returns true if any of the APIs are currently active/loading\n *\n * @example\n * const isLoading = useLoading(['/api/forums', '/api/threads']);\n * if (isLoading) return <Spinner />;\n */\n function useLoading(apiList: string[]): boolean {\n return useSelector((state: RootState) => {\n const cdeebee = selectCdeebee(state);\n return cdeebee.request.active.some(q => apiList.includes(q.api));\n });\n }\n\n /**\n * Get the successful request history for a specific API endpoint.\n *\n * @param api - The API endpoint\n * @returns Array of successful request history entries\n *\n * @example\n * const history = useRequestHistory('/api/forums');\n * console.log(`Made ${history.length} successful requests`);\n */\n function useRequestHistory(api: string) {\n return useSelector((state: RootState) => {\n const cdeebee = selectCdeebee(state);\n return cdeebee.request.done[api] ?? [];\n });\n }\n\n /**\n * Get the error history for a specific API endpoint.\n *\n * @param api - The API endpoint\n * @returns Array of error history entries\n *\n * @example\n * const errors = useRequestErrors('/api/forums');\n * if (errors.length > 0) {\n * console.error('Last error:', errors[errors.length - 1]);\n * }\n */\n function useRequestErrors(api: string) {\n return useSelector((state: RootState) => {\n const cdeebee = selectCdeebee(state);\n return cdeebee.request.errors[api] ?? [];\n });\n }\n\n /**\n * Get a specific list from storage with full type safety.\n *\n * @param listName - The name of the list in storage\n * @returns The list data\n *\n * @example\n * const forums = useStorageList('forumList');\n * const forumArray = Object.values(forums);\n */\n function useStorageList<K extends keyof Storage>(listName: K): Storage[K] {\n return useSelector((state: RootState) => {\n const cdeebee = selectCdeebee(state);\n return cdeebee.storage[listName];\n });\n }\n\n /**\n * Get the entire cdeebee storage.\n *\n * @returns The complete storage object\n *\n * @example\n * const storage = useStorage();\n * console.log(Object.keys(storage)); // ['forumList', 'threadList', ...]\n */\n function useStorage(): Storage {\n return useSelector((state: RootState) => {\n const cdeebee = selectCdeebee(state);\n return cdeebee.storage;\n });\n }\n\n /**\n * Check if any request is currently loading (across all APIs).\n *\n * @returns true if any request is active\n *\n * @example\n * const isAnythingLoading = useIsLoading();\n * if (isAnythingLoading) return <GlobalSpinner />;\n */\n function useIsLoading(): boolean {\n return useSelector((state: RootState) => {\n const cdeebee = selectCdeebee(state);\n return cdeebee.request.active.length > 0;\n });\n }\n\n return {\n useLoading,\n useRequestHistory,\n useRequestErrors,\n useStorageList,\n useStorage,\n useIsLoading,\n };\n}\n\n/**\n * Standalone hook that can be used without createCdeebeeHooks.\n * Assumes the cdeebee slice is at state.cdeebee.\n *\n * @param apiList - Array of API endpoints to check\n * @returns true if any of the APIs are currently active/loading\n *\n * @example\n * const isLoading = useLoading(['/api/forums', '/api/threads']);\n */\nexport function useLoading<Storage = unknown>(apiList: string[]): boolean {\n return useSelector((state: { cdeebee: CdeebeeState<Storage> }) => {\n return state.cdeebee.request.active.some(q => apiList.includes(q.api));\n });\n}\n\n/**\n * Standalone hook that can be used without createCdeebeeHooks.\n * Assumes the cdeebee slice is at state.cdeebee.\n *\n * @param api - The API endpoint\n * @returns Array of successful request history entries\n */\nexport function useRequestHistory<Storage = unknown>(api: string) {\n return useSelector((state: { cdeebee: CdeebeeState<Storage> }) => {\n return state.cdeebee.request.done[api] ?? [];\n });\n}\n\n/**\n * Standalone hook that can be used without createCdeebeeHooks.\n * Assumes the cdeebee slice is at state.cdeebee.\n *\n * @param api - The API endpoint\n * @returns Array of error history entries\n */\nexport function useRequestErrors<Storage = unknown>(api: string) {\n return useSelector((state: { cdeebee: CdeebeeState<Storage> }) => {\n return state.cdeebee.request.errors[api] ?? [];\n });\n}\n\n/**\n * Standalone hook that can be used without createCdeebeeHooks.\n * Assumes the cdeebee slice is at state.cdeebee.\n *\n * @param listName - The name of the list in storage\n * @returns The list data\n */\nexport function useStorageList<Storage, K extends keyof Storage>(listName: K): Storage[K] {\n return useSelector((state: { cdeebee: CdeebeeState<Storage> }) => {\n return state.cdeebee.storage[listName];\n });\n}\n\n/**\n * Standalone hook that can be used without createCdeebeeHooks.\n * Assumes the cdeebee slice is at state.cdeebee.\n *\n * @returns The complete storage object\n */\nexport function useStorage<Storage>(): Storage {\n return useSelector((state: { cdeebee: CdeebeeState<Storage> }) => {\n return state.cdeebee.storage;\n });\n}\n\n/**\n * Standalone hook that can be used without createCdeebeeHooks.\n * Assumes the cdeebee slice is at state.cdeebee.\n *\n * @returns true if any request is active\n */\nexport function useIsLoading<Storage = unknown>(): boolean {\n return useSelector((state: { cdeebee: CdeebeeState<Storage> }) => {\n return state.cdeebee.request.active.length > 0;\n });\n}\n"],"names":["checkModule","settings","module","result","isRecord","value","mergeDeepRight","left","right","rightRecord","key","leftValue","rightValue","omit","keys","obj","batchingUpdate","state","valueList","i","item","path","current","j","pathKey","index","nextIsNumeric","next","AbortControllerStore","api","requestId","controller","apiSet","excludeRequestId","requestIds","abortStore","abortQuery","currentRequestId","abortManager","signal","cleanup","QueryQueue","task","previousPromise","queryQueue","request","createAsyncThunk","options","rejectWithValue","getState","startedAt","abort","withCallback","executeRequest","method","body","headers","extraHeaders","b","requestData","formData","fileKey","bodyKey","response","responseType","error","isDataWithPrimaryKey","normalizeDataWithPrimaryKey","data","primaryKey","applyStrategy","existingValue","newValue","strategy","defaultNormalize","cdeebee","strategyList","keyList","currentStorage","keyListToOmit","responseValue","normalizedValue","initialState","factory","storage","createSlice","action","builder","q","normalize","currentState","normalizedData","createCdeebeeHooks","selectCdeebee","useLoading","apiList","useSelector","useRequestHistory","useRequestErrors","useStorageList","listName","useStorage","useIsLoading"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../lib/reducer/helpers.ts","../lib/reducer/abortController.ts","../lib/reducer/queryQueue.ts","../lib/reducer/request.ts","../lib/reducer/storage.ts","../lib/reducer/index.ts","../lib/hooks/createCdeebeeHooks.ts","../lib/hooks/selectors.ts"],"sourcesContent":["import { type WritableDraft } from '@reduxjs/toolkit';\nimport { type CdeebeeSettings, type CdeebeeModule, CdeebeeValueList } from './types';\n\nexport function checkModule(settings: CdeebeeSettings<unknown> | WritableDraft<CdeebeeSettings<unknown>>, module: CdeebeeModule, result: () => void) {\n if (settings.modules.includes(module)) {\n result();\n }\n}\n\nexport function isRecord(value: unknown): value is Record<string, unknown> {\n return value !== null && typeof value === 'object' && !Array.isArray(value);\n}\n\nexport function mergeDeepRight<T>(\n left: T,\n right: Partial<T> | Record<string, unknown>\n): T {\n if (!isRecord(left) || !isRecord(right)) {\n return right as T;\n }\n\n const result = { ...left } as Record<string, unknown>;\n const rightRecord = right as Record<string, unknown>;\n\n for (const key in rightRecord) {\n if (Object.prototype.hasOwnProperty.call(rightRecord, key)) {\n const leftValue = result[key];\n const rightValue = rightRecord[key];\n\n if (\n isRecord(leftValue) &&\n isRecord(rightValue) &&\n !Array.isArray(leftValue) &&\n !Array.isArray(rightValue)\n ) {\n result[key] = mergeDeepRight(leftValue, rightValue);\n } else {\n result[key] = rightValue;\n }\n }\n }\n\n return result as T;\n}\n\nexport function omit<T extends Record<string, unknown>>(keys: string[], obj: T): Omit<T, keyof T> {\n const result = { ...obj };\n for (const key of keys) {\n delete result[key];\n }\n return result as Omit<T, keyof T>;\n}\n\n/**\n * Extract primary key values from API response data.\n * Handles responses with format: { listName: { data: [...], primaryKey: 'id' } }\n * Returns a flat array of all extracted IDs from all lists.\n */\nexport function extractResultIdList(response: unknown): string[] {\n if (!isRecord(response)) {\n return [];\n }\n\n const ids: string[] = [];\n\n for (const key of Object.keys(response)) {\n const value = response[key];\n\n if (\n isRecord(value) &&\n Array.isArray(value.data) &&\n typeof value.primaryKey === 'string'\n ) {\n const primaryKey = value.primaryKey;\n for (const item of value.data) {\n if (isRecord(item) && primaryKey in item) {\n ids.push(String(item[primaryKey]));\n }\n }\n }\n }\n\n return ids;\n}\n\nexport function batchingUpdate<T extends Record<string, unknown>>(\n state: T,\n valueList: CdeebeeValueList<T>\n): void {\n for (let i = 0; i < valueList.length; i++) {\n const item = valueList[i] as { key: readonly (string | number)[]; value: unknown };\n const path = item.key;\n const value = item.value;\n\n if (path.length === 0) {\n continue;\n }\n\n let current: Record<string, unknown> | unknown[] = state as Record<string, unknown>;\n\n for (let j = 0; j < path.length - 1; j++) {\n const pathKey = path[j];\n\n if (Array.isArray(current)) {\n const index = typeof pathKey === 'number' ? pathKey : Number(pathKey);\n if (!(index in current) || !isRecord(current[index])) {\n current[index] = {};\n }\n current = current[index] as Record<string, unknown>;\n } else {\n const key = String(pathKey);\n if (!(key in current)) {\n const nextIsNumeric = typeof path[j + 1] === 'number' || (!isNaN(Number(path[j + 1])) && String(Number(path[j + 1])) === String(path[j + 1]));\n current[key] = nextIsNumeric ? [] : {};\n }\n const next = current[key];\n current = (Array.isArray(next) ? next : (isRecord(next) ? next : {})) as Record<string, unknown> | unknown[];\n }\n }\n\n if (Array.isArray(current)) {\n continue; // Can't update array element directly\n }\n current[String(path[path.length - 1])] = value;\n }\n}\n","interface RequestController {\n requestId: string;\n controller: AbortController;\n api: string;\n}\n\nclass AbortControllerStore {\n private byRequestId = new Map<string, RequestController>();\n private byApi = new Map<string, Set<string>>();\n\n add(api: string, requestId: string, controller: AbortController): void {\n const item: RequestController = { requestId, controller, api };\n this.byRequestId.set(requestId, item);\n\n if (!this.byApi.has(api)) {\n this.byApi.set(api, new Set());\n }\n this.byApi.get(api)!.add(requestId);\n }\n\n delete(requestId: string): void {\n const item = this.byRequestId.get(requestId);\n if (!item) return;\n\n this.byRequestId.delete(requestId);\n const apiSet = this.byApi.get(item.api);\n if (apiSet) {\n apiSet.delete(requestId);\n if (apiSet.size === 0) {\n this.byApi.delete(item.api);\n }\n }\n }\n\n abortAllForApi(api: string, excludeRequestId: string): void {\n const requestIds = this.byApi.get(api);\n if (!requestIds) return;\n\n requestIds.forEach(requestId => {\n if (requestId !== excludeRequestId) {\n const item = this.byRequestId.get(requestId);\n if (item) {\n item.controller.abort();\n this.delete(requestId);\n }\n }\n });\n }\n}\n\nconst abortStore = new AbortControllerStore();\n\nexport function abortQuery(api: string, currentRequestId: string): void {\n abortStore.abortAllForApi(api, currentRequestId);\n}\n\nexport function abortManager(signal: AbortSignal, api: string, requestId: string) {\n const controller = new AbortController();\n\n const cleanup = () => {\n abortStore.delete(requestId);\n };\n\n signal.addEventListener('abort', () => {\n controller.abort();\n cleanup();\n });\n\n return {\n controller,\n init: () => abortStore.add(api, requestId, controller),\n drop: cleanup,\n };\n}\n","class QueryQueue {\n private currentPromise: Promise<unknown> = Promise.resolve();\n private queueLength = 0;\n\n async enqueue<T>(task: () => Promise<T>): Promise<T> {\n this.queueLength++;\n\n const previousPromise = this.currentPromise;\n\n this.currentPromise = previousPromise\n .then(() => task(), () => task())\n .finally(() => {\n this.queueLength--;\n });\n\n return this.currentPromise as Promise<T>;\n }\n\n getQueueLength(): number {\n return this.queueLength;\n }\n\n clear(): void {\n this.queueLength = 0;\n }\n}\n\nexport const queryQueue = new QueryQueue();\n\n","import { createAsyncThunk } from '@reduxjs/toolkit';\nimport { checkModule } from './helpers';\nimport { abortManager } from './abortController';\nimport { queryQueue } from './queryQueue';\nimport { type CdeebeeState, type CdeebeeRequestOptions } from './types';\n\nexport const request = createAsyncThunk(\n 'cdeebee/request',\n async (options: CdeebeeRequestOptions<unknown>, { rejectWithValue, getState, requestId, signal }) => {\n const startedAt = new Date().toUTCString();\n const { cdeebee: { settings } } = getState() as { cdeebee: CdeebeeState<unknown> };\n\n const abort = abortManager(signal, options.api, requestId);\n const withCallback = options.onResult && typeof options.onResult === 'function';\n\n checkModule(settings, 'cancelation', abort.init);\n\n const executeRequest = async () => {\n try {\n const { method = 'POST', body, headers = {} } = options;\n const baseHeaders = typeof settings.mergeWithHeaders === 'function'\n ? settings.mergeWithHeaders()\n : (settings.mergeWithHeaders ?? {});\n\n const extraHeaders: Record<string, string> = { ...baseHeaders, ...headers };\n\n const baseData = typeof settings.mergeWithData === 'function'\n ? settings.mergeWithData()\n : (settings.mergeWithData ?? {});\n\n const b = { ...baseData, ...(body ?? {}) };\n let requestData: FormData | string = JSON.stringify(b);\n\n // handling files\n if (options.files) {\n const formData = new FormData();\n const fileKey = options.fileKey || settings.fileKey;\n const bodyKey = options.bodyKey || settings.bodyKey;\n\n for (let i = 0; i < options.files.length; i += 1) {\n if (fileKey) {\n formData.append(fileKey, options.files[i]);\n }\n }\n\n if (bodyKey) {\n formData.append(bodyKey, requestData);\n }\n requestData = formData;\n }\n // [end] handling files\n\n const response = await fetch(options.api, {\n method,\n headers: {\n 'ui-request-id': requestId,\n 'Content-Type': 'application/json',\n ...extraHeaders,\n },\n signal: abort.controller.signal,\n body: requestData,\n });\n\n checkModule(settings, 'cancelation', abort.drop);\n\n let result: unknown;\n const responseType = options.responseType || 'json';\n\n if (responseType === 'text') {\n result = await response.text();\n } else if (responseType === 'blob') {\n result = await response.blob();\n } else {\n // default: json\n result = await response.json();\n }\n\n if (!response.ok) {\n if (withCallback) options.onResult!(result);\n return rejectWithValue(response);\n }\n\n if (withCallback) options.onResult!(result);\n return { result, startedAt, endedAt: new Date().toUTCString() };\n } catch (error) {\n checkModule(settings, 'cancelation', abort.drop);\n\n if (withCallback) options.onResult!(error);\n\n if (error instanceof Error && error.name === 'AbortError') {\n return rejectWithValue({ message: 'Request was cancelled', cancelled: true });\n }\n\n return rejectWithValue({ message: error instanceof Error ? error.message : 'Unknown error occurred' });\n }\n };\n\n if (settings.modules.includes('queryQueue')) {\n return queryQueue.enqueue(executeRequest);\n }\n\n return executeRequest();\n },\n);\n\n","import { type CdeebeeListStrategy, type CdeebeeState } from './types';\nimport { isRecord, mergeDeepRight, omit } from './helpers';\n\ntype ResponseValue = Record<string, unknown>;\n\ntype IResponse = Record<string, ResponseValue>;\n\ntype StorageData = Record<string, unknown>;\n\nfunction isDataWithPrimaryKey(value: unknown): value is { data: unknown[]; primaryKey: string } {\n return (\n isRecord(value) &&\n Array.isArray(value.data) &&\n typeof value.primaryKey === 'string'\n );\n}\nfunction normalizeDataWithPrimaryKey(data: unknown[], primaryKey: string): Record<string, unknown> {\n const result: Record<string, unknown> = {};\n \n for (const item of data) {\n if (isRecord(item) && primaryKey in item) {\n const key = String(item[primaryKey]);\n result[key] = item;\n }\n }\n \n return result;\n}\n\nfunction applyStrategy(\n existingValue: StorageData,\n newValue: StorageData | ResponseValue,\n strategy: string,\n key: string\n): ResponseValue {\n if (strategy === 'replace') {\n return newValue as ResponseValue;\n } else if (strategy === 'merge') {\n return mergeDeepRight(existingValue, newValue as StorageData) as ResponseValue;\n } else if (strategy === 'skip') {\n return existingValue as ResponseValue;\n } else {\n console.warn(`Cdeebee: Unknown strategy \"${strategy}\" for key \"${key}\". Skipping normalization.`);\n return mergeDeepRight(existingValue, newValue as StorageData) as ResponseValue;\n }\n}\n\nexport function defaultNormalize<T>(\n cdeebee: CdeebeeState<T>,\n response: IResponse,\n strategyList: CdeebeeListStrategy<T> \n): Record<string, ResponseValue> {\n const keyList = Object.keys(response);\n const currentStorage = isRecord(cdeebee.storage) ? (cdeebee.storage as Record<string, unknown>) : {};\n \n const result = { ...currentStorage } as Record<string, ResponseValue>;\n const keyListToOmit = new Set<string>();\n\n for (const key of keyList) {\n const responseValue = response[key];\n\n if (responseValue === null || responseValue === undefined || typeof responseValue === 'string') {\n keyListToOmit.add(key);\n continue;\n }\n\n const strategy = strategyList[key as keyof T] ?? 'merge';\n \n // For 'skip' strategy, if key doesn't exist in storage, skip it entirely\n if (strategy === 'skip' && !(key in currentStorage)) {\n continue;\n }\n \n const existingValue = key in currentStorage ? (currentStorage[key] as StorageData) : {};\n\n if (isDataWithPrimaryKey(responseValue)) {\n const normalizedValue = normalizeDataWithPrimaryKey(responseValue.data, responseValue.primaryKey);\n result[key] = applyStrategy(existingValue, normalizedValue, strategy, key);\n continue;\n }\n\n if (isRecord(responseValue)) {\n result[key] = applyStrategy(existingValue, responseValue as StorageData, strategy, key);\n } else {\n result[key] = responseValue;\n }\n }\n\n return keyListToOmit.size > 0 ? omit(Array.from(keyListToOmit), result) : result;\n}\n","import { createSlice, current, type PayloadAction } from '@reduxjs/toolkit';\n\nimport { type CdeebeeSettings, type CdeebeeState, type CdeebeeValueList, type CdeebeeListStrategy } from './types';\nimport { checkModule, mergeDeepRight, batchingUpdate, extractResultIdList } from './helpers';\nimport { abortQuery } from './abortController';\nimport { request } from './request';\nimport { defaultNormalize } from './storage';\n\nconst initialState: CdeebeeState<unknown> = {\n settings: {\n modules: ['history', 'listener', 'storage', 'cancelation'],\n fileKey: 'file',\n bodyKey: 'value',\n listStrategy: {},\n mergeWithData: {},\n mergeWithHeaders: {},\n },\n storage: {},\n request: {\n active: [],\n errors: {},\n done: {},\n lastResultIdList: {},\n },\n};\n\nexport const factory = <T>(settings: CdeebeeSettings<T>, storage?: T) => {\n const slice = createSlice({\n name: 'cdeebee',\n initialState: mergeDeepRight(initialState, { settings, storage: storage ?? {} }) as CdeebeeState<T>,\n reducers: {\n set(state, action: { payload: CdeebeeValueList<T> }) {\n // Directly mutate state.storage using Immer Draft\n // This is more performant than creating a new object\n // Immer will track changes and create minimal updates\n batchingUpdate(state.storage as Record<string, unknown>, action.payload);\n },\n historyClear(state, action: PayloadAction<string | undefined>) {\n const api = action.payload;\n\n if (api) {\n delete state.request.done[api];\n delete state.request.errors[api];\n } else {\n state.request.done = {};\n state.request.errors = {};\n }\n }\n },\n extraReducers: builder => {\n builder\n .addCase(request.pending, (state, action) => {\n const api = action.meta.arg.api;\n const requestId = action.meta.requestId;\n\n if (action.meta.arg.historyClear) {\n checkModule(state.settings, 'history', () => {\n delete state.request.done[api];\n delete state.request.errors[api];\n });\n }\n\n checkModule(state.settings, 'cancelation', () => {\n abortQuery(api, requestId);\n });\n checkModule(state.settings, 'listener', () => {\n state.request.active.push({ api, requestId });\n });\n })\n .addCase(request.fulfilled, (state, action) => {\n const requestId = action.meta.requestId;\n const api = action.meta.arg.api;\n\n checkModule(state.settings, 'listener', () => {\n state.request.active = state.request.active.filter(q => !(q.api === api && q.requestId === requestId));\n });\n checkModule(state.settings, 'history', () => {\n if (!state.request.done[api]) state.request.done[api] = [];\n state.request.done[api].push({ api, request: action.payload, requestId });\n });\n checkModule(state.settings, 'storage', () => {\n if (action.meta.arg.ignore) {\n return;\n }\n\n const strategyList = (action.meta.arg.listStrategy ?? state.settings.listStrategy ?? {}) as CdeebeeListStrategy<T>;\n const normalize = action.meta.arg.normalize ?? state.settings.normalize ?? defaultNormalize;\n\n const currentState = current(state) as CdeebeeState<T>;\n // Type assertion is safe here because we've already checked isRecord\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const normalizedData = normalize(currentState, action.payload.result as any, strategyList);\n\n // Normalize already handles merge/replace/skip and preserves keys not in response\n // Simply apply the result\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n (state.storage as any) = normalizedData;\n\n // Extract and store result IDs for filtering\n state.request.lastResultIdList[api] = extractResultIdList(action.payload.result);\n });\n })\n .addCase(request.rejected, (state, action) => {\n const requestId = action.meta.requestId;\n const api = action.meta.arg.api;\n\n checkModule(state.settings, 'listener', () => {\n state.request.active = state.request.active.filter(q => !(q.api === api && q.requestId === requestId));\n });\n checkModule(state.settings, 'history', () => {\n if (!state.request.errors[api]) state.request.errors[api] = [];\n state.request.errors[api].push({ requestId: requestId, api, request: action.error });\n });\n });\n },\n });\n\n return slice;\n};\n","import { useSelector } from 'react-redux';\nimport { type CdeebeeState } from '../reducer/types';\n\n/**\n * Generic hook factory that creates a selector hook for cdeebee state.\n * This allows the hooks to work with any Redux root state structure.\n *\n * @template RootState - The shape of the Redux root state\n * @template Storage - The shape of the cdeebee storage\n * @param selectCdeebee - Function to select the cdeebee slice from root state\n * @returns An object containing all cdeebee hooks\n */\nexport function createCdeebeeHooks<RootState, Storage>(\n selectCdeebee: (state: RootState) => CdeebeeState<Storage>\n) {\n /**\n * Check if any of the specified APIs are currently loading.\n *\n * @param apiList - Array of API endpoints to check\n * @returns true if any of the APIs are currently active/loading\n *\n * @example\n * const isLoading = useLoading(['/api/forums', '/api/threads']);\n * if (isLoading) return <Spinner />;\n */\n function useLoading(apiList: string[]): boolean {\n return useSelector((state: RootState) => {\n const cdeebee = selectCdeebee(state);\n return cdeebee.request.active.some(q => apiList.includes(q.api));\n });\n }\n\n /**\n * Get the successful request history for a specific API endpoint.\n *\n * @param api - The API endpoint\n * @returns Array of successful request history entries\n *\n * @example\n * const history = useRequestHistory('/api/forums');\n * console.log(`Made ${history.length} successful requests`);\n */\n function useRequestHistory(api: string) {\n return useSelector((state: RootState) => {\n const cdeebee = selectCdeebee(state);\n return cdeebee.request.done[api] ?? [];\n });\n }\n\n /**\n * Get the error history for a specific API endpoint.\n *\n * @param api - The API endpoint\n * @returns Array of error history entries\n *\n * @example\n * const errors = useRequestErrors('/api/forums');\n * if (errors.length > 0) {\n * console.error('Last error:', errors[errors.length - 1]);\n * }\n */\n function useRequestErrors(api: string) {\n return useSelector((state: RootState) => {\n const cdeebee = selectCdeebee(state);\n return cdeebee.request.errors[api] ?? [];\n });\n }\n\n /**\n * Get a specific list from storage with full type safety.\n *\n * @param listName - The name of the list in storage\n * @returns The list data\n *\n * @example\n * const forums = useStorageList('forumList');\n * const forumArray = Object.values(forums);\n */\n function useStorageList<K extends keyof Storage>(listName: K): Storage[K] {\n return useSelector((state: RootState) => {\n const cdeebee = selectCdeebee(state);\n return cdeebee.storage[listName];\n });\n }\n\n /**\n * Get the entire cdeebee storage.\n *\n * @returns The complete storage object\n *\n * @example\n * const storage = useStorage();\n * console.log(Object.keys(storage)); // ['forumList', 'threadList', ...]\n */\n function useStorage(): Storage {\n return useSelector((state: RootState) => {\n const cdeebee = selectCdeebee(state);\n return cdeebee.storage;\n });\n }\n\n /**\n * Check if any request is currently loading (across all APIs).\n *\n * @returns true if any request is active\n *\n * @example\n * const isAnythingLoading = useIsLoading();\n * if (isAnythingLoading) return <GlobalSpinner />;\n */\n function useIsLoading(): boolean {\n return useSelector((state: RootState) => {\n const cdeebee = selectCdeebee(state);\n return cdeebee.request.active.length > 0;\n });\n }\n\n /**\n * Get the list of IDs returned by the last successful request to an API.\n * Useful for filtering storage data to show only results from a specific request.\n *\n * @param api - The API endpoint\n * @returns Array of primary key IDs from the last response\n *\n * @example\n * const productList = useStorageList('productList');\n * const lastIds = useLastResultIdList('/api/search');\n * const displayResults = lastIds.map(id => productList[id]).filter(Boolean);\n */\n function useLastResultIdList(api: string): string[] {\n return useSelector((state: RootState) => {\n const cdeebee = selectCdeebee(state);\n return cdeebee.request.lastResultIdList[api] ?? [];\n });\n }\n\n return {\n useLoading,\n useRequestHistory,\n useRequestErrors,\n useStorageList,\n useStorage,\n useIsLoading,\n useLastResultIdList,\n };\n}\n","import { useSelector } from 'react-redux';\nimport { type CdeebeeState } from '../reducer/types';\n\n/**\n * Standalone hook that can be used without createCdeebeeHooks.\n * Assumes the cdeebee slice is at state.cdeebee.\n *\n * @param apiList - Array of API endpoints to check\n * @returns true if any of the APIs are currently active/loading\n *\n * @example\n * const isLoading = useLoading(['/api/forums', '/api/threads']);\n */\nexport function useLoading<Storage = unknown>(apiList: string[]): boolean {\n return useSelector((state: { cdeebee: CdeebeeState<Storage> }) => {\n return state.cdeebee.request.active.some(q => apiList.includes(q.api));\n });\n}\n\n/**\n * Standalone hook that can be used without createCdeebeeHooks.\n * Assumes the cdeebee slice is at state.cdeebee.\n *\n * @param api - The API endpoint\n * @returns Array of successful request history entries\n */\nexport function useRequestHistory<Storage = unknown>(api: string) {\n return useSelector((state: { cdeebee: CdeebeeState<Storage> }) => {\n return state.cdeebee.request.done[api] ?? [];\n });\n}\n\n/**\n * Standalone hook that can be used without createCdeebeeHooks.\n * Assumes the cdeebee slice is at state.cdeebee.\n *\n * @param api - The API endpoint\n * @returns Array of error history entries\n */\nexport function useRequestErrors<Storage = unknown>(api: string) {\n return useSelector((state: { cdeebee: CdeebeeState<Storage> }) => {\n return state.cdeebee.request.errors[api] ?? [];\n });\n}\n\n/**\n * Standalone hook that can be used without createCdeebeeHooks.\n * Assumes the cdeebee slice is at state.cdeebee.\n *\n * @param listName - The name of the list in storage\n * @returns The list data\n */\nexport function useStorageList<Storage, K extends keyof Storage>(listName: K): Storage[K] {\n return useSelector((state: { cdeebee: CdeebeeState<Storage> }) => {\n return state.cdeebee.storage[listName];\n });\n}\n\n/**\n * Standalone hook that can be used without createCdeebeeHooks.\n * Assumes the cdeebee slice is at state.cdeebee.\n *\n * @returns The complete storage object\n */\nexport function useStorage<Storage>(): Storage {\n return useSelector((state: { cdeebee: CdeebeeState<Storage> }) => {\n return state.cdeebee.storage;\n });\n}\n\n/**\n * Standalone hook that can be used without createCdeebeeHooks.\n * Assumes the cdeebee slice is at state.cdeebee.\n *\n * @returns true if any request is active\n */\nexport function useIsLoading<Storage = unknown>(): boolean {\n return useSelector((state: { cdeebee: CdeebeeState<Storage> }) => {\n return state.cdeebee.request.active.length > 0;\n });\n}\n\n/**\n * Standalone hook that can be used without createCdeebeeHooks.\n * Assumes the cdeebee slice is at state.cdeebee.\n *\n * Get the list of IDs returned by the last successful request to an API.\n * Useful for filtering storage data to show only results from a specific request.\n *\n * @param api - The API endpoint\n * @returns Array of primary key IDs from the last response\n *\n * @example\n * const productList = useStorageList('productList');\n * const lastIds = useLastResultIdList('/api/search');\n * const displayResults = lastIds.map(id => productList[id]).filter(Boolean);\n */\nexport function useLastResultIdList<Storage = unknown>(api: string): string[] {\n return useSelector((state: { cdeebee: CdeebeeState<Storage> }) => {\n return state.cdeebee.request.lastResultIdList[api] ?? [];\n });\n}\n"],"names":["checkModule","settings","module","result","isRecord","value","mergeDeepRight","left","right","rightRecord","key","leftValue","rightValue","omit","keys","obj","extractResultIdList","response","ids","primaryKey","item","batchingUpdate","state","valueList","i","path","current","j","pathKey","index","nextIsNumeric","next","AbortControllerStore","api","requestId","controller","apiSet","excludeRequestId","requestIds","abortStore","abortQuery","currentRequestId","abortManager","signal","cleanup","QueryQueue","task","previousPromise","queryQueue","request","createAsyncThunk","options","rejectWithValue","getState","startedAt","abort","withCallback","executeRequest","method","body","headers","extraHeaders","b","requestData","formData","fileKey","bodyKey","responseType","error","isDataWithPrimaryKey","normalizeDataWithPrimaryKey","data","applyStrategy","existingValue","newValue","strategy","defaultNormalize","cdeebee","strategyList","keyList","currentStorage","keyListToOmit","responseValue","normalizedValue","initialState","factory","storage","createSlice","action","builder","q","normalize","currentState","normalizedData","createCdeebeeHooks","selectCdeebee","useLoading","apiList","useSelector","useRequestHistory","useRequestErrors","useStorageList","listName","useStorage","useIsLoading","useLastResultIdList"],"mappings":"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"}
|