@classytic/arc-next 0.1.2 → 0.2.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/dist/hooks.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"hooks.js","names":[],"sources":["../src/hooks.ts"],"sourcesContent":["\"use client\";\n\nimport { useQueryClient } from \"@tanstack/react-query\";\nimport { useCallback } from \"react\";\nimport { createOptimisticMutation } from \"./mutation.js\";\nimport {\n createListQuery,\n createDetailQuery,\n createInfiniteListQuery,\n updateListCache,\n getItemId,\n createQueryKeys,\n createCacheUtils,\n DEFAULT_QUERY_CONFIG,\n} from \"./query.js\";\nimport type {\n QueryKeys,\n CacheUtils,\n ListQueryOptions,\n DetailQueryOptions,\n ListQueryResult,\n DetailQueryResult,\n InfiniteListQueryOptions,\n InfiniteListQueryResult,\n} from \"./query.js\";\nimport {\n isOffsetPagination,\n isKeysetPagination,\n} from \"./api.js\";\nimport type { PaginatedResponse } from \"./api.js\";\nimport type { MutationCallbacks } from \"./mutation.js\";\nimport { getAuthMode, getAuthContext } from \"./client.js\";\nimport type { ArcClient, ToastHandler, UseRouterHook } from \"./client.js\";\n\n// Re-export UseRouterHook for backward compatibility\nexport type { UseRouterHook } from \"./client.js\";\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface CrudApi<T, TCreate = Partial<T>, TUpdate = Partial<T>> {\n getAll: (options: {\n token?: string | null;\n organizationId?: string | null;\n params?: Record<string, unknown>;\n options?: { signal?: AbortSignal; [key: string]: unknown };\n }) => Promise<unknown>;\n\n getById: (options: {\n id: string;\n token?: string | null;\n organizationId?: string | null;\n params?: { select?: string; populate?: string | string[] };\n options?: { signal?: AbortSignal; [key: string]: unknown };\n }) => Promise<unknown>;\n\n create: (options: {\n token?: string | null;\n organizationId?: string | null;\n data: TCreate;\n }) => Promise<unknown>;\n\n update: (options: {\n token?: string | null;\n organizationId?: string | null;\n id: string;\n data: TUpdate;\n }) => Promise<unknown>;\n\n delete: (options: {\n token?: string | null;\n organizationId?: string | null;\n id: string;\n }) => Promise<unknown>;\n}\n\nexport interface CrudHooksConfig<T, TCreate = Partial<T>, TUpdate = Partial<T>> {\n api: CrudApi<T, TCreate, TUpdate>;\n entityKey: string;\n singular: string;\n plural?: string;\n defaults?: {\n staleTime?: number;\n gcTime?: number;\n refetchOnWindowFocus?: boolean;\n structuralSharing?: boolean;\n messages?: {\n createSuccess?: string;\n createError?: string;\n updateSuccess?: string;\n updateError?: string;\n deleteSuccess?: string;\n deleteError?: string;\n };\n };\n callbacks?: {\n onCreate?: MutationCallbacks<T, { data: TCreate }>;\n onUpdate?: MutationCallbacks<T, { id: string; data: TUpdate }>;\n onDelete?: MutationCallbacks<unknown, { id: string }>;\n };\n client?: ArcClient;\n}\n\nexport interface MutationParams<TData> {\n token?: string | null;\n organizationId?: string | null;\n data: TData;\n}\n\nexport interface UpdateParams<TData> extends MutationParams<TData> {\n id: string;\n}\n\nexport interface DeleteParams {\n token?: string | null;\n organizationId?: string | null;\n id: string;\n}\n\nexport interface CallOptions<TData = unknown> {\n onSuccess?: (data: TData) => void;\n onError?: (error: Error) => void;\n silent?: boolean;\n}\n\nexport interface CrudActions<T, TCreate, TUpdate> {\n create: (params: MutationParams<TCreate>, options?: CallOptions<T>) => Promise<T>;\n update: (params: UpdateParams<TUpdate>, options?: CallOptions<T>) => Promise<T>;\n remove: (params: DeleteParams, options?: CallOptions) => Promise<unknown>;\n isCreating: boolean;\n isUpdating: boolean;\n isDeleting: boolean;\n isMutating: boolean;\n}\n\nexport interface NavigationOptions {\n scroll?: boolean;\n replace?: boolean;\n}\n\nexport type NavigateFn<T> = (href: string, item: T, options?: NavigationOptions) => void;\n\nexport interface CrudHooksReturn<T, TCreate, TUpdate> {\n KEYS: QueryKeys;\n cache: CacheUtils<T>;\n useList: {\n /** New signature — auto-injects token/orgId from configureAuth() context */\n (params?: Record<string, unknown>, options?: ListQueryOptions): ListQueryResult<T>;\n /** Legacy signature — explicit token */\n (token: string | null, params?: Record<string, unknown>, options?: ListQueryOptions): ListQueryResult<T>;\n };\n useDetail: {\n /** New signature — auto-injects token from configureAuth() context */\n (id: string | null, options?: DetailQueryOptions): DetailQueryResult<T>;\n /** Legacy signature — explicit token */\n (id: string | null, token: string | null, options?: DetailQueryOptions): DetailQueryResult<T>;\n };\n useInfiniteList: {\n /** New signature — auto-injects token/orgId from configureAuth() context */\n (params?: Record<string, unknown>, options?: InfiniteListQueryOptions): InfiniteListQueryResult<T>;\n /** Legacy signature — explicit token */\n (token: string | null, params?: Record<string, unknown>, options?: InfiniteListQueryOptions): InfiniteListQueryResult<T>;\n };\n useActions: () => CrudActions<T, TCreate, TUpdate>;\n useNavigation: () => NavigateFn<T>;\n}\n\n// ============================================================================\n// Navigation Configuration (Global)\n// ============================================================================\n\nlet useRouterHook: UseRouterHook | null = null;\n\n/**\n * Configure the router hook for useNavigation. Call once at app init.\n *\n * @example\n * import { useRouter } from \"next/navigation\";\n * configureNavigation(useRouter);\n */\nexport function configureNavigation(hook: UseRouterHook): void {\n useRouterHook = hook;\n}\n\n// ============================================================================\n// Enabled Rule\n// ============================================================================\n\nfunction createEnabledRule(token: string | null, options: { public?: boolean; enabled?: boolean }): boolean {\n // Cookie-based auth: no token needed, queries always enabled (cookies sent via credentials: 'include')\n if (getAuthMode() === 'cookie' || options.public) {\n return options.enabled ?? true;\n }\n // Bearer token auth: require token to enable queries\n return options.enabled !== undefined ? options.enabled && !!token : !!token;\n}\n\n// ============================================================================\n// Create CRUD Hooks Factory\n// ============================================================================\n\nexport function createCrudHooks<T, TCreate = Partial<T>, TUpdate = Partial<T>>({\n api,\n entityKey,\n singular,\n defaults = {},\n callbacks = {},\n client,\n}: CrudHooksConfig<T, TCreate, TUpdate>): CrudHooksReturn<T, TCreate, TUpdate> {\n const KEYS = createQueryKeys(entityKey);\n const cache = createCacheUtils<T>(KEYS);\n\n // Resolve toast handler: client instance → global\n const instanceToast: ToastHandler | undefined = client?.toast;\n // Resolve navigation hook: client instance → global\n const instanceNavigation: UseRouterHook | null = client?.navigation ?? null;\n\n const config = {\n ...DEFAULT_QUERY_CONFIG,\n ...defaults,\n structuralSharing: defaults.structuralSharing,\n messages: {\n createSuccess: `${singular} created successfully`,\n createError: `Failed to create ${singular.toLowerCase()}`,\n updateSuccess: `${singular} updated successfully`,\n updateError: `Failed to update ${singular.toLowerCase()}`,\n deleteSuccess: `${singular} deleted successfully`,\n deleteError: `Failed to delete ${singular.toLowerCase()}`,\n ...defaults.messages,\n },\n };\n\n // ========== useList ==========\n\n function useList(\n tokenOrParams?: string | null | Record<string, unknown>,\n paramsOrOptions?: Record<string, unknown> | ListQueryOptions,\n maybeOptions?: ListQueryOptions,\n ): ListQueryResult<T> {\n let token: string | null;\n let params: Record<string, unknown>;\n let options: ListQueryOptions;\n\n // Detect which overload: first arg is string|null = legacy, object/undefined = new\n if (tokenOrParams === null || typeof tokenOrParams === 'string') {\n token = tokenOrParams;\n params = (paramsOrOptions as Record<string, unknown>) ?? {};\n options = maybeOptions ?? {};\n } else {\n const auth = getAuthContext();\n token = auth.token;\n params = (tokenOrParams as Record<string, unknown>) ?? {};\n options = (paramsOrOptions as ListQueryOptions) ?? {};\n if (auth.organizationId && !params.organizationId) {\n params = { ...params, organizationId: auth.organizationId };\n }\n }\n\n const { organizationId, ...restParams } = params;\n const scope = options._scope || (organizationId ? \"tenant\" : \"super-admin\");\n const { request: requestOpts, ...queryOpts } = options;\n\n return createListQuery<T>({\n queryKey: KEYS.scopedList(scope, { organizationId, ...restParams }),\n queryFn: () => api.getAll({ token, organizationId: organizationId as string | null, params: restParams, options: { ...requestOpts } }),\n enabled: createEnabledRule(token, queryOpts),\n options: {\n staleTime: queryOpts.staleTime ?? config.staleTime,\n gcTime: queryOpts.gcTime ?? config.gcTime,\n refetchOnWindowFocus: queryOpts.refetchOnWindowFocus ?? config.refetchOnWindowFocus,\n structuralSharing: queryOpts.structuralSharing ?? config.structuralSharing,\n refetchInterval: queryOpts.refetchInterval,\n refetchIntervalInBackground: queryOpts.refetchIntervalInBackground,\n },\n prefillDetailCache: queryOpts.prefillDetailCache ?? true,\n detailKeyBuilder: (id) => KEYS.detail(id),\n });\n }\n\n // ========== useDetail ==========\n\n function useDetail(\n id: string | null,\n tokenOrOptions?: string | null | DetailQueryOptions,\n maybeOptions?: DetailQueryOptions,\n ): DetailQueryResult<T> {\n let token: string | null;\n let options: DetailQueryOptions;\n\n // Detect which overload: second arg is string|null = legacy, object/undefined = new\n if (tokenOrOptions === null || typeof tokenOrOptions === 'string') {\n token = tokenOrOptions;\n options = maybeOptions ?? {};\n } else {\n const auth = getAuthContext();\n token = auth.token;\n options = (tokenOrOptions as DetailQueryOptions) ?? {};\n if (auth.organizationId && !options.organizationId) {\n options = { ...options, organizationId: auth.organizationId };\n }\n }\n\n const { organizationId, params: queryParams, request: requestOpts, ...restOptions } = options;\n\n return createDetailQuery<T>({\n queryKey: queryParams ? [...KEYS.detail(id || \"\"), queryParams] : KEYS.detail(id || \"\"),\n queryFn: () => api.getById({ id: id!, token, organizationId, params: queryParams, options: { ...requestOpts } }),\n enabled: !!id && createEnabledRule(token, restOptions),\n options: {\n staleTime: restOptions.staleTime ?? config.staleTime,\n gcTime: restOptions.gcTime ?? config.gcTime,\n structuralSharing: restOptions.structuralSharing ?? config.structuralSharing,\n refetchInterval: restOptions.refetchInterval,\n refetchIntervalInBackground: restOptions.refetchIntervalInBackground,\n },\n });\n }\n\n // ========== useActions ==========\n\n function useActions(): CrudActions<T, TCreate, TUpdate> {\n const queryClient = useQueryClient();\n\n const createMutation = createOptimisticMutation({\n mutationFn: ({ token, organizationId, data }: MutationParams<TCreate>) =>\n api.create({ token, organizationId, data }),\n queryClient,\n queryKeys: [KEYS.lists()],\n optimisticUpdate: (oldData, { data }) => {\n const optimisticItem = {\n ...(data as object),\n _optimistic: true,\n [getItemId(data) ? \"id\" : \"_id\"]: getItemId(data) ?? `temp-${Date.now()}`,\n };\n return updateListCache(oldData, (arr: unknown[]) => [optimisticItem, ...(arr || [])]);\n },\n onSuccess: (data, variables) => {\n callbacks.onCreate?.onSuccess?.(data as T, { data: variables.data }, undefined);\n },\n onError: (error, variables) => {\n callbacks.onCreate?.onError?.(error, { data: variables.data }, undefined);\n },\n messages: { success: config.messages.createSuccess, error: config.messages.createError },\n toastHandler: instanceToast,\n });\n\n const updateMutation = createOptimisticMutation({\n mutationFn: ({ token, organizationId, id, data }: UpdateParams<TUpdate>) =>\n api.update({ token, organizationId, id, data }),\n queryClient,\n queryKeys: [KEYS.lists()],\n optimisticUpdate: (oldData, { id, data }) => {\n const updated = updateListCache(oldData, (arr: unknown[]) =>\n (arr || []).map((item) => (getItemId(item) === id ? { ...(item as object), ...(data as object) } : item))\n );\n queryClient.setQueryData(KEYS.detail(id), (current: unknown) =>\n current ? { ...(current as object), data: { ...((current as { data?: object }).data || {}), ...(data as object) } } : current\n );\n return updated;\n },\n onSuccess: (data, { id }) => {\n queryClient.invalidateQueries({ queryKey: KEYS.detail(id) });\n callbacks.onUpdate?.onSuccess?.(data as T, { id, data: {} as TUpdate }, undefined);\n },\n onError: (error, { id, data }) => {\n callbacks.onUpdate?.onError?.(error, { id, data }, undefined);\n },\n messages: { success: config.messages.updateSuccess, error: config.messages.updateError },\n toastHandler: instanceToast,\n });\n\n const deleteMutation = createOptimisticMutation({\n mutationFn: ({ token, organizationId, id }: DeleteParams) => api.delete({ token, organizationId, id }),\n queryClient,\n queryKeys: [KEYS.lists()],\n optimisticUpdate: (oldData, { id }) => {\n queryClient.removeQueries({ queryKey: KEYS.detail(id) });\n return updateListCache(oldData, (arr: unknown[]) => (arr || []).filter((item) => getItemId(item) !== id));\n },\n onSuccess: (data, { id }) => {\n callbacks.onDelete?.onSuccess?.(data, { id }, undefined);\n },\n onError: (error, { id }) => {\n callbacks.onDelete?.onError?.(error, { id }, undefined);\n },\n messages: { success: config.messages.deleteSuccess, error: config.messages.deleteError },\n toastHandler: instanceToast,\n });\n\n const resolveAuth = <P extends { token?: string | null; organizationId?: string | null }>(params: P): P => {\n const auth = getAuthContext();\n return {\n ...params,\n token: params.token ?? auth.token,\n organizationId: params.organizationId ?? auth.organizationId,\n };\n };\n\n const create = async (params: MutationParams<TCreate>, options?: CallOptions<T>): Promise<T> => {\n try {\n const result = await createMutation.mutateAsync(resolveAuth(params));\n options?.onSuccess?.(result as T);\n return result as T;\n } catch (error) {\n options?.onError?.(error as Error);\n throw error;\n }\n };\n\n const update = async (params: UpdateParams<TUpdate>, options?: CallOptions<T>): Promise<T> => {\n try {\n const result = await updateMutation.mutateAsync(resolveAuth(params));\n options?.onSuccess?.(result as T);\n return result as T;\n } catch (error) {\n options?.onError?.(error as Error);\n throw error;\n }\n };\n\n const remove = async (params: DeleteParams, options?: CallOptions): Promise<unknown> => {\n try {\n const result = await deleteMutation.mutateAsync(resolveAuth(params));\n options?.onSuccess?.(result);\n return result;\n } catch (error) {\n options?.onError?.(error as Error);\n throw error;\n }\n };\n\n return {\n create,\n update,\n remove,\n isCreating: createMutation.isPending,\n isUpdating: updateMutation.isPending,\n isDeleting: deleteMutation.isPending,\n isMutating: createMutation.isPending || updateMutation.isPending || deleteMutation.isPending,\n };\n }\n\n // ========== useInfiniteList ==========\n\n function useInfiniteList(\n tokenOrParams?: string | null | Record<string, unknown>,\n paramsOrOptions?: Record<string, unknown> | InfiniteListQueryOptions,\n maybeOptions?: InfiniteListQueryOptions,\n ): InfiniteListQueryResult<T> {\n let token: string | null;\n let params: Record<string, unknown>;\n let options: InfiniteListQueryOptions;\n\n if (tokenOrParams === null || typeof tokenOrParams === 'string') {\n token = tokenOrParams;\n params = (paramsOrOptions as Record<string, unknown>) ?? {};\n options = maybeOptions ?? {};\n } else {\n const auth = getAuthContext();\n token = auth.token;\n params = (tokenOrParams as Record<string, unknown>) ?? {};\n options = (paramsOrOptions as InfiniteListQueryOptions) ?? {};\n if (auth.organizationId && !params.organizationId) {\n params = { ...params, organizationId: auth.organizationId };\n }\n }\n\n const { organizationId, ...restParams } = params;\n const scope = options._scope || (organizationId ? \"tenant\" : \"super-admin\");\n const { request: requestOpts, ...queryOpts } = options;\n\n return createInfiniteListQuery<T>({\n queryKey: [...KEYS.scopedList(scope, { organizationId, ...restParams }), 'infinite'],\n queryFn: ({ pageParam }) => {\n const paginationParams = typeof pageParam === 'string'\n ? { after: pageParam }\n : { page: pageParam };\n\n return api.getAll({\n token,\n organizationId: organizationId as string | null,\n params: { ...restParams, ...paginationParams },\n options: { ...requestOpts },\n });\n },\n enabled: createEnabledRule(token, queryOpts),\n initialPageParam: restParams.after ? restParams.after : 1,\n getNextPageParam: (lastPage) => {\n const page = lastPage as PaginatedResponse<T>;\n if (isKeysetPagination(page)) {\n return page.hasMore ? page.next : undefined;\n }\n if (isOffsetPagination(page)) {\n return page.hasNext ? page.page + 1 : undefined;\n }\n // Fallback: check common pagination fields\n const p = page as unknown as Record<string, unknown>;\n if (typeof p.hasNext === 'boolean' && typeof p.page === 'number') {\n return p.hasNext ? (p.page as number) + 1 : undefined;\n }\n return undefined;\n },\n options: {\n staleTime: queryOpts.staleTime ?? config.staleTime,\n gcTime: queryOpts.gcTime ?? config.gcTime,\n refetchOnWindowFocus: queryOpts.refetchOnWindowFocus ?? config.refetchOnWindowFocus,\n structuralSharing: queryOpts.structuralSharing ?? config.structuralSharing,\n },\n });\n }\n\n // ========== useNavigation ==========\n\n function useNavigation(): NavigateFn<T> {\n const queryClient = useQueryClient();\n const activeRouterHook = instanceNavigation ?? useRouterHook;\n const router = activeRouterHook?.();\n\n return useCallback(\n (href: string, item: T, options: NavigationOptions = {}) => {\n const id = getItemId(item);\n if (id) {\n queryClient.setQueryData(KEYS.detail(id), { data: item });\n }\n\n if (!router) return;\n\n const { scroll = true, replace = false } = options;\n if (replace) {\n router.replace(href, { scroll });\n } else {\n router.push(href, { scroll });\n }\n },\n [queryClient, router]\n );\n }\n\n return {\n KEYS,\n cache,\n useList,\n useDetail,\n useInfiniteList,\n useActions,\n useNavigation,\n };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"hooks.js","names":[],"sources":["../src/hooks.ts"],"sourcesContent":["\"use client\";\n\nimport { useQueryClient, useMutation, type QueryKey } from \"@tanstack/react-query\";\nimport { useCallback, useRef } from \"react\";\nimport { createOptimisticMutation, useMutationWithTransition } from \"./mutation.js\";\nimport type { MutationMessages } from \"./mutation.js\";\nimport {\n createListQuery,\n createDetailQuery,\n createInfiniteListQuery,\n updateListCache,\n getItemId,\n createQueryKeys,\n createCacheUtils,\n DEFAULT_QUERY_CONFIG,\n} from \"./query.js\";\nimport type {\n QueryKeys,\n CacheUtils,\n ListQueryOptions,\n DetailQueryOptions,\n ListQueryResult,\n DetailQueryResult,\n InfiniteListQueryOptions,\n InfiniteListQueryResult,\n} from \"./query.js\";\nimport {\n isOffsetPagination,\n isKeysetPagination,\n} from \"./api.js\";\nimport type { PaginatedResponse } from \"./api.js\";\nimport type { MutationCallbacks, TransitionMutationReturn } from \"./mutation.js\";\nimport { getAuthMode, getAuthContext } from \"./client.js\";\nimport type { ArcClient, ToastHandler, UseRouterHook } from \"./client.js\";\n\n// Re-export UseRouterHook for backward compatibility\nexport type { UseRouterHook } from \"./client.js\";\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface CrudApi<T, TCreate = Partial<T>, TUpdate = Partial<T>> {\n getAll: (options: {\n token?: string | null;\n organizationId?: string | null;\n params?: Record<string, unknown>;\n options?: { signal?: AbortSignal; [key: string]: unknown };\n }) => Promise<unknown>;\n\n getById: (options: {\n id: string;\n token?: string | null;\n organizationId?: string | null;\n params?: { select?: string; populate?: string | string[] };\n options?: { signal?: AbortSignal; [key: string]: unknown };\n }) => Promise<unknown>;\n\n create: (options: {\n token?: string | null;\n organizationId?: string | null;\n data: TCreate;\n }) => Promise<unknown>;\n\n update: (options: {\n token?: string | null;\n organizationId?: string | null;\n id: string;\n data: TUpdate;\n }) => Promise<unknown>;\n\n delete: (options: {\n token?: string | null;\n organizationId?: string | null;\n id: string;\n }) => Promise<unknown>;\n\n upload?: (options: {\n token?: string | null;\n organizationId?: string | null;\n data: FormData;\n id?: string;\n path?: string;\n }) => Promise<unknown>;\n\n search?: (options: {\n token?: string | null;\n organizationId?: string | null;\n params?: Record<string, unknown>;\n options?: { signal?: AbortSignal; [key: string]: unknown };\n }) => Promise<unknown>;\n}\n\nexport interface CrudHooksConfig<T, TCreate = Partial<T>, TUpdate = Partial<T>> {\n api: CrudApi<T, TCreate, TUpdate>;\n entityKey: string;\n singular: string;\n plural?: string;\n defaults?: {\n staleTime?: number;\n gcTime?: number;\n refetchOnWindowFocus?: boolean;\n structuralSharing?: boolean;\n messages?: {\n createSuccess?: string;\n createError?: string;\n updateSuccess?: string;\n updateError?: string;\n deleteSuccess?: string;\n deleteError?: string;\n };\n };\n callbacks?: {\n onCreate?: MutationCallbacks<T, { data: TCreate }>;\n onUpdate?: MutationCallbacks<T, { id: string; data: TUpdate }>;\n onDelete?: MutationCallbacks<unknown, { id: string }>;\n };\n client?: ArcClient;\n}\n\nexport interface MutationParams<TData> {\n token?: string | null;\n organizationId?: string | null;\n data: TData;\n}\n\nexport interface UpdateParams<TData> extends MutationParams<TData> {\n id: string;\n}\n\nexport interface DeleteParams {\n token?: string | null;\n organizationId?: string | null;\n id: string;\n}\n\nexport interface CallOptions<TData = unknown> {\n onSuccess?: (data: TData) => void;\n onError?: (error: Error) => void;\n onSettled?: (data: TData | undefined, error: Error | null) => void;\n silent?: boolean;\n}\n\nexport interface CrudActions<T, TCreate, TUpdate> {\n create: (params: MutationParams<TCreate>, options?: CallOptions<T>) => Promise<T>;\n update: (params: UpdateParams<TUpdate>, options?: CallOptions<T>) => Promise<T>;\n remove: (params: DeleteParams, options?: CallOptions) => Promise<unknown>;\n isCreating: boolean;\n isUpdating: boolean;\n isDeleting: boolean;\n isMutating: boolean;\n}\n\nexport interface NavigationOptions {\n scroll?: boolean;\n replace?: boolean;\n}\n\nexport type NavigateFn<T> = (href: string, item: T, options?: NavigationOptions) => void;\n\nexport interface CrudHooksReturn<T, TCreate, TUpdate> {\n KEYS: QueryKeys;\n cache: CacheUtils<T>;\n useList: {\n /** New signature — auto-injects token/orgId from configureAuth() context */\n (params?: Record<string, unknown>, options?: ListQueryOptions<T>): ListQueryResult<T>;\n /** Legacy signature — explicit token */\n (token: string | null, params?: Record<string, unknown>, options?: ListQueryOptions<T>): ListQueryResult<T>;\n };\n useDetail: {\n /** New signature — auto-injects token from configureAuth() context */\n (id: string | null, options?: DetailQueryOptions<T>): DetailQueryResult<T>;\n /** Legacy signature — explicit token */\n (id: string | null, token: string | null, options?: DetailQueryOptions<T>): DetailQueryResult<T>;\n };\n useInfiniteList: {\n /** New signature — auto-injects token/orgId from configureAuth() context */\n (params?: Record<string, unknown>, options?: InfiniteListQueryOptions): InfiniteListQueryResult<T>;\n /** Legacy signature — explicit token */\n (token: string | null, params?: Record<string, unknown>, options?: InfiniteListQueryOptions): InfiniteListQueryResult<T>;\n };\n useActions: () => CrudActions<T, TCreate, TUpdate>;\n useUpload: (options?: {\n invalidateQueries?: QueryKey[];\n messages?: MutationMessages;\n onSuccess?: (data: unknown) => void;\n onError?: (error: Error) => void;\n onSettled?: (data: unknown | undefined, error: Error | null) => void;\n }) => TransitionMutationReturn<unknown, { data: FormData; id?: string; path?: string }>;\n useSearch: (query: string, params?: Record<string, unknown>, options?: ListQueryOptions<T>) => ListQueryResult<T>;\n useCustomMutation: <TData = unknown, TVariables = unknown>(config: {\n mutationFn: (variables: TVariables) => Promise<TData>;\n invalidateQueries?: QueryKey[];\n messages?: MutationMessages;\n onSuccess?: (data: TData, variables: TVariables) => void;\n onError?: (error: Error, variables: TVariables) => void;\n onSettled?: (data: TData | undefined, error: Error | null, variables: TVariables) => void;\n }) => TransitionMutationReturn<TData, TVariables>;\n useNavigation: () => NavigateFn<T>;\n}\n\n// ============================================================================\n// Navigation Configuration (Global)\n// ============================================================================\n\nlet useRouterHook: UseRouterHook | null = null;\n\n/**\n * Configure the router hook for useNavigation. Call once at app init.\n *\n * @example\n * import { useRouter } from \"next/navigation\";\n * configureNavigation(useRouter);\n */\nexport function configureNavigation(hook: UseRouterHook): void {\n useRouterHook = hook;\n}\n\n// ============================================================================\n// Enabled Rule\n// ============================================================================\n\nfunction createEnabledRule(token: string | null, options: { public?: boolean; enabled?: boolean }): boolean {\n // Cookie-based auth: no token needed, queries always enabled (cookies sent via credentials: 'include')\n if (getAuthMode() === 'cookie' || options.public) {\n return options.enabled ?? true;\n }\n // Bearer token auth: require token to enable queries\n return options.enabled !== undefined ? options.enabled && !!token : !!token;\n}\n\n// ============================================================================\n// Create CRUD Hooks Factory\n// ============================================================================\n\nexport function createCrudHooks<T, TCreate = Partial<T>, TUpdate = Partial<T>>({\n api,\n entityKey,\n singular,\n defaults = {},\n callbacks = {},\n client,\n}: CrudHooksConfig<T, TCreate, TUpdate>): CrudHooksReturn<T, TCreate, TUpdate> {\n const KEYS = createQueryKeys(entityKey);\n const cache = createCacheUtils<T>(KEYS);\n\n // Resolve toast handler: client instance → global\n const instanceToast: ToastHandler | undefined = client?.toast;\n // Resolve navigation hook: client instance → global\n const instanceNavigation: UseRouterHook | null = client?.navigation ?? null;\n\n const config = {\n ...DEFAULT_QUERY_CONFIG,\n ...defaults,\n structuralSharing: defaults.structuralSharing,\n messages: {\n createSuccess: `${singular} created successfully`,\n createError: `Failed to create ${singular.toLowerCase()}`,\n updateSuccess: `${singular} updated successfully`,\n updateError: `Failed to update ${singular.toLowerCase()}`,\n deleteSuccess: `${singular} deleted successfully`,\n deleteError: `Failed to delete ${singular.toLowerCase()}`,\n ...defaults.messages,\n },\n };\n\n // ========== useList ==========\n\n function useList(\n tokenOrParams?: string | null | Record<string, unknown>,\n paramsOrOptions?: Record<string, unknown> | ListQueryOptions,\n maybeOptions?: ListQueryOptions,\n ): ListQueryResult<T> {\n let token: string | null;\n let params: Record<string, unknown>;\n let options: ListQueryOptions;\n\n // Detect which overload: first arg is string|null = legacy, object/undefined = new\n if (tokenOrParams === null || typeof tokenOrParams === 'string') {\n token = tokenOrParams;\n params = (paramsOrOptions as Record<string, unknown>) ?? {};\n options = maybeOptions ?? {};\n } else {\n const auth = getAuthContext();\n token = auth.token;\n params = (tokenOrParams as Record<string, unknown>) ?? {};\n options = (paramsOrOptions as ListQueryOptions) ?? {};\n if (auth.organizationId && !params.organizationId) {\n params = { ...params, organizationId: auth.organizationId };\n }\n }\n\n const { organizationId, ...restParams } = params;\n const scope = options._scope || (organizationId ? \"tenant\" : \"super-admin\");\n const { request: requestOpts, ...queryOpts } = options;\n\n return createListQuery<T>({\n queryKey: KEYS.scopedList(scope, { organizationId, ...restParams }),\n queryFn: ({ signal }) => api.getAll({ token, organizationId: organizationId as string | null, params: restParams, options: { signal, ...requestOpts } }),\n enabled: createEnabledRule(token, queryOpts),\n options: {\n staleTime: queryOpts.staleTime ?? config.staleTime,\n gcTime: queryOpts.gcTime ?? config.gcTime,\n refetchOnWindowFocus: queryOpts.refetchOnWindowFocus ?? config.refetchOnWindowFocus,\n structuralSharing: queryOpts.structuralSharing ?? config.structuralSharing,\n refetchInterval: queryOpts.refetchInterval,\n refetchIntervalInBackground: queryOpts.refetchIntervalInBackground,\n },\n prefillDetailCache: queryOpts.prefillDetailCache ?? true,\n detailKeyBuilder: (id) => KEYS.detail(id),\n select: queryOpts.select,\n });\n }\n\n // ========== useDetail ==========\n\n function useDetail(\n id: string | null,\n tokenOrOptions?: string | null | DetailQueryOptions,\n maybeOptions?: DetailQueryOptions,\n ): DetailQueryResult<T> {\n let token: string | null;\n let options: DetailQueryOptions;\n\n // Detect which overload: second arg is string|null = legacy, object/undefined = new\n if (tokenOrOptions === null || typeof tokenOrOptions === 'string') {\n token = tokenOrOptions;\n options = maybeOptions ?? {};\n } else {\n const auth = getAuthContext();\n token = auth.token;\n options = (tokenOrOptions as DetailQueryOptions) ?? {};\n if (auth.organizationId && !options.organizationId) {\n options = { ...options, organizationId: auth.organizationId };\n }\n }\n\n const { organizationId, params: queryParams, request: requestOpts, ...restOptions } = options;\n\n return createDetailQuery<T>({\n queryKey: queryParams ? [...KEYS.detail(id || \"\"), queryParams] : KEYS.detail(id || \"\"),\n queryFn: ({ signal }) => api.getById({ id: id!, token, organizationId, params: queryParams, options: { signal, ...requestOpts } }),\n enabled: !!id && createEnabledRule(token, restOptions),\n options: {\n staleTime: restOptions.staleTime ?? config.staleTime,\n gcTime: restOptions.gcTime ?? config.gcTime,\n structuralSharing: restOptions.structuralSharing ?? config.structuralSharing,\n refetchInterval: restOptions.refetchInterval,\n refetchIntervalInBackground: restOptions.refetchIntervalInBackground,\n },\n select: restOptions.select,\n });\n }\n\n // ========== useActions ==========\n\n function useActions(): CrudActions<T, TCreate, TUpdate> {\n const queryClient = useQueryClient();\n const silentRef = useRef(false);\n const shouldToast = useCallback(() => !silentRef.current, []);\n\n const createMutation = createOptimisticMutation({\n mutationFn: ({ token, organizationId, data }: MutationParams<TCreate>) =>\n api.create({ token, organizationId, data }),\n queryClient,\n queryKeys: [KEYS.lists()],\n shouldToast,\n optimisticUpdate: (oldData, { data }) => {\n const optimisticItem = {\n ...(data as object),\n _optimistic: true,\n [getItemId(data) ? \"id\" : \"_id\"]: getItemId(data) ?? `temp-${Date.now()}`,\n };\n return updateListCache(oldData, (arr: unknown[]) => [optimisticItem, ...(arr || [])]);\n },\n onSuccess: (data, variables) => {\n callbacks.onCreate?.onSuccess?.(data as T, { data: variables.data }, undefined);\n },\n onError: (error, variables) => {\n callbacks.onCreate?.onError?.(error, { data: variables.data }, undefined);\n },\n onSettled: (data, error, variables) => {\n callbacks.onCreate?.onSettled?.(data as T | undefined, error, { data: variables.data }, undefined);\n },\n messages: { success: config.messages.createSuccess, error: config.messages.createError },\n toastHandler: instanceToast,\n });\n\n const updateMutation = createOptimisticMutation({\n mutationFn: ({ token, organizationId, id, data }: UpdateParams<TUpdate>) =>\n api.update({ token, organizationId, id, data }),\n queryClient,\n queryKeys: [KEYS.lists()],\n shouldToast,\n optimisticUpdate: (oldData, { id, data }) => {\n const updated = updateListCache(oldData, (arr: unknown[]) =>\n (arr || []).map((item) => (getItemId(item) === id ? { ...(item as object), ...(data as object) } : item))\n );\n queryClient.setQueryData(KEYS.detail(id), (current: unknown) =>\n current ? { ...(current as object), data: { ...((current as { data?: object }).data || {}), ...(data as object) } } : current\n );\n return updated;\n },\n onSuccess: (data, { id, data: updateData }) => {\n queryClient.invalidateQueries({ queryKey: KEYS.detail(id) });\n callbacks.onUpdate?.onSuccess?.(data as T, { id, data: updateData }, undefined);\n },\n onError: (error, { id, data }) => {\n callbacks.onUpdate?.onError?.(error, { id, data }, undefined);\n },\n onSettled: (data, error, { id, data: updateData }) => {\n callbacks.onUpdate?.onSettled?.(data as T | undefined, error, { id, data: updateData }, undefined);\n },\n messages: { success: config.messages.updateSuccess, error: config.messages.updateError },\n toastHandler: instanceToast,\n });\n\n const deleteMutation = createOptimisticMutation({\n mutationFn: ({ token, organizationId, id }: DeleteParams) => api.delete({ token, organizationId, id }),\n queryClient,\n queryKeys: [KEYS.lists()],\n shouldToast,\n optimisticUpdate: (oldData, { id }) => {\n queryClient.removeQueries({ queryKey: KEYS.detail(id) });\n return updateListCache(oldData, (arr: unknown[]) => (arr || []).filter((item) => getItemId(item) !== id));\n },\n onSuccess: (data, { id }) => {\n callbacks.onDelete?.onSuccess?.(data, { id }, undefined);\n },\n onError: (error, { id }) => {\n callbacks.onDelete?.onError?.(error, { id }, undefined);\n },\n onSettled: (data, error, { id }) => {\n callbacks.onDelete?.onSettled?.(data, error, { id }, undefined);\n },\n messages: { success: config.messages.deleteSuccess, error: config.messages.deleteError },\n toastHandler: instanceToast,\n });\n\n const resolveAuth = <P extends { token?: string | null; organizationId?: string | null }>(params: P): P => {\n const auth = getAuthContext();\n return {\n ...params,\n token: params.token ?? auth.token,\n organizationId: params.organizationId ?? auth.organizationId,\n };\n };\n\n const create = async (params: MutationParams<TCreate>, options?: CallOptions<T>): Promise<T> => {\n silentRef.current = options?.silent ?? false;\n try {\n const result = await createMutation.mutateAsync(resolveAuth(params));\n options?.onSuccess?.(result as T);\n options?.onSettled?.(result as T, null);\n return result as T;\n } catch (error) {\n options?.onError?.(error as Error);\n options?.onSettled?.(undefined, error as Error);\n throw error;\n } finally {\n silentRef.current = false;\n }\n };\n\n const update = async (params: UpdateParams<TUpdate>, options?: CallOptions<T>): Promise<T> => {\n silentRef.current = options?.silent ?? false;\n try {\n const result = await updateMutation.mutateAsync(resolveAuth(params));\n options?.onSuccess?.(result as T);\n options?.onSettled?.(result as T, null);\n return result as T;\n } catch (error) {\n options?.onError?.(error as Error);\n options?.onSettled?.(undefined, error as Error);\n throw error;\n } finally {\n silentRef.current = false;\n }\n };\n\n const remove = async (params: DeleteParams, options?: CallOptions): Promise<unknown> => {\n silentRef.current = options?.silent ?? false;\n try {\n const result = await deleteMutation.mutateAsync(resolveAuth(params));\n options?.onSuccess?.(result);\n options?.onSettled?.(result, null);\n return result;\n } catch (error) {\n options?.onError?.(error as Error);\n options?.onSettled?.(undefined, error as Error);\n throw error;\n } finally {\n silentRef.current = false;\n }\n };\n\n return {\n create,\n update,\n remove,\n isCreating: createMutation.isPending,\n isUpdating: updateMutation.isPending,\n isDeleting: deleteMutation.isPending,\n isMutating: createMutation.isPending || updateMutation.isPending || deleteMutation.isPending,\n };\n }\n\n // ========== useInfiniteList ==========\n\n function useInfiniteList(\n tokenOrParams?: string | null | Record<string, unknown>,\n paramsOrOptions?: Record<string, unknown> | InfiniteListQueryOptions,\n maybeOptions?: InfiniteListQueryOptions,\n ): InfiniteListQueryResult<T> {\n let token: string | null;\n let params: Record<string, unknown>;\n let options: InfiniteListQueryOptions;\n\n if (tokenOrParams === null || typeof tokenOrParams === 'string') {\n token = tokenOrParams;\n params = (paramsOrOptions as Record<string, unknown>) ?? {};\n options = maybeOptions ?? {};\n } else {\n const auth = getAuthContext();\n token = auth.token;\n params = (tokenOrParams as Record<string, unknown>) ?? {};\n options = (paramsOrOptions as InfiniteListQueryOptions) ?? {};\n if (auth.organizationId && !params.organizationId) {\n params = { ...params, organizationId: auth.organizationId };\n }\n }\n\n const { organizationId, ...restParams } = params;\n const scope = options._scope || (organizationId ? \"tenant\" : \"super-admin\");\n const { request: requestOpts, ...queryOpts } = options;\n\n return createInfiniteListQuery<T>({\n queryKey: [...KEYS.scopedList(scope, { organizationId, ...restParams }), 'infinite'],\n queryFn: ({ pageParam, signal }) => {\n const paginationParams = typeof pageParam === 'string'\n ? { after: pageParam }\n : { page: pageParam };\n\n return api.getAll({\n token,\n organizationId: organizationId as string | null,\n params: { ...restParams, ...paginationParams },\n options: { signal, ...requestOpts },\n });\n },\n enabled: createEnabledRule(token, queryOpts),\n initialPageParam: restParams.after ? restParams.after : 1,\n getNextPageParam: (lastPage) => {\n const page = lastPage as PaginatedResponse<T>;\n if (isKeysetPagination(page)) {\n return page.hasMore ? page.next : undefined;\n }\n if (isOffsetPagination(page)) {\n return page.hasNext ? page.page + 1 : undefined;\n }\n // Fallback: check common pagination fields\n const p = page as unknown as Record<string, unknown>;\n if (typeof p.hasNext === 'boolean' && typeof p.page === 'number') {\n return p.hasNext ? (p.page as number) + 1 : undefined;\n }\n return undefined;\n },\n options: {\n staleTime: queryOpts.staleTime ?? config.staleTime,\n gcTime: queryOpts.gcTime ?? config.gcTime,\n refetchOnWindowFocus: queryOpts.refetchOnWindowFocus ?? config.refetchOnWindowFocus,\n structuralSharing: queryOpts.structuralSharing ?? config.structuralSharing,\n },\n });\n }\n\n // ========== useUpload ==========\n\n function useUpload(options?: {\n invalidateQueries?: QueryKey[];\n messages?: MutationMessages;\n onSuccess?: (data: unknown) => void;\n onError?: (error: Error) => void;\n onSettled?: (data: unknown | undefined, error: Error | null) => void;\n }) {\n if (!api.upload) {\n throw new Error(`[arc-next] \"${entityKey}\" api does not define an upload method`);\n }\n\n const uploadApi = api.upload;\n\n return useMutationWithTransition<unknown, { data: FormData; id?: string; path?: string }>({\n mutationFn: ({ data, id, path }) => {\n const auth = getAuthContext();\n return uploadApi({ token: auth.token, organizationId: auth.organizationId, data, id, path });\n },\n invalidateQueries: options?.invalidateQueries ?? [KEYS.lists()],\n onSuccess: (data) => options?.onSuccess?.(data),\n onError: (error) => options?.onError?.(error),\n onSettled: (data, error) => options?.onSettled?.(data, error),\n messages: options?.messages ?? {\n success: `${singular} uploaded successfully`,\n error: `Failed to upload ${singular.toLowerCase()}`,\n },\n toastHandler: instanceToast,\n });\n }\n\n // ========== useSearch ==========\n\n function useSearch(\n query: string,\n params?: Record<string, unknown>,\n options?: ListQueryOptions<T>,\n ): ListQueryResult<T> {\n if (!api.search) {\n throw new Error(`[arc-next] \"${entityKey}\" api does not define a search method`);\n }\n\n const searchApi = api.search;\n const auth = getAuthContext();\n const token = auth.token;\n const organizationId = params?.organizationId as string | null ?? auth.organizationId;\n const { organizationId: _, ...restParams } = params ?? {};\n const searchParams = { q: query, ...restParams };\n const { request: requestOpts, ...queryOpts } = options ?? {};\n\n // Include organizationId in query key when present to isolate per-tenant search cache\n const searchKeyParams = organizationId\n ? { organizationId, ...searchParams }\n : searchParams;\n\n return createListQuery<T>({\n queryKey: [...KEYS.lists(), 'search', searchKeyParams],\n queryFn: ({ signal }) => searchApi({\n token,\n organizationId,\n params: searchParams,\n options: { signal, ...requestOpts },\n }),\n enabled: query.length > 0 && createEnabledRule(token, queryOpts),\n options: {\n staleTime: queryOpts.staleTime ?? config.staleTime,\n gcTime: queryOpts.gcTime ?? config.gcTime,\n },\n select: queryOpts.select,\n });\n }\n\n // ========== useCustomMutation ==========\n\n function useCustomMutation<TData = unknown, TVariables = unknown>(mutationConfig: {\n mutationFn: (variables: TVariables) => Promise<TData>;\n invalidateQueries?: QueryKey[];\n messages?: MutationMessages;\n onSuccess?: (data: TData, variables: TVariables) => void;\n onError?: (error: Error, variables: TVariables) => void;\n onSettled?: (data: TData | undefined, error: Error | null, variables: TVariables) => void;\n }) {\n return useMutationWithTransition<TData, TVariables>({\n mutationFn: mutationConfig.mutationFn,\n invalidateQueries: mutationConfig.invalidateQueries ?? [KEYS.lists()],\n onSuccess: mutationConfig.onSuccess,\n onError: mutationConfig.onError,\n onSettled: mutationConfig.onSettled,\n messages: mutationConfig.messages,\n toastHandler: instanceToast,\n });\n }\n\n // ========== useNavigation ==========\n\n function useNavigation(): NavigateFn<T> {\n const queryClient = useQueryClient();\n const activeRouterHook = instanceNavigation ?? useRouterHook;\n const router = activeRouterHook?.();\n\n return useCallback(\n (href: string, item: T, options: NavigationOptions = {}) => {\n const id = getItemId(item);\n if (id) {\n queryClient.setQueryData(KEYS.detail(id), { data: item });\n }\n\n if (!router) return;\n\n const { scroll = true, replace = false } = options;\n if (replace) {\n router.replace(href, { scroll });\n } else {\n router.push(href, { scroll });\n }\n },\n [queryClient, router]\n );\n }\n\n return {\n KEYS,\n cache,\n useList,\n useDetail,\n useInfiniteList,\n useActions,\n useUpload,\n useSearch,\n useCustomMutation,\n useNavigation,\n };\n}\n"],"mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  import { ToastHandler } from "./client.js";
2
2
  import * as _tanstack_react_query0 from "@tanstack/react-query";
3
- import { QueryClient, QueryKey } from "@tanstack/react-query";
3
+ import { QueryClient, QueryKey, UseMutateAsyncFunction, UseMutateFunction } from "@tanstack/react-query";
4
4
 
5
5
  //#region src/mutation.d.ts
6
6
  interface MutationMessages {
@@ -13,6 +13,16 @@ interface MutationCallbacks<TData, TVariables, TContext = unknown> {
13
13
  onError?: (error: Error, variables: TVariables, context: TContext) => void | Promise<void>;
14
14
  onSettled?: (data: TData | undefined, error: Error | null, variables: TVariables, context: TContext) => void | Promise<void>;
15
15
  }
16
+ interface TransitionMutationReturn<TData, TVariables> {
17
+ mutate: UseMutateFunction<TData, Error, TVariables>;
18
+ mutateAsync: UseMutateAsyncFunction<TData, Error, TVariables>;
19
+ isPending: boolean;
20
+ isSuccess: boolean;
21
+ isError: boolean;
22
+ error: Error | null;
23
+ data: TData | undefined;
24
+ reset: () => void;
25
+ }
16
26
  /**
17
27
  * Configure toast handler. Call once at app init.
18
28
  *
@@ -30,11 +40,13 @@ interface TransitionMutationConfig<TData, TVariables> {
30
40
  messages?: MutationMessages;
31
41
  useTransition?: boolean;
32
42
  showToast?: boolean;
43
+ /** Per-call toast guard — return false to suppress toast for this invocation */
44
+ shouldToast?: () => boolean;
33
45
  toastHandler?: ToastHandler;
34
46
  }
35
47
  declare function useMutationWithTransition<TData, TVariables>(config: TransitionMutationConfig<TData, TVariables>): {
36
- mutate: _tanstack_react_query0.UseMutateFunction<TData, Error, TVariables, unknown>;
37
- mutateAsync: _tanstack_react_query0.UseMutateAsyncFunction<TData, Error, TVariables, unknown>;
48
+ mutate: UseMutateFunction<TData, Error, TVariables, unknown>;
49
+ mutateAsync: UseMutateAsyncFunction<TData, Error, TVariables, unknown>;
38
50
  isPending: boolean;
39
51
  isSuccess: boolean;
40
52
  isError: boolean;
@@ -54,13 +66,13 @@ interface OptimisticMutationConfig<TData, TVariables> {
54
66
  toastHandler?: ToastHandler;
55
67
  }
56
68
  declare function useMutationWithOptimistic<TData, TVariables>(config: OptimisticMutationConfig<TData, TVariables>): {
57
- mutate: _tanstack_react_query0.UseMutateFunction<TData, Error, TVariables, {
69
+ mutate: UseMutateFunction<TData, Error, TVariables, {
58
70
  previous: {
59
71
  key: readonly unknown[];
60
72
  data: unknown;
61
73
  }[];
62
74
  }>;
63
- mutateAsync: _tanstack_react_query0.UseMutateAsyncFunction<TData, Error, TVariables, {
75
+ mutateAsync: UseMutateAsyncFunction<TData, Error, TVariables, {
64
76
  previous: {
65
77
  key: readonly unknown[];
66
78
  data: unknown;
@@ -80,19 +92,13 @@ interface CreateOptimisticMutationConfig<TData, TVariables> {
80
92
  optimisticUpdate?: (oldData: unknown, variables: TVariables) => unknown;
81
93
  onSuccess?: (data: TData, variables: TVariables) => void;
82
94
  onError?: (error: Error, variables: TVariables) => void;
95
+ onSettled?: (data: TData | undefined, error: Error | null, variables: TVariables) => void;
83
96
  messages?: MutationMessages;
97
+ /** Per-call toast guard — return false to suppress toast for this invocation */
98
+ shouldToast?: () => boolean;
84
99
  toastHandler?: ToastHandler;
85
100
  }
86
- declare function createOptimisticMutation<TData, TVariables>({
87
- mutationFn,
88
- queryClient,
89
- queryKeys,
90
- optimisticUpdate,
91
- onSuccess,
92
- onError,
93
- messages,
94
- toastHandler: instanceToast
95
- }: CreateOptimisticMutationConfig<TData, TVariables>): _tanstack_react_query0.UseMutationResult<TData, Error, TVariables, {
101
+ declare function createOptimisticMutation<TData, TVariables>(config: CreateOptimisticMutationConfig<TData, TVariables>): _tanstack_react_query0.UseMutationResult<TData, Error, TVariables, {
96
102
  previous: {
97
103
  key: readonly unknown[];
98
104
  data: [readonly unknown[], unknown][];
@@ -114,5 +120,5 @@ declare const QUERY_CONFIGS: {
114
120
  };
115
121
  };
116
122
  //#endregion
117
- export { CreateOptimisticMutationConfig, MutationCallbacks, MutationMessages, OptimisticMutationConfig, QUERY_CONFIGS, type ToastHandler, TransitionMutationConfig, configureToast, createOptimisticMutation, useMutationWithOptimistic, useMutationWithTransition };
123
+ export { CreateOptimisticMutationConfig, MutationCallbacks, MutationMessages, OptimisticMutationConfig, QUERY_CONFIGS, type ToastHandler, TransitionMutationConfig, TransitionMutationReturn, configureToast, createOptimisticMutation, useMutationWithOptimistic, useMutationWithTransition };
118
124
  //# sourceMappingURL=mutation.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"mutation.d.ts","names":[],"sources":["../src/mutation.ts"],"mappings":";;;;;UAciB,gBAAA;EACf,OAAA,cAAqB,IAAA,WAAe,SAAA;EACpC,KAAA,cAAmB,KAAA,EAAO,KAAA,EAAO,SAAA;AAAA;AAAA,UAGlB,iBAAA;EACf,QAAA,IAAY,SAAA,EAAW,UAAA,KAAe,QAAA,GAAW,OAAA,CAAQ,QAAA;EACzD,SAAA,IAAa,IAAA,EAAM,KAAA,EAAO,SAAA,EAAW,UAAA,EAAY,OAAA,EAAS,QAAA,YAAoB,OAAA;EAC9E,OAAA,IAAW,KAAA,EAAO,KAAA,EAAO,SAAA,EAAW,UAAA,EAAY,OAAA,EAAS,QAAA,YAAoB,OAAA;EAC7E,SAAA,IAAa,IAAA,EAAM,KAAA,cAAmB,KAAA,EAAO,KAAA,SAAc,SAAA,EAAW,UAAA,EAAY,OAAA,EAAS,QAAA,YAAoB,OAAA;AAAA;;;;;;AAJjH;;iBAuBgB,cAAA,CAAe,OAAA,EAAS,YAAA;AAAA,UAyCvB,wBAAA;EACf,UAAA,GAAa,SAAA,EAAW,UAAA,KAAe,OAAA,CAAQ,KAAA;EAC/C,iBAAA,GAAoB,QAAA;EACpB,SAAA,IAAa,IAAA,EAAM,KAAA,EAAO,SAAA,EAAW,UAAA;EACrC,OAAA,IAAW,KAAA,EAAO,KAAA,EAAO,SAAA,EAAW,UAAA;EACpC,SAAA,IAAa,IAAA,EAAM,KAAA,cAAmB,KAAA,EAAO,KAAA,SAAc,SAAA,EAAW,UAAA;EACtE,QAAA,GAAW,gBAAA;EACX,aAAA;EACA,SAAA;EACA,YAAA,GAAe,YAAA;AAAA;AAAA,iBAGD,yBAAA,mBAAA,CAA6C,MAAA,EAAQ,wBAAA,CAAyB,KAAA,EAAO,UAAA;;;;;;SAkDxE,KAAA;;;;UAUZ,wBAAA;EACf,UAAA,GAAa,SAAA,EAAW,UAAA,KAAe,OAAA,CAAQ,KAAA;EAC/C,SAAA,GAAY,QAAA;EACZ,gBAAA,IAAoB,OAAA,WAAkB,SAAA,EAAW,UAAA;EACjD,SAAA,IAAa,IAAA,EAAM,KAAA,EAAO,SAAA,EAAW,UAAA;EACrC,OAAA,IAAW,KAAA,EAAO,KAAA,EAAO,SAAA,EAAW,UAAA;EACpC,SAAA,IAAa,IAAA,EAAM,KAAA,cAAmB,KAAA,EAAO,KAAA,SAAc,SAAA,EAAW,UAAA;EACtE,QAAA,GAAW,gBAAA;EACX,SAAA;EACA,YAAA,GAAe,YAAA;AAAA;AAAA,iBAGD,yBAAA,mBAAA,CAA6C,MAAA,EAAQ,wBAAA,CAAyB,KAAA,EAAO,UAAA;;;;;;;;;;;;;;;;SA4DxE,KAAA;;;;UAUZ,8BAAA;EACf,UAAA,GAAa,SAAA,EAAW,UAAA,KAAe,OAAA,CAAQ,KAAA;EAC/C,WAAA,EAAa,WAAA;EACb,SAAA,EAAW,QAAA;EACX,gBAAA,IAAoB,OAAA,WAAkB,SAAA,EAAW,UAAA;EACjD,SAAA,IAAa,IAAA,EAAM,KAAA,EAAO,SAAA,EAAW,UAAA;EACrC,OAAA,IAAW,KAAA,EAAO,KAAA,EAAO,SAAA,EAAW,UAAA;EACpC,QAAA,GAAW,gBAAA;EACX,YAAA,GAAe,YAAA;AAAA;AAAA,iBAGD,wBAAA,mBAAA,CAAA;EACd,UAAA;EACA,WAAA;EACA,SAAA;EACA,gBAAA;EACA,SAAA;EACA,OAAA;EACA,QAAA;EACA,YAAA,EAAc;AAAA,GACb,8BAAA,CAA+B,KAAA,EAAO,UAAA,IAAW,sBAAA,CAAA,iBAAA,CAAA,KAAA,EAAA,KAAA,EAAA,UAAA;;;;;;cA6CvC,aAAA;EAAA"}
1
+ {"version":3,"file":"mutation.d.ts","names":[],"sources":["../src/mutation.ts"],"mappings":"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"}
package/dist/mutation.js CHANGED
@@ -49,11 +49,11 @@ function useMutationWithTransition(config) {
49
49
  };
50
50
  if (withTransition && invalidateQueries.length > 0) startTransition(invalidate);
51
51
  else invalidate();
52
- if (toast) showToast("success", messages, data, variables, void 0, instanceToast);
52
+ if (toast && (config.shouldToast?.() ?? true)) showToast("success", messages, data, variables, void 0, instanceToast);
53
53
  onSuccess?.(data, variables);
54
54
  },
55
55
  onError: (error, variables) => {
56
- if (toast) showToast("error", messages, null, variables, error, instanceToast);
56
+ if (toast && (config.shouldToast?.() ?? true)) showToast("error", messages, null, variables, error, instanceToast);
57
57
  onError?.(error, variables);
58
58
  },
59
59
  onSettled: (data, error, variables) => {
@@ -112,7 +112,8 @@ function useMutationWithOptimistic(config) {
112
112
  reset: mutation.reset
113
113
  };
114
114
  }
115
- function createOptimisticMutation({ mutationFn, queryClient, queryKeys, optimisticUpdate, onSuccess, onError, messages, toastHandler: instanceToast }) {
115
+ function createOptimisticMutation(config) {
116
+ const { mutationFn, queryClient, queryKeys, optimisticUpdate, onSuccess, onError, onSettled, messages, toastHandler: instanceToast } = config;
116
117
  return useMutation({
117
118
  mutationFn,
118
119
  onMutate: async (variables) => {
@@ -132,7 +133,7 @@ function createOptimisticMutation({ mutationFn, queryClient, queryKeys, optimist
132
133
  return { previous };
133
134
  },
134
135
  onSuccess: (data, variables) => {
135
- if (messages?.success) showToast("success", messages, data, variables, void 0, instanceToast);
136
+ if ((config.shouldToast?.() ?? true) && messages?.success) showToast("success", messages, data, variables, void 0, instanceToast);
136
137
  queryKeys.forEach((key) => queryClient.invalidateQueries({ queryKey: key }));
137
138
  onSuccess?.(data, variables);
138
139
  },
@@ -140,8 +141,11 @@ function createOptimisticMutation({ mutationFn, queryClient, queryKeys, optimist
140
141
  context?.previous?.forEach(({ data }) => {
141
142
  data.forEach(([qKey, qData]) => queryClient.setQueryData(qKey, qData));
142
143
  });
143
- showToast("error", messages, null, variables, error, instanceToast);
144
+ if (config.shouldToast?.() ?? true) showToast("error", messages, null, variables, error, instanceToast);
144
145
  onError?.(error, variables);
146
+ },
147
+ onSettled: (data, error, variables) => {
148
+ onSettled?.(data, error, variables);
145
149
  }
146
150
  });
147
151
  }
@@ -1 +1 @@
1
- {"version":3,"file":"mutation.js","names":[],"sources":["../src/mutation.ts"],"sourcesContent":["\"use client\";\n\nimport { useMutation, useQueryClient, type QueryClient, type QueryKey } from \"@tanstack/react-query\";\nimport { useTransition } from \"react\";\nimport { isArcApiError } from \"./client.js\";\nimport type { ToastHandler } from \"./client.js\";\n\n// Re-export for backward compatibility\nexport type { ToastHandler } from \"./client.js\";\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface MutationMessages {\n success?: string | ((data: unknown, variables: unknown) => string);\n error?: string | ((error: Error, variables: unknown) => string);\n}\n\nexport interface MutationCallbacks<TData, TVariables, TContext = unknown> {\n onMutate?: (variables: TVariables) => TContext | Promise<TContext>;\n onSuccess?: (data: TData, variables: TVariables, context: TContext) => void | Promise<void>;\n onError?: (error: Error, variables: TVariables, context: TContext) => void | Promise<void>;\n onSettled?: (data: TData | undefined, error: Error | null, variables: TVariables, context: TContext) => void | Promise<void>;\n}\n\n// ============================================================================\n// Toast Configuration\n// ============================================================================\n\nlet toastHandler: ToastHandler = {\n success: (msg) => console.log(\"[Success]\", msg),\n error: (msg) => console.error(\"[Error]\", msg),\n};\n\n/**\n * Configure toast handler. Call once at app init.\n *\n * @example\n * import { toast } from \"sonner\";\n * configureToast({ success: toast.success, error: toast.error });\n */\nexport function configureToast(handler: ToastHandler): void {\n toastHandler = handler;\n}\n\nfunction showToast(\n type: \"success\" | \"error\",\n messages: MutationMessages | undefined,\n data: unknown,\n variables: unknown,\n error?: Error,\n handler?: ToastHandler,\n) {\n const activeHandler = handler ?? toastHandler;\n\n if (type === \"success\") {\n const msg = messages?.success;\n if (!msg) return;\n\n const text = typeof msg === \"function\" ? msg(data, variables) : msg;\n activeHandler.success(text);\n } else {\n const msg = messages?.error;\n let defaultMsg = error?.message || \"An error occurred\";\n if (isArcApiError(error) && error.fieldErrors) {\n const fields = Object.entries(error.fieldErrors);\n if (fields.length > 0) {\n defaultMsg = fields.map(([k, v]) => `${k}: ${v}`).join(', ');\n }\n }\n const text = typeof msg === \"function\"\n ? msg(error as Error, variables)\n : msg || defaultMsg;\n\n activeHandler.error(text);\n }\n}\n\n// ============================================================================\n// Mutation with React 19 Transitions\n// ============================================================================\n\nexport interface TransitionMutationConfig<TData, TVariables> {\n mutationFn: (variables: TVariables) => Promise<TData>;\n invalidateQueries?: QueryKey[];\n onSuccess?: (data: TData, variables: TVariables) => void;\n onError?: (error: Error, variables: TVariables) => void;\n onSettled?: (data: TData | undefined, error: Error | null, variables: TVariables) => void;\n messages?: MutationMessages;\n useTransition?: boolean;\n showToast?: boolean;\n toastHandler?: ToastHandler;\n}\n\nexport function useMutationWithTransition<TData, TVariables>(config: TransitionMutationConfig<TData, TVariables>) {\n const {\n mutationFn,\n invalidateQueries = [],\n onSuccess,\n onError,\n onSettled,\n messages,\n useTransition: withTransition = true,\n showToast: toast = true,\n toastHandler: instanceToast,\n } = config;\n\n const queryClient = useQueryClient();\n const [isTransitioning, startTransition] = useTransition();\n\n const mutation = useMutation({\n mutationFn,\n\n onSuccess: (data, variables) => {\n const invalidate = () => {\n invalidateQueries.forEach((key) => queryClient.invalidateQueries({ queryKey: key }));\n };\n\n if (withTransition && invalidateQueries.length > 0) {\n startTransition(invalidate);\n } else {\n invalidate();\n }\n\n if (toast) showToast(\"success\", messages, data, variables, undefined, instanceToast);\n onSuccess?.(data, variables);\n },\n\n onError: (error, variables) => {\n if (toast) showToast(\"error\", messages, null, variables, error as Error, instanceToast);\n onError?.(error as Error, variables);\n },\n\n onSettled: (data, error, variables) => {\n onSettled?.(data, error as Error | null, variables);\n },\n });\n\n return {\n mutate: mutation.mutate,\n mutateAsync: mutation.mutateAsync,\n isPending: mutation.isPending || isTransitioning,\n isSuccess: mutation.isSuccess,\n isError: mutation.isError,\n error: mutation.error as Error | null,\n data: mutation.data,\n reset: mutation.reset,\n };\n}\n\n// ============================================================================\n// Mutation with Optimistic Updates\n// ============================================================================\n\nexport interface OptimisticMutationConfig<TData, TVariables> {\n mutationFn: (variables: TVariables) => Promise<TData>;\n queryKeys?: QueryKey[];\n optimisticUpdate?: (oldData: unknown, variables: TVariables) => unknown;\n onSuccess?: (data: TData, variables: TVariables) => void;\n onError?: (error: Error, variables: TVariables) => void;\n onSettled?: (data: TData | undefined, error: Error | null, variables: TVariables) => void;\n messages?: MutationMessages;\n showToast?: boolean;\n toastHandler?: ToastHandler;\n}\n\nexport function useMutationWithOptimistic<TData, TVariables>(config: OptimisticMutationConfig<TData, TVariables>) {\n const {\n mutationFn,\n queryKeys = [],\n optimisticUpdate,\n onSuccess,\n onError,\n onSettled,\n messages,\n showToast: toast = true,\n toastHandler: instanceToast,\n } = config;\n\n const queryClient = useQueryClient();\n\n const mutation = useMutation({\n mutationFn,\n\n onMutate: async (variables) => {\n await Promise.all(queryKeys.map((key) => queryClient.cancelQueries({ queryKey: key })));\n\n const previous = queryKeys.map((key) => ({\n key,\n data: queryClient.getQueryData(key),\n }));\n\n if (optimisticUpdate) {\n queryKeys.forEach((key) => {\n queryClient.setQueryData(key, (old: unknown) => optimisticUpdate(old, variables));\n });\n }\n\n return { previous };\n },\n\n onSuccess: (data, variables) => {\n queryKeys.forEach((key) => queryClient.invalidateQueries({ queryKey: key }));\n if (toast) showToast(\"success\", messages, data, variables, undefined, instanceToast);\n onSuccess?.(data, variables);\n },\n\n onError: (error, variables, context) => {\n const ctx = context as { previous?: Array<{ key: QueryKey; data: unknown }> };\n ctx?.previous?.forEach(({ key, data }) => queryClient.setQueryData(key, data));\n\n if (toast) showToast(\"error\", messages, null, variables, error as Error, instanceToast);\n onError?.(error as Error, variables);\n },\n\n onSettled: (data, error, variables) => {\n onSettled?.(data, error as Error | null, variables);\n },\n });\n\n return {\n mutate: mutation.mutate,\n mutateAsync: mutation.mutateAsync,\n isPending: mutation.isPending,\n isSuccess: mutation.isSuccess,\n isError: mutation.isError,\n error: mutation.error as Error | null,\n data: mutation.data,\n reset: mutation.reset,\n };\n}\n\n// ============================================================================\n// Optimistic Mutation for CRUD Factory (handles multiple matching queries)\n// ============================================================================\n\nexport interface CreateOptimisticMutationConfig<TData, TVariables> {\n mutationFn: (variables: TVariables) => Promise<TData>;\n queryClient: QueryClient;\n queryKeys: QueryKey[];\n optimisticUpdate?: (oldData: unknown, variables: TVariables) => unknown;\n onSuccess?: (data: TData, variables: TVariables) => void;\n onError?: (error: Error, variables: TVariables) => void;\n messages?: MutationMessages;\n toastHandler?: ToastHandler;\n}\n\nexport function createOptimisticMutation<TData, TVariables>({\n mutationFn,\n queryClient,\n queryKeys,\n optimisticUpdate,\n onSuccess,\n onError,\n messages,\n toastHandler: instanceToast,\n}: CreateOptimisticMutationConfig<TData, TVariables>) {\n return useMutation({\n mutationFn,\n\n onMutate: async (variables) => {\n await Promise.all(queryKeys.map((key) => queryClient.cancelQueries({ queryKey: key, exact: false })));\n\n const previous = queryKeys.map((key) => ({\n key,\n data: queryClient.getQueriesData({ queryKey: key }),\n }));\n\n if (optimisticUpdate) {\n queryKeys.forEach((key) => {\n queryClient.getQueriesData({ queryKey: key }).forEach(([qKey, qData]) => {\n queryClient.setQueryData(qKey, optimisticUpdate(qData, variables));\n });\n });\n }\n\n return { previous };\n },\n\n onSuccess: (data, variables) => {\n if (messages?.success) showToast(\"success\", messages, data, variables, undefined, instanceToast);\n queryKeys.forEach((key) => queryClient.invalidateQueries({ queryKey: key }));\n onSuccess?.(data, variables);\n },\n\n onError: (error, variables, context) => {\n const ctx = context as { previous?: Array<{ key: QueryKey; data: Array<[QueryKey, unknown]> }> };\n ctx?.previous?.forEach(({ data }) => {\n data.forEach(([qKey, qData]) => queryClient.setQueryData(qKey, qData));\n });\n\n showToast(\"error\", messages, null, variables, error as Error, instanceToast);\n onError?.(error as Error, variables);\n },\n });\n}\n\n// ============================================================================\n// Query Config Presets\n// ============================================================================\n\nexport const QUERY_CONFIGS = {\n realtime: { staleTime: 20_000, refetchInterval: 30_000 },\n frequent: { staleTime: 60_000 },\n stable: { staleTime: 300_000 },\n static: { staleTime: 600_000 },\n} as const;\n"],"mappings":"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"}
1
+ {"version":3,"file":"mutation.js","names":[],"sources":["../src/mutation.ts"],"sourcesContent":["\"use client\";\n\nimport { useMutation, useQueryClient, type QueryClient, type QueryKey, type UseMutateFunction, type UseMutateAsyncFunction } from \"@tanstack/react-query\";\nimport { useTransition } from \"react\";\nimport { isArcApiError } from \"./client.js\";\nimport type { ToastHandler } from \"./client.js\";\n\n// Re-export for backward compatibility\nexport type { ToastHandler } from \"./client.js\";\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface MutationMessages {\n success?: string | ((data: unknown, variables: unknown) => string);\n error?: string | ((error: Error, variables: unknown) => string);\n}\n\nexport interface MutationCallbacks<TData, TVariables, TContext = unknown> {\n onMutate?: (variables: TVariables) => TContext | Promise<TContext>;\n onSuccess?: (data: TData, variables: TVariables, context: TContext) => void | Promise<void>;\n onError?: (error: Error, variables: TVariables, context: TContext) => void | Promise<void>;\n onSettled?: (data: TData | undefined, error: Error | null, variables: TVariables, context: TContext) => void | Promise<void>;\n}\n\nexport interface TransitionMutationReturn<TData, TVariables> {\n mutate: UseMutateFunction<TData, Error, TVariables>;\n mutateAsync: UseMutateAsyncFunction<TData, Error, TVariables>;\n isPending: boolean;\n isSuccess: boolean;\n isError: boolean;\n error: Error | null;\n data: TData | undefined;\n reset: () => void;\n}\n\n// ============================================================================\n// Toast Configuration\n// ============================================================================\n\nlet toastHandler: ToastHandler = {\n success: (msg) => console.log(\"[Success]\", msg),\n error: (msg) => console.error(\"[Error]\", msg),\n};\n\n/**\n * Configure toast handler. Call once at app init.\n *\n * @example\n * import { toast } from \"sonner\";\n * configureToast({ success: toast.success, error: toast.error });\n */\nexport function configureToast(handler: ToastHandler): void {\n toastHandler = handler;\n}\n\nfunction showToast(\n type: \"success\" | \"error\",\n messages: MutationMessages | undefined,\n data: unknown,\n variables: unknown,\n error?: Error,\n handler?: ToastHandler,\n) {\n const activeHandler = handler ?? toastHandler;\n\n if (type === \"success\") {\n const msg = messages?.success;\n if (!msg) return;\n\n const text = typeof msg === \"function\" ? msg(data, variables) : msg;\n activeHandler.success(text);\n } else {\n const msg = messages?.error;\n let defaultMsg = error?.message || \"An error occurred\";\n if (isArcApiError(error) && error.fieldErrors) {\n const fields = Object.entries(error.fieldErrors);\n if (fields.length > 0) {\n defaultMsg = fields.map(([k, v]) => `${k}: ${v}`).join(', ');\n }\n }\n const text = typeof msg === \"function\"\n ? msg(error as Error, variables)\n : msg || defaultMsg;\n\n activeHandler.error(text);\n }\n}\n\n// ============================================================================\n// Mutation with React 19 Transitions\n// ============================================================================\n\nexport interface TransitionMutationConfig<TData, TVariables> {\n mutationFn: (variables: TVariables) => Promise<TData>;\n invalidateQueries?: QueryKey[];\n onSuccess?: (data: TData, variables: TVariables) => void;\n onError?: (error: Error, variables: TVariables) => void;\n onSettled?: (data: TData | undefined, error: Error | null, variables: TVariables) => void;\n messages?: MutationMessages;\n useTransition?: boolean;\n showToast?: boolean;\n /** Per-call toast guard — return false to suppress toast for this invocation */\n shouldToast?: () => boolean;\n toastHandler?: ToastHandler;\n}\n\nexport function useMutationWithTransition<TData, TVariables>(config: TransitionMutationConfig<TData, TVariables>) {\n const {\n mutationFn,\n invalidateQueries = [],\n onSuccess,\n onError,\n onSettled,\n messages,\n useTransition: withTransition = true,\n showToast: toast = true,\n toastHandler: instanceToast,\n } = config;\n\n const queryClient = useQueryClient();\n const [isTransitioning, startTransition] = useTransition();\n\n const mutation = useMutation({\n mutationFn,\n\n onSuccess: (data, variables) => {\n const invalidate = () => {\n invalidateQueries.forEach((key) => queryClient.invalidateQueries({ queryKey: key }));\n };\n\n if (withTransition && invalidateQueries.length > 0) {\n startTransition(invalidate);\n } else {\n invalidate();\n }\n\n const doToast = toast && (config.shouldToast?.() ?? true);\n if (doToast) showToast(\"success\", messages, data, variables, undefined, instanceToast);\n onSuccess?.(data, variables);\n },\n\n onError: (error, variables) => {\n const doToast = toast && (config.shouldToast?.() ?? true);\n if (doToast) showToast(\"error\", messages, null, variables, error as Error, instanceToast);\n onError?.(error as Error, variables);\n },\n\n onSettled: (data, error, variables) => {\n onSettled?.(data, error as Error | null, variables);\n },\n });\n\n return {\n mutate: mutation.mutate,\n mutateAsync: mutation.mutateAsync,\n isPending: mutation.isPending || isTransitioning,\n isSuccess: mutation.isSuccess,\n isError: mutation.isError,\n error: mutation.error as Error | null,\n data: mutation.data,\n reset: mutation.reset,\n };\n}\n\n// ============================================================================\n// Mutation with Optimistic Updates\n// ============================================================================\n\nexport interface OptimisticMutationConfig<TData, TVariables> {\n mutationFn: (variables: TVariables) => Promise<TData>;\n queryKeys?: QueryKey[];\n optimisticUpdate?: (oldData: unknown, variables: TVariables) => unknown;\n onSuccess?: (data: TData, variables: TVariables) => void;\n onError?: (error: Error, variables: TVariables) => void;\n onSettled?: (data: TData | undefined, error: Error | null, variables: TVariables) => void;\n messages?: MutationMessages;\n showToast?: boolean;\n toastHandler?: ToastHandler;\n}\n\nexport function useMutationWithOptimistic<TData, TVariables>(config: OptimisticMutationConfig<TData, TVariables>) {\n const {\n mutationFn,\n queryKeys = [],\n optimisticUpdate,\n onSuccess,\n onError,\n onSettled,\n messages,\n showToast: toast = true,\n toastHandler: instanceToast,\n } = config;\n\n const queryClient = useQueryClient();\n\n const mutation = useMutation({\n mutationFn,\n\n onMutate: async (variables) => {\n await Promise.all(queryKeys.map((key) => queryClient.cancelQueries({ queryKey: key })));\n\n const previous = queryKeys.map((key) => ({\n key,\n data: queryClient.getQueryData(key),\n }));\n\n if (optimisticUpdate) {\n queryKeys.forEach((key) => {\n queryClient.setQueryData(key, (old: unknown) => optimisticUpdate(old, variables));\n });\n }\n\n return { previous };\n },\n\n onSuccess: (data, variables) => {\n queryKeys.forEach((key) => queryClient.invalidateQueries({ queryKey: key }));\n if (toast) showToast(\"success\", messages, data, variables, undefined, instanceToast);\n onSuccess?.(data, variables);\n },\n\n onError: (error, variables, context) => {\n const ctx = context as { previous?: Array<{ key: QueryKey; data: unknown }> };\n ctx?.previous?.forEach(({ key, data }) => queryClient.setQueryData(key, data));\n\n if (toast) showToast(\"error\", messages, null, variables, error as Error, instanceToast);\n onError?.(error as Error, variables);\n },\n\n onSettled: (data, error, variables) => {\n onSettled?.(data, error as Error | null, variables);\n },\n });\n\n return {\n mutate: mutation.mutate,\n mutateAsync: mutation.mutateAsync,\n isPending: mutation.isPending,\n isSuccess: mutation.isSuccess,\n isError: mutation.isError,\n error: mutation.error as Error | null,\n data: mutation.data,\n reset: mutation.reset,\n };\n}\n\n// ============================================================================\n// Optimistic Mutation for CRUD Factory (handles multiple matching queries)\n// ============================================================================\n\nexport interface CreateOptimisticMutationConfig<TData, TVariables> {\n mutationFn: (variables: TVariables) => Promise<TData>;\n queryClient: QueryClient;\n queryKeys: QueryKey[];\n optimisticUpdate?: (oldData: unknown, variables: TVariables) => unknown;\n onSuccess?: (data: TData, variables: TVariables) => void;\n onError?: (error: Error, variables: TVariables) => void;\n onSettled?: (data: TData | undefined, error: Error | null, variables: TVariables) => void;\n messages?: MutationMessages;\n /** Per-call toast guard — return false to suppress toast for this invocation */\n shouldToast?: () => boolean;\n toastHandler?: ToastHandler;\n}\n\nexport function createOptimisticMutation<TData, TVariables>(config: CreateOptimisticMutationConfig<TData, TVariables>) {\n const {\n mutationFn,\n queryClient,\n queryKeys,\n optimisticUpdate,\n onSuccess,\n onError,\n onSettled,\n messages,\n toastHandler: instanceToast,\n } = config;\n return useMutation({\n mutationFn,\n\n onMutate: async (variables) => {\n await Promise.all(queryKeys.map((key) => queryClient.cancelQueries({ queryKey: key, exact: false })));\n\n const previous = queryKeys.map((key) => ({\n key,\n data: queryClient.getQueriesData({ queryKey: key }),\n }));\n\n if (optimisticUpdate) {\n queryKeys.forEach((key) => {\n queryClient.getQueriesData({ queryKey: key }).forEach(([qKey, qData]) => {\n queryClient.setQueryData(qKey, optimisticUpdate(qData, variables));\n });\n });\n }\n\n return { previous };\n },\n\n onSuccess: (data, variables) => {\n const doToast = config.shouldToast?.() ?? true;\n if (doToast && messages?.success) showToast(\"success\", messages, data, variables, undefined, instanceToast);\n queryKeys.forEach((key) => queryClient.invalidateQueries({ queryKey: key }));\n onSuccess?.(data, variables);\n },\n\n onError: (error, variables, context) => {\n const ctx = context as { previous?: Array<{ key: QueryKey; data: Array<[QueryKey, unknown]> }> };\n ctx?.previous?.forEach(({ data }) => {\n data.forEach(([qKey, qData]) => queryClient.setQueryData(qKey, qData));\n });\n\n const doToast = config.shouldToast?.() ?? true;\n if (doToast) showToast(\"error\", messages, null, variables, error as Error, instanceToast);\n onError?.(error as Error, variables);\n },\n\n onSettled: (data, error, variables) => {\n onSettled?.(data, error as Error | null, variables);\n },\n });\n}\n\n// ============================================================================\n// Query Config Presets\n// ============================================================================\n\nexport const QUERY_CONFIGS = {\n realtime: { staleTime: 20_000, refetchInterval: 30_000 },\n frequent: { staleTime: 60_000 },\n stable: { staleTime: 300_000 },\n static: { staleTime: 600_000 },\n} as const;\n"],"mappings":"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"}
package/dist/query.d.ts CHANGED
@@ -17,7 +17,7 @@ interface RequestPassthrough {
17
17
  headerOptions?: Record<string, string>;
18
18
  signal?: AbortSignal;
19
19
  }
20
- interface ListQueryOptions {
20
+ interface ListQueryOptions<TData = unknown> {
21
21
  public?: boolean;
22
22
  enabled?: boolean;
23
23
  staleTime?: number;
@@ -28,10 +28,12 @@ interface ListQueryOptions {
28
28
  refetchInterval?: number | false;
29
29
  refetchIntervalInBackground?: boolean;
30
30
  _scope?: string;
31
+ /** Transform raw API response before returning. Runs on each render, receives raw data. */
32
+ select?: (data: unknown) => TData;
31
33
  /** Pass-through options for the underlying fetch request (cache, revalidate, tags, headers) */
32
34
  request?: RequestPassthrough;
33
35
  }
34
- interface DetailQueryOptions {
36
+ interface DetailQueryOptions<TData = unknown> {
35
37
  public?: boolean;
36
38
  organizationId?: string | null;
37
39
  enabled?: boolean;
@@ -45,6 +47,8 @@ interface DetailQueryOptions {
45
47
  select?: string;
46
48
  populate?: string | string[];
47
49
  };
50
+ /** Transform raw API response before returning. Runs on each render, receives raw data. */
51
+ select?: (data: unknown) => TData;
48
52
  /** Pass-through options for the underlying fetch request (cache, revalidate, tags, headers) */
49
53
  request?: RequestPassthrough;
50
54
  }
@@ -107,6 +111,7 @@ interface CreateListQueryConfig {
107
111
  options?: Record<string, unknown>;
108
112
  prefillDetailCache?: boolean;
109
113
  detailKeyBuilder?: (id: string) => QueryKey;
114
+ select?: (data: unknown) => unknown;
110
115
  }
111
116
  declare function createListQuery<T>({
112
117
  queryKey,
@@ -114,7 +119,8 @@ declare function createListQuery<T>({
114
119
  enabled,
115
120
  options,
116
121
  prefillDetailCache,
117
- detailKeyBuilder
122
+ detailKeyBuilder,
123
+ select
118
124
  }: CreateListQueryConfig): ListQueryResult<T>;
119
125
  interface CreateDetailQueryConfig {
120
126
  queryKey: QueryKey;
@@ -123,12 +129,14 @@ interface CreateDetailQueryConfig {
123
129
  }) => Promise<unknown>;
124
130
  enabled?: boolean;
125
131
  options?: Record<string, unknown>;
132
+ select?: (data: unknown) => unknown;
126
133
  }
127
134
  declare function createDetailQuery<T>({
128
135
  queryKey,
129
136
  queryFn,
130
137
  enabled,
131
- options
138
+ options,
139
+ select
132
140
  }: CreateDetailQueryConfig): DetailQueryResult<T>;
133
141
  interface InfiniteListQueryOptions {
134
142
  public?: boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"query.d.ts","names":[],"sources":["../src/query.ts"],"mappings":"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"}
1
+ {"version":3,"file":"query.d.ts","names":[],"sources":["../src/query.ts"],"mappings":"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"}
package/dist/query.js CHANGED
@@ -47,25 +47,23 @@ function extractItem(data) {
47
47
  }
48
48
  function updateListCache(listData, updater) {
49
49
  if (!listData) return listData;
50
- if (typeof listData === "object" && "docs" in listData) {
51
- const d = listData;
52
- const updatedDocs = updater(d.docs);
53
- return {
54
- ...d,
55
- docs: updatedDocs,
56
- total: updatedDocs.length,
57
- totalDocs: updatedDocs.length
58
- };
59
- }
60
50
  if (Array.isArray(listData)) return updater(listData);
61
- if (typeof listData === "object" && "data" in listData) {
62
- const d = listData;
63
- if (Array.isArray(d.data)) return {
64
- ...d,
65
- data: updater(d.data)
66
- };
51
+ if (typeof listData !== "object") return listData;
52
+ const d = listData;
53
+ const arrayField = "docs" in d ? "docs" : Array.isArray(d.data) ? "data" : "items" in d && Array.isArray(d.items) ? "items" : "results" in d && Array.isArray(d.results) ? "results" : null;
54
+ if (!arrayField) return listData;
55
+ const updated = updater(d[arrayField]);
56
+ const original = d[arrayField];
57
+ const delta = updated.length - original.length;
58
+ const result = {
59
+ ...d,
60
+ [arrayField]: updated
61
+ };
62
+ if (delta !== 0) {
63
+ if (d.total != null) result.total = Math.max(0, Number(d.total) + delta);
64
+ if (d.totalDocs != null) result.totalDocs = Math.max(0, Number(d.totalDocs) + delta);
67
65
  }
68
- return listData;
66
+ return result;
69
67
  }
70
68
  function createQueryKeys(entityKey) {
71
69
  return {
@@ -109,14 +107,15 @@ function createCacheUtils(KEYS) {
109
107
  removeDetail: (client, id) => client.removeQueries({ queryKey: KEYS.detail(id) })
110
108
  };
111
109
  }
112
- function createListQuery({ queryKey, queryFn, enabled = true, options = {}, prefillDetailCache = true, detailKeyBuilder }) {
110
+ function createListQuery({ queryKey, queryFn, enabled = true, options = {}, prefillDetailCache = true, detailKeyBuilder, select }) {
113
111
  const queryClient = useQueryClient();
114
112
  const query = useQuery({
115
113
  queryKey,
116
- queryFn: () => queryFn({}),
114
+ queryFn: ({ signal }) => queryFn({ signal }),
117
115
  enabled,
118
116
  ...DEFAULT_QUERY_CONFIG,
119
117
  ...options,
118
+ ...select ? { select } : {},
120
119
  placeholderData: keepPreviousData
121
120
  });
122
121
  const items = extractItems(query.data);
@@ -146,13 +145,14 @@ function createListQuery({ queryKey, queryFn, enabled = true, options = {}, pref
146
145
  data: query.data
147
146
  };
148
147
  }
149
- function createDetailQuery({ queryKey, queryFn, enabled = true, options = {} }) {
148
+ function createDetailQuery({ queryKey, queryFn, enabled = true, options = {}, select }) {
150
149
  const query = useQuery({
151
150
  queryKey,
152
- queryFn: () => queryFn({}),
151
+ queryFn: ({ signal }) => queryFn({ signal }),
153
152
  enabled,
154
153
  ...DEFAULT_QUERY_CONFIG,
155
- ...options
154
+ ...options,
155
+ ...select ? { select } : {}
156
156
  });
157
157
  return {
158
158
  item: extractItem(query.data),
@@ -169,7 +169,10 @@ function createDetailQuery({ queryKey, queryFn, enabled = true, options = {} })
169
169
  function createInfiniteListQuery({ queryKey, queryFn, enabled = true, options = {}, initialPageParam = 1, getNextPageParam, getPreviousPageParam }) {
170
170
  const query = useInfiniteQuery({
171
171
  queryKey,
172
- queryFn: ({ pageParam }) => queryFn({ pageParam }),
172
+ queryFn: ({ pageParam, signal }) => queryFn({
173
+ pageParam,
174
+ signal
175
+ }),
173
176
  enabled,
174
177
  initialPageParam,
175
178
  getNextPageParam,