@recats/cdeebee 3.0.0-beta.3 → 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 CHANGED
@@ -1,17 +1,15 @@
1
1
  # cdeebee
2
2
 
3
- [![npm](https://img.shields.io/npm/v/@recats/cdeebee.svg)](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',
@@ -127,6 +124,8 @@ function MyComponent() {
127
124
  method: 'POST',
128
125
  body: { filter: 'active' },
129
126
  onResult: (result) => {
127
+ // onResult is always called with the response data
128
+ // For JSON responses, result is already parsed
130
129
  console.log('Request completed:', result);
131
130
  },
132
131
  }));
@@ -168,7 +167,6 @@ interface CdeebeeSettings<T> {
168
167
  modules: CdeebeeModule[]; // Active modules: 'history' | 'listener' | 'storage' | 'cancelation'
169
168
  fileKey: string; // Key name for file uploads in FormData
170
169
  bodyKey: string; // Key name for request body in FormData
171
- primaryKey: string; // Primary key field name in API responses (default: 'primaryKey')
172
170
  listStrategy?: CdeebeeListStrategy<T>; // Merge strategy per list: 'merge' | 'replace'
173
171
  mergeWithData?: unknown; // Data to merge with every request body
174
172
  mergeWithHeaders?: Record<string, string>; // Headers to merge with every request
@@ -189,7 +187,9 @@ interface CdeebeeRequestOptions<T> {
189
187
  bodyKey?: string; // Override default bodyKey
190
188
  listStrategy?: CdeebeeListStrategy<T>; // Override list strategy for this request
191
189
  normalize?: (storage, result, strategyList) => T; // Override normalization
192
- onResult?: (response: T) => void; // Callback called with response data on success
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')
193
193
  }
194
194
  ```
195
195
 
@@ -209,27 +209,7 @@ listStrategy: {
209
209
 
210
210
  ## API Response Format
211
211
 
212
- cdeebee expects API responses in a specific format for automatic normalization:
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:
212
+ cdeebee expects API responses in a normalized format where data is already organized as objects with keys representing entity IDs:
233
213
 
234
214
  ```typescript
235
215
  {
@@ -260,6 +240,61 @@ dispatch(request({
260
240
  }));
261
241
  ```
262
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
+
263
298
  ### Custom Headers
264
299
 
265
300
  ```typescript
package/dist/index.cjs CHANGED
@@ -1,2 +1,2 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const K=require("@reduxjs/toolkit");function d(r,n,i){r.modules.includes(n)&&i()}function f(r){return r!==null&&typeof r=="object"&&!Array.isArray(r)}function C(r){return f(r)&&Array.isArray(r.data)}function z(r,n){return f(r)&&Object.prototype.hasOwnProperty.call(r,n)}function w(r,n){if(!f(r)||!f(n))return n;const i={...r},a=n;for(const e in a)if(Object.prototype.hasOwnProperty.call(a,e)){const c=i[e],t=a[e];f(c)&&f(t)&&!Array.isArray(c)&&!Array.isArray(t)?i[e]=w(c,t):i[e]=t}return i}function O(r,n){const i={...n};for(const a of r)delete i[a];return i}function D(r,n){for(let i=0;i<n.length;i++){const a=n[i],e=a.key,c=a.value;if(e.length===0)continue;let t=r;for(let o=0;o<e.length-1;o++){const s=e[o];if(Array.isArray(t)){const l=typeof s=="number"?s:Number(s);(!(l in t)||!f(t[l]))&&(t[l]={}),t=t[l]}else{const l=String(s);if(!(l in t)){const y=typeof e[o+1]=="number"||!isNaN(Number(e[o+1]))&&String(Number(e[o+1]))===String(e[o+1]);t[l]=y?[]:{}}const u=t[l];t=Array.isArray(u)||f(u)?u:{}}}Array.isArray(t)||(t[String(e[e.length-1])]=c)}}class I{constructor(){this.byRequestId=new Map,this.byApi=new Map}add(n,i,a){const e={requestId:i,controller:a,api:n};this.byRequestId.set(i,e),this.byApi.has(n)||this.byApi.set(n,new Set),this.byApi.get(n).add(i)}delete(n){const i=this.byRequestId.get(n);if(!i)return;this.byRequestId.delete(n);const a=this.byApi.get(i.api);a&&(a.delete(n),a.size===0&&this.byApi.delete(i.api))}abortAllForApi(n,i){const a=this.byApi.get(n);a&&a.forEach(e=>{if(e!==i){const c=this.byRequestId.get(e);c&&(c.controller.abort(),this.delete(e))}})}}const R=new I;function N(r,n){R.abortAllForApi(r,n)}function P(r,n,i){const a=new AbortController,e=()=>{R.delete(i)};return r.addEventListener("abort",()=>{a.abort(),e()}),{controller:a,init:()=>R.add(n,i,a),drop:e}}const q=K.createAsyncThunk("cdeebee/request",async(r,{rejectWithValue:n,getState:i,requestId:a,signal:e})=>{const c=new Date().toUTCString(),{cdeebee:{settings:t}}=i(),o=P(e,r.api,a);d(t,"cancelation",o.init);try{const{method:s="POST",body:l,headers:u={}}=r,y={...t.mergeWithHeaders??{},...u},A={...t.mergeWithData??{},...l??{}};let b=JSON.stringify(A);if(r.files){const p=new FormData,m=r.fileKey||t.fileKey,S=r.bodyKey||t.bodyKey;for(let k=0;k<r.files.length;k+=1)m&&p.append(m,r.files[k]);S&&p.append(S,b),b=p}const g=await fetch(r.api,{method:s,headers:{"ui-request-id":a,"Content-Type":"application/json",...y},signal:o.controller.signal,body:b});if(d(t,"cancelation",o.drop),!g.ok)return n(g);const h=await g.json();return r.onResult&&typeof r.onResult=="function"&&r.onResult(h),{result:h,startedAt:c,endedAt:new Date().toUTCString()}}catch(s){return d(t,"cancelation",o.drop),s instanceof Error&&s.name==="AbortError"?n({message:"Request was cancelled",cancelled:!0}):n({message:s instanceof Error?s.message:"Unknown error occurred"})}});function j(r,n,i){const a=Object.keys(n),e=r.settings.primaryKey,c=f(r.storage)?r.storage:{},t={...c},o=new Set;for(const s of a){const l=n[s];if(l==null||typeof l=="string"){o.add(s);continue}if(C(l)&&z(l,e)){const u=l[e];if(typeof u!="string"){console.warn(`Cdeebee: Primary key "${e}" is not a string for API "${s}". Skipping normalization.`),t[s]=l;continue}const y={},A=l.data,b=A.length;for(let p=0;p<b;p++){const m=A[p];if(f(m)&&m[u]){const S=m[u];y[S]=m}}const g=i[s]??"merge",h=s in c?c[s]:{};g==="replace"?t[s]=y:(g==="merge"||console.warn(`Cdeebee: Unknown strategy "${g}" for key "${s}". Skipping normalization.`),t[s]=w(h,y))}else t[s]=l}return o.size>0?O(Array.from(o),t):t}const v={settings:{modules:["history","listener","storage","cancelation"],fileKey:"file",bodyKey:"value",primaryKey:"primaryKey",listStrategy:{},mergeWithData:{},mergeWithHeaders:{}},storage:{},request:{active:[],errors:{},done:{}}},T=(r,n)=>K.createSlice({name:"cdeebee",initialState:w(v,{settings:r,storage:n??{}}),reducers:{set(a,e){D(a.storage,e.payload)}},extraReducers:a=>{a.addCase(q.pending,(e,c)=>{const t=c.meta.arg.api,o=c.meta.requestId;d(e.settings,"cancelation",()=>{N(t,o)}),d(e.settings,"listener",()=>{e.request.active.push({api:t,requestId:o})})}).addCase(q.fulfilled,(e,c)=>{const t=c.meta.requestId,o=c.meta.arg.api;d(e.settings,"listener",()=>{e.request.active=e.request.active.filter(s=>!(s.api===o&&s.requestId===t))}),d(e.settings,"history",()=>{e.request.done[o]||(e.request.done[o]=[]),e.request.done[o].push({api:o,request:c.payload,requestId:t})}),d(e.settings,"storage",()=>{const s=c.meta.arg.listStrategy??e.settings.listStrategy??{},l=c.meta.arg.normalize??e.settings.normalize??j,u=K.current(e),y=l(u,c.payload.result,s);e.storage=y})}).addCase(q.rejected,(e,c)=>{const t=c.meta.requestId,o=c.meta.arg.api;d(e.settings,"listener",()=>{e.request.active=e.request.active.filter(s=>!(s.api===o&&s.requestId===t))}),d(e.settings,"history",()=>{e.request.errors[o]||(e.request.errors[o]=[]),e.request.errors[o].push({requestId:t,api:o,request:c.error})})})}});exports.batchingUpdate=D;exports.factory=T;exports.request=q;
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
@@ -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":"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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 {
@@ -44,7 +46,6 @@ declare interface CdeebeeSettings<T> {
44
46
  modules: CdeebeeModule[];
45
47
  fileKey: string;
46
48
  bodyKey: string;
47
- primaryKey: string;
48
49
  mergeWithData: unknown;
49
50
  mergeWithHeaders: unknown;
50
51
  listStrategy?: CdeebeeListStrategy<T>;
@@ -83,7 +84,7 @@ declare type Paths<T, P extends readonly (string | number)[] = []> = IsArray<T>
83
84
  }[KeyOf<T>] : P;
84
85
 
85
86
  export declare const request: AsyncThunk< {
86
- result: any;
87
+ result: unknown;
87
88
  startedAt: string;
88
89
  endedAt: string;
89
90
  }, CdeebeeRequestOptions<unknown>, AsyncThunkConfig>;
package/dist/index.js CHANGED
@@ -1,171 +1,146 @@
1
- import { createAsyncThunk as R, createSlice as D, current as C } from "@reduxjs/toolkit";
2
- function d(r, n, i) {
3
- r.modules.includes(n) && i();
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 f(r) {
6
- return r !== null && typeof r == "object" && !Array.isArray(r);
5
+ function y(n) {
6
+ return n !== null && typeof n == "object" && !Array.isArray(n);
7
7
  }
8
- function z(r) {
9
- return f(r) && Array.isArray(r.data);
10
- }
11
- function I(r, n) {
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 m(n, s) {
9
+ if (!y(n) || !y(s))
10
+ return s;
11
+ const o = { ...n }, a = s;
18
12
  for (const e in a)
19
13
  if (Object.prototype.hasOwnProperty.call(a, e)) {
20
- const c = i[e], t = a[e];
21
- f(c) && f(t) && !Array.isArray(c) && !Array.isArray(t) ? i[e] = q(c, t) : i[e] = t;
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;
22
16
  }
23
- return i;
17
+ return o;
24
18
  }
25
- function N(r, n) {
26
- const i = { ...n };
27
- for (const a of r)
28
- delete i[a];
29
- return i;
19
+ function K(n, s) {
20
+ const o = { ...s };
21
+ for (const a of n)
22
+ delete o[a];
23
+ return o;
30
24
  }
31
- function O(r, n) {
32
- for (let i = 0; i < n.length; i++) {
33
- const a = n[i], e = a.key, c = a.value;
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;
34
28
  if (e.length === 0)
35
29
  continue;
36
- let t = r;
37
- for (let o = 0; o < e.length - 1; o++) {
38
- const s = e[o];
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 s == "number" ? s : Number(s);
41
- (!(l in t) || !f(t[l])) && (t[l] = {}), t = t[l];
34
+ const l = typeof c == "number" ? c : Number(c);
35
+ (!(l in t) || !y(t[l])) && (t[l] = {}), t = t[l];
42
36
  } else {
43
- const l = String(s);
37
+ const l = String(c);
44
38
  if (!(l in t)) {
45
- const u = typeof e[o + 1] == "number" || !isNaN(Number(e[o + 1])) && String(Number(e[o + 1])) === String(e[o + 1]);
46
- t[l] = u ? [] : {};
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 ? [] : {};
47
41
  }
48
- const y = t[l];
49
- t = Array.isArray(y) || f(y) ? y : {};
42
+ const u = t[l];
43
+ t = Array.isArray(u) || y(u) ? u : {};
50
44
  }
51
45
  }
52
- Array.isArray(t) || (t[String(e[e.length - 1])] = c);
46
+ Array.isArray(t) || (t[String(e[e.length - 1])] = i);
53
47
  }
54
48
  }
55
- class x {
49
+ class T {
56
50
  constructor() {
57
51
  this.byRequestId = /* @__PURE__ */ new Map(), this.byApi = /* @__PURE__ */ new Map();
58
52
  }
59
- add(n, i, a) {
60
- const e = { requestId: i, controller: a, api: n };
61
- this.byRequestId.set(i, e), this.byApi.has(n) || this.byApi.set(n, /* @__PURE__ */ new Set()), this.byApi.get(n).add(i);
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);
62
56
  }
63
- delete(n) {
64
- const i = this.byRequestId.get(n);
65
- if (!i) return;
66
- this.byRequestId.delete(n);
67
- const a = this.byApi.get(i.api);
68
- a && (a.delete(n), a.size === 0 && this.byApi.delete(i.api));
57
+ delete(s) {
58
+ const o = this.byRequestId.get(s);
59
+ if (!o) return;
60
+ this.byRequestId.delete(s);
61
+ const a = this.byApi.get(o.api);
62
+ a && (a.delete(s), a.size === 0 && this.byApi.delete(o.api));
69
63
  }
70
- abortAllForApi(n, i) {
71
- const a = this.byApi.get(n);
64
+ abortAllForApi(s, o) {
65
+ const a = this.byApi.get(s);
72
66
  a && a.forEach((e) => {
73
- if (e !== i) {
74
- const c = this.byRequestId.get(e);
75
- c && (c.controller.abort(), this.delete(e));
67
+ if (e !== o) {
68
+ const i = this.byRequestId.get(e);
69
+ i && (i.controller.abort(), this.delete(e));
76
70
  }
77
71
  });
78
72
  }
79
73
  }
80
- const K = new x();
81
- function P(r, n) {
82
- K.abortAllForApi(r, n);
74
+ const S = new T();
75
+ function j(n, s) {
76
+ S.abortAllForApi(n, s);
83
77
  }
84
- function j(r, n, i) {
78
+ function I(n, s, o) {
85
79
  const a = new AbortController(), e = () => {
86
- K.delete(i);
80
+ S.delete(o);
87
81
  };
88
- return r.addEventListener("abort", () => {
82
+ return n.addEventListener("abort", () => {
89
83
  a.abort(), e();
90
84
  }), {
91
85
  controller: a,
92
- init: () => K.add(n, i, a),
86
+ init: () => S.add(s, o, a),
93
87
  drop: e
94
88
  };
95
89
  }
96
- const k = R(
90
+ const q = N(
97
91
  "cdeebee/request",
98
- async (r, { rejectWithValue: n, getState: i, requestId: a, signal: e }) => {
99
- const c = (/* @__PURE__ */ new Date()).toUTCString(), { cdeebee: { settings: t } } = i(), o = j(e, r.api, a);
100
- d(t, "cancelation", o.init);
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
+ d(t, "cancelation", r.init);
101
95
  try {
102
- const { method: s = "POST", body: l, headers: y = {} } = r, u = { ...t.mergeWithHeaders ?? {}, ...y }, A = { ...t.mergeWithData ?? {}, ...l ?? {} };
103
- let h = JSON.stringify(A);
104
- if (r.files) {
105
- const p = new FormData(), m = r.fileKey || t.fileKey, S = r.bodyKey || t.bodyKey;
106
- for (let w = 0; w < r.files.length; w += 1)
107
- m && p.append(m, r.files[w]);
108
- S && p.append(S, h), h = p;
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
+ if (n.files) {
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;
109
103
  }
110
- const g = await fetch(r.api, {
111
- method: s,
104
+ const b = await fetch(n.api, {
105
+ method: l,
112
106
  headers: {
113
107
  "ui-request-id": a,
114
108
  "Content-Type": "application/json",
115
- ...u
109
+ ...z
116
110
  },
117
- signal: o.controller.signal,
118
- body: h
119
- });
120
- if (d(t, "cancelation", o.drop), !g.ok)
121
- return n(g);
122
- const b = await g.json();
123
- return r.onResult && typeof r.onResult == "function" && r.onResult(b), { result: b, startedAt: c, endedAt: (/* @__PURE__ */ new Date()).toUTCString() };
124
- } catch (s) {
125
- return d(t, "cancelation", o.drop), s instanceof Error && s.name === "AbortError" ? n({
126
- message: "Request was cancelled",
127
- cancelled: !0
128
- }) : n({
129
- message: s instanceof Error ? s.message : "Unknown error occurred"
111
+ signal: r.controller.signal,
112
+ body: p
130
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" });
131
120
  }
132
121
  }
133
122
  );
134
- function v(r, n, i) {
135
- const a = Object.keys(n), e = r.settings.primaryKey, c = f(r.storage) ? r.storage : {}, t = { ...c }, o = /* @__PURE__ */ new Set();
136
- for (const s of a) {
137
- const l = n[s];
138
- if (l == null || typeof l == "string") {
139
- o.add(s);
123
+ function O(n, s, o) {
124
+ const a = Object.keys(s), e = y(n.storage) ? n.storage : {}, i = { ...e }, t = /* @__PURE__ */ new Set();
125
+ for (const r of a) {
126
+ const c = s[r];
127
+ if (c == null || typeof c == "string") {
128
+ t.add(r);
140
129
  continue;
141
130
  }
142
- if (z(l) && I(l, e)) {
143
- const y = l[e];
144
- if (typeof y != "string") {
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));
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));
158
134
  } else
159
- t[s] = l;
135
+ i[r] = c;
160
136
  }
161
- return o.size > 0 ? N(Array.from(o), t) : t;
137
+ return t.size > 0 ? K(Array.from(t), i) : i;
162
138
  }
163
- const T = {
139
+ const E = {
164
140
  settings: {
165
141
  modules: ["history", "listener", "storage", "cancelation"],
166
142
  fileKey: "file",
167
143
  bodyKey: "value",
168
- primaryKey: "primaryKey",
169
144
  listStrategy: {},
170
145
  mergeWithData: {},
171
146
  mergeWithHeaders: {}
@@ -176,45 +151,47 @@ const T = {
176
151
  errors: {},
177
152
  done: {}
178
153
  }
179
- }, U = (r, n) => D({
154
+ }, M = (n, s) => x({
180
155
  name: "cdeebee",
181
- initialState: q(T, { settings: r, storage: n ?? {} }),
156
+ initialState: m(E, { settings: n, storage: s ?? {} }),
182
157
  reducers: {
183
158
  set(a, e) {
184
- O(a.storage, e.payload);
159
+ v(a.storage, e.payload);
185
160
  }
186
161
  },
187
162
  extraReducers: (a) => {
188
- a.addCase(k.pending, (e, c) => {
189
- const t = c.meta.arg.api, o = c.meta.requestId;
163
+ a.addCase(q.pending, (e, i) => {
164
+ const t = i.meta.arg.api, r = i.meta.requestId;
190
165
  d(e.settings, "cancelation", () => {
191
- P(t, o);
166
+ j(t, r);
192
167
  }), d(e.settings, "listener", () => {
193
- e.request.active.push({ api: t, requestId: o });
168
+ e.request.active.push({ api: t, requestId: r });
194
169
  });
195
- }).addCase(k.fulfilled, (e, c) => {
196
- const t = c.meta.requestId, o = c.meta.arg.api;
170
+ }).addCase(q.fulfilled, (e, i) => {
171
+ const t = i.meta.requestId, r = i.meta.arg.api;
197
172
  d(e.settings, "listener", () => {
198
- e.request.active = e.request.active.filter((s) => !(s.api === o && s.requestId === t));
173
+ e.request.active = e.request.active.filter((c) => !(c.api === r && c.requestId === t));
199
174
  }), d(e.settings, "history", () => {
200
- e.request.done[o] || (e.request.done[o] = []), e.request.done[o].push({ api: o, request: c.payload, requestId: t });
175
+ e.request.done[r] || (e.request.done[r] = []), e.request.done[r].push({ api: r, request: i.payload, requestId: t });
201
176
  }), d(e.settings, "storage", () => {
202
- const s = c.meta.arg.listStrategy ?? e.settings.listStrategy ?? {}, l = c.meta.arg.normalize ?? e.settings.normalize ?? v, y = C(e), u = l(y, c.payload.result, s);
203
- e.storage = u;
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;
204
181
  });
205
- }).addCase(k.rejected, (e, c) => {
206
- const t = c.meta.requestId, o = c.meta.arg.api;
182
+ }).addCase(q.rejected, (e, i) => {
183
+ const t = i.meta.requestId, r = i.meta.arg.api;
207
184
  d(e.settings, "listener", () => {
208
- e.request.active = e.request.active.filter((s) => !(s.api === o && s.requestId === t));
185
+ e.request.active = e.request.active.filter((c) => !(c.api === r && c.requestId === t));
209
186
  }), d(e.settings, "history", () => {
210
- e.request.errors[o] || (e.request.errors[o] = []), e.request.errors[o].push({ requestId: t, api: o, request: c.error });
187
+ e.request.errors[r] || (e.request.errors[r] = []), e.request.errors[r].push({ requestId: t, api: r, request: i.error });
211
188
  });
212
189
  });
213
190
  }
214
191
  });
215
192
  export {
216
- O as batchingUpdate,
217
- U as factory,
218
- k as request
193
+ v as batchingUpdate,
194
+ M as factory,
195
+ q as request
219
196
  };
220
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 { 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 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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@recats/cdeebee",
3
- "version": "3.0.0-beta.3",
3
+ "version": "3.0.0-beta.5",
4
4
  "description": "React Redux data-logic library",
5
5
  "repository": "git@github.com:recats/cdeebee.git",
6
6
  "author": "recats",