@recats/cdeebee 3.0.0-beta.4 → 3.0.0-beta.5
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 +60 -1
- package/dist/index.cjs +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.js +86 -89
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -124,6 +124,8 @@ function MyComponent() {
|
|
|
124
124
|
method: 'POST',
|
|
125
125
|
body: { filter: 'active' },
|
|
126
126
|
onResult: (result) => {
|
|
127
|
+
// onResult is always called with the response data
|
|
128
|
+
// For JSON responses, result is already parsed
|
|
127
129
|
console.log('Request completed:', result);
|
|
128
130
|
},
|
|
129
131
|
}));
|
|
@@ -185,7 +187,9 @@ interface CdeebeeRequestOptions<T> {
|
|
|
185
187
|
bodyKey?: string; // Override default bodyKey
|
|
186
188
|
listStrategy?: CdeebeeListStrategy<T>; // Override list strategy for this request
|
|
187
189
|
normalize?: (storage, result, strategyList) => T; // Override normalization
|
|
188
|
-
onResult?: (response: T) => void; // Callback called with response data on
|
|
190
|
+
onResult?: (response: T) => void; // Callback called with response data (always called, even on errors)
|
|
191
|
+
ignore?: boolean; // Skip storing result in storage
|
|
192
|
+
responseType?: 'json' | 'text' | 'blob'; // Response parsing type (default: 'json')
|
|
189
193
|
}
|
|
190
194
|
```
|
|
191
195
|
|
|
@@ -236,6 +240,61 @@ dispatch(request({
|
|
|
236
240
|
}));
|
|
237
241
|
```
|
|
238
242
|
|
|
243
|
+
### Handling Different Response Types
|
|
244
|
+
|
|
245
|
+
By default, cdeebee parses responses as JSON. For other response types (CSV, text files, images, etc.), use the `responseType` option:
|
|
246
|
+
|
|
247
|
+
```typescript
|
|
248
|
+
// CSV/text response
|
|
249
|
+
dispatch(request({
|
|
250
|
+
api: '/api/export',
|
|
251
|
+
responseType: 'text',
|
|
252
|
+
ignore: true, // Don't store in storage
|
|
253
|
+
onResult: (csvData) => {
|
|
254
|
+
// csvData is a string
|
|
255
|
+
downloadCSV(csvData);
|
|
256
|
+
},
|
|
257
|
+
}));
|
|
258
|
+
|
|
259
|
+
// Binary file (image, PDF, etc.)
|
|
260
|
+
dispatch(request({
|
|
261
|
+
api: '/api/image/123',
|
|
262
|
+
responseType: 'blob',
|
|
263
|
+
ignore: true,
|
|
264
|
+
onResult: (blob) => {
|
|
265
|
+
// blob is a Blob object
|
|
266
|
+
const url = URL.createObjectURL(blob);
|
|
267
|
+
setImageUrl(url);
|
|
268
|
+
},
|
|
269
|
+
}));
|
|
270
|
+
|
|
271
|
+
// JSON (default)
|
|
272
|
+
dispatch(request({
|
|
273
|
+
api: '/api/data',
|
|
274
|
+
// responseType: 'json' is default
|
|
275
|
+
onResult: (data) => {
|
|
276
|
+
console.log(data); // Already parsed JSON
|
|
277
|
+
},
|
|
278
|
+
}));
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
### Ignoring Storage Updates
|
|
282
|
+
|
|
283
|
+
Use the `ignore` option to prevent storing the response in storage while still receiving it in the `onResult` callback:
|
|
284
|
+
|
|
285
|
+
```typescript
|
|
286
|
+
// Export CSV without storing in storage
|
|
287
|
+
dispatch(request({
|
|
288
|
+
api: '/api/export',
|
|
289
|
+
responseType: 'text',
|
|
290
|
+
ignore: true,
|
|
291
|
+
onResult: (csvData) => {
|
|
292
|
+
// Handle CSV data directly
|
|
293
|
+
downloadFile(csvData, 'export.csv');
|
|
294
|
+
},
|
|
295
|
+
}));
|
|
296
|
+
```
|
|
297
|
+
|
|
239
298
|
### Custom Headers
|
|
240
299
|
|
|
241
300
|
```typescript
|
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 S=require("@reduxjs/toolkit");function d(n,s,o){n.modules.includes(s)&&o()}function f(n){return n!==null&&typeof n=="object"&&!Array.isArray(n)}function p(n,s){if(!f(n)||!f(s))return s;const o={...n},a=s;for(const e in a)if(Object.prototype.hasOwnProperty.call(a,e)){const i=o[e],t=a[e];f(i)&&f(t)&&!Array.isArray(i)&&!Array.isArray(t)?o[e]=p(i,t):o[e]=t}return o}function D(n,s){const o={...s};for(const a of n)delete o[a];return o}function C(n,s){for(let o=0;o<s.length;o++){const a=s[o],e=a.key,i=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])]=i)}}class K{constructor(){this.byRequestId=new Map,this.byApi=new Map}add(s,o,a){const e={requestId:o,controller:a,api:s};this.byRequestId.set(o,e),this.byApi.has(s)||this.byApi.set(s,new Set),this.byApi.get(s).add(o)}delete(s){const o=this.byRequestId.get(s);if(!o)return;this.byRequestId.delete(s);const a=this.byApi.get(o.api);a&&(a.delete(s),a.size===0&&this.byApi.delete(o.api))}abortAllForApi(s,o){const a=this.byApi.get(s);a&&a.forEach(e=>{if(e!==o){const i=this.byRequestId.get(e);i&&(i.controller.abort(),this.delete(e))}})}}const w=new K;function T(n,s){w.abortAllForApi(n,s)}function j(n,s,o){const a=new AbortController,e=()=>{w.delete(o)};return n.addEventListener("abort",()=>{a.abort(),e()}),{controller:a,init:()=>w.add(s,o,a),drop:e}}const m=S.createAsyncThunk("cdeebee/request",async(n,{rejectWithValue:s,getState:o,requestId:a,signal:e})=>{const i=new Date().toUTCString(),{cdeebee:{settings:t}}=o(),r=j(e,n.api,a),c=n.onResult&&typeof n.onResult=="function";d(t,"cancelation",r.init);try{const{method:l="POST",body:u,headers:y={}}=n,N={...t.mergeWithHeaders??{},...y},v={...t.mergeWithData??{},...u??{}};let h=JSON.stringify(v);if(n.files){const A=new FormData,R=n.fileKey||t.fileKey,z=n.bodyKey||t.bodyKey;for(let q=0;q<n.files.length;q+=1)R&&A.append(R,n.files[q]);z&&A.append(z,h),h=A}const b=await fetch(n.api,{method:l,headers:{"ui-request-id":a,"Content-Type":"application/json",...N},signal:r.controller.signal,body:h});d(t,"cancelation",r.drop);let g;const k=n.responseType||"json";return k==="text"?g=await b.text():k==="blob"?g=await b.blob():g=await b.json(),b.ok?(c&&n.onResult(g),{result:g,startedAt:i,endedAt:new Date().toUTCString()}):(c&&n.onResult(g),s(b))}catch(l){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"})}});function x(n,s,o){const a=Object.keys(s),e=f(n.storage)?n.storage:{},i={...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=o[r]??"merge",y=r in e?e[r]:{};u==="replace"?i[r]=c:(u==="merge"||console.warn(`Cdeebee: Unknown strategy "${u}" for key "${r}". Skipping normalization.`),i[r]=p(y,c))}else i[r]=c}return t.size>0?D(Array.from(t),i):i}const O={settings:{modules:["history","listener","storage","cancelation"],fileKey:"file",bodyKey:"value",listStrategy:{},mergeWithData:{},mergeWithHeaders:{}},storage:{},request:{active:[],errors:{},done:{}}},I=(n,s)=>S.createSlice({name:"cdeebee",initialState:p(O,{settings:n,storage:s??{}}),reducers:{set(a,e){C(a.storage,e.payload)}},extraReducers:a=>{a.addCase(m.pending,(e,i)=>{const t=i.meta.arg.api,r=i.meta.requestId;d(e.settings,"cancelation",()=>{T(t,r)}),d(e.settings,"listener",()=>{e.request.active.push({api:t,requestId:r})})}).addCase(m.fulfilled,(e,i)=>{const t=i.meta.requestId,r=i.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:i.payload,requestId:t})}),d(e.settings,"storage",()=>{if(i.meta.arg.ignore)return;const c=i.meta.arg.listStrategy??e.settings.listStrategy??{},l=i.meta.arg.normalize??e.settings.normalize??x,u=S.current(e),y=l(u,i.payload.result,c);e.storage=y})}).addCase(m.rejected,(e,i)=>{const t=i.meta.requestId,r=i.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:i.error})})})}});exports.batchingUpdate=C;exports.factory=I;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\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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"}
|
|
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 // 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 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","strategy","existingValue","initialState","factory","storage","createSlice","action","builder","q","normalize","currentState","normalizedData"],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -32,6 +32,8 @@ export declare interface CdeebeeRequestOptions<T> extends Partial<Pick<CdeebeeSe
|
|
|
32
32
|
body?: unknown;
|
|
33
33
|
headers?: Record<string, string>;
|
|
34
34
|
onResult?: (response: T) => void;
|
|
35
|
+
ignore?: boolean;
|
|
36
|
+
responseType?: 'json' | 'text' | 'blob';
|
|
35
37
|
}
|
|
36
38
|
|
|
37
39
|
declare interface CdeebeeRequestState {
|
|
@@ -82,7 +84,7 @@ declare type Paths<T, P extends readonly (string | number)[] = []> = IsArray<T>
|
|
|
82
84
|
}[KeyOf<T>] : P;
|
|
83
85
|
|
|
84
86
|
export declare const request: AsyncThunk< {
|
|
85
|
-
result:
|
|
87
|
+
result: unknown;
|
|
86
88
|
startedAt: string;
|
|
87
89
|
endedAt: string;
|
|
88
90
|
}, CdeebeeRequestOptions<unknown>, AsyncThunkConfig>;
|
package/dist/index.js
CHANGED
|
@@ -1,30 +1,30 @@
|
|
|
1
|
-
import { createAsyncThunk as
|
|
2
|
-
function d(n, s,
|
|
3
|
-
n.modules.includes(s) &&
|
|
1
|
+
import { createAsyncThunk as N, createSlice as x, current as D } from "@reduxjs/toolkit";
|
|
2
|
+
function d(n, s, o) {
|
|
3
|
+
n.modules.includes(s) && o();
|
|
4
4
|
}
|
|
5
|
-
function
|
|
5
|
+
function y(n) {
|
|
6
6
|
return n !== null && typeof n == "object" && !Array.isArray(n);
|
|
7
7
|
}
|
|
8
|
-
function
|
|
9
|
-
if (!
|
|
8
|
+
function m(n, s) {
|
|
9
|
+
if (!y(n) || !y(s))
|
|
10
10
|
return s;
|
|
11
|
-
const
|
|
11
|
+
const o = { ...n }, a = s;
|
|
12
12
|
for (const e in a)
|
|
13
13
|
if (Object.prototype.hasOwnProperty.call(a, e)) {
|
|
14
|
-
const
|
|
15
|
-
|
|
14
|
+
const i = o[e], t = a[e];
|
|
15
|
+
y(i) && y(t) && !Array.isArray(i) && !Array.isArray(t) ? o[e] = m(i, t) : o[e] = t;
|
|
16
16
|
}
|
|
17
|
-
return
|
|
17
|
+
return o;
|
|
18
18
|
}
|
|
19
|
-
function
|
|
20
|
-
const
|
|
19
|
+
function K(n, s) {
|
|
20
|
+
const o = { ...s };
|
|
21
21
|
for (const a of n)
|
|
22
|
-
delete
|
|
23
|
-
return
|
|
22
|
+
delete o[a];
|
|
23
|
+
return o;
|
|
24
24
|
}
|
|
25
|
-
function
|
|
26
|
-
for (let
|
|
27
|
-
const a = s[
|
|
25
|
+
function v(n, s) {
|
|
26
|
+
for (let o = 0; o < s.length; o++) {
|
|
27
|
+
const a = s[o], e = a.key, i = a.value;
|
|
28
28
|
if (e.length === 0)
|
|
29
29
|
continue;
|
|
30
30
|
let t = n;
|
|
@@ -32,116 +32,111 @@ function K(n, s) {
|
|
|
32
32
|
const c = e[r];
|
|
33
33
|
if (Array.isArray(t)) {
|
|
34
34
|
const l = typeof c == "number" ? c : Number(c);
|
|
35
|
-
(!(l in t) || !
|
|
35
|
+
(!(l in t) || !y(t[l])) && (t[l] = {}), t = t[l];
|
|
36
36
|
} else {
|
|
37
37
|
const l = String(c);
|
|
38
38
|
if (!(l in t)) {
|
|
39
|
-
const
|
|
40
|
-
t[l] =
|
|
39
|
+
const f = typeof e[r + 1] == "number" || !isNaN(Number(e[r + 1])) && String(Number(e[r + 1])) === String(e[r + 1]);
|
|
40
|
+
t[l] = f ? [] : {};
|
|
41
41
|
}
|
|
42
42
|
const u = t[l];
|
|
43
|
-
t = Array.isArray(u) ||
|
|
43
|
+
t = Array.isArray(u) || y(u) ? u : {};
|
|
44
44
|
}
|
|
45
45
|
}
|
|
46
|
-
Array.isArray(t) || (t[String(e[e.length - 1])] =
|
|
46
|
+
Array.isArray(t) || (t[String(e[e.length - 1])] = i);
|
|
47
47
|
}
|
|
48
48
|
}
|
|
49
|
-
class
|
|
49
|
+
class T {
|
|
50
50
|
constructor() {
|
|
51
51
|
this.byRequestId = /* @__PURE__ */ new Map(), this.byApi = /* @__PURE__ */ new Map();
|
|
52
52
|
}
|
|
53
|
-
add(s,
|
|
54
|
-
const e = { requestId:
|
|
55
|
-
this.byRequestId.set(
|
|
53
|
+
add(s, o, a) {
|
|
54
|
+
const e = { requestId: o, controller: a, api: s };
|
|
55
|
+
this.byRequestId.set(o, e), this.byApi.has(s) || this.byApi.set(s, /* @__PURE__ */ new Set()), this.byApi.get(s).add(o);
|
|
56
56
|
}
|
|
57
57
|
delete(s) {
|
|
58
|
-
const
|
|
59
|
-
if (!
|
|
58
|
+
const o = this.byRequestId.get(s);
|
|
59
|
+
if (!o) return;
|
|
60
60
|
this.byRequestId.delete(s);
|
|
61
|
-
const a = this.byApi.get(
|
|
62
|
-
a && (a.delete(s), a.size === 0 && this.byApi.delete(
|
|
61
|
+
const a = this.byApi.get(o.api);
|
|
62
|
+
a && (a.delete(s), a.size === 0 && this.byApi.delete(o.api));
|
|
63
63
|
}
|
|
64
|
-
abortAllForApi(s,
|
|
64
|
+
abortAllForApi(s, o) {
|
|
65
65
|
const a = this.byApi.get(s);
|
|
66
66
|
a && a.forEach((e) => {
|
|
67
|
-
if (e !==
|
|
68
|
-
const
|
|
69
|
-
|
|
67
|
+
if (e !== o) {
|
|
68
|
+
const i = this.byRequestId.get(e);
|
|
69
|
+
i && (i.controller.abort(), this.delete(e));
|
|
70
70
|
}
|
|
71
71
|
});
|
|
72
72
|
}
|
|
73
73
|
}
|
|
74
|
-
const
|
|
75
|
-
function
|
|
76
|
-
|
|
74
|
+
const S = new T();
|
|
75
|
+
function j(n, s) {
|
|
76
|
+
S.abortAllForApi(n, s);
|
|
77
77
|
}
|
|
78
|
-
function I(n, s,
|
|
78
|
+
function I(n, s, o) {
|
|
79
79
|
const a = new AbortController(), e = () => {
|
|
80
|
-
|
|
80
|
+
S.delete(o);
|
|
81
81
|
};
|
|
82
82
|
return n.addEventListener("abort", () => {
|
|
83
83
|
a.abort(), e();
|
|
84
84
|
}), {
|
|
85
85
|
controller: a,
|
|
86
|
-
init: () =>
|
|
86
|
+
init: () => S.add(s, o, a),
|
|
87
87
|
drop: e
|
|
88
88
|
};
|
|
89
89
|
}
|
|
90
|
-
const
|
|
90
|
+
const q = N(
|
|
91
91
|
"cdeebee/request",
|
|
92
|
-
async (n, { rejectWithValue: s, getState:
|
|
93
|
-
const
|
|
92
|
+
async (n, { rejectWithValue: s, getState: o, requestId: a, signal: e }) => {
|
|
93
|
+
const i = (/* @__PURE__ */ new Date()).toUTCString(), { cdeebee: { settings: t } } = o(), r = I(e, n.api, a), c = n.onResult && typeof n.onResult == "function";
|
|
94
94
|
d(t, "cancelation", r.init);
|
|
95
95
|
try {
|
|
96
|
-
const { method:
|
|
97
|
-
let
|
|
96
|
+
const { method: l = "POST", body: u, headers: f = {} } = n, z = { ...t.mergeWithHeaders ?? {}, ...f }, C = { ...t.mergeWithData ?? {}, ...u ?? {} };
|
|
97
|
+
let p = JSON.stringify(C);
|
|
98
98
|
if (n.files) {
|
|
99
|
-
const
|
|
100
|
-
for (let
|
|
101
|
-
k &&
|
|
102
|
-
|
|
99
|
+
const h = new FormData(), k = n.fileKey || t.fileKey, R = n.bodyKey || t.bodyKey;
|
|
100
|
+
for (let A = 0; A < n.files.length; A += 1)
|
|
101
|
+
k && h.append(k, n.files[A]);
|
|
102
|
+
R && h.append(R, p), p = h;
|
|
103
103
|
}
|
|
104
|
-
const
|
|
105
|
-
method:
|
|
104
|
+
const b = await fetch(n.api, {
|
|
105
|
+
method: l,
|
|
106
106
|
headers: {
|
|
107
107
|
"ui-request-id": a,
|
|
108
108
|
"Content-Type": "application/json",
|
|
109
|
-
...
|
|
109
|
+
...z
|
|
110
110
|
},
|
|
111
111
|
signal: r.controller.signal,
|
|
112
|
-
body:
|
|
113
|
-
});
|
|
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({
|
|
120
|
-
message: "Request was cancelled",
|
|
121
|
-
cancelled: !0
|
|
122
|
-
}) : s({
|
|
123
|
-
message: c instanceof Error ? c.message : "Unknown error occurred"
|
|
112
|
+
body: p
|
|
124
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" });
|
|
125
120
|
}
|
|
126
121
|
}
|
|
127
122
|
);
|
|
128
|
-
function O(n, s,
|
|
129
|
-
const a = Object.keys(s), e =
|
|
123
|
+
function O(n, s, o) {
|
|
124
|
+
const a = Object.keys(s), e = y(n.storage) ? n.storage : {}, i = { ...e }, t = /* @__PURE__ */ new Set();
|
|
130
125
|
for (const r of a) {
|
|
131
126
|
const c = s[r];
|
|
132
127
|
if (c == null || typeof c == "string") {
|
|
133
128
|
t.add(r);
|
|
134
129
|
continue;
|
|
135
130
|
}
|
|
136
|
-
if (
|
|
137
|
-
const u =
|
|
138
|
-
u === "replace" ?
|
|
131
|
+
if (y(c) && Object.keys(c).length > 0) {
|
|
132
|
+
const u = o[r] ?? "merge", f = r in e ? e[r] : {};
|
|
133
|
+
u === "replace" ? i[r] = c : (u === "merge" || console.warn(`Cdeebee: Unknown strategy "${u}" for key "${r}". Skipping normalization.`), i[r] = m(f, c));
|
|
139
134
|
} else
|
|
140
|
-
|
|
135
|
+
i[r] = c;
|
|
141
136
|
}
|
|
142
|
-
return t.size > 0 ?
|
|
137
|
+
return t.size > 0 ? K(Array.from(t), i) : i;
|
|
143
138
|
}
|
|
144
|
-
const
|
|
139
|
+
const E = {
|
|
145
140
|
settings: {
|
|
146
141
|
modules: ["history", "listener", "storage", "cancelation"],
|
|
147
142
|
fileKey: "file",
|
|
@@ -156,45 +151,47 @@ const j = {
|
|
|
156
151
|
errors: {},
|
|
157
152
|
done: {}
|
|
158
153
|
}
|
|
159
|
-
},
|
|
154
|
+
}, M = (n, s) => x({
|
|
160
155
|
name: "cdeebee",
|
|
161
|
-
initialState:
|
|
156
|
+
initialState: m(E, { settings: n, storage: s ?? {} }),
|
|
162
157
|
reducers: {
|
|
163
158
|
set(a, e) {
|
|
164
|
-
|
|
159
|
+
v(a.storage, e.payload);
|
|
165
160
|
}
|
|
166
161
|
},
|
|
167
162
|
extraReducers: (a) => {
|
|
168
|
-
a.addCase(
|
|
169
|
-
const t =
|
|
163
|
+
a.addCase(q.pending, (e, i) => {
|
|
164
|
+
const t = i.meta.arg.api, r = i.meta.requestId;
|
|
170
165
|
d(e.settings, "cancelation", () => {
|
|
171
|
-
|
|
166
|
+
j(t, r);
|
|
172
167
|
}), d(e.settings, "listener", () => {
|
|
173
168
|
e.request.active.push({ api: t, requestId: r });
|
|
174
169
|
});
|
|
175
|
-
}).addCase(
|
|
176
|
-
const t =
|
|
170
|
+
}).addCase(q.fulfilled, (e, i) => {
|
|
171
|
+
const t = i.meta.requestId, r = i.meta.arg.api;
|
|
177
172
|
d(e.settings, "listener", () => {
|
|
178
173
|
e.request.active = e.request.active.filter((c) => !(c.api === r && c.requestId === t));
|
|
179
174
|
}), d(e.settings, "history", () => {
|
|
180
|
-
e.request.done[r] || (e.request.done[r] = []), e.request.done[r].push({ api: r, request:
|
|
175
|
+
e.request.done[r] || (e.request.done[r] = []), e.request.done[r].push({ api: r, request: i.payload, requestId: t });
|
|
181
176
|
}), d(e.settings, "storage", () => {
|
|
182
|
-
|
|
183
|
-
|
|
177
|
+
if (i.meta.arg.ignore)
|
|
178
|
+
return;
|
|
179
|
+
const c = i.meta.arg.listStrategy ?? e.settings.listStrategy ?? {}, l = i.meta.arg.normalize ?? e.settings.normalize ?? O, u = D(e), f = l(u, i.payload.result, c);
|
|
180
|
+
e.storage = f;
|
|
184
181
|
});
|
|
185
|
-
}).addCase(
|
|
186
|
-
const t =
|
|
182
|
+
}).addCase(q.rejected, (e, i) => {
|
|
183
|
+
const t = i.meta.requestId, r = i.meta.arg.api;
|
|
187
184
|
d(e.settings, "listener", () => {
|
|
188
185
|
e.request.active = e.request.active.filter((c) => !(c.api === r && c.requestId === t));
|
|
189
186
|
}), d(e.settings, "history", () => {
|
|
190
|
-
e.request.errors[r] || (e.request.errors[r] = []), e.request.errors[r].push({ requestId: t, api: r, request:
|
|
187
|
+
e.request.errors[r] || (e.request.errors[r] = []), e.request.errors[r].push({ requestId: t, api: r, request: i.error });
|
|
191
188
|
});
|
|
192
189
|
});
|
|
193
190
|
}
|
|
194
191
|
});
|
|
195
192
|
export {
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
193
|
+
v as batchingUpdate,
|
|
194
|
+
M as factory,
|
|
195
|
+
q as request
|
|
199
196
|
};
|
|
200
197
|
//# 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 { 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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"}
|
|
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 // 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 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","strategy","existingValue","initialState","factory","storage","createSlice","action","builder","q","normalize","currentState","normalizedData"],"mappings":"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"}
|