@recats/cdeebee 3.0.0-beta.3 → 3.0.0-beta.4
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 +4 -28
- package/dist/index.cjs +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +0 -1
- package/dist/index.js +102 -122
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,17 +1,15 @@
|
|
|
1
1
|
# cdeebee
|
|
2
2
|
|
|
3
|
-
[](https://www.npmjs.com/package/@recats/cdeebee)
|
|
4
|
-
|
|
5
3
|
A Redux-based data management library that provides a uniform way to access, fetch, update, and manage application data with minimal boilerplate code.
|
|
6
4
|
|
|
7
5
|
## Installation
|
|
8
6
|
|
|
9
7
|
```sh
|
|
10
|
-
npm i @recats/cdeebee
|
|
8
|
+
npm i @recats/cdeebee@beta
|
|
11
9
|
# or
|
|
12
|
-
yarn add @recats/cdeebee
|
|
10
|
+
yarn add @recats/cdeebee@beta
|
|
13
11
|
# or
|
|
14
|
-
pnpm add @recats/cdeebee
|
|
12
|
+
pnpm add @recats/cdeebee@beta
|
|
15
13
|
```
|
|
16
14
|
|
|
17
15
|
## What is cdeebee?
|
|
@@ -84,7 +82,6 @@ export const cdeebeeSlice = factory<Storage>(
|
|
|
84
82
|
modules: ['history', 'listener', 'cancelation', 'storage'],
|
|
85
83
|
fileKey: 'file',
|
|
86
84
|
bodyKey: 'value',
|
|
87
|
-
primaryKey: 'id',
|
|
88
85
|
listStrategy: {
|
|
89
86
|
forumList: 'merge',
|
|
90
87
|
threadList: 'replace',
|
|
@@ -168,7 +165,6 @@ interface CdeebeeSettings<T> {
|
|
|
168
165
|
modules: CdeebeeModule[]; // Active modules: 'history' | 'listener' | 'storage' | 'cancelation'
|
|
169
166
|
fileKey: string; // Key name for file uploads in FormData
|
|
170
167
|
bodyKey: string; // Key name for request body in FormData
|
|
171
|
-
primaryKey: string; // Primary key field name in API responses (default: 'primaryKey')
|
|
172
168
|
listStrategy?: CdeebeeListStrategy<T>; // Merge strategy per list: 'merge' | 'replace'
|
|
173
169
|
mergeWithData?: unknown; // Data to merge with every request body
|
|
174
170
|
mergeWithHeaders?: Record<string, string>; // Headers to merge with every request
|
|
@@ -209,27 +205,7 @@ listStrategy: {
|
|
|
209
205
|
|
|
210
206
|
## API Response Format
|
|
211
207
|
|
|
212
|
-
cdeebee expects API responses in a
|
|
213
|
-
|
|
214
|
-
```typescript
|
|
215
|
-
{
|
|
216
|
-
forumList: {
|
|
217
|
-
primaryKey: 'id', // The field name specified in settings.primaryKey
|
|
218
|
-
data: [
|
|
219
|
-
{ id: 1, title: 'Forum 1' },
|
|
220
|
-
{ id: 2, title: 'Forum 2' },
|
|
221
|
-
]
|
|
222
|
-
},
|
|
223
|
-
threadList: {
|
|
224
|
-
primaryKey: 'id',
|
|
225
|
-
data: [
|
|
226
|
-
{ id: 101, title: 'Thread 1', forumID: 1 },
|
|
227
|
-
]
|
|
228
|
-
}
|
|
229
|
-
}
|
|
230
|
-
```
|
|
231
|
-
|
|
232
|
-
The library automatically normalizes this into:
|
|
208
|
+
cdeebee expects API responses in a normalized format where data is already organized as objects with keys representing entity IDs:
|
|
233
209
|
|
|
234
210
|
```typescript
|
|
235
211
|
{
|
package/dist/index.cjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const q=require("@reduxjs/toolkit");function d(n,s,i){n.modules.includes(s)&&i()}function f(n){return n!==null&&typeof n=="object"&&!Array.isArray(n)}function b(n,s){if(!f(n)||!f(s))return s;const i={...n},a=s;for(const e in a)if(Object.prototype.hasOwnProperty.call(a,e)){const o=i[e],t=a[e];f(o)&&f(t)&&!Array.isArray(o)&&!Array.isArray(t)?i[e]=b(o,t):i[e]=t}return i}function v(n,s){const i={...s};for(const a of n)delete i[a];return i}function z(n,s){for(let i=0;i<s.length;i++){const a=s[i],e=a.key,o=a.value;if(e.length===0)continue;let t=n;for(let r=0;r<e.length-1;r++){const c=e[r];if(Array.isArray(t)){const l=typeof c=="number"?c:Number(c);(!(l in t)||!f(t[l]))&&(t[l]={}),t=t[l]}else{const l=String(c);if(!(l in t)){const y=typeof e[r+1]=="number"||!isNaN(Number(e[r+1]))&&String(Number(e[r+1]))===String(e[r+1]);t[l]=y?[]:{}}const u=t[l];t=Array.isArray(u)||f(u)?u:{}}}Array.isArray(t)||(t[String(e[e.length-1])]=o)}}class C{constructor(){this.byRequestId=new Map,this.byApi=new Map}add(s,i,a){const e={requestId:i,controller:a,api:s};this.byRequestId.set(i,e),this.byApi.has(s)||this.byApi.set(s,new Set),this.byApi.get(s).add(i)}delete(s){const i=this.byRequestId.get(s);if(!i)return;this.byRequestId.delete(s);const a=this.byApi.get(i.api);a&&(a.delete(s),a.size===0&&this.byApi.delete(i.api))}abortAllForApi(s,i){const a=this.byApi.get(s);a&&a.forEach(e=>{if(e!==i){const o=this.byRequestId.get(e);o&&(o.controller.abort(),this.delete(e))}})}}const S=new C;function D(n,s){S.abortAllForApi(n,s)}function K(n,s,i){const a=new AbortController,e=()=>{S.delete(i)};return n.addEventListener("abort",()=>{a.abort(),e()}),{controller:a,init:()=>S.add(s,i,a),drop:e}}const g=q.createAsyncThunk("cdeebee/request",async(n,{rejectWithValue:s,getState:i,requestId:a,signal:e})=>{const o=new Date().toUTCString(),{cdeebee:{settings:t}}=i(),r=K(e,n.api,a);d(t,"cancelation",r.init);try{const{method:c="POST",body:l,headers:u={}}=n,y={...t.mergeWithHeaders??{},...u},N={...t.mergeWithData??{},...l??{}};let m=JSON.stringify(N);if(n.files){const h=new FormData,w=n.fileKey||t.fileKey,R=n.bodyKey||t.bodyKey;for(let A=0;A<n.files.length;A+=1)w&&h.append(w,n.files[A]);R&&h.append(R,m),m=h}const p=await fetch(n.api,{method:c,headers:{"ui-request-id":a,"Content-Type":"application/json",...y},signal:r.controller.signal,body:m});if(d(t,"cancelation",r.drop),!p.ok)return s(p);const k=await p.json();return n.onResult&&typeof n.onResult=="function"&&n.onResult(k),{result:k,startedAt:o,endedAt:new Date().toUTCString()}}catch(c){return d(t,"cancelation",r.drop),c instanceof Error&&c.name==="AbortError"?s({message:"Request was cancelled",cancelled:!0}):s({message:c instanceof Error?c.message:"Unknown error occurred"})}});function O(n,s,i){const a=Object.keys(s),e=f(n.storage)?n.storage:{},o={...e},t=new Set;for(const r of a){const c=s[r];if(c==null||typeof c=="string"){t.add(r);continue}if(f(c)&&Object.keys(c).length>0){const u=i[r]??"merge",y=r in e?e[r]:{};u==="replace"?o[r]=c:(u==="merge"||console.warn(`Cdeebee: Unknown strategy "${u}" for key "${r}". Skipping normalization.`),o[r]=b(y,c))}else o[r]=c}return t.size>0?v(Array.from(t),o):o}const j={settings:{modules:["history","listener","storage","cancelation"],fileKey:"file",bodyKey:"value",listStrategy:{},mergeWithData:{},mergeWithHeaders:{}},storage:{},request:{active:[],errors:{},done:{}}},I=(n,s)=>q.createSlice({name:"cdeebee",initialState:b(j,{settings:n,storage:s??{}}),reducers:{set(a,e){z(a.storage,e.payload)}},extraReducers:a=>{a.addCase(g.pending,(e,o)=>{const t=o.meta.arg.api,r=o.meta.requestId;d(e.settings,"cancelation",()=>{D(t,r)}),d(e.settings,"listener",()=>{e.request.active.push({api:t,requestId:r})})}).addCase(g.fulfilled,(e,o)=>{const t=o.meta.requestId,r=o.meta.arg.api;d(e.settings,"listener",()=>{e.request.active=e.request.active.filter(c=>!(c.api===r&&c.requestId===t))}),d(e.settings,"history",()=>{e.request.done[r]||(e.request.done[r]=[]),e.request.done[r].push({api:r,request:o.payload,requestId:t})}),d(e.settings,"storage",()=>{const c=o.meta.arg.listStrategy??e.settings.listStrategy??{},l=o.meta.arg.normalize??e.settings.normalize??O,u=q.current(e),y=l(u,o.payload.result,c);e.storage=y})}).addCase(g.rejected,(e,o)=>{const t=o.meta.requestId,r=o.meta.arg.api;d(e.settings,"listener",()=>{e.request.active=e.request.active.filter(c=>!(c.api===r&&c.requestId===t))}),d(e.settings,"history",()=>{e.request.errors[r]||(e.request.errors[r]=[]),e.request.errors[r].push({requestId:t,api:r,request:o.error})})})}});exports.batchingUpdate=z;exports.factory=I;exports.request=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/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\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 if (!response.ok) {\n return rejectWithValue(response);\n }\n const result = await response.json();\n if (options.onResult && typeof options.onResult === 'function') {\n options.onResult(result);\n }\n return { result, startedAt, endedAt: new Date().toUTCString() };\n } catch (error) {\n checkModule(settings, 'cancelation', abort.drop);\n if (error instanceof Error && error.name === 'AbortError') {\n return rejectWithValue({\n message: 'Request was cancelled',\n cancelled: true,\n });\n }\n return rejectWithValue({\n message: error instanceof Error ? error.message : 'Unknown error occurred',\n });\n }\n },\n);\n\n","import { type CdeebeeListStrategy, type CdeebeeState } from './types';\nimport { hasDataProperty, hasProperty, isRecord, mergeDeepRight, omit } from './helpers';\n\ntype ResponseValue = Record<string, unknown> & {\n data?: unknown[];\n [key: string]: unknown;\n};\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 primaryKey = cdeebee.settings.primaryKey;\n const currentStorage = isRecord(cdeebee.storage) ? (cdeebee.storage as Record<string, unknown>) : {};\n \n // Start with existing storage to preserve keys not in response\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 if (hasDataProperty(responseValue) && hasProperty(responseValue, primaryKey)) {\n const primaryKeyValue = responseValue[primaryKey];\n \n if (typeof primaryKeyValue !== 'string') {\n console.warn(`Cdeebee: Primary key \"${primaryKey}\" is not a string for API \"${key}\". Skipping normalization.`);\n result[key] = responseValue;\n continue;\n }\n\n // Pre-allocate storage data object\n const newStorageData: StorageData = {};\n const dataArray = responseValue.data;\n const dataLength = dataArray.length;\n\n for (let i = 0; i < dataLength; i++) {\n const element = dataArray[i];\n if (isRecord(element) && element[primaryKeyValue]) {\n const elementKey = element[primaryKeyValue] as string;\n newStorageData[elementKey] = element;\n }\n }\n\n const strategy = strategyList[key as keyof T] ?? 'merge';\n const existingValue = key in currentStorage ? (currentStorage[key] as StorageData) : {};\n\n if (strategy === 'replace') {\n // Replace: completely replace the value\n result[key] = newStorageData as ResponseValue;\n } else if (strategy === 'merge') {\n // Merge: merge with existing value\n result[key] = mergeDeepRight(existingValue, newStorageData) as ResponseValue;\n } else {\n // Unknown strategy: warn and fall back to merge\n console.warn(`Cdeebee: Unknown strategy \"${strategy}\" for key \"${key}\". Skipping normalization.`);\n result[key] = mergeDeepRight(existingValue, newStorageData) 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 primaryKey: 'primaryKey',\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 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 const normalizedData = normalize(currentState, action.payload.result, 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","hasDataProperty","hasProperty","prop","mergeDeepRight","left","right","rightRecord","key","leftValue","rightValue","omit","keys","obj","batchingUpdate","state","valueList","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","method","body","headers","extraHeaders","b","requestData","formData","fileKey","bodyKey","i","response","error","defaultNormalize","cdeebee","strategyList","keyList","primaryKey","currentStorage","keyListToOmit","responseValue","primaryKeyValue","newStorageData","dataArray","dataLength","element","elementKey","strategy","existingValue","initialState","factory","storage","createSlice","action","builder","q","normalize","currentState","normalizedData"],"mappings":"oHAEO,SAASA,EAAYC,EAAoCC,EAAuBC,EAAoB,CACrGF,EAAS,QAAQ,SAASC,CAAM,GAClCC,EAAA,CAEJ,CACO,SAASC,EAASC,EAAkD,CACzE,OAAOA,IAAU,MAAQ,OAAOA,GAAU,UAAY,CAAC,MAAM,QAAQA,CAAK,CAC5E,CAEQ,SAASC,EAAgBD,EAAwE,CACvG,OAAOD,EAASC,CAAK,GAAK,MAAM,QAAQA,EAAM,IAAI,CACpD,CAEQ,SAASE,EAAYF,EAAgBG,EAAuB,CAClE,OAAOJ,EAASC,CAAK,GAAK,OAAO,UAAU,eAAe,KAAKA,EAAOG,CAAI,CAC5E,CAEO,SAASC,EACdC,EACAC,EACG,CACH,GAAI,CAACP,EAASM,CAAI,GAAK,CAACN,EAASO,CAAK,EACpC,OAAOA,EAGT,MAAMR,EAAS,CAAE,GAAGO,CAAA,EACdE,EAAcD,EAEpB,UAAWE,KAAOD,EAChB,GAAI,OAAO,UAAU,eAAe,KAAKA,EAAaC,CAAG,EAAG,CAC1D,MAAMC,EAAYX,EAAOU,CAAG,EACtBE,EAAaH,EAAYC,CAAG,EAGhCT,EAASU,CAAS,GAClBV,EAASW,CAAU,GACnB,CAAC,MAAM,QAAQD,CAAS,GACxB,CAAC,MAAM,QAAQC,CAAU,EAEzBZ,EAAOU,CAAG,EAAIJ,EAAeK,EAAWC,CAAU,EAElDZ,EAAOU,CAAG,EAAIE,CAElB,CAGF,OAAOZ,CACT,CAEO,SAASa,EAAwCC,EAAgBC,EAA0B,CAChG,MAAMf,EAAS,CAAE,GAAGe,CAAA,EACpB,UAAWL,KAAOI,EAChB,OAAOd,EAAOU,CAAG,EAEnB,OAAOV,CACT,CAqBO,SAASgB,EACdC,EACAC,EACM,CACN,QAAS,EAAI,EAAG,EAAIA,EAAU,OAAQ,IAAK,CACzC,MAAMC,EAAOD,EAAU,CAAC,EAClBE,EAAOD,EAAK,IACZjB,EAAQiB,EAAK,MAEnB,GAAIC,EAAK,SAAW,EAClB,SAGF,IAAIC,EAA+CJ,EAEnD,QAASK,EAAI,EAAGA,EAAIF,EAAK,OAAS,EAAGE,IAAK,CACxC,MAAMC,EAAUH,EAAKE,CAAC,EAEtB,GAAI,MAAM,QAAQD,CAAO,EAAG,CAC1B,MAAMG,EAAQ,OAAOD,GAAY,SAAWA,EAAU,OAAOA,CAAO,GAChE,EAAEC,KAASH,IAAY,CAACpB,EAASoB,EAAQG,CAAK,CAAC,KACjDH,EAAQG,CAAK,EAAI,CAAA,GAEnBH,EAAUA,EAAQG,CAAK,CACzB,KAAO,CACL,MAAMd,EAAM,OAAOa,CAAO,EAC1B,GAAI,EAAEb,KAAOW,GAAU,CACrB,MAAMI,EAAgB,OAAOL,EAAKE,EAAI,CAAC,GAAM,UAAa,CAAC,MAAM,OAAOF,EAAKE,EAAI,CAAC,CAAC,CAAC,GAAK,OAAO,OAAOF,EAAKE,EAAI,CAAC,CAAC,CAAC,IAAM,OAAOF,EAAKE,EAAI,CAAC,CAAC,EAC3ID,EAAQX,CAAG,EAAIe,EAAgB,CAAA,EAAK,CAAA,CACtC,CACA,MAAMC,EAAOL,EAAQX,CAAG,EACxBW,EAAW,MAAM,QAAQK,CAAI,GAAYzB,EAASyB,CAAI,EAArBA,EAAgC,CAAA,CACnE,CACF,CAEI,MAAM,QAAQL,CAAO,IAGzBA,EAAQ,OAAOD,EAAKA,EAAK,OAAS,CAAC,CAAC,CAAC,EAAIlB,EAC3C,CACF,CChHA,MAAMyB,CAAqB,CAA3B,aAAA,CACE,KAAQ,gBAAkB,IAC1B,KAAQ,UAAY,GAAyB,CAE7C,IAAIC,EAAaC,EAAmBC,EAAmC,CACrE,MAAMX,EAA0B,CAAE,UAAAU,EAAW,WAAAC,EAAY,IAAAF,CAAA,EACzD,KAAK,YAAY,IAAIC,EAAWV,CAAI,EAE/B,KAAK,MAAM,IAAIS,CAAG,GACrB,KAAK,MAAM,IAAIA,EAAK,IAAI,GAAK,EAE/B,KAAK,MAAM,IAAIA,CAAG,EAAG,IAAIC,CAAS,CACpC,CAEA,OAAOA,EAAyB,CAC9B,MAAMV,EAAO,KAAK,YAAY,IAAIU,CAAS,EAC3C,GAAI,CAACV,EAAM,OAEX,KAAK,YAAY,OAAOU,CAAS,EACjC,MAAME,EAAS,KAAK,MAAM,IAAIZ,EAAK,GAAG,EAClCY,IACFA,EAAO,OAAOF,CAAS,EACnBE,EAAO,OAAS,GAClB,KAAK,MAAM,OAAOZ,EAAK,GAAG,EAGhC,CAEA,eAAeS,EAAaI,EAAgC,CAC1D,MAAMC,EAAa,KAAK,MAAM,IAAIL,CAAG,EAChCK,GAELA,EAAW,QAAQJ,GAAa,CAC9B,GAAIA,IAAcG,EAAkB,CAClC,MAAMb,EAAO,KAAK,YAAY,IAAIU,CAAS,EACvCV,IACFA,EAAK,WAAW,MAAA,EAChB,KAAK,OAAOU,CAAS,EAEzB,CACF,CAAC,CACH,CACF,CAEA,MAAMK,EAAa,IAAIP,EAEhB,SAASQ,EAAWP,EAAaQ,EAAgC,CACtEF,EAAW,eAAeN,EAAKQ,CAAgB,CACjD,CAEO,SAASC,EAAaC,EAAqBV,EAAaC,EAAmB,CAChF,MAAMC,EAAa,IAAI,gBAEjBS,EAAU,IAAM,CACpBL,EAAW,OAAOL,CAAS,CAC7B,EAEA,OAAAS,EAAO,iBAAiB,QAAS,IAAM,CACrCR,EAAW,MAAA,EACXS,EAAA,CACF,CAAC,EAEM,CACL,WAAAT,EACA,KAAM,IAAMI,EAAW,IAAIN,EAAKC,EAAWC,CAAU,EACrD,KAAMS,CAAA,CAEV,CCpEO,MAAMC,EAAUC,EAAAA,iBACrB,kBACA,MAAOC,EAAyC,CAAE,gBAAAC,EAAkB,SAAAC,EAAU,UAAAf,EAAW,OAAAS,KAAa,CACpG,MAAMO,EAAY,IAAI,KAAA,EAAO,YAAA,EACvB,CAAE,QAAS,CAAE,SAAA/C,CAAA,CAAS,EAAM8C,EAAA,EAE5BE,EAAQT,EAAaC,EAAQI,EAAQ,IAAKb,CAAS,EAEzDhC,EAAYC,EAAU,cAAegD,EAAM,IAAI,EAE/C,GAAI,CACF,KAAM,CAAE,OAAAC,EAAS,OAAQ,KAAAC,EAAM,QAAAC,EAAU,CAAA,GAAOP,EAC1CQ,EAAuC,CAAE,GAAIpD,EAAS,kBAAoB,CAAA,EAAK,GAAGmD,CAAA,EAElFE,EAAI,CAAE,GAAIrD,EAAS,eAAiB,GAAK,GAAIkD,GAAQ,EAAC,EAC5D,IAAII,EAAiC,KAAK,UAAUD,CAAC,EAGrD,GAAIT,EAAQ,MAAO,CACjB,MAAMW,EAAW,IAAI,SACfC,EAAUZ,EAAQ,SAAW5C,EAAS,QACtCyD,EAAUb,EAAQ,SAAW5C,EAAS,QAE5C,QAAS0D,EAAI,EAAGA,EAAId,EAAQ,MAAM,OAAQc,GAAK,EACzCF,GACFD,EAAS,OAAOC,EAASZ,EAAQ,MAAMc,CAAC,CAAC,EAIzCD,GACFF,EAAS,OAAOE,EAASH,CAAW,EAEtCA,EAAcC,CAChB,CAGA,MAAMI,EAAW,MAAM,MAAMf,EAAQ,IAAK,CACxC,OAAAK,EACA,QAAS,CACP,gBAAiBlB,EACjB,eAAgB,mBAChB,GAAGqB,CAAA,EAEL,OAAQJ,EAAM,WAAW,OACzB,KAAMM,CAAA,CACP,EAID,GAFAvD,EAAYC,EAAU,cAAegD,EAAM,IAAI,EAE3C,CAACW,EAAS,GACZ,OAAOd,EAAgBc,CAAQ,EAEjC,MAAMzD,EAAS,MAAMyD,EAAS,KAAA,EAC9B,OAAIf,EAAQ,UAAY,OAAOA,EAAQ,UAAa,YAClDA,EAAQ,SAAS1C,CAAM,EAElB,CAAE,OAAAA,EAAQ,UAAA6C,EAAW,YAAa,KAAA,EAAO,aAAY,CAC9D,OAASa,EAAO,CAEd,OADA7D,EAAYC,EAAU,cAAegD,EAAM,IAAI,EAC3CY,aAAiB,OAASA,EAAM,OAAS,aACpCf,EAAgB,CACrB,QAAS,wBACT,UAAW,EAAA,CACZ,EAEIA,EAAgB,CACrB,QAASe,aAAiB,MAAQA,EAAM,QAAU,wBAAA,CACnD,CACH,CACF,CACF,EC/DO,SAASC,EACdC,EACAH,EACAI,EAC+B,CAC/B,MAAMC,EAAU,OAAO,KAAKL,CAAQ,EAC9BM,EAAaH,EAAQ,SAAS,WAC9BI,EAAiB/D,EAAS2D,EAAQ,OAAO,EAAKA,EAAQ,QAAsC,CAAA,EAG5F5D,EAAS,CAAE,GAAGgE,CAAA,EACdC,MAAoB,IAE1B,UAAWvD,KAAOoD,EAAS,CACzB,MAAMI,EAAgBT,EAAS/C,CAAG,EAElC,GAAIwD,GAAkB,MAAuC,OAAOA,GAAkB,SAAU,CAC9FD,EAAc,IAAIvD,CAAG,EACrB,QACF,CAEA,GAAIP,EAAgB+D,CAAa,GAAK9D,EAAY8D,EAAeH,CAAU,EAAG,CAC5E,MAAMI,EAAkBD,EAAcH,CAAU,EAEhD,GAAI,OAAOI,GAAoB,SAAU,CACvC,QAAQ,KAAK,yBAAyBJ,CAAU,8BAA8BrD,CAAG,4BAA4B,EAC7GV,EAAOU,CAAG,EAAIwD,EACd,QACF,CAGA,MAAME,EAA8B,CAAA,EAC9BC,EAAYH,EAAc,KAC1BI,EAAaD,EAAU,OAE7B,QAASb,EAAI,EAAGA,EAAIc,EAAYd,IAAK,CACnC,MAAMe,EAAUF,EAAUb,CAAC,EAC3B,GAAIvD,EAASsE,CAAO,GAAKA,EAAQJ,CAAe,EAAG,CACjD,MAAMK,EAAaD,EAAQJ,CAAe,EAC1CC,EAAeI,CAAU,EAAID,CAC/B,CACF,CAEA,MAAME,EAAWZ,EAAanD,CAAc,GAAK,QAC3CgE,EAAgBhE,KAAOsD,EAAkBA,EAAetD,CAAG,EAAoB,CAAA,EAEjF+D,IAAa,UAEfzE,EAAOU,CAAG,EAAI0D,GACLK,IAAa,SAKtB,QAAQ,KAAK,8BAA8BA,CAAQ,cAAc/D,CAAG,4BAA4B,EAChGV,EAAOU,CAAG,EAAIJ,EAAeoE,EAAeN,CAAc,EAE9D,MACEpE,EAAOU,CAAG,EAAIwD,CAElB,CAEA,OAAOD,EAAc,KAAO,EAAIpD,EAAK,MAAM,KAAKoD,CAAa,EAAGjE,CAAM,EAAIA,CAC5E,CCnEA,MAAM2E,EAAsC,CAC1C,SAAU,CACR,QAAS,CAAC,UAAW,WAAY,UAAW,aAAa,EACzD,QAAS,OACT,QAAS,QACT,WAAY,aACZ,aAAc,CAAA,EACd,cAAe,CAAA,EACf,iBAAkB,CAAA,CAAC,EAErB,QAAS,CAAA,EACT,QAAS,CACP,OAAQ,CAAA,EACR,OAAQ,CAAA,EACR,KAAM,CAAA,CAAC,CAEX,EAEaC,EAAU,CAAI9E,EAA8B+E,IACzCC,EAAAA,YAAY,CACxB,KAAM,UACN,aAAcxE,EAAeqE,EAAc,CAAE,SAAA7E,EAAU,QAAS+E,GAAW,CAAA,EAAI,EAC/E,SAAU,CACR,IAAI5D,EAAO8D,EAA0C,CAInD/D,EAAeC,EAAM,QAAoC8D,EAAO,OAAO,CACzE,CAAA,EAEF,cAAeC,GAAW,CACxBA,EACG,QAAQxC,EAAQ,QAAS,CAACvB,EAAO8D,IAAW,CAC3C,MAAMnD,EAAMmD,EAAO,KAAK,IAAI,IACtBlD,EAAYkD,EAAO,KAAK,UAE9BlF,EAAYoB,EAAM,SAAU,cAAe,IAAM,CAC/CkB,EAAWP,EAAKC,CAAS,CAC3B,CAAC,EACDhC,EAAYoB,EAAM,SAAU,WAAY,IAAM,CAC5CA,EAAM,QAAQ,OAAO,KAAK,CAAE,IAAAW,EAAK,UAAAC,EAAW,CAC9C,CAAC,CACH,CAAC,EACA,QAAQW,EAAQ,UAAW,CAACvB,EAAO8D,IAAW,CAC7C,MAAMlD,EAAYkD,EAAO,KAAK,UACxBnD,EAAMmD,EAAO,KAAK,IAAI,IAE5BlF,EAAYoB,EAAM,SAAU,WAAY,IAAM,CAC5CA,EAAM,QAAQ,OAASA,EAAM,QAAQ,OAAO,OAAOgE,GAAK,EAAEA,EAAE,MAAQrD,GAAOqD,EAAE,YAAcpD,EAAU,CACvG,CAAC,EACDhC,EAAYoB,EAAM,SAAU,UAAW,IAAM,CACtCA,EAAM,QAAQ,KAAKW,CAAG,IAAIX,EAAM,QAAQ,KAAKW,CAAG,EAAI,CAAA,GACzDX,EAAM,QAAQ,KAAKW,CAAG,EAAE,KAAK,CAAE,IAAAA,EAAK,QAASmD,EAAO,QAAS,UAAAlD,CAAA,CAAW,CAC1E,CAAC,EACDhC,EAAYoB,EAAM,SAAU,UAAW,IAAM,CAC3C,MAAM4C,EAAekB,EAAO,KAAK,IAAI,cAAgB9D,EAAM,SAAS,cAAgB,CAAA,EAC9EiE,EAAYH,EAAO,KAAK,IAAI,WAAa9D,EAAM,SAAS,WAAa0C,EAErEwB,EAAe9D,EAAAA,QAAQJ,CAAK,EAC5BmE,EAAiBF,EAAUC,EAAcJ,EAAO,QAAQ,OAAQlB,CAAY,EAKjF5C,EAAM,QAAkBmE,CAC3B,CAAC,CACH,CAAC,EACA,QAAQ5C,EAAQ,SAAU,CAACvB,EAAO8D,IAAW,CAC5C,MAAMlD,EAAYkD,EAAO,KAAK,UACxBnD,EAAMmD,EAAO,KAAK,IAAI,IAE5BlF,EAAYoB,EAAM,SAAU,WAAY,IAAM,CAC5CA,EAAM,QAAQ,OAASA,EAAM,QAAQ,OAAO,OAAOgE,GAAK,EAAEA,EAAE,MAAQrD,GAAOqD,EAAE,YAAcpD,EAAU,CACvG,CAAC,EACDhC,EAAYoB,EAAM,SAAU,UAAW,IAAM,CACtCA,EAAM,QAAQ,OAAOW,CAAG,IAAIX,EAAM,QAAQ,OAAOW,CAAG,EAAI,CAAA,GAC7DX,EAAM,QAAQ,OAAOW,CAAG,EAAE,KAAK,CAAE,UAAAC,EAAsB,IAAAD,EAAK,QAASmD,EAAO,KAAA,CAAO,CACrF,CAAC,CACH,CAAC,CACL,CAAA,CACD"}
|
|
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\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 if (!response.ok) {\n return rejectWithValue(response);\n }\n const result = await response.json();\n if (options.onResult && typeof options.onResult === 'function') {\n options.onResult(result);\n }\n return { result, startedAt, endedAt: new Date().toUTCString() };\n } catch (error) {\n checkModule(settings, 'cancelation', abort.drop);\n if (error instanceof Error && error.name === 'AbortError') {\n return rejectWithValue({\n message: 'Request was cancelled',\n cancelled: true,\n });\n }\n return rejectWithValue({\n message: error instanceof Error ? error.message : 'Unknown error occurred',\n });\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 // Start with existing storage to preserve keys not in response\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) && Object.keys(responseValue).length > 0;\n\n if (isNormalized) {\n const strategy = strategyList[key as keyof T] ?? 'merge';\n const existingValue = key in currentStorage ? (currentStorage[key] as StorageData) : {};\n\n if (strategy === 'replace') {\n // Replace: completely replace the value\n result[key] = responseValue as ResponseValue;\n } else if (strategy === 'merge') {\n // Merge: merge with existing value\n result[key] = mergeDeepRight(existingValue, responseValue as StorageData) as ResponseValue;\n } else {\n // Unknown strategy: warn and fall back to merge\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 // Not a normalized object, store as-is\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 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 const normalizedData = normalize(currentState, action.payload.result, 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","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","method","body","headers","extraHeaders","b","requestData","formData","fileKey","bodyKey","i","response","error","defaultNormalize","cdeebee","strategyList","keyList","currentStorage","keyListToOmit","responseValue","strategy","existingValue","initialState","factory","storage","createSlice","action","builder","q","normalize","currentState","normalizedData"],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -1,171 +1,151 @@
|
|
|
1
|
-
import { createAsyncThunk as
|
|
2
|
-
function d(
|
|
3
|
-
|
|
1
|
+
import { createAsyncThunk as z, createSlice as N, current as C } from "@reduxjs/toolkit";
|
|
2
|
+
function d(n, s, i) {
|
|
3
|
+
n.modules.includes(s) && i();
|
|
4
4
|
}
|
|
5
|
-
function f(
|
|
6
|
-
return
|
|
5
|
+
function f(n) {
|
|
6
|
+
return n !== null && typeof n == "object" && !Array.isArray(n);
|
|
7
7
|
}
|
|
8
|
-
function
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
return f(r) && Object.prototype.hasOwnProperty.call(r, n);
|
|
13
|
-
}
|
|
14
|
-
function q(r, n) {
|
|
15
|
-
if (!f(r) || !f(n))
|
|
16
|
-
return n;
|
|
17
|
-
const i = { ...r }, a = n;
|
|
8
|
+
function g(n, s) {
|
|
9
|
+
if (!f(n) || !f(s))
|
|
10
|
+
return s;
|
|
11
|
+
const i = { ...n }, a = s;
|
|
18
12
|
for (const e in a)
|
|
19
13
|
if (Object.prototype.hasOwnProperty.call(a, e)) {
|
|
20
|
-
const
|
|
21
|
-
f(
|
|
14
|
+
const o = i[e], t = a[e];
|
|
15
|
+
f(o) && f(t) && !Array.isArray(o) && !Array.isArray(t) ? i[e] = g(o, t) : i[e] = t;
|
|
22
16
|
}
|
|
23
17
|
return i;
|
|
24
18
|
}
|
|
25
|
-
function
|
|
26
|
-
const i = { ...
|
|
27
|
-
for (const a of
|
|
19
|
+
function D(n, s) {
|
|
20
|
+
const i = { ...s };
|
|
21
|
+
for (const a of n)
|
|
28
22
|
delete i[a];
|
|
29
23
|
return i;
|
|
30
24
|
}
|
|
31
|
-
function
|
|
32
|
-
for (let i = 0; i <
|
|
33
|
-
const a =
|
|
25
|
+
function K(n, s) {
|
|
26
|
+
for (let i = 0; i < s.length; i++) {
|
|
27
|
+
const a = s[i], e = a.key, o = a.value;
|
|
34
28
|
if (e.length === 0)
|
|
35
29
|
continue;
|
|
36
|
-
let t =
|
|
37
|
-
for (let
|
|
38
|
-
const
|
|
30
|
+
let t = n;
|
|
31
|
+
for (let r = 0; r < e.length - 1; r++) {
|
|
32
|
+
const c = e[r];
|
|
39
33
|
if (Array.isArray(t)) {
|
|
40
|
-
const l = typeof
|
|
34
|
+
const l = typeof c == "number" ? c : Number(c);
|
|
41
35
|
(!(l in t) || !f(t[l])) && (t[l] = {}), t = t[l];
|
|
42
36
|
} else {
|
|
43
|
-
const l = String(
|
|
37
|
+
const l = String(c);
|
|
44
38
|
if (!(l in t)) {
|
|
45
|
-
const
|
|
46
|
-
t[l] =
|
|
39
|
+
const y = typeof e[r + 1] == "number" || !isNaN(Number(e[r + 1])) && String(Number(e[r + 1])) === String(e[r + 1]);
|
|
40
|
+
t[l] = y ? [] : {};
|
|
47
41
|
}
|
|
48
|
-
const
|
|
49
|
-
t = Array.isArray(
|
|
42
|
+
const u = t[l];
|
|
43
|
+
t = Array.isArray(u) || f(u) ? u : {};
|
|
50
44
|
}
|
|
51
45
|
}
|
|
52
|
-
Array.isArray(t) || (t[String(e[e.length - 1])] =
|
|
46
|
+
Array.isArray(t) || (t[String(e[e.length - 1])] = o);
|
|
53
47
|
}
|
|
54
48
|
}
|
|
55
|
-
class
|
|
49
|
+
class v {
|
|
56
50
|
constructor() {
|
|
57
51
|
this.byRequestId = /* @__PURE__ */ new Map(), this.byApi = /* @__PURE__ */ new Map();
|
|
58
52
|
}
|
|
59
|
-
add(
|
|
60
|
-
const e = { requestId: i, controller: a, api:
|
|
61
|
-
this.byRequestId.set(i, e), this.byApi.has(
|
|
53
|
+
add(s, i, a) {
|
|
54
|
+
const e = { requestId: i, controller: a, api: s };
|
|
55
|
+
this.byRequestId.set(i, e), this.byApi.has(s) || this.byApi.set(s, /* @__PURE__ */ new Set()), this.byApi.get(s).add(i);
|
|
62
56
|
}
|
|
63
|
-
delete(
|
|
64
|
-
const i = this.byRequestId.get(
|
|
57
|
+
delete(s) {
|
|
58
|
+
const i = this.byRequestId.get(s);
|
|
65
59
|
if (!i) return;
|
|
66
|
-
this.byRequestId.delete(
|
|
60
|
+
this.byRequestId.delete(s);
|
|
67
61
|
const a = this.byApi.get(i.api);
|
|
68
|
-
a && (a.delete(
|
|
62
|
+
a && (a.delete(s), a.size === 0 && this.byApi.delete(i.api));
|
|
69
63
|
}
|
|
70
|
-
abortAllForApi(
|
|
71
|
-
const a = this.byApi.get(
|
|
64
|
+
abortAllForApi(s, i) {
|
|
65
|
+
const a = this.byApi.get(s);
|
|
72
66
|
a && a.forEach((e) => {
|
|
73
67
|
if (e !== i) {
|
|
74
|
-
const
|
|
75
|
-
|
|
68
|
+
const o = this.byRequestId.get(e);
|
|
69
|
+
o && (o.controller.abort(), this.delete(e));
|
|
76
70
|
}
|
|
77
71
|
});
|
|
78
72
|
}
|
|
79
73
|
}
|
|
80
|
-
const
|
|
81
|
-
function
|
|
82
|
-
|
|
74
|
+
const q = new v();
|
|
75
|
+
function x(n, s) {
|
|
76
|
+
q.abortAllForApi(n, s);
|
|
83
77
|
}
|
|
84
|
-
function
|
|
78
|
+
function I(n, s, i) {
|
|
85
79
|
const a = new AbortController(), e = () => {
|
|
86
|
-
|
|
80
|
+
q.delete(i);
|
|
87
81
|
};
|
|
88
|
-
return
|
|
82
|
+
return n.addEventListener("abort", () => {
|
|
89
83
|
a.abort(), e();
|
|
90
84
|
}), {
|
|
91
85
|
controller: a,
|
|
92
|
-
init: () =>
|
|
86
|
+
init: () => q.add(s, i, a),
|
|
93
87
|
drop: e
|
|
94
88
|
};
|
|
95
89
|
}
|
|
96
|
-
const
|
|
90
|
+
const A = z(
|
|
97
91
|
"cdeebee/request",
|
|
98
|
-
async (
|
|
99
|
-
const
|
|
100
|
-
d(t, "cancelation",
|
|
92
|
+
async (n, { rejectWithValue: s, getState: i, requestId: a, signal: e }) => {
|
|
93
|
+
const o = (/* @__PURE__ */ new Date()).toUTCString(), { cdeebee: { settings: t } } = i(), r = I(e, n.api, a);
|
|
94
|
+
d(t, "cancelation", r.init);
|
|
101
95
|
try {
|
|
102
|
-
const { method:
|
|
103
|
-
let
|
|
104
|
-
if (
|
|
105
|
-
const
|
|
106
|
-
for (let
|
|
107
|
-
|
|
108
|
-
|
|
96
|
+
const { method: c = "POST", body: l, headers: u = {} } = n, y = { ...t.mergeWithHeaders ?? {}, ...u }, R = { ...t.mergeWithData ?? {}, ...l ?? {} };
|
|
97
|
+
let m = JSON.stringify(R);
|
|
98
|
+
if (n.files) {
|
|
99
|
+
const b = new FormData(), k = n.fileKey || t.fileKey, w = n.bodyKey || t.bodyKey;
|
|
100
|
+
for (let h = 0; h < n.files.length; h += 1)
|
|
101
|
+
k && b.append(k, n.files[h]);
|
|
102
|
+
w && b.append(w, m), m = b;
|
|
109
103
|
}
|
|
110
|
-
const
|
|
111
|
-
method:
|
|
104
|
+
const p = await fetch(n.api, {
|
|
105
|
+
method: c,
|
|
112
106
|
headers: {
|
|
113
107
|
"ui-request-id": a,
|
|
114
108
|
"Content-Type": "application/json",
|
|
115
|
-
...
|
|
109
|
+
...y
|
|
116
110
|
},
|
|
117
|
-
signal:
|
|
118
|
-
body:
|
|
111
|
+
signal: r.controller.signal,
|
|
112
|
+
body: m
|
|
119
113
|
});
|
|
120
|
-
if (d(t, "cancelation",
|
|
121
|
-
return
|
|
122
|
-
const
|
|
123
|
-
return
|
|
124
|
-
} catch (
|
|
125
|
-
return d(t, "cancelation",
|
|
114
|
+
if (d(t, "cancelation", r.drop), !p.ok)
|
|
115
|
+
return s(p);
|
|
116
|
+
const S = await p.json();
|
|
117
|
+
return n.onResult && typeof n.onResult == "function" && n.onResult(S), { result: S, startedAt: o, endedAt: (/* @__PURE__ */ new Date()).toUTCString() };
|
|
118
|
+
} catch (c) {
|
|
119
|
+
return d(t, "cancelation", r.drop), c instanceof Error && c.name === "AbortError" ? s({
|
|
126
120
|
message: "Request was cancelled",
|
|
127
121
|
cancelled: !0
|
|
128
|
-
}) :
|
|
129
|
-
message:
|
|
122
|
+
}) : s({
|
|
123
|
+
message: c instanceof Error ? c.message : "Unknown error occurred"
|
|
130
124
|
});
|
|
131
125
|
}
|
|
132
126
|
}
|
|
133
127
|
);
|
|
134
|
-
function
|
|
135
|
-
const a = Object.keys(
|
|
136
|
-
for (const
|
|
137
|
-
const
|
|
138
|
-
if (
|
|
139
|
-
|
|
128
|
+
function O(n, s, i) {
|
|
129
|
+
const a = Object.keys(s), e = f(n.storage) ? n.storage : {}, o = { ...e }, t = /* @__PURE__ */ new Set();
|
|
130
|
+
for (const r of a) {
|
|
131
|
+
const c = s[r];
|
|
132
|
+
if (c == null || typeof c == "string") {
|
|
133
|
+
t.add(r);
|
|
140
134
|
continue;
|
|
141
135
|
}
|
|
142
|
-
if (
|
|
143
|
-
const y =
|
|
144
|
-
|
|
145
|
-
console.warn(`Cdeebee: Primary key "${e}" is not a string for API "${s}". Skipping normalization.`), t[s] = l;
|
|
146
|
-
continue;
|
|
147
|
-
}
|
|
148
|
-
const u = {}, A = l.data, h = A.length;
|
|
149
|
-
for (let p = 0; p < h; p++) {
|
|
150
|
-
const m = A[p];
|
|
151
|
-
if (f(m) && m[y]) {
|
|
152
|
-
const S = m[y];
|
|
153
|
-
u[S] = m;
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
const g = i[s] ?? "merge", b = s in c ? c[s] : {};
|
|
157
|
-
g === "replace" ? t[s] = u : (g === "merge" || console.warn(`Cdeebee: Unknown strategy "${g}" for key "${s}". Skipping normalization.`), t[s] = q(b, u));
|
|
136
|
+
if (f(c) && Object.keys(c).length > 0) {
|
|
137
|
+
const u = i[r] ?? "merge", y = r in e ? e[r] : {};
|
|
138
|
+
u === "replace" ? o[r] = c : (u === "merge" || console.warn(`Cdeebee: Unknown strategy "${u}" for key "${r}". Skipping normalization.`), o[r] = g(y, c));
|
|
158
139
|
} else
|
|
159
|
-
|
|
140
|
+
o[r] = c;
|
|
160
141
|
}
|
|
161
|
-
return
|
|
142
|
+
return t.size > 0 ? D(Array.from(t), o) : o;
|
|
162
143
|
}
|
|
163
|
-
const
|
|
144
|
+
const j = {
|
|
164
145
|
settings: {
|
|
165
146
|
modules: ["history", "listener", "storage", "cancelation"],
|
|
166
147
|
fileKey: "file",
|
|
167
148
|
bodyKey: "value",
|
|
168
|
-
primaryKey: "primaryKey",
|
|
169
149
|
listStrategy: {},
|
|
170
150
|
mergeWithData: {},
|
|
171
151
|
mergeWithHeaders: {}
|
|
@@ -176,45 +156,45 @@ const T = {
|
|
|
176
156
|
errors: {},
|
|
177
157
|
done: {}
|
|
178
158
|
}
|
|
179
|
-
},
|
|
159
|
+
}, E = (n, s) => N({
|
|
180
160
|
name: "cdeebee",
|
|
181
|
-
initialState:
|
|
161
|
+
initialState: g(j, { settings: n, storage: s ?? {} }),
|
|
182
162
|
reducers: {
|
|
183
163
|
set(a, e) {
|
|
184
|
-
|
|
164
|
+
K(a.storage, e.payload);
|
|
185
165
|
}
|
|
186
166
|
},
|
|
187
167
|
extraReducers: (a) => {
|
|
188
|
-
a.addCase(
|
|
189
|
-
const t =
|
|
168
|
+
a.addCase(A.pending, (e, o) => {
|
|
169
|
+
const t = o.meta.arg.api, r = o.meta.requestId;
|
|
190
170
|
d(e.settings, "cancelation", () => {
|
|
191
|
-
|
|
171
|
+
x(t, r);
|
|
192
172
|
}), d(e.settings, "listener", () => {
|
|
193
|
-
e.request.active.push({ api: t, requestId:
|
|
173
|
+
e.request.active.push({ api: t, requestId: r });
|
|
194
174
|
});
|
|
195
|
-
}).addCase(
|
|
196
|
-
const t =
|
|
175
|
+
}).addCase(A.fulfilled, (e, o) => {
|
|
176
|
+
const t = o.meta.requestId, r = o.meta.arg.api;
|
|
197
177
|
d(e.settings, "listener", () => {
|
|
198
|
-
e.request.active = e.request.active.filter((
|
|
178
|
+
e.request.active = e.request.active.filter((c) => !(c.api === r && c.requestId === t));
|
|
199
179
|
}), d(e.settings, "history", () => {
|
|
200
|
-
e.request.done[
|
|
180
|
+
e.request.done[r] || (e.request.done[r] = []), e.request.done[r].push({ api: r, request: o.payload, requestId: t });
|
|
201
181
|
}), d(e.settings, "storage", () => {
|
|
202
|
-
const
|
|
203
|
-
e.storage =
|
|
182
|
+
const c = o.meta.arg.listStrategy ?? e.settings.listStrategy ?? {}, l = o.meta.arg.normalize ?? e.settings.normalize ?? O, u = C(e), y = l(u, o.payload.result, c);
|
|
183
|
+
e.storage = y;
|
|
204
184
|
});
|
|
205
|
-
}).addCase(
|
|
206
|
-
const t =
|
|
185
|
+
}).addCase(A.rejected, (e, o) => {
|
|
186
|
+
const t = o.meta.requestId, r = o.meta.arg.api;
|
|
207
187
|
d(e.settings, "listener", () => {
|
|
208
|
-
e.request.active = e.request.active.filter((
|
|
188
|
+
e.request.active = e.request.active.filter((c) => !(c.api === r && c.requestId === t));
|
|
209
189
|
}), d(e.settings, "history", () => {
|
|
210
|
-
e.request.errors[
|
|
190
|
+
e.request.errors[r] || (e.request.errors[r] = []), e.request.errors[r].push({ requestId: t, api: r, request: o.error });
|
|
211
191
|
});
|
|
212
192
|
});
|
|
213
193
|
}
|
|
214
194
|
});
|
|
215
195
|
export {
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
196
|
+
K as batchingUpdate,
|
|
197
|
+
E as factory,
|
|
198
|
+
A as request
|
|
219
199
|
};
|
|
220
200
|
//# 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\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 if (!response.ok) {\n return rejectWithValue(response);\n }\n const result = await response.json();\n if (options.onResult && typeof options.onResult === 'function') {\n options.onResult(result);\n }\n return { result, startedAt, endedAt: new Date().toUTCString() };\n } catch (error) {\n checkModule(settings, 'cancelation', abort.drop);\n if (error instanceof Error && error.name === 'AbortError') {\n return rejectWithValue({\n message: 'Request was cancelled',\n cancelled: true,\n });\n }\n return rejectWithValue({\n message: error instanceof Error ? error.message : 'Unknown error occurred',\n });\n }\n },\n);\n\n","import { type CdeebeeListStrategy, type CdeebeeState } from './types';\nimport { hasDataProperty, hasProperty, isRecord, mergeDeepRight, omit } from './helpers';\n\ntype ResponseValue = Record<string, unknown> & {\n data?: unknown[];\n [key: string]: unknown;\n};\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 primaryKey = cdeebee.settings.primaryKey;\n const currentStorage = isRecord(cdeebee.storage) ? (cdeebee.storage as Record<string, unknown>) : {};\n \n // Start with existing storage to preserve keys not in response\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 if (hasDataProperty(responseValue) && hasProperty(responseValue, primaryKey)) {\n const primaryKeyValue = responseValue[primaryKey];\n \n if (typeof primaryKeyValue !== 'string') {\n console.warn(`Cdeebee: Primary key \"${primaryKey}\" is not a string for API \"${key}\". Skipping normalization.`);\n result[key] = responseValue;\n continue;\n }\n\n // Pre-allocate storage data object\n const newStorageData: StorageData = {};\n const dataArray = responseValue.data;\n const dataLength = dataArray.length;\n\n for (let i = 0; i < dataLength; i++) {\n const element = dataArray[i];\n if (isRecord(element) && element[primaryKeyValue]) {\n const elementKey = element[primaryKeyValue] as string;\n newStorageData[elementKey] = element;\n }\n }\n\n const strategy = strategyList[key as keyof T] ?? 'merge';\n const existingValue = key in currentStorage ? (currentStorage[key] as StorageData) : {};\n\n if (strategy === 'replace') {\n // Replace: completely replace the value\n result[key] = newStorageData as ResponseValue;\n } else if (strategy === 'merge') {\n // Merge: merge with existing value\n result[key] = mergeDeepRight(existingValue, newStorageData) as ResponseValue;\n } else {\n // Unknown strategy: warn and fall back to merge\n console.warn(`Cdeebee: Unknown strategy \"${strategy}\" for key \"${key}\". Skipping normalization.`);\n result[key] = mergeDeepRight(existingValue, newStorageData) 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 primaryKey: 'primaryKey',\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 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 const normalizedData = normalize(currentState, action.payload.result, 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","hasDataProperty","hasProperty","prop","mergeDeepRight","left","right","rightRecord","key","leftValue","rightValue","omit","keys","obj","batchingUpdate","state","valueList","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","method","body","headers","extraHeaders","b","requestData","formData","fileKey","bodyKey","i","response","error","defaultNormalize","cdeebee","strategyList","keyList","primaryKey","currentStorage","keyListToOmit","responseValue","primaryKeyValue","newStorageData","dataArray","dataLength","element","elementKey","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/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\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 if (!response.ok) {\n return rejectWithValue(response);\n }\n const result = await response.json();\n if (options.onResult && typeof options.onResult === 'function') {\n options.onResult(result);\n }\n return { result, startedAt, endedAt: new Date().toUTCString() };\n } catch (error) {\n checkModule(settings, 'cancelation', abort.drop);\n if (error instanceof Error && error.name === 'AbortError') {\n return rejectWithValue({\n message: 'Request was cancelled',\n cancelled: true,\n });\n }\n return rejectWithValue({\n message: error instanceof Error ? error.message : 'Unknown error occurred',\n });\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 // Start with existing storage to preserve keys not in response\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) && Object.keys(responseValue).length > 0;\n\n if (isNormalized) {\n const strategy = strategyList[key as keyof T] ?? 'merge';\n const existingValue = key in currentStorage ? (currentStorage[key] as StorageData) : {};\n\n if (strategy === 'replace') {\n // Replace: completely replace the value\n result[key] = responseValue as ResponseValue;\n } else if (strategy === 'merge') {\n // Merge: merge with existing value\n result[key] = mergeDeepRight(existingValue, responseValue as StorageData) as ResponseValue;\n } else {\n // Unknown strategy: warn and fall back to merge\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 // Not a normalized object, store as-is\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 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 const normalizedData = normalize(currentState, action.payload.result, 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","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","method","body","headers","extraHeaders","b","requestData","formData","fileKey","bodyKey","i","response","error","defaultNormalize","cdeebee","strategyList","keyList","currentStorage","keyListToOmit","responseValue","strategy","existingValue","initialState","factory","storage","createSlice","action","builder","q","normalize","currentState","normalizedData"],"mappings":"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"}
|