@recats/cdeebee 3.0.0-beta.6 → 3.0.0-beta.8
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 +113 -4
- package/dist/index.cjs +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +166 -129
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -36,7 +36,7 @@ For example, a forum application might have this structure:
|
|
|
36
36
|
}
|
|
37
37
|
```
|
|
38
38
|
|
|
39
|
-
After fetching data, the storage might look like:
|
|
39
|
+
After fetching data from the API (which returns data in the format `{ data: [...], primaryKey: 'id' }`), cdeebee automatically normalizes it and the storage might look like:
|
|
40
40
|
|
|
41
41
|
```typescript
|
|
42
42
|
{
|
|
@@ -52,6 +52,8 @@ After fetching data, the storage might look like:
|
|
|
52
52
|
}
|
|
53
53
|
```
|
|
54
54
|
|
|
55
|
+
**Note:** The API should return list data in the format `{ data: [...], primaryKey: 'fieldName' }`. cdeebee automatically converts this format into the normalized storage structure shown above. See the [API Response Format](#api-response-format) section for details.
|
|
56
|
+
|
|
55
57
|
### Modules
|
|
56
58
|
|
|
57
59
|
cdeebee uses a modular architecture with the following modules:
|
|
@@ -60,6 +62,7 @@ cdeebee uses a modular architecture with the following modules:
|
|
|
60
62
|
- **`history`**: Tracks request history (successful and failed requests)
|
|
61
63
|
- **`listener`**: Tracks active requests for loading states
|
|
62
64
|
- **`cancelation`**: Manages request cancellation (automatically cancels previous requests to the same API)
|
|
65
|
+
- **`queryQueue`**: Processes requests sequentially in the order they were sent, ensuring they complete and are stored in the correct sequence
|
|
63
66
|
|
|
64
67
|
## Quick Start
|
|
65
68
|
|
|
@@ -79,7 +82,7 @@ interface Storage {
|
|
|
79
82
|
// Create cdeebee slice
|
|
80
83
|
export const cdeebeeSlice = factory<Storage>(
|
|
81
84
|
{
|
|
82
|
-
modules: ['history', 'listener', 'cancelation', 'storage'],
|
|
85
|
+
modules: ['history', 'listener', 'cancelation', 'storage', 'queryQueue'],
|
|
83
86
|
fileKey: 'file',
|
|
84
87
|
bodyKey: 'value',
|
|
85
88
|
listStrategy: {
|
|
@@ -164,7 +167,7 @@ The `factory` function accepts a settings object with the following options:
|
|
|
164
167
|
|
|
165
168
|
```typescript
|
|
166
169
|
interface CdeebeeSettings<T> {
|
|
167
|
-
modules: CdeebeeModule[]; // Active modules: 'history' | 'listener' | 'storage' | 'cancelation'
|
|
170
|
+
modules: CdeebeeModule[]; // Active modules: 'history' | 'listener' | 'storage' | 'cancelation' | 'queryQueue'
|
|
168
171
|
fileKey: string; // Key name for file uploads in FormData
|
|
169
172
|
bodyKey: string; // Key name for request body in FormData
|
|
170
173
|
listStrategy?: CdeebeeListStrategy<T>; // Merge strategy per list: 'merge' | 'replace'
|
|
@@ -209,7 +212,32 @@ listStrategy: {
|
|
|
209
212
|
|
|
210
213
|
## API Response Format
|
|
211
214
|
|
|
212
|
-
cdeebee expects API responses in a
|
|
215
|
+
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.
|
|
216
|
+
|
|
217
|
+
### List Format
|
|
218
|
+
|
|
219
|
+
For lists (collections of entities), the API should return data in the following format:
|
|
220
|
+
|
|
221
|
+
```typescript
|
|
222
|
+
{
|
|
223
|
+
forumList: {
|
|
224
|
+
data: [
|
|
225
|
+
{ id: 1, title: 'Forum 1' },
|
|
226
|
+
{ id: 2, title: 'Forum 2' },
|
|
227
|
+
],
|
|
228
|
+
primaryKey: 'id',
|
|
229
|
+
},
|
|
230
|
+
threadList: {
|
|
231
|
+
data: [
|
|
232
|
+
{ id: 101, title: 'Thread 1', forumID: 1 },
|
|
233
|
+
{ id: 102, title: 'Thread 2', forumID: 1 },
|
|
234
|
+
],
|
|
235
|
+
primaryKey: 'id',
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
cdeebee automatically converts this format into normalized storage:
|
|
213
241
|
|
|
214
242
|
```typescript
|
|
215
243
|
{
|
|
@@ -219,10 +247,62 @@ cdeebee expects API responses in a normalized format where data is already organ
|
|
|
219
247
|
},
|
|
220
248
|
threadList: {
|
|
221
249
|
101: { id: 101, title: 'Thread 1', forumID: 1 },
|
|
250
|
+
102: { id: 102, title: 'Thread 2', forumID: 1 },
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
The `primaryKey` field specifies which property of each item should be used as the key in the normalized structure. The `primaryKey` value is converted to a string to ensure consistent key types.
|
|
256
|
+
|
|
257
|
+
**Example:**
|
|
258
|
+
|
|
259
|
+
If your API returns:
|
|
260
|
+
```typescript
|
|
261
|
+
{
|
|
262
|
+
sessionList: {
|
|
263
|
+
data: [
|
|
264
|
+
{
|
|
265
|
+
sessionID: 1,
|
|
266
|
+
token: 'da6ec385bc7e4f84a510c3ecca07f3',
|
|
267
|
+
expiresAt: '2034-03-28T22:36:09'
|
|
268
|
+
}
|
|
269
|
+
],
|
|
270
|
+
primaryKey: 'sessionID',
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
It will be automatically normalized to:
|
|
276
|
+
```typescript
|
|
277
|
+
{
|
|
278
|
+
sessionList: {
|
|
279
|
+
'1': {
|
|
280
|
+
sessionID: 1,
|
|
281
|
+
token: 'da6ec385bc7e4f84a510c3ecca07f3',
|
|
282
|
+
expiresAt: '2034-03-28T22:36:09'
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
### Non-List Data
|
|
289
|
+
|
|
290
|
+
For non-list data (configuration objects, simple values, etc.), you can return them as regular objects:
|
|
291
|
+
|
|
292
|
+
```typescript
|
|
293
|
+
{
|
|
294
|
+
config: {
|
|
295
|
+
theme: 'dark',
|
|
296
|
+
language: 'en',
|
|
297
|
+
},
|
|
298
|
+
userPreferences: {
|
|
299
|
+
notifications: true,
|
|
222
300
|
}
|
|
223
301
|
}
|
|
224
302
|
```
|
|
225
303
|
|
|
304
|
+
These will be stored as-is in the storage.
|
|
305
|
+
|
|
226
306
|
## Advanced Usage
|
|
227
307
|
|
|
228
308
|
### File Uploads
|
|
@@ -326,6 +406,34 @@ dispatch(request({ api: '/api/data', body: { query: 'slow' } }));
|
|
|
326
406
|
dispatch(request({ api: '/api/data', body: { query: 'fast' } }));
|
|
327
407
|
```
|
|
328
408
|
|
|
409
|
+
### Sequential Request Processing (queryQueue)
|
|
410
|
+
|
|
411
|
+
When the `queryQueue` module is enabled, all requests are processed sequentially in the order they were sent. This ensures that:
|
|
412
|
+
|
|
413
|
+
- Requests complete in the exact order they were dispatched
|
|
414
|
+
- Data is stored in the store in the correct sequence
|
|
415
|
+
- Even if a faster request is sent after a slower one, it will wait for the previous request to complete
|
|
416
|
+
|
|
417
|
+
This is particularly useful when you need to maintain data consistency and ensure that updates happen in the correct order.
|
|
418
|
+
|
|
419
|
+
```typescript
|
|
420
|
+
// Enable queryQueue module
|
|
421
|
+
const cdeebeeSlice = factory<Storage>({
|
|
422
|
+
modules: ['history', 'listener', 'storage', 'queryQueue'],
|
|
423
|
+
// ... other settings
|
|
424
|
+
});
|
|
425
|
+
|
|
426
|
+
// Send multiple requests - they will be processed sequentially
|
|
427
|
+
dispatch(request({ api: '/api/data', body: { id: 1 } })); // Completes first
|
|
428
|
+
dispatch(request({ api: '/api/data', body: { id: 2 } })); // Waits for #1, then completes
|
|
429
|
+
dispatch(request({ api: '/api/data', body: { id: 3 } })); // Waits for #2, then completes
|
|
430
|
+
|
|
431
|
+
// Even if request #3 is faster, it will still complete last
|
|
432
|
+
// All requests are stored in the store in order: 1 → 2 → 3
|
|
433
|
+
```
|
|
434
|
+
|
|
435
|
+
**Note:** The `queryQueue` module processes requests sequentially across all APIs. If you need parallel processing for different APIs, you would need separate cdeebee instances or disable the module for those specific requests.
|
|
436
|
+
|
|
329
437
|
### Manual State Updates
|
|
330
438
|
|
|
331
439
|
You can manually update the storage using the `set` action:
|
|
@@ -386,6 +494,7 @@ export type {
|
|
|
386
494
|
CdeebeeRequestOptions,
|
|
387
495
|
CdeebeeValueList,
|
|
388
496
|
CdeebeeActiveRequest,
|
|
497
|
+
CdeebeeModule,
|
|
389
498
|
} from '@recats/cdeebee';
|
|
390
499
|
```
|
|
391
500
|
|
package/dist/index.cjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const S=require("@reduxjs/toolkit");function
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const S=require("@reduxjs/toolkit");function y(t,r,n){t.modules.includes(r)&&n()}function f(t){return t!==null&&typeof t=="object"&&!Array.isArray(t)}function p(t,r){if(!f(t)||!f(r))return r;const n={...t},o=r;for(const e in o)if(Object.prototype.hasOwnProperty.call(o,e)){const a=n[e],s=o[e];f(a)&&f(s)&&!Array.isArray(a)&&!Array.isArray(s)?n[e]=p(a,s):n[e]=s}return n}function L(t,r){const n={...r};for(const o of t)delete n[o];return n}function P(t,r){for(let n=0;n<r.length;n++){const o=r[n],e=o.key,a=o.value;if(e.length===0)continue;let s=t;for(let i=0;i<e.length-1;i++){const c=e[i];if(Array.isArray(s)){const l=typeof c=="number"?c:Number(c);(!(l in s)||!f(s[l]))&&(s[l]={}),s=s[l]}else{const l=String(c);if(!(l in s)){const d=typeof e[i+1]=="number"||!isNaN(Number(e[i+1]))&&String(Number(e[i+1]))===String(e[i+1]);s[l]=d?[]:{}}const u=s[l];s=Array.isArray(u)||f(u)?u:{}}}Array.isArray(s)||(s[String(e[e.length-1])]=a)}}class T{constructor(){this.byRequestId=new Map,this.byApi=new Map}add(r,n,o){const e={requestId:n,controller:o,api:r};this.byRequestId.set(n,e),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 o=this.byApi.get(n.api);o&&(o.delete(r),o.size===0&&this.byApi.delete(n.api))}abortAllForApi(r,n){const o=this.byApi.get(r);o&&o.forEach(e=>{if(e!==n){const a=this.byRequestId.get(e);a&&(a.controller.abort(),this.delete(e))}})}}const w=new T;function x(t,r){w.abortAllForApi(t,r)}function N(t,r,n){const o=new AbortController,e=()=>{w.delete(n)};return t.addEventListener("abort",()=>{o.abort(),e()}),{controller:o,init:()=>w.add(r,n,o),drop:e}}class j{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 I=new j,m=S.createAsyncThunk("cdeebee/request",async(t,{rejectWithValue:r,getState:n,requestId:o,signal:e})=>{const a=new Date().toUTCString(),{cdeebee:{settings:s}}=n(),i=N(e,t.api,o),c=t.onResult&&typeof t.onResult=="function";y(s,"cancelation",i.init);const l=async()=>{try{const{method:u="POST",body:d,headers:z={}}=t,C={...s.mergeWithHeaders??{},...z},v={...s.mergeWithData??{},...d??{}};let b=JSON.stringify(v);if(t.files){const q=new FormData,R=t.fileKey||s.fileKey,K=t.bodyKey||s.bodyKey;for(let A=0;A<t.files.length;A+=1)R&&q.append(R,t.files[A]);K&&q.append(K,b),b=q}const h=await fetch(t.api,{method:u,headers:{"ui-request-id":o,"Content-Type":"application/json",...C},signal:i.controller.signal,body:b});y(s,"cancelation",i.drop);let g;const k=t.responseType||"json";return k==="text"?g=await h.text():k==="blob"?g=await h.blob():g=await h.json(),h.ok?(c&&t.onResult(g),{result:g,startedAt:a,endedAt:new Date().toUTCString()}):(c&&t.onResult(g),r(h))}catch(u){return y(s,"cancelation",i.drop),c&&t.onResult(u),u instanceof Error&&u.name==="AbortError"?r({message:"Request was cancelled",cancelled:!0}):r({message:u instanceof Error?u.message:"Unknown error occurred"})}};return s.modules.includes("queryQueue")?I.enqueue(l):l()});function O(t){return f(t)&&Array.isArray(t.data)&&typeof t.primaryKey=="string"}function Q(t,r){const n={};for(const o of t)if(f(o)&&r in o){const e=String(o[r]);n[e]=o}return n}function D(t,r,n,o){return n==="replace"?r:(n==="merge"||console.warn(`Cdeebee: Unknown strategy "${n}" for key "${o}". Skipping normalization.`),p(t,r))}function U(t,r,n){const o=Object.keys(r),e=f(t.storage)?t.storage:{},a={...e},s=new Set;for(const i of o){const c=r[i];if(c==null||typeof c=="string"){s.add(i);continue}const l=n[i]??"merge",u=i in e?e[i]:{};if(O(c)){const d=Q(c.data,c.primaryKey);a[i]=D(u,d,l,i);continue}f(c)?a[i]=D(u,c,l,i):a[i]=c}return s.size>0?L(Array.from(s),a):a}const E={settings:{modules:["history","listener","storage","cancelation"],fileKey:"file",bodyKey:"value",listStrategy:{},mergeWithData:{},mergeWithHeaders:{}},storage:{},request:{active:[],errors:{},done:{}}},M=(t,r)=>S.createSlice({name:"cdeebee",initialState:p(E,{settings:t,storage:r??{}}),reducers:{set(o,e){P(o.storage,e.payload)}},extraReducers:o=>{o.addCase(m.pending,(e,a)=>{const s=a.meta.arg.api,i=a.meta.requestId;y(e.settings,"cancelation",()=>{x(s,i)}),y(e.settings,"listener",()=>{e.request.active.push({api:s,requestId:i})})}).addCase(m.fulfilled,(e,a)=>{const s=a.meta.requestId,i=a.meta.arg.api;y(e.settings,"listener",()=>{e.request.active=e.request.active.filter(c=>!(c.api===i&&c.requestId===s))}),y(e.settings,"history",()=>{e.request.done[i]||(e.request.done[i]=[]),e.request.done[i].push({api:i,request:a.payload,requestId:s})}),y(e.settings,"storage",()=>{if(a.meta.arg.ignore)return;const c=a.meta.arg.listStrategy??e.settings.listStrategy??{},l=a.meta.arg.normalize??e.settings.normalize??U,u=S.current(e),d=l(u,a.payload.result,c);e.storage=d})}).addCase(m.rejected,(e,a)=>{const s=a.meta.requestId,i=a.meta.arg.api;y(e.settings,"listener",()=>{e.request.active=e.request.active.filter(c=>!(c.api===i&&c.requestId===s))}),y(e.settings,"history",()=>{e.request.errors[i]||(e.request.errors[i]=[]),e.request.errors[i].push({requestId:s,api:i,request:a.error})})})}});exports.batchingUpdate=P;exports.factory=M;exports.request=m;
|
|
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/request.ts","../lib/reducer/storage.ts","../lib/reducer/index.ts"],"sourcesContent":["import { type CdeebeeSettings, type CdeebeeModule, CdeebeeValueList } from './types';\n\nexport function checkModule(settings: 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","import { createAsyncThunk } from '@reduxjs/toolkit';\nimport { checkModule } from './helpers';\nimport { abortManager } from './abortController';\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 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\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\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 isNormalized = isRecord(responseValue);\n const strategy = strategyList[key as keyof T] ?? 'merge';\n\n if (isNormalized) {\n const existingValue = key in currentStorage ? (currentStorage[key] as StorageData) : {};\n\n if (strategy === 'replace') {\n result[key] = responseValue as ResponseValue;\n } else if (strategy === 'merge') {\n result[key] = mergeDeepRight(existingValue, responseValue as StorageData) as ResponseValue;\n } else {\n console.warn(`Cdeebee: Unknown strategy \"${strategy}\" for key \"${key}\". Skipping normalization.`);\n result[key] = mergeDeepRight(existingValue, responseValue as StorageData) as ResponseValue;\n }\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 } from '@reduxjs/toolkit';\n\nimport { type CdeebeeSettings, type CdeebeeState, type CdeebeeValueList } 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 },\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 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 ?? {};\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 const normalizedData = normalize(currentState, action.payload.result as Record<string, Record<string, unknown>>, strategyList);\n\n // Normalize already handles merge/replace 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"],"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","request","createAsyncThunk","options","rejectWithValue","getState","startedAt","abort","withCallback","method","body","headers","extraHeaders","b","requestData","formData","fileKey","bodyKey","response","responseType","error","defaultNormalize","cdeebee","strategyList","keyList","currentStorage","keyListToOmit","responseValue","isNormalized","strategy","existingValue","initialState","factory","storage","createSlice","action","builder","q","normalize","currentState","normalizedData"],"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"],"sourcesContent":["import { type CdeebeeSettings, type CdeebeeModule, CdeebeeValueList } from './types';\n\nexport function checkModule(settings: 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 {\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 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 } from '@reduxjs/toolkit';\n\nimport { type CdeebeeSettings, type CdeebeeState, type CdeebeeValueList } 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 },\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 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 ?? {};\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 const normalizedData = normalize(currentState, action.payload.result as Record<string, Record<string, unknown>>, strategyList);\n\n // Normalize already handles merge/replace 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"],"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"],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -23,7 +23,7 @@ declare interface CdeebeeHistoryState {
|
|
|
23
23
|
|
|
24
24
|
declare type CdeebeeListStrategy<T> = Record<keyof T, CdeebeeStrategy>;
|
|
25
25
|
|
|
26
|
-
declare type CdeebeeModule = 'history' | 'listener' | 'storage' | 'cancelation';
|
|
26
|
+
export declare type CdeebeeModule = 'history' | 'listener' | 'storage' | 'cancelation' | 'queryQueue';
|
|
27
27
|
|
|
28
28
|
export declare interface CdeebeeRequestOptions<T> extends Partial<Pick<CdeebeeSettings<T>, 'fileKey' | 'bodyKey' | 'normalize' | 'listStrategy'>> {
|
|
29
29
|
api: string;
|
package/dist/index.js
CHANGED
|
@@ -1,143 +1,180 @@
|
|
|
1
|
-
import { createAsyncThunk as
|
|
2
|
-
function
|
|
3
|
-
|
|
1
|
+
import { createAsyncThunk as P, createSlice as x, current as L } from "@reduxjs/toolkit";
|
|
2
|
+
function y(t, r, n) {
|
|
3
|
+
t.modules.includes(r) && n();
|
|
4
4
|
}
|
|
5
|
-
function
|
|
6
|
-
return
|
|
5
|
+
function f(t) {
|
|
6
|
+
return t !== null && typeof t == "object" && !Array.isArray(t);
|
|
7
7
|
}
|
|
8
|
-
function
|
|
9
|
-
if (!
|
|
10
|
-
return
|
|
11
|
-
const
|
|
12
|
-
for (const e in
|
|
13
|
-
if (Object.prototype.hasOwnProperty.call(
|
|
14
|
-
const
|
|
15
|
-
|
|
8
|
+
function h(t, r) {
|
|
9
|
+
if (!f(t) || !f(r))
|
|
10
|
+
return r;
|
|
11
|
+
const n = { ...t }, o = r;
|
|
12
|
+
for (const e in o)
|
|
13
|
+
if (Object.prototype.hasOwnProperty.call(o, e)) {
|
|
14
|
+
const a = n[e], s = o[e];
|
|
15
|
+
f(a) && f(s) && !Array.isArray(a) && !Array.isArray(s) ? n[e] = h(a, s) : n[e] = s;
|
|
16
16
|
}
|
|
17
|
-
return
|
|
17
|
+
return n;
|
|
18
18
|
}
|
|
19
|
-
function
|
|
20
|
-
const
|
|
21
|
-
for (const
|
|
22
|
-
delete o
|
|
23
|
-
return
|
|
19
|
+
function v(t, r) {
|
|
20
|
+
const n = { ...r };
|
|
21
|
+
for (const o of t)
|
|
22
|
+
delete n[o];
|
|
23
|
+
return n;
|
|
24
24
|
}
|
|
25
|
-
function
|
|
26
|
-
for (let
|
|
27
|
-
const
|
|
25
|
+
function N(t, r) {
|
|
26
|
+
for (let n = 0; n < r.length; n++) {
|
|
27
|
+
const o = r[n], e = o.key, a = o.value;
|
|
28
28
|
if (e.length === 0)
|
|
29
29
|
continue;
|
|
30
|
-
let
|
|
31
|
-
for (let
|
|
32
|
-
const c = e[
|
|
33
|
-
if (Array.isArray(
|
|
30
|
+
let s = t;
|
|
31
|
+
for (let i = 0; i < e.length - 1; i++) {
|
|
32
|
+
const c = e[i];
|
|
33
|
+
if (Array.isArray(s)) {
|
|
34
34
|
const l = typeof c == "number" ? c : Number(c);
|
|
35
|
-
(!(l in
|
|
35
|
+
(!(l in s) || !f(s[l])) && (s[l] = {}), s = s[l];
|
|
36
36
|
} else {
|
|
37
37
|
const l = String(c);
|
|
38
|
-
if (!(l in
|
|
39
|
-
const
|
|
40
|
-
|
|
38
|
+
if (!(l in s)) {
|
|
39
|
+
const d = typeof e[i + 1] == "number" || !isNaN(Number(e[i + 1])) && String(Number(e[i + 1])) === String(e[i + 1]);
|
|
40
|
+
s[l] = d ? [] : {};
|
|
41
41
|
}
|
|
42
|
-
const u =
|
|
43
|
-
|
|
42
|
+
const u = s[l];
|
|
43
|
+
s = Array.isArray(u) || f(u) ? u : {};
|
|
44
44
|
}
|
|
45
45
|
}
|
|
46
|
-
Array.isArray(
|
|
46
|
+
Array.isArray(s) || (s[String(e[e.length - 1])] = a);
|
|
47
47
|
}
|
|
48
48
|
}
|
|
49
49
|
class T {
|
|
50
50
|
constructor() {
|
|
51
51
|
this.byRequestId = /* @__PURE__ */ new Map(), this.byApi = /* @__PURE__ */ new Map();
|
|
52
52
|
}
|
|
53
|
-
add(
|
|
54
|
-
const e = { requestId:
|
|
55
|
-
this.byRequestId.set(
|
|
53
|
+
add(r, n, o) {
|
|
54
|
+
const e = { requestId: n, controller: o, api: r };
|
|
55
|
+
this.byRequestId.set(n, e), this.byApi.has(r) || this.byApi.set(r, /* @__PURE__ */ new Set()), this.byApi.get(r).add(n);
|
|
56
56
|
}
|
|
57
|
-
delete(
|
|
58
|
-
const
|
|
59
|
-
if (!
|
|
60
|
-
this.byRequestId.delete(
|
|
61
|
-
const
|
|
62
|
-
|
|
57
|
+
delete(r) {
|
|
58
|
+
const n = this.byRequestId.get(r);
|
|
59
|
+
if (!n) return;
|
|
60
|
+
this.byRequestId.delete(r);
|
|
61
|
+
const o = this.byApi.get(n.api);
|
|
62
|
+
o && (o.delete(r), o.size === 0 && this.byApi.delete(n.api));
|
|
63
63
|
}
|
|
64
|
-
abortAllForApi(
|
|
65
|
-
const
|
|
66
|
-
|
|
67
|
-
if (e !==
|
|
68
|
-
const
|
|
69
|
-
|
|
64
|
+
abortAllForApi(r, n) {
|
|
65
|
+
const o = this.byApi.get(r);
|
|
66
|
+
o && o.forEach((e) => {
|
|
67
|
+
if (e !== n) {
|
|
68
|
+
const a = this.byRequestId.get(e);
|
|
69
|
+
a && (a.controller.abort(), this.delete(e));
|
|
70
70
|
}
|
|
71
71
|
});
|
|
72
72
|
}
|
|
73
73
|
}
|
|
74
74
|
const S = new T();
|
|
75
|
-
function I(
|
|
76
|
-
S.abortAllForApi(
|
|
75
|
+
function I(t, r) {
|
|
76
|
+
S.abortAllForApi(t, r);
|
|
77
77
|
}
|
|
78
|
-
function j(
|
|
79
|
-
const
|
|
80
|
-
S.delete(
|
|
78
|
+
function j(t, r, n) {
|
|
79
|
+
const o = new AbortController(), e = () => {
|
|
80
|
+
S.delete(n);
|
|
81
81
|
};
|
|
82
|
-
return
|
|
83
|
-
|
|
82
|
+
return t.addEventListener("abort", () => {
|
|
83
|
+
o.abort(), e();
|
|
84
84
|
}), {
|
|
85
|
-
controller:
|
|
86
|
-
init: () => S.add(
|
|
85
|
+
controller: o,
|
|
86
|
+
init: () => S.add(r, n, o),
|
|
87
87
|
drop: e
|
|
88
88
|
};
|
|
89
89
|
}
|
|
90
|
-
|
|
90
|
+
class O {
|
|
91
|
+
constructor() {
|
|
92
|
+
this.currentPromise = Promise.resolve(), this.queueLength = 0;
|
|
93
|
+
}
|
|
94
|
+
async enqueue(r) {
|
|
95
|
+
this.queueLength++;
|
|
96
|
+
const n = this.currentPromise;
|
|
97
|
+
return this.currentPromise = n.then(() => r(), () => r()).finally(() => {
|
|
98
|
+
this.queueLength--;
|
|
99
|
+
}), this.currentPromise;
|
|
100
|
+
}
|
|
101
|
+
getQueueLength() {
|
|
102
|
+
return this.queueLength;
|
|
103
|
+
}
|
|
104
|
+
clear() {
|
|
105
|
+
this.queueLength = 0;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
const Q = new O(), A = P(
|
|
91
109
|
"cdeebee/request",
|
|
92
|
-
async (
|
|
93
|
-
const
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
110
|
+
async (t, { rejectWithValue: r, getState: n, requestId: o, signal: e }) => {
|
|
111
|
+
const a = (/* @__PURE__ */ new Date()).toUTCString(), { cdeebee: { settings: s } } = n(), i = j(e, t.api, o), c = t.onResult && typeof t.onResult == "function";
|
|
112
|
+
y(s, "cancelation", i.init);
|
|
113
|
+
const l = async () => {
|
|
114
|
+
try {
|
|
115
|
+
const { method: u = "POST", body: d, headers: D = {} } = t, z = { ...s.mergeWithHeaders ?? {}, ...D }, C = { ...s.mergeWithData ?? {}, ...d ?? {} };
|
|
116
|
+
let p = JSON.stringify(C);
|
|
117
|
+
if (t.files) {
|
|
118
|
+
const b = new FormData(), k = t.fileKey || s.fileKey, R = t.bodyKey || s.bodyKey;
|
|
119
|
+
for (let q = 0; q < t.files.length; q += 1)
|
|
120
|
+
k && b.append(k, t.files[q]);
|
|
121
|
+
R && b.append(R, p), p = b;
|
|
122
|
+
}
|
|
123
|
+
const m = await fetch(t.api, {
|
|
124
|
+
method: u,
|
|
125
|
+
headers: {
|
|
126
|
+
"ui-request-id": o,
|
|
127
|
+
"Content-Type": "application/json",
|
|
128
|
+
...z
|
|
129
|
+
},
|
|
130
|
+
signal: i.controller.signal,
|
|
131
|
+
body: p
|
|
132
|
+
});
|
|
133
|
+
y(s, "cancelation", i.drop);
|
|
134
|
+
let g;
|
|
135
|
+
const w = t.responseType || "json";
|
|
136
|
+
return w === "text" ? g = await m.text() : w === "blob" ? g = await m.blob() : g = await m.json(), m.ok ? (c && t.onResult(g), { result: g, startedAt: a, endedAt: (/* @__PURE__ */ new Date()).toUTCString() }) : (c && t.onResult(g), r(m));
|
|
137
|
+
} catch (u) {
|
|
138
|
+
return y(s, "cancelation", i.drop), c && t.onResult(u), u instanceof Error && u.name === "AbortError" ? r({ message: "Request was cancelled", cancelled: !0 }) : r({ message: u instanceof Error ? u.message : "Unknown error occurred" });
|
|
103
139
|
}
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
headers: {
|
|
107
|
-
"ui-request-id": a,
|
|
108
|
-
"Content-Type": "application/json",
|
|
109
|
-
...C
|
|
110
|
-
},
|
|
111
|
-
signal: r.controller.signal,
|
|
112
|
-
body: p
|
|
113
|
-
});
|
|
114
|
-
d(t, "cancelation", r.drop);
|
|
115
|
-
let g;
|
|
116
|
-
const w = n.responseType || "json";
|
|
117
|
-
return w === "text" ? g = await b.text() : w === "blob" ? g = await b.blob() : g = await b.json(), b.ok ? (c && n.onResult(g), { result: g, startedAt: i, endedAt: (/* @__PURE__ */ new Date()).toUTCString() }) : (c && n.onResult(g), s(b));
|
|
118
|
-
} catch (l) {
|
|
119
|
-
return d(t, "cancelation", r.drop), c && n.onResult(l), l instanceof Error && l.name === "AbortError" ? s({ message: "Request was cancelled", cancelled: !0 }) : s({ message: l instanceof Error ? l.message : "Unknown error occurred" });
|
|
120
|
-
}
|
|
140
|
+
};
|
|
141
|
+
return s.modules.includes("queryQueue") ? Q.enqueue(l) : l();
|
|
121
142
|
}
|
|
122
143
|
);
|
|
123
|
-
function
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
144
|
+
function E(t) {
|
|
145
|
+
return f(t) && Array.isArray(t.data) && typeof t.primaryKey == "string";
|
|
146
|
+
}
|
|
147
|
+
function U(t, r) {
|
|
148
|
+
const n = {};
|
|
149
|
+
for (const o of t)
|
|
150
|
+
if (f(o) && r in o) {
|
|
151
|
+
const e = String(o[r]);
|
|
152
|
+
n[e] = o;
|
|
153
|
+
}
|
|
154
|
+
return n;
|
|
155
|
+
}
|
|
156
|
+
function K(t, r, n, o) {
|
|
157
|
+
return n === "replace" ? r : (n === "merge" || console.warn(`Cdeebee: Unknown strategy "${n}" for key "${o}". Skipping normalization.`), h(t, r));
|
|
158
|
+
}
|
|
159
|
+
function M(t, r, n) {
|
|
160
|
+
const o = Object.keys(r), e = f(t.storage) ? t.storage : {}, a = { ...e }, s = /* @__PURE__ */ new Set();
|
|
161
|
+
for (const i of o) {
|
|
162
|
+
const c = r[i];
|
|
127
163
|
if (c == null || typeof c == "string") {
|
|
128
|
-
|
|
164
|
+
s.add(i);
|
|
165
|
+
continue;
|
|
166
|
+
}
|
|
167
|
+
const l = n[i] ?? "merge", u = i in e ? e[i] : {};
|
|
168
|
+
if (E(c)) {
|
|
169
|
+
const d = U(c.data, c.primaryKey);
|
|
170
|
+
a[i] = K(u, d, l, i);
|
|
129
171
|
continue;
|
|
130
172
|
}
|
|
131
|
-
|
|
132
|
-
if (l) {
|
|
133
|
-
const f = r in e ? e[r] : {};
|
|
134
|
-
u === "replace" ? i[r] = c : (u === "merge" || console.warn(`Cdeebee: Unknown strategy "${u}" for key "${r}". Skipping normalization.`), i[r] = m(f, c));
|
|
135
|
-
} else
|
|
136
|
-
i[r] = c;
|
|
173
|
+
f(c) ? a[i] = K(u, c, l, i) : a[i] = c;
|
|
137
174
|
}
|
|
138
|
-
return
|
|
175
|
+
return s.size > 0 ? v(Array.from(s), a) : a;
|
|
139
176
|
}
|
|
140
|
-
const
|
|
177
|
+
const W = {
|
|
141
178
|
settings: {
|
|
142
179
|
modules: ["history", "listener", "storage", "cancelation"],
|
|
143
180
|
fileKey: "file",
|
|
@@ -152,47 +189,47 @@ const E = {
|
|
|
152
189
|
errors: {},
|
|
153
190
|
done: {}
|
|
154
191
|
}
|
|
155
|
-
},
|
|
192
|
+
}, H = (t, r) => x({
|
|
156
193
|
name: "cdeebee",
|
|
157
|
-
initialState:
|
|
194
|
+
initialState: h(W, { settings: t, storage: r ?? {} }),
|
|
158
195
|
reducers: {
|
|
159
|
-
set(
|
|
160
|
-
|
|
196
|
+
set(o, e) {
|
|
197
|
+
N(o.storage, e.payload);
|
|
161
198
|
}
|
|
162
199
|
},
|
|
163
|
-
extraReducers: (
|
|
164
|
-
|
|
165
|
-
const
|
|
166
|
-
|
|
167
|
-
I(
|
|
168
|
-
}),
|
|
169
|
-
e.request.active.push({ api:
|
|
200
|
+
extraReducers: (o) => {
|
|
201
|
+
o.addCase(A.pending, (e, a) => {
|
|
202
|
+
const s = a.meta.arg.api, i = a.meta.requestId;
|
|
203
|
+
y(e.settings, "cancelation", () => {
|
|
204
|
+
I(s, i);
|
|
205
|
+
}), y(e.settings, "listener", () => {
|
|
206
|
+
e.request.active.push({ api: s, requestId: i });
|
|
170
207
|
});
|
|
171
|
-
}).addCase(
|
|
172
|
-
const
|
|
173
|
-
|
|
174
|
-
e.request.active = e.request.active.filter((c) => !(c.api ===
|
|
175
|
-
}),
|
|
176
|
-
e.request.done[
|
|
177
|
-
}),
|
|
178
|
-
if (
|
|
208
|
+
}).addCase(A.fulfilled, (e, a) => {
|
|
209
|
+
const s = a.meta.requestId, i = a.meta.arg.api;
|
|
210
|
+
y(e.settings, "listener", () => {
|
|
211
|
+
e.request.active = e.request.active.filter((c) => !(c.api === i && c.requestId === s));
|
|
212
|
+
}), y(e.settings, "history", () => {
|
|
213
|
+
e.request.done[i] || (e.request.done[i] = []), e.request.done[i].push({ api: i, request: a.payload, requestId: s });
|
|
214
|
+
}), y(e.settings, "storage", () => {
|
|
215
|
+
if (a.meta.arg.ignore)
|
|
179
216
|
return;
|
|
180
|
-
const c =
|
|
181
|
-
e.storage =
|
|
217
|
+
const c = a.meta.arg.listStrategy ?? e.settings.listStrategy ?? {}, l = a.meta.arg.normalize ?? e.settings.normalize ?? M, u = L(e), d = l(u, a.payload.result, c);
|
|
218
|
+
e.storage = d;
|
|
182
219
|
});
|
|
183
|
-
}).addCase(
|
|
184
|
-
const
|
|
185
|
-
|
|
186
|
-
e.request.active = e.request.active.filter((c) => !(c.api ===
|
|
187
|
-
}),
|
|
188
|
-
e.request.errors[
|
|
220
|
+
}).addCase(A.rejected, (e, a) => {
|
|
221
|
+
const s = a.meta.requestId, i = a.meta.arg.api;
|
|
222
|
+
y(e.settings, "listener", () => {
|
|
223
|
+
e.request.active = e.request.active.filter((c) => !(c.api === i && c.requestId === s));
|
|
224
|
+
}), y(e.settings, "history", () => {
|
|
225
|
+
e.request.errors[i] || (e.request.errors[i] = []), e.request.errors[i].push({ requestId: s, api: i, request: a.error });
|
|
189
226
|
});
|
|
190
227
|
});
|
|
191
228
|
}
|
|
192
229
|
});
|
|
193
230
|
export {
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
231
|
+
N as batchingUpdate,
|
|
232
|
+
H as factory,
|
|
233
|
+
A as request
|
|
197
234
|
};
|
|
198
235
|
//# 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/request.ts","../lib/reducer/storage.ts","../lib/reducer/index.ts"],"sourcesContent":["import { type CdeebeeSettings, type CdeebeeModule, CdeebeeValueList } from './types';\n\nexport function checkModule(settings: 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","import { createAsyncThunk } from '@reduxjs/toolkit';\nimport { checkModule } from './helpers';\nimport { abortManager } from './abortController';\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 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\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\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 isNormalized = isRecord(responseValue);\n const strategy = strategyList[key as keyof T] ?? 'merge';\n\n if (isNormalized) {\n const existingValue = key in currentStorage ? (currentStorage[key] as StorageData) : {};\n\n if (strategy === 'replace') {\n result[key] = responseValue as ResponseValue;\n } else if (strategy === 'merge') {\n result[key] = mergeDeepRight(existingValue, responseValue as StorageData) as ResponseValue;\n } else {\n console.warn(`Cdeebee: Unknown strategy \"${strategy}\" for key \"${key}\". Skipping normalization.`);\n result[key] = mergeDeepRight(existingValue, responseValue as StorageData) as ResponseValue;\n }\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 } from '@reduxjs/toolkit';\n\nimport { type CdeebeeSettings, type CdeebeeState, type CdeebeeValueList } 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 },\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 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 ?? {};\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 const normalizedData = normalize(currentState, action.payload.result as Record<string, Record<string, unknown>>, strategyList);\n\n // Normalize already handles merge/replace 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"],"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","request","createAsyncThunk","options","rejectWithValue","getState","startedAt","abort","withCallback","method","body","headers","extraHeaders","b","requestData","formData","fileKey","bodyKey","response","responseType","error","defaultNormalize","cdeebee","strategyList","keyList","currentStorage","keyListToOmit","responseValue","isNormalized","strategy","existingValue","initialState","factory","storage","createSlice","action","builder","q","normalize","currentState","normalizedData"],"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"],"sourcesContent":["import { type CdeebeeSettings, type CdeebeeModule, CdeebeeValueList } from './types';\n\nexport function checkModule(settings: 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 {\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 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 } from '@reduxjs/toolkit';\n\nimport { type CdeebeeSettings, type CdeebeeState, type CdeebeeValueList } 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 },\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 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 ?? {};\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 const normalizedData = normalize(currentState, action.payload.result as Record<string, Record<string, unknown>>, strategyList);\n\n // Normalize already handles merge/replace 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"],"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"],"mappings":"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"}
|