npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

@sindika/query-toolkit

v0.1.0

Published

Tanstack Query Helper

Downloads

94

Readme

Nedo React Query Toolkit

A TypeScript-first TanStack Query wrapper designed specifically for Sindika applications. This library provides a standardized, type-safe way to handle API interactions with automatic CRUD operations, pagination, and state management.

Features

  • 🔒 Type-Safe: Full TypeScript support with strict typing for resources and methods
  • 🚀 CRUD Operations: Automatic Create, Read, Update, Delete operations
  • 📄 Pagination: Built-in pagination with TanStack Table integration
  • 🔄 Cache Management: Smart invalidation and cache management
  • 🎯 Sindika Backend: Designed for Sindika's standardized response format
  • 🪝 React Hooks: Easy-to-use React hooks for all operations

Installation

npm install @sindika/query-toolkit

Quick Start

1. Create a Repository

Basic Repository (Full CRUD)

import type { RoleResponse } from "@/types/role/RoleResponse";
import type { RoleCreateRequest } from "@/types/role/RoleCreateRequest";
import type { RoleUpdateRequest } from "@/types/role/RoleUpdateRequest";
import type { RolePaginatedResponse } from "@/types/role/RolePaginatedResponse";

import { AxiosSingleton } from "@/api/axios/AxiosSingleton";
import {
  type CrudTypes,
  createRepository,
} from "@/lib/query-toolkit/createRepository";

type RoleRepository = CrudTypes<
  RoleCreateRequest,
  RoleUpdateRequest,
  RoleResponse,
  RolePaginatedResponse
>;

export const roleRepository = createRepository<RoleRepository>()({
  collection: "role",
  http: AxiosSingleton.getInstance(),
});

Advanced Repository (Custom Methods)

import type { AxiosRequestConfig } from "axios";
import type BaseRequest from "@/types/common/BaseRequest";
import type BaseResponse from "@/types/common/BaseResponse";
import type { AuthTokenRequest } from "@/types/auth/AuthTokenRequest";
import type { AuthTokenResponse } from "@/types/auth/AuthTokenResponse";

import { AxiosSingleton } from "@/api/axios/AxiosSingleton";
import {
  createRepository,
  type RequestParam,
} from "@/lib/query-toolkit/createRepository";

export const authRepository = createRepository()({
  only: [], // Disable default CRUD methods
  collection: "auth",
  http: AxiosSingleton.getInstance(),
  extraMethods: ({ http, collection }) => ({
    userInfo: (_: undefined, option?: AxiosRequestConfig) =>
      http
        .get<BaseResponse<AuthUserInfoResponse>>(`${collection}/userinfo`, {
          signal: option?.signal,
        })
        .then((e) => e.data),

    token: (
      { body: data }: RequestParam<BaseRequest<AuthTokenRequest>>,
      option?: AxiosRequestConfig
    ) =>
      http
        .post<BaseResponse<AuthTokenResponse>>(`${collection}/token`, data, {
          signal: option?.signal,
        })
        .then((e) => e.data),
  }),
});

2. Register Repositories

import { authRepository } from "./auth/authRepository";
import { roleRepository } from "./role/roleRepository";
import { userRepository } from "./user/userRepository";

export const repositories = {
  auth: authRepository,
  role: roleRepository,
  user: userRepository,
} as const;

export type AppRepositories = typeof repositories;

3. Create Query Toolkit Hooks

import { repositories } from "@/repository/repositories";
import { createUseOne } from "@/lib/query-toolkit/createUseOne";
import { createQueryOption } from "@/lib/query-toolkit/createQueryOption";
import { createInvalidation } from "@/lib/query-toolkit/createInvalidation";
import { createUsePaginationUrl } from "@/lib/query-toolkit/createUsePaginationUrl";
import { createUsePaginationInternal } from "@/lib/query-toolkit/createUsePaginationInternal";
import { createUseMutationCreateUpdate } from "@/lib/query-toolkit/createUseMutationCreateUpdateDelete";

export const usePaginationUrl = createUsePaginationUrl(repositories);
export const usePaginationInternal = createUsePaginationInternal(repositories);
export const useOne = createUseOne(repositories);

export const { useCreate, useDelete, useUpdate } =
  createUseMutationCreateUpdate(repositories);
export const useInvalidation = createInvalidation(repositories);
export const appQueryOptions = createQueryOption(repositories);

Usage Examples

Single Resource Queries

// Simple query without parameters
const { data: userInfoData } = useOne({
  resource: "auth", // Type-safe resource selection
  selectMethod: "userInfo",
});

// Query with parameters
const { data: single, isPending: isPendingSingle } = useOne({
  resource: "profile",
  selectMethod: "getSingle",
  params: { pathParam: { id } },
});

Pagination with URL State

// Pagination state stored in URL search params (using nuqs library)
const {
  search,
  refetch,
  rowCount,
  setSearch,
  isFetching,
  items: data,
  tableState: { sorting, pagination },
  tableCallbacks: { onSortingChange, onPaginationChange },
} = usePaginationUrl({
  resource: "role",
  selectMethod: "getListPagination",
  getParams: (state) => ({ body: state }),
});

Pagination with Internal State

// Pagination with internal useState
const {
  search,
  refetch,
  rowCount,
  setSearch,
  isFetching,
  items: data,
  tableState: { sorting, pagination },
  tableCallbacks: { onSortingChange, onPaginationChange },
} = usePaginationInternal({
  resource: "profile",
  selectMethod: "getListPagination",
  getParams: (state) => ({ body: state }),
  initialState: {
    sorting: [
      {
        desc: false,
        id: "name",
      },
    ],
  },
});

Mutations (Create/Update/Delete)

const invalidation = useInvalidation();

const { mutate, isPending } = useCreate({
  resource: "customEvent",
  selectMethod: "create",
  mutationOptions: {
    onError: (error) => {
      toast.error(error.message);
      form.setServerError(error.error);
    },
    onSuccess: (data) => {
      toast.success(data.message ?? "Custom event created successfully");

      // Invalidate related queries
      invalidation.invalidatePagination({
        resource: "customEvent",
        selectMethod: "getListPagination",
      });

      closeModal();
    },
  },
});

// Usage
const handleSubmit = (formData) => {
  mutate({
    params: { body: formData },
  });
};

Cache Invalidation

const invalidation = useInvalidation();

// Invalidate specific pagination
invalidation.invalidatePagination({
  resource: "customEvent",
  selectMethod: "getListPagination",
});

// Invalidate single resource
invalidation.invalidateOne({
  resource: "user",
  selectMethod: "getSingle",
  params: { pathParam: { id: userId } },
});

API Reference

Repository Types

CrudTypes<TCreate, TUpdate, TResponse, TPaginated>

  • TCreate: Type for create request payload
  • TUpdate: Type for update request payload
  • TResponse: Type for single resource response
  • TPaginated: Type for paginated list response

Repository Options

{
  collection: string;           // API collection name
  http: AxiosInstance;         // Axios instance
  only?: CrudMethod[];         // Include only specific CRUD methods
  except?: CrudMethod[];       // Exclude specific CRUD methods
  extraMethods?: (config) => Methods; // Additional custom methods
}

Hook Options

useOne Options

{
  resource: keyof Repositories;
  selectMethod: string;
  params?: RequestParams;
  queryOptions?: UseQueryOptions;
}

usePagination Options

{
  resource: keyof Repositories;
  selectMethod: string;
  getParams: (state) => RequestParams;
  initialState?: TableState;
  queryOptions?: UseQueryOptions;
}

Mutation Options

{
  resource: keyof Repositories;
  selectMethod: string;
  mutationOptions?: UseMutationOptions;
}

TypeScript Support

This library provides full TypeScript support with:

  • Resource Type Safety: resource parameter is strictly typed to repository keys
  • Method Type Safety: selectMethod is typed based on available repository methods
  • Parameter Type Safety: Request parameters are typed based on method signatures
  • Response Type Safety: All responses are properly typed based on repository definitions

Requirements

  • TanStack Query v5+
  • Axios

License

MIT

Contributing

This library is designed specifically for Sindika's backend architecture and response standards. If you need modifications for your use case, please fork the repository or create a custom wrapper.