@recats/cdeebee 3.0.0-beta.9 → 3.0.0
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 +293 -25
- package/dist/index.cjs +2 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +194 -8
- package/dist/index.js +347 -237
- package/dist/index.js.map +1 -1
- package/package.json +17 -10
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":["../lib/reducer/helpers.ts","../lib/reducer/abortController.ts","../lib/reducer/queryQueue.ts","../lib/reducer/request.ts","../lib/reducer/storage.ts","../lib/reducer/index.ts"],"sourcesContent":["import { type CdeebeeSettings, type CdeebeeModule, CdeebeeValueList } from './types';\n\nexport function checkModule(settings: CdeebeeSettings<unknown>, module: CdeebeeModule, result: () => void) {\n if (settings.modules.includes(module)) {\n result();\n }\n}\nexport function isRecord(value: unknown): value is Record<string, unknown> {\n return value !== null && typeof value === 'object' && !Array.isArray(value);\n}\n\nexport function hasDataProperty(value: unknown): value is Record<string, unknown> & { data: unknown[] } {\n return isRecord(value) && Array.isArray(value.data);\n}\n\nexport function hasProperty(value: unknown, prop: string): boolean {\n return isRecord(value) && Object.prototype.hasOwnProperty.call(value, prop);\n}\n\nexport function mergeDeepRight<T>(\n left: T,\n right: Partial<T> | Record<string, unknown>\n): T {\n if (!isRecord(left) || !isRecord(right)) {\n return right as T;\n }\n\n const result = { ...left } as Record<string, unknown>;\n const rightRecord = right as Record<string, unknown>;\n\n for (const key in rightRecord) {\n if (Object.prototype.hasOwnProperty.call(rightRecord, key)) {\n const leftValue = result[key];\n const rightValue = rightRecord[key];\n\n if (\n isRecord(leftValue) &&\n isRecord(rightValue) &&\n !Array.isArray(leftValue) &&\n !Array.isArray(rightValue)\n ) {\n result[key] = mergeDeepRight(leftValue, rightValue);\n } else {\n result[key] = rightValue;\n }\n }\n }\n\n return result as T;\n}\n\nexport function omit<T extends Record<string, unknown>>(keys: string[], obj: T): Omit<T, keyof T> {\n const result = { ...obj };\n for (const key of keys) {\n delete result[key];\n }\n return result as Omit<T, keyof T>;\n}\n\nexport function assocPath<T>(path: (string | number)[], value: unknown, obj: T): T {\n if (path.length === 0) {\n return value as T;\n }\n\n const [first, ...rest] = path;\n const firstKey = String(first);\n const result = Array.isArray(obj) ? [...obj] : { ...obj } as Record<string, unknown>;\n\n if (rest.length === 0) {\n (result as Record<string, unknown>)[firstKey] = value;\n } else {\n const currentValue = (result as Record<string, unknown>)[firstKey];\n (result as Record<string, unknown>)[firstKey] = assocPath(rest, value, currentValue ?? {});\n }\n\n return result as T;\n}\n\nexport function batchingUpdate<T extends Record<string, unknown>>(\n state: T,\n valueList: CdeebeeValueList<T>\n): void {\n for (let i = 0; i < valueList.length; i++) {\n const item = valueList[i] as { key: readonly (string | number)[]; value: unknown };\n const path = item.key;\n const value = item.value;\n \n if (path.length === 0) {\n continue;\n }\n\n let current: Record<string, unknown> | unknown[] = state as Record<string, unknown>;\n \n for (let j = 0; j < path.length - 1; j++) {\n const pathKey = path[j];\n \n if (Array.isArray(current)) {\n const index = typeof pathKey === 'number' ? pathKey : Number(pathKey);\n if (!(index in current) || !isRecord(current[index])) {\n current[index] = {};\n }\n current = current[index] as Record<string, unknown>;\n } else {\n const key = String(pathKey);\n if (!(key in current)) {\n const nextIsNumeric = typeof path[j + 1] === 'number' || (!isNaN(Number(path[j + 1])) && String(Number(path[j + 1])) === String(path[j + 1]));\n current[key] = nextIsNumeric ? [] : {};\n }\n const next = current[key];\n current = (Array.isArray(next) ? next : (isRecord(next) ? next : {})) as Record<string, unknown> | unknown[];\n }\n }\n \n if (Array.isArray(current)) {\n continue; // Can't update array element directly\n }\n current[String(path[path.length - 1])] = value;\n }\n}\n","interface RequestController {\n requestId: string;\n controller: AbortController;\n api: string;\n}\n\nclass AbortControllerStore {\n private byRequestId = new Map<string, RequestController>();\n private byApi = new Map<string, Set<string>>();\n\n add(api: string, requestId: string, controller: AbortController): void {\n const item: RequestController = { requestId, controller, api };\n this.byRequestId.set(requestId, item);\n\n if (!this.byApi.has(api)) {\n this.byApi.set(api, new Set());\n }\n this.byApi.get(api)!.add(requestId);\n }\n\n delete(requestId: string): void {\n const item = this.byRequestId.get(requestId);\n if (!item) return;\n\n this.byRequestId.delete(requestId);\n const apiSet = this.byApi.get(item.api);\n if (apiSet) {\n apiSet.delete(requestId);\n if (apiSet.size === 0) {\n this.byApi.delete(item.api);\n }\n }\n }\n\n abortAllForApi(api: string, excludeRequestId: string): void {\n const requestIds = this.byApi.get(api);\n if (!requestIds) return;\n\n requestIds.forEach(requestId => {\n if (requestId !== excludeRequestId) {\n const item = this.byRequestId.get(requestId);\n if (item) {\n item.controller.abort();\n this.delete(requestId);\n }\n }\n });\n }\n}\n\nconst abortStore = new AbortControllerStore();\n\nexport function abortQuery(api: string, currentRequestId: string): void {\n abortStore.abortAllForApi(api, currentRequestId);\n}\n\nexport function abortManager(signal: AbortSignal, api: string, requestId: string) {\n const controller = new AbortController();\n\n const cleanup = () => {\n abortStore.delete(requestId);\n };\n\n signal.addEventListener('abort', () => {\n controller.abort();\n cleanup();\n });\n\n return {\n controller,\n init: () => abortStore.add(api, requestId, controller),\n drop: cleanup,\n };\n}\n","class QueryQueue {\n private currentPromise: Promise<unknown> = Promise.resolve();\n private queueLength = 0;\n\n async enqueue<T>(task: () => Promise<T>): Promise<T> {\n this.queueLength++;\n \n const previousPromise = this.currentPromise;\n \n this.currentPromise = previousPromise\n .then(() => task(), () => task())\n .finally(() => {\n this.queueLength--;\n });\n\n return this.currentPromise as Promise<T>;\n }\n\n getQueueLength(): number {\n return this.queueLength;\n }\n\n clear(): void {\n this.queueLength = 0;\n }\n}\n\nexport const queryQueue = new QueryQueue();\n\n","import { createAsyncThunk } from '@reduxjs/toolkit';\nimport { checkModule } from './helpers';\nimport { abortManager } from './abortController';\nimport { queryQueue } from './queryQueue';\nimport { type CdeebeeState, type CdeebeeRequestOptions } from './types';\n\nexport const request = createAsyncThunk(\n 'cdeebee/request',\n async (options: CdeebeeRequestOptions<unknown>, { rejectWithValue, getState, requestId, signal }) => {\n const startedAt = new Date().toUTCString();\n const { cdeebee: { settings } } = getState() as { cdeebee: CdeebeeState<unknown> };\n\n const abort = abortManager(signal, options.api, requestId);\n const withCallback = options.onResult && typeof options.onResult === 'function';\n\n checkModule(settings, 'cancelation', abort.init);\n\n const executeRequest = async () => {\n try {\n const { method = 'POST', body, headers = {} } = options;\n const extraHeaders: Record<string, string> = { ...(settings.mergeWithHeaders ?? {}), ...headers };\n\n const b = { ...(settings.mergeWithData ?? {}), ...(body ?? {}) };\n let requestData: FormData | string = JSON.stringify(b);\n\n // handling files\n if (options.files) {\n const formData = new FormData();\n const fileKey = options.fileKey || settings.fileKey;\n const bodyKey = options.bodyKey || settings.bodyKey;\n\n for (let i = 0; i < options.files.length; i += 1) {\n if (fileKey) {\n formData.append(fileKey, options.files[i]);\n }\n }\n\n if (bodyKey) {\n formData.append(bodyKey, requestData);\n }\n requestData = formData;\n }\n // [end] handling files\n \n const response = await fetch(options.api, {\n method,\n headers: {\n 'ui-request-id': requestId,\n 'Content-Type': 'application/json',\n ...extraHeaders,\n },\n signal: abort.controller.signal,\n body: requestData,\n });\n\n checkModule(settings, 'cancelation', abort.drop);\n\n let result: unknown;\n const responseType = options.responseType || 'json';\n \n if (responseType === 'text') {\n result = await response.text();\n } else if (responseType === 'blob') {\n result = await response.blob();\n } else {\n // default: json\n result = await response.json();\n }\n\n if (!response.ok) {\n if (withCallback) options.onResult!(result);\n return rejectWithValue(response);\n }\n\n if (withCallback) options.onResult!(result);\n return { result, startedAt, endedAt: new Date().toUTCString() };\n } catch (error) {\n checkModule(settings, 'cancelation', abort.drop);\n\n if (withCallback) options.onResult!(error); \n\n if (error instanceof Error && error.name === 'AbortError') {\n return rejectWithValue({ message: 'Request was cancelled', cancelled: true });\n }\n\n return rejectWithValue({ message: error instanceof Error ? error.message : 'Unknown error occurred' });\n }\n };\n\n if (settings.modules.includes('queryQueue')) {\n return queryQueue.enqueue(executeRequest);\n }\n\n return executeRequest();\n },\n);\n\n","import { type CdeebeeListStrategy, type CdeebeeState } from './types';\nimport { isRecord, mergeDeepRight, omit } from './helpers';\n\ntype ResponseValue = Record<string, unknown>;\n\ntype IResponse = Record<string, ResponseValue>;\n\ntype StorageData = Record<string, unknown>;\n\nfunction isDataWithPrimaryKey(value: unknown): value is { data: unknown[]; primaryKey: string } {\n return (\n isRecord(value) &&\n Array.isArray(value.data) &&\n typeof value.primaryKey === 'string'\n );\n}\nfunction normalizeDataWithPrimaryKey(data: unknown[], primaryKey: string): Record<string, unknown> {\n const result: Record<string, unknown> = {};\n \n for (const item of data) {\n if (isRecord(item) && primaryKey in item) {\n const key = String(item[primaryKey]);\n result[key] = item;\n }\n }\n \n return result;\n}\n\nfunction applyStrategy(\n existingValue: StorageData,\n newValue: StorageData | ResponseValue,\n strategy: string,\n key: string\n): ResponseValue {\n if (strategy === 'replace') {\n return newValue as ResponseValue;\n } else if (strategy === 'merge') {\n return mergeDeepRight(existingValue, newValue as StorageData) as ResponseValue;\n } else if (strategy === 'skip') {\n return existingValue as ResponseValue;\n } else {\n console.warn(`Cdeebee: Unknown strategy \"${strategy}\" for key \"${key}\". Skipping normalization.`);\n return mergeDeepRight(existingValue, newValue as StorageData) as ResponseValue;\n }\n}\n\nexport function defaultNormalize<T>(\n cdeebee: CdeebeeState<T>,\n response: IResponse,\n strategyList: CdeebeeListStrategy<T> \n): Record<string, ResponseValue> {\n const keyList = Object.keys(response);\n const currentStorage = isRecord(cdeebee.storage) ? (cdeebee.storage as Record<string, unknown>) : {};\n \n const result = { ...currentStorage } as Record<string, ResponseValue>;\n const keyListToOmit = new Set<string>();\n\n for (const key of keyList) {\n const responseValue = response[key];\n\n if (responseValue === null || responseValue === undefined || typeof responseValue === 'string') {\n keyListToOmit.add(key);\n continue;\n }\n\n const strategy = strategyList[key as keyof T] ?? 'merge';\n \n // For 'skip' strategy, if key doesn't exist in storage, skip it entirely\n if (strategy === 'skip' && !(key in currentStorage)) {\n continue;\n }\n \n const existingValue = key in currentStorage ? (currentStorage[key] as StorageData) : {};\n\n if (isDataWithPrimaryKey(responseValue)) {\n const normalizedValue = normalizeDataWithPrimaryKey(responseValue.data, responseValue.primaryKey);\n result[key] = applyStrategy(existingValue, normalizedValue, strategy, key);\n continue;\n }\n\n if (isRecord(responseValue)) {\n result[key] = applyStrategy(existingValue, responseValue as StorageData, strategy, key);\n } else {\n result[key] = responseValue;\n }\n }\n\n return keyListToOmit.size > 0 ? omit(Array.from(keyListToOmit), result) : result;\n}\n","import { createSlice, current } 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/skip and preserves keys not in response\n // Simply apply the result\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n (state.storage as any) = normalizedData;\n });\n })\n .addCase(request.rejected, (state, action) => {\n const requestId = action.meta.requestId;\n const api = action.meta.arg.api;\n\n checkModule(state.settings, 'listener', () => {\n state.request.active = state.request.active.filter(q => !(q.api === api && q.requestId === requestId));\n });\n checkModule(state.settings, 'history', () => {\n if (!state.request.errors[api]) state.request.errors[api] = [];\n state.request.errors[api].push({ requestId: requestId, api, request: action.error });\n });\n });\n },\n });\n\n return slice;\n};\n"],"names":["checkModule","settings","module","result","isRecord","value","mergeDeepRight","left","right","rightRecord","key","leftValue","rightValue","omit","keys","obj","batchingUpdate","state","valueList","i","item","path","current","j","pathKey","index","nextIsNumeric","next","AbortControllerStore","api","requestId","controller","apiSet","excludeRequestId","requestIds","abortStore","abortQuery","currentRequestId","abortManager","signal","cleanup","QueryQueue","task","previousPromise","queryQueue","request","createAsyncThunk","options","rejectWithValue","getState","startedAt","abort","withCallback","executeRequest","method","body","headers","extraHeaders","b","requestData","formData","fileKey","bodyKey","response","responseType","error","isDataWithPrimaryKey","normalizeDataWithPrimaryKey","data","primaryKey","applyStrategy","existingValue","newValue","strategy","defaultNormalize","cdeebee","strategyList","keyList","currentStorage","keyListToOmit","responseValue","normalizedValue","initialState","factory","storage","createSlice","action","builder","q","normalize","currentState","normalizedData"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../lib/reducer/helpers.ts","../lib/reducer/abortController.ts","../lib/reducer/queryQueue.ts","../lib/reducer/request.ts","../lib/reducer/storage.ts","../lib/reducer/index.ts","../lib/hooks/createCdeebeeHooks.ts","../lib/hooks/selectors.ts"],"sourcesContent":["import { type WritableDraft } from '@reduxjs/toolkit';\nimport { type CdeebeeSettings, type CdeebeeModule, CdeebeeValueList } from './types';\n\nexport function checkModule<T = unknown>(settings: CdeebeeSettings<T> | WritableDraft<CdeebeeSettings<T>>, module: CdeebeeModule, result: () => void) {\n if (settings.modules.includes(module)) {\n result();\n }\n}\n\nexport function isRecord(value: unknown): value is Record<string, unknown> {\n return value !== null && typeof value === 'object' && !Array.isArray(value);\n}\n\nexport function mergeDeepRight<T>(\n left: T,\n right: Partial<T> | Record<string, unknown>\n): T {\n if (!isRecord(left) || !isRecord(right)) {\n return right as T;\n }\n\n const result = { ...left } as Record<string, unknown>;\n const rightRecord = right as Record<string, unknown>;\n\n for (const key in rightRecord) {\n if (Object.prototype.hasOwnProperty.call(rightRecord, key)) {\n const leftValue = result[key];\n const rightValue = rightRecord[key];\n\n if (\n isRecord(leftValue) &&\n isRecord(rightValue) &&\n !Array.isArray(leftValue) &&\n !Array.isArray(rightValue)\n ) {\n result[key] = mergeDeepRight(leftValue, rightValue);\n } else {\n result[key] = rightValue;\n }\n }\n }\n\n return result as T;\n}\n\nexport function omit<T extends Record<string, unknown>>(keys: string[], obj: T): Omit<T, keyof T> {\n const result = { ...obj };\n for (const key of keys) {\n delete result[key];\n }\n return result as Omit<T, keyof T>;\n}\n\n/**\n * Extract primary key values from API response data per list.\n * Handles responses with format: { listName: { data: [...], primaryKey: 'id' } }\n * Returns a map of listName -> array of IDs.\n */\nexport function extractLastResultIdList(response: unknown): Record<string, string[]> {\n if (!isRecord(response)) {\n return {};\n }\n\n const result: Record<string, string[]> = {};\n\n for (const listName of Object.keys(response)) {\n const value = response[listName];\n\n if (\n isRecord(value) &&\n Array.isArray(value.data) &&\n typeof value.primaryKey === 'string'\n ) {\n const primaryKey = value.primaryKey;\n const idList: string[] = [];\n\n for (const item of value.data) {\n if (isRecord(item) && primaryKey in item) {\n idList.push(String(item[primaryKey]));\n }\n }\n\n result[listName] = idList;\n }\n }\n\n return result;\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 const lastKey = path[path.length - 1];\n if (Array.isArray(current)) {\n const index = typeof lastKey === 'number' ? lastKey : Number(lastKey);\n current[index] = value;\n } else {\n current[String(lastKey)] = value;\n }\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 requestIDList = this.byApi.get(api);\n if (!requestIDList) return;\n\n const toAbort = Array.from(requestIDList).filter(id => id !== excludeRequestId);\n\n for (const requestId of toAbort) {\n const item = this.byRequestId.get(requestId);\n if (item) {\n item.controller.abort();\n this.delete(requestId);\n }\n }\n }\n}\n\nconst abortStore = new AbortControllerStore();\n\nexport function abortQuery(api: string, currentRequestId: string): void {\n abortStore.abortAllForApi(api, currentRequestId);\n}\n\nexport function abortManager(signal: AbortSignal, api: string, requestId: string) {\n const controller = new AbortController();\n\n const cleanup = () => {\n abortStore.delete(requestId);\n };\n\n signal.addEventListener('abort', () => {\n controller.abort();\n cleanup();\n });\n\n return {\n controller,\n init: () => abortStore.add(api, requestId, controller),\n drop: cleanup,\n };\n}\n","class QueryQueue {\n private currentPromise: Promise<unknown> = Promise.resolve();\n private queueLength = 0;\n\n async enqueue<T>(task: () => Promise<T>): Promise<T> {\n this.queueLength++;\n\n const previousPromise = this.currentPromise;\n\n this.currentPromise = previousPromise\n .then(() => task(), () => task())\n .finally(() => {\n this.queueLength--;\n });\n\n return this.currentPromise as Promise<T>;\n }\n\n getQueueLength(): number {\n return this.queueLength;\n }\n\n clear(): void {\n this.queueLength = 0;\n this.currentPromise = Promise.resolve();\n }\n}\n\nexport const queryQueue = new QueryQueue();\n\n","import { createAsyncThunk } from '@reduxjs/toolkit';\nimport { checkModule } from './helpers';\nimport { abortManager } from './abortController';\nimport { queryQueue } from './queryQueue';\nimport { type CdeebeeState, type CdeebeeRequestOptions } from './types';\n\nexport const request = createAsyncThunk(\n 'cdeebee/request',\n async (options: CdeebeeRequestOptions<unknown>, { rejectWithValue, getState, requestId, signal }) => {\n const startedAt = new Date().toUTCString();\n const { cdeebee: { settings } } = getState() as { cdeebee: CdeebeeState<unknown> };\n\n const abort = abortManager(signal, options.api, requestId);\n const withCallback = options.onResult && typeof options.onResult === 'function';\n\n checkModule(settings, 'cancelation', abort.init);\n\n const executeRequest = async () => {\n try {\n const { method = 'POST', body, headers = {} } = options;\n const baseHeaders = typeof settings.mergeWithHeaders === 'function'\n ? settings.mergeWithHeaders()\n : (settings.mergeWithHeaders ?? {});\n\n const extraHeaders: Record<string, string> = { ...baseHeaders, ...headers };\n\n const baseData = typeof settings.mergeWithData === 'function'\n ? settings.mergeWithData()\n : (settings.mergeWithData ?? {});\n\n const b = { ...baseData, ...(body ?? {}) };\n let requestData: FormData | string = JSON.stringify(b);\n const isFormData = !!options.files;\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 fetchHeaders: Record<string, string> = {\n 'ui-request-id': requestId,\n ...(isFormData ? {} : { 'Content-Type': 'application/json' }),\n ...extraHeaders,\n };\n\n const isGet = method === 'GET';\n\n const response = await fetch(options.api, {\n method,\n headers: fetchHeaders,\n signal: abort.controller.signal,\n ...(isGet ? {} : { 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({ status: response.status, statusText: response.statusText, data: result });\n }\n\n if (withCallback) options.onResult!(result);\n return { result, startedAt, endedAt: new Date().toUTCString() };\n } catch (error) {\n checkModule(settings, 'cancelation', abort.drop);\n\n if (withCallback) options.onResult!(error);\n\n if (error instanceof Error && error.name === 'AbortError') {\n return rejectWithValue({ message: 'Request was cancelled', cancelled: true });\n }\n\n return rejectWithValue({ message: error instanceof Error ? error.message : 'Unknown error occurred' });\n }\n };\n\n if (settings.modules.includes('queryQueue')) {\n return queryQueue.enqueue(executeRequest);\n }\n\n return executeRequest();\n },\n);\n\n","import { type CdeebeeListStrategy, type CdeebeeState } from './types';\nimport { isRecord, mergeDeepRight, omit } from './helpers';\n\ntype ResponseValue = Record<string, unknown>;\n\ntype IResponse = Record<string, ResponseValue>;\n\ntype StorageData = Record<string, unknown>;\n\nfunction isDataWithPrimaryKey(value: unknown): value is { data: unknown[]; primaryKey: string } {\n return (\n isRecord(value) &&\n Array.isArray(value.data) &&\n typeof value.primaryKey === 'string'\n );\n}\nfunction normalizeDataWithPrimaryKey(data: unknown[], primaryKey: string): Record<string, unknown> {\n const result: Record<string, unknown> = {};\n\n for (const item of data) {\n if (isRecord(item) && primaryKey in item) {\n const key = String(item[primaryKey]);\n result[key] = item;\n }\n }\n\n return result;\n}\n\nfunction applyStrategy(\n existingValue: StorageData,\n newValue: StorageData | ResponseValue,\n strategy: string,\n key: string\n): ResponseValue {\n if (strategy === 'replace') {\n return newValue as ResponseValue;\n } else if (strategy === 'merge') {\n return mergeDeepRight(existingValue, newValue as StorageData) as ResponseValue;\n } else if (strategy === 'skip') {\n return existingValue as ResponseValue;\n } else {\n console.warn(`Cdeebee: Unknown strategy \"${strategy}\" for key \"${key}\". Skipping normalization.`);\n return mergeDeepRight(existingValue, newValue as StorageData) as ResponseValue;\n }\n}\n\nexport function defaultNormalize<T>(\n cdeebee: CdeebeeState<T>,\n response: IResponse,\n strategyList: CdeebeeListStrategy<T>\n): Record<string, ResponseValue> {\n const keyList = Object.keys(response);\n const currentStorage = isRecord(cdeebee.storage) ? (cdeebee.storage as Record<string, unknown>) : {};\n\n const result = { ...currentStorage } as Record<string, ResponseValue>;\n const keyListToOmit = new Set<string>();\n\n for (const key of keyList) {\n const responseValue = response[key];\n\n if (responseValue === null || responseValue === undefined || typeof responseValue === 'string') {\n keyListToOmit.add(key);\n continue;\n }\n\n const strategy = strategyList[key as keyof T] ?? 'merge';\n\n // For 'skip' strategy, if key doesn't exist in storage, skip it entirely\n if (strategy === 'skip' && !(key in currentStorage)) {\n continue;\n }\n\n const existingValue = key in currentStorage ? (currentStorage[key] as StorageData) : {};\n\n if (isDataWithPrimaryKey(responseValue)) {\n const normalizedValue = normalizeDataWithPrimaryKey(responseValue.data, responseValue.primaryKey);\n result[key] = applyStrategy(existingValue, normalizedValue, strategy, key);\n continue;\n }\n\n if (isRecord(responseValue)) {\n result[key] = applyStrategy(existingValue, responseValue as StorageData, strategy, key);\n } else {\n result[key] = responseValue;\n }\n }\n\n return keyListToOmit.size > 0 ? omit(Array.from(keyListToOmit), result) : result;\n}\n","import { createSlice, current, type PayloadAction } from '@reduxjs/toolkit';\n\nimport { type CdeebeeSettings, type CdeebeeState, type CdeebeeValueList, type CdeebeeListStrategy } from './types';\nimport { checkModule, mergeDeepRight, batchingUpdate, extractLastResultIdList } from './helpers';\nimport { abortQuery } from './abortController';\nimport { request } from './request';\nimport { defaultNormalize } from './storage';\n\nconst initialState: CdeebeeState<unknown> = {\n settings: {\n modules: ['history', 'listener', 'storage', 'cancelation'],\n fileKey: 'file',\n bodyKey: 'value',\n listStrategy: {},\n mergeWithData: {},\n mergeWithHeaders: {},\n },\n storage: {},\n request: {\n active: [],\n errors: {},\n done: {},\n lastResultIdList: {},\n },\n};\n\nexport const factory = <T>(settings: CdeebeeSettings<T>, storage?: T) => {\n const slice = createSlice({\n name: 'cdeebee',\n initialState: mergeDeepRight(initialState as CdeebeeState<T>, { settings, storage: storage ?? {} }) as CdeebeeState<T>,\n reducers: {\n set(state, action: { payload: CdeebeeValueList<T> }) {\n // Directly mutate state.storage using Immer Draft\n // This is more performant than creating a new object\n // Immer will track changes and create minimal updates\n batchingUpdate(state.storage as Record<string, unknown>, action.payload);\n },\n historyClear(state, action: PayloadAction<string | undefined>) {\n const api = action.payload;\n\n if (api) {\n delete state.request.done[api];\n delete state.request.errors[api];\n } else {\n state.request.done = {};\n state.request.errors = {};\n }\n }\n },\n extraReducers: builder => {\n builder\n .addCase(request.pending, (state, action) => {\n const api = action.meta.arg.api;\n const requestId = action.meta.requestId;\n\n if (action.meta.arg.historyClear) {\n checkModule(state.settings, 'history', () => {\n delete state.request.done[api];\n delete state.request.errors[api];\n });\n }\n\n checkModule(state.settings, 'cancelation', () => {\n abortQuery(api, requestId);\n });\n checkModule(state.settings, 'listener', () => {\n state.request.active.push({ api, requestId });\n });\n })\n .addCase(request.fulfilled, (state, action) => {\n const requestId = action.meta.requestId;\n const api = action.meta.arg.api;\n\n checkModule(state.settings, 'listener', () => {\n state.request.active = state.request.active.filter(q => !(q.api === api && q.requestId === requestId));\n });\n checkModule(state.settings, 'history', () => {\n if (!state.request.done[api]) state.request.done[api] = [];\n state.request.done[api].push({ api, request: action.payload, requestId });\n const max = state.settings.maxHistorySize;\n if (max && state.request.done[api].length > max) {\n state.request.done[api] = state.request.done[api].slice(-max);\n }\n });\n checkModule(state.settings, 'storage', () => {\n if (action.meta.arg.ignore) {\n return;\n }\n\n const strategyList = (action.meta.arg.listStrategy ?? state.settings.listStrategy ?? {}) as CdeebeeListStrategy<T>;\n const normalize = (action.meta.arg.normalize ?? state.settings.normalize ?? defaultNormalize) as NonNullable<CdeebeeSettings<T>['normalize']>;\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/skip and preserves keys not in response\n // Simply apply the result\n (state.storage as any) = normalizedData;\n\n // Extract and store result IDs for filtering per list\n state.request.lastResultIdList[api] = extractLastResultIdList(action.payload.result);\n });\n })\n .addCase(request.rejected, (state, action) => {\n const requestId = action.meta.requestId;\n const api = action.meta.arg.api;\n\n checkModule(state.settings, 'listener', () => {\n state.request.active = state.request.active.filter(q => !(q.api === api && q.requestId === requestId));\n });\n checkModule(state.settings, 'history', () => {\n if (!state.request.errors[api]) state.request.errors[api] = [];\n state.request.errors[api].push({ requestId: requestId, api, request: action.error });\n const max = state.settings.maxHistorySize;\n if (max && state.request.errors[api].length > max) {\n state.request.errors[api] = state.request.errors[api].slice(-max);\n }\n });\n });\n },\n });\n\n return slice;\n};\n","import { useSelector } from 'react-redux';\nimport { type CdeebeeState, type CdeebeeHistoryState } from '../reducer/types';\n\nconst EMPTY_ARRAY: readonly never[] = [];\nconst EMPTY_HISTORY: readonly CdeebeeHistoryState[] = EMPTY_ARRAY;\nconst EMPTY_ID_LIST: readonly string[] = EMPTY_ARRAY;\n\n/**\n * Generic hook factory that creates a selector hook for cdeebee state.\n * This allows the hooks to work with any Redux root state structure.\n *\n * @template RootState - The shape of the Redux root state\n * @template Storage - The shape of the cdeebee storage\n * @param selectCdeebee - Function to select the cdeebee slice from root state\n * @returns An object containing all cdeebee hooks\n */\nexport function createCdeebeeHooks<RootState, Storage>(\n selectCdeebee: (state: RootState) => CdeebeeState<Storage>\n) {\n /**\n * Check if any of the specified APIs are currently loading.\n *\n * @param apiList - Array of API endpoints to check\n * @returns true if any of the APIs are currently active/loading\n *\n * @example\n * const isLoading = useLoading(['/api/forums', '/api/threads']);\n * if (isLoading) return <Spinner />;\n */\n function useLoading(apiList: string[]): boolean {\n return useSelector((state: RootState) => {\n const cdeebee = selectCdeebee(state);\n return cdeebee.request.active.some(q => apiList.includes(q.api));\n });\n }\n\n /**\n * Get the successful request history for a specific API endpoint.\n *\n * @param api - The API endpoint\n * @returns Array of successful request history entries\n *\n * @example\n * const history = useRequestHistory('/api/forums');\n * console.log(`Made ${history.length} successful requests`);\n */\n function useRequestHistory(api: string) {\n return useSelector((state: RootState) => {\n const cdeebee = selectCdeebee(state);\n return cdeebee.request.done[api] ?? EMPTY_HISTORY;\n });\n }\n\n /**\n * Get the error history for a specific API endpoint.\n *\n * @param api - The API endpoint\n * @returns Array of error history entries\n *\n * @example\n * const errors = useRequestErrors('/api/forums');\n * if (errors.length > 0) {\n * console.error('Last error:', errors[errors.length - 1]);\n * }\n */\n function useRequestErrors(api: string) {\n return useSelector((state: RootState) => {\n const cdeebee = selectCdeebee(state);\n return cdeebee.request.errors[api] ?? EMPTY_HISTORY;\n });\n }\n\n /**\n * Get a specific list from storage with full type safety.\n *\n * @param listName - The name of the list in storage\n * @returns The list data\n *\n * @example\n * const forums = useStorageList('forumList');\n * const forumArray = Object.values(forums);\n */\n function useStorageList<K extends keyof Storage>(listName: K): Storage[K] {\n return useSelector((state: RootState) => {\n const cdeebee = selectCdeebee(state);\n return cdeebee.storage[listName];\n });\n }\n\n /**\n * Get the entire cdeebee storage.\n *\n * @returns The complete storage object\n *\n * @example\n * const storage = useStorage();\n * console.log(Object.keys(storage)); // ['forumList', 'threadList', ...]\n */\n function useStorage(): Storage {\n return useSelector((state: RootState) => {\n const cdeebee = selectCdeebee(state);\n return cdeebee.storage;\n });\n }\n\n /**\n * Check if any request is currently loading (across all APIs).\n *\n * @returns true if any request is active\n *\n * @example\n * const isAnythingLoading = useIsLoading();\n * if (isAnythingLoading) return <GlobalSpinner />;\n */\n function useIsLoading(): boolean {\n return useSelector((state: RootState) => {\n const cdeebee = selectCdeebee(state);\n return cdeebee.request.active.length > 0;\n });\n }\n\n /**\n * Get the list of IDs returned by the last successful request to an API for a specific list.\n * Useful for filtering storage data to show only results from a specific request.\n *\n * @param api - The API endpoint\n * @param listName - The name of the list in storage (typed from Storage)\n * @returns Array of primary key IDs from the last response for that list\n *\n * @example\n * const productList = useStorageList('productList');\n * const lastIDList = useLastResultIdList('/api/search', 'productList');\n * const displayResults = lastIDList.map(id => productList[id]).filter(Boolean);\n */\n function useLastResultIdList<K extends keyof Storage>(api: string, listName: K): string[] {\n return useSelector((state: RootState) => {\n const cdeebee = selectCdeebee(state);\n return cdeebee.request.lastResultIdList[api]?.[listName as string] ?? EMPTY_ID_LIST;\n });\n }\n\n return {\n useLoading,\n useRequestHistory,\n useRequestErrors,\n useStorageList,\n useStorage,\n useIsLoading,\n useLastResultIdList,\n };\n}\n","import { useSelector } from 'react-redux';\nimport { type CdeebeeState, type CdeebeeHistoryState } from '../reducer/types';\n\nconst EMPTY_ARRAY: readonly never[] = [];\nconst EMPTY_HISTORY: readonly CdeebeeHistoryState[] = EMPTY_ARRAY;\nconst EMPTY_ID_LIST: readonly string[] = EMPTY_ARRAY;\n\n/**\n * Standalone hook that can be used without createCdeebeeHooks.\n * Assumes the cdeebee slice is at state.cdeebee.\n *\n * @param apiList - Array of API endpoints to check\n * @returns true if any of the APIs are currently active/loading\n *\n * @example\n * const isLoading = useLoading(['/api/forums', '/api/threads']);\n */\nexport function useLoading<Storage = unknown>(apiList: string[]): boolean {\n return useSelector((state: { cdeebee: CdeebeeState<Storage> }) => {\n return state.cdeebee.request.active.some(q => apiList.includes(q.api));\n });\n}\n\n/**\n * Standalone hook that can be used without createCdeebeeHooks.\n * Assumes the cdeebee slice is at state.cdeebee.\n *\n * @param api - The API endpoint\n * @returns Array of successful request history entries\n */\nexport function useRequestHistory<Storage = unknown>(api: string) {\n return useSelector((state: { cdeebee: CdeebeeState<Storage> }) => {\n return state.cdeebee.request.done[api] ?? EMPTY_HISTORY;\n });\n}\n\n/**\n * Standalone hook that can be used without createCdeebeeHooks.\n * Assumes the cdeebee slice is at state.cdeebee.\n *\n * @param api - The API endpoint\n * @returns Array of error history entries\n */\nexport function useRequestErrors<Storage = unknown>(api: string) {\n return useSelector((state: { cdeebee: CdeebeeState<Storage> }) => {\n return state.cdeebee.request.errors[api] ?? EMPTY_HISTORY;\n });\n}\n\n/**\n * Standalone hook that can be used without createCdeebeeHooks.\n * Assumes the cdeebee slice is at state.cdeebee.\n *\n * @param listName - The name of the list in storage\n * @returns The list data\n */\nexport function useStorageList<Storage, K extends keyof Storage>(listName: K): Storage[K] {\n return useSelector((state: { cdeebee: CdeebeeState<Storage> }) => {\n return state.cdeebee.storage[listName];\n });\n}\n\n/**\n * Standalone hook that can be used without createCdeebeeHooks.\n * Assumes the cdeebee slice is at state.cdeebee.\n *\n * @returns The complete storage object\n */\nexport function useStorage<Storage>(): Storage {\n return useSelector((state: { cdeebee: CdeebeeState<Storage> }) => {\n return state.cdeebee.storage;\n });\n}\n\n/**\n * Standalone hook that can be used without createCdeebeeHooks.\n * Assumes the cdeebee slice is at state.cdeebee.\n *\n * @returns true if any request is active\n */\nexport function useIsLoading<Storage = unknown>(): boolean {\n return useSelector((state: { cdeebee: CdeebeeState<Storage> }) => {\n return state.cdeebee.request.active.length > 0;\n });\n}\n\n/**\n * Standalone hook that can be used without createCdeebeeHooks.\n * Assumes the cdeebee slice is at state.cdeebee.\n *\n * Get the list of IDs returned by the last successful request to an API for a specific list.\n * Useful for filtering storage data to show only results from a specific request.\n *\n * @param api - The API endpoint\n * @param listName - The name of the list in storage (typed from Storage)\n * @returns Array of primary key IDs from the last response for that list\n *\n * @example\n * const productList = useStorageList('productList');\n * const lastIDList = useLastResultIdList('/api/search', 'productList');\n * const displayResults = lastIDList.map(id => productList[id]).filter(Boolean);\n */\nexport function useLastResultIdList<Storage, K extends keyof Storage>(api: string, listName: K): string[] {\n return useSelector((state: { cdeebee: CdeebeeState<Storage> }) => {\n return state.cdeebee.request.lastResultIdList[api]?.[listName as string] ?? EMPTY_ID_LIST;\n });\n}\n"],"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
|
|
3
|
+
"version": "3.0.0",
|
|
4
4
|
"description": "React Redux data-logic library",
|
|
5
5
|
"repository": "git@github.com:recats/cdeebee.git",
|
|
6
6
|
"author": "recats",
|
|
@@ -35,20 +35,27 @@
|
|
|
35
35
|
"LICENSE"
|
|
36
36
|
],
|
|
37
37
|
"devDependencies": {
|
|
38
|
+
"@eslint/eslintrc": "^3.3.5",
|
|
39
|
+
"@eslint/js": "^10.0.1",
|
|
38
40
|
"@reduxjs/toolkit": "^2.11.2",
|
|
39
|
-
"@types/lodash": "^4.17.
|
|
40
|
-
"@types/node": "^
|
|
41
|
-
"@
|
|
42
|
-
"
|
|
43
|
-
"
|
|
41
|
+
"@types/lodash": "^4.17.24",
|
|
42
|
+
"@types/node": "^25.5.0",
|
|
43
|
+
"@types/react": "^19.2.14",
|
|
44
|
+
"@vitest/coverage-v8": "^4.1.0",
|
|
45
|
+
"eslint": "^10.0.3",
|
|
46
|
+
"jsdom": "^28.1.0",
|
|
47
|
+
"react": "^19.2.4",
|
|
48
|
+
"react-redux": "^9.2.0",
|
|
44
49
|
"typescript": "^5.9.3",
|
|
45
|
-
"typescript-eslint": "^8.
|
|
46
|
-
"vite": "^
|
|
50
|
+
"typescript-eslint": "^8.57.0",
|
|
51
|
+
"vite": "^8.0.0",
|
|
47
52
|
"vite-plugin-dts": "^4.5.4",
|
|
48
|
-
"vitest": "^
|
|
53
|
+
"vitest": "^4.1.0"
|
|
49
54
|
},
|
|
50
55
|
"peerDependencies": {
|
|
51
|
-
"@reduxjs/toolkit": ">=2"
|
|
56
|
+
"@reduxjs/toolkit": ">=2",
|
|
57
|
+
"react": ">=19",
|
|
58
|
+
"react-redux": ">=9"
|
|
52
59
|
},
|
|
53
60
|
"scripts": {
|
|
54
61
|
"lint": "eslint lib/**/*.ts",
|