@docyrus/tanstack-db-generator
v0.9.5
Published
Code generator utilities for TanStack Query / Database integration with Docyrus API
Readme
@docyrus/tanstack-db-generator
Generate TanStack Query collections and TypeScript types from OpenAPI 3.1.0 specifications.
Installation
npm install @docyrus/tanstack-db-generator
# or
pnpm add @docyrus/tanstack-db-generatorUsage
CLI
# Generate all collections and types from OpenAPI spec
tanstack-db-generator path/to/openapi-spec.json
# Specify output directory
tanstack-db-generator path/to/openapi-spec.json -o ./src/generated
# Generate data source collections for selected apps only
tanstack-db-generator path/to/openapi-spec.json --apps crm support
# Generate only specific data source collections (appSlug/dataSourceSlug format)
tanstack-db-generator path/to/openapi-spec.json --dataSources crm/contacts crm/accounts
# Combine both filters (intersection — must match both)
tanstack-db-generator path/to/openapi-spec.json --apps crm --dataSources crm/contacts
# Comma-separated values are also accepted
tanstack-db-generator path/to/openapi-spec.json --apps crm,support
tanstack-db-generator path/to/openapi-spec.json --dataSources crm/contacts,crm/accountsProgrammatic API
import { generateFromOpenAPI } from '@docyrus/tanstack-db-generator';
const spec = JSON.parse(fs.readFileSync('openapi-spec.json', 'utf-8'));
// Generate all collections
await generateFromOpenAPI(spec, './src');
// Generate with filters
await generateFromOpenAPI(spec, './src', {
apps: ['crm', 'support'],
dataSources: ['crm/contacts', 'crm/accounts']
});Filtering Data Sources
The --apps and --dataSources options let you selectively generate collections for a subset of the spec:
| Option | Format | Example |
|--------|--------|---------|
| --apps | <appSlug> [appSlug...] | --apps crm support |
| --dataSources | <appSlug/dataSourceSlug> [...] | --dataSources crm/contacts crm/accounts |
Behavior:
- When neither filter is provided, all data source collections and non-data-source endpoint groups are generated.
- When either filter is provided, only matching data source collections are generated. Non-data-source endpoint groups are still always (re)generated so they stay in sync with the spec on every run.
- When both filters are provided, they are combined as an intersection — a data source must match both the app filter and the data source filter.
- The generator validates filter values against the spec and throws an error if an unknown app or data source is requested.
- All existing
*.collection.tsfiles in the output collections folder are removed before generation, so filtered runs do not leave stale files behind.
Features
- Automatically generates TanStack Query collections for CRUD operations
- Creates TypeScript type definitions from OpenAPI schemas
- Supports dataSource endpoints with the following pattern:
GET /v1/apps/:appName/data-sources/:dataSourceName/items- List itemsGET /v1/apps/:appName/data-sources/:dataSourceName/items/:itemId- Get single itemPOST /v1/apps/:appName/data-sources/:dataSourceName/items- Create itemPATCH /v1/apps/:appName/data-sources/:dataSourceName/items/:itemId- Update itemDELETE /v1/apps/:appName/data-sources/:dataSourceName/items/:itemId- Delete itemDELETE /v1/apps/:appName/data-sources/:dataSourceName/items- Delete many items
Generated Files Structure
src/db/
├── types/
│ └── index.ts # TypeScript interfaces and Zod schemas
├── collections/
│ ├── app-datasource.collection.ts # Individual collection files
│ └── index.ts # Exports all collections
└── index.ts # Main entry pointRequired client setup
The generated CRUD methods (list, get, create, update, delete, deleteMany) call client.get/post/patch/delete and return the result directly — they do not read .data from a Docyrus { success, data } envelope themselves. Register @docyrus/app-utils' envelopeUnwrapInterceptor on your RestApiClient before any collection method runs, otherwise list() returns the envelope object instead of the typed array and TanStack DB breaks.
import { RestApiClient } from '@docyrus/api-client';
import { envelopeUnwrapInterceptor } from '@docyrus/app-utils';
const client = new RestApiClient({ baseURL: 'https://api.example.com' });
client.addInterceptor(envelopeUnwrapInterceptor);If your client is built elsewhere (e.g. by @docyrus/signin's DocyrusAuthProvider), register the interceptor on the resulting instance the same way — registration is idempotent.
The interceptor is shape-strict and lossless: domain payloads that carry their own data field (e.g. AppConfig, UserAppConfig, records with a data column) are left alone, and envelopes carrying meta (paginated lists), error, or message are preserved so callers can read them. See @docyrus/app-utils → Envelope handling for the full table.
Example Usage
After generation, you can use the collections in your React components:
import { useDrizzleQuery } from '@tanstack/react-db';
import { baseContactCollection } from './collections';
function ContactList() {
const { data, isLoading, error } = useDrizzleQuery(
baseContactCollection.list()
);
if (isLoading) return <div>Loading...</div>;
if (error) return <div>Error: {error.message}</div>;
return (
<ul>
{data?.data.map(contact => (
<li key={contact.id}>{contact.name}</li>
))}
</ul>
);
}License
MIT
