Installation

Install the full stack or individual packages in a React project.

#React stack

bash
# Full React stack
pnpm add @void-snippets/core @void-snippets/client @void-snippets/react

# Required peer dependencies
pnpm add axios @tanstack/react-query

# Only needed if you use socket hooks
pnpm add socket.io-client

# Only needed if you use the routing contract
pnpm add react-router

#React peer dependency versions

PeerMinimumRequired for
react>=17.0.0All React hooks
axios^1.6.0@void-snippets/client
@tanstack/react-query^5.0.0createResourceHooks
socket.io-client>=4.6.0createSocketHooks
react-router>=7.0.0createRouteContract
TypeScript^5.4.0Everything

#Angular stack

@void-snippets/angular does not use axios — it uses Angular's built-in HttpClient. Install the Angular package alongside core:

bash
pnpm add @void-snippets/core @void-snippets/angular

# Required peer dependencies
pnpm add @tanstack/angular-query-experimental rxjs

#Angular peer dependency versions

PeerMinimumRequired for
@angular/core>=19.0.0inject(), signal()
@angular/common>=19.0.0HttpClient
rxjs>=7.0.0Observable → Promise bridge
@tanstack/angular-query-experimental>=5.0.0createResourceInject
TypeScript^5.4.0Everything

No axios, no configure() call. Angular's HttpClient — configured through interceptors in provideHttpClient(...) — handles auth, CSRF, tracing, and retry. AngularResourceService picks up the interceptor chain automatically.

#One-time app setup

Do this once at your app's entry point, before any service is called.

1. Configure the HTTP client:

typescript
// main.ts
import axios from 'axios';
import { configure } from '@void-snippets/client';

configure(
  axios.create({
    baseURL: import.meta.env.VITE_API_URL,
    headers: { 'Content-Type': 'application/json' },
  })
);

2. Wrap your app with QueryClientProvider:

tsx
// main.tsx
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';

const queryClient = new QueryClient({
  defaultOptions: { queries: { retry: 1, staleTime: 30_000 } },
});

root.render(
  <QueryClientProvider client={queryClient}>
    <App />
  </QueryClientProvider>
);

#Angular one-time app setup

Do this once in app.config.ts, before any service is injected.

typescript
// app.config.ts
import { ApplicationConfig } from '@angular/core';
import { provideHttpClient, withFetch, withInterceptors } from '@angular/common/http';
import { provideVoidAngular } from '@void-snippets/angular';
import { authInterceptor } from './core/auth.interceptor';

export const appConfig: ApplicationConfig = {
  providers: [
    // withFetch() enables OS-level network cancellation when TanStack Query aborts a request.
    provideHttpClient(
      withFetch(),
      withInterceptors([authInterceptor]),
    ),

    // One-call setup — registers TanStack Angular Query with enterprise defaults.
    provideVoidAngular({
      queryClientConfig: {
        defaultOptions: {
          queries:   { staleTime: 30_000, retry: 1 },
          mutations: { retry: 0 },
        },
      },
    }),
  ],
};

There is no configure() call for Angular — auth, CSRF, and retry are wired once through provideHttpClient(...) interceptors, and every AngularResourceService subclass inherits them automatically.

#NestJS stack

@void-snippets/nestjs needs core plus whichever ORM your app already uses — it never installs an ORM for you:

bash
pnpm add @void-snippets/core @void-snippets/nestjs

# plus whichever ORM you use
pnpm add typeorm @nestjs/typeorm      # TypeORM
# or
pnpm add mongoose @nestjs/mongoose    # Mongoose

# only if you validate request bodies with DTOs
pnpm add class-validator class-transformer

#NestJS peer dependency versions

PeerMinimumRequired for
@nestjs/common>=10.0.0Everything
typeorm + @nestjs/typeorm>=0.3.0forTypeOrmResource
mongoose + @nestjs/mongoose>=7.0.0forMongooseResource
class-validator + class-transformerany recentDTO body validation (optional)
TypeScript^5.4.0Everything

class-validator and class-transformer are optional. You only need them once you attach a DTO class to a resource — the generated controller then validates the request body for you, with no global ValidationPipe to wire up yourself.

Build note: unlike the other packages, @void-snippets/nestjs ships CommonJS compiled with tsc, not tsup/esbuild. NestJS's dependency injection relies on a TypeScript feature (emitDecoratorMetadata) that esbuild-based bundlers don't emit.

#NestJS one-time app setup

Do this once in your root AppModule, before any feature module that registers a resource:

typescript
// app.module.ts
import { Module } from '@nestjs/common';
import { VoidResourceModule } from '@void-snippets/nestjs';
import { ContactsModule } from './contacts/contacts.module';

@Module({
  imports: [
    VoidResourceModule.forRoot({
      cursorSecret: process.env.CURSOR_SECRET, // signs cursors so they can't be tampered with
      maxLimit: 200,                            // hard ceiling on ?limit= for every resource
      defaultLimit: 25,                         // page size when a request omits ?limit=
    }),
    ContactsModule,
    // ...your other feature modules
  ],
})
export class AppModule {}

forRoot() sets defaults shared by every resource in your app, so you configure them once instead of repeating the same options in every defineResource() call. Any option a resource sets for itself overrides the app-wide default.