tzurot-types
Use when creating types, constants, Zod schemas, or working with data validation. Covers common-types package organization, runtime validation, and type guards across microservices.
Installation
Follow the repository instructions for this skill and your agent. Review the files and dependencies before adding it to your workflow.
View source ↗GuidesSkill instructions
Tzurot v3 Types & Constants
Use this skill when: Creating new types, adding constants, validating data at service boundaries, or sharing code across microservices.
Quick Reference
// Import from common-types
import { TIMEOUTS, RETRY_CONFIG, PersonalityConfigSchema } from '@tzurot/common-types';
// Constants: SCREAMING_SNAKE_CASE + as const
export const MY_CONFIG = { VALUE: 123 } as const;
// Runtime validation at service boundaries
const validated = MySchema.parse(untrustedData);
// Type inference from Zod
type MyType = z.infer<typeof MySchema>;
Package Structure
packages/common-types/src/
├── constants/ # Application constants by domain
│ ├── timing.ts # TIMEOUTS, INTERVALS, RETRY_CONFIG
│ ├── queue.ts # REDIS_KEY_PREFIXES, QUEUE_CONFIG
│ ├── discord.ts # TEXT_LIMITS, DISCORD_LIMITS
│ └── ai.ts # AI_DEFAULTS, MODEL_DEFAULTS
├── types/ # TypeScript interfaces + Zod schemas
│ ├── schemas.ts # Zod schemas for validation
│ └── *.ts # Domain-specific types
├── services/ # Shared service classes
└── utils/ # Utility functions
When to Add to Common-Types
| Content | Add to Common-Types? | Location |
|---|---|---|
| Value used in 2+ files | ✅ Yes | constants/<domain>.ts |
| BullMQ job payloads | ✅ Yes | types/queue-types.ts |
| HTTP API contracts | ✅ Yes | types/schemas.ts |
| Type guards for Discord | ✅ Yes | types/discord-types.ts |
| Service-internal types | ❌ No | Keep in service |
| Test-only values | ❌ No | Keep in test file |
Constants Patterns
Create Constants For
// ✅ Timeouts and delays
import { TIMEOUTS } from '@tzurot/common-types';
await delay(TIMEOUTS.CACHE_TTL);
// ✅ Redis key prefixes
import { REDIS_KEY_PREFIXES } from '@tzurot/common-types';
await redis.set(`${REDIS_KEY_PREFIXES.WEBHOOK_MESSAGE}${id}`, data);
// ✅ API limits
import { TEXT_LIMITS } from '@tzurot/common-types';
if (content.length > TEXT_LIMITS.MESSAGE_MAX_LENGTH) {
/* chunk */
}
Don't Create Constants For
// ✅ FINE - One-off strings
logger.info('Personality cache initialized');
// ✅ FINE - Self-documenting values
const defaultTemperature = 0.8;
// ✅ FINE - Test-specific data
const mockUserId = 'test-user-123';
Constant Naming
export const RETRY_CONFIG = {
/** Standard retry attempts */
MAX_ATTEMPTS: 3,
/** Initial delay (1 second) */
INITIAL_DELAY_MS: 1000,
} as const; // Always use 'as const'
Zod Schema Patterns
Runtime Validation at Boundaries
import { z } from 'zod';
// Define schema
export const PersonalityConfigSchema = z.object({
name: z.string().min(1).max(100),
systemPrompt: z.string().min(10),
model: z.string(),
temperature: z.number().min(0).max(2).optional(),
});
// Infer type
export type PersonalityConfig = z.infer<typeof PersonalityConfigSchema>;
// Validate at service boundary
app.post('/api/personality', (req, res) => {
try {
const config = PersonalityConfigSchema.parse(req.body);
// config is now type-safe
} catch (error) {
if (error instanceof z.ZodError) {
return res.status(400).json({ errors: error.errors });
}
throw error;
}
});
Type Guards
// packages/common-types/src/types/discord-types.ts
import type { Channel, TextChannel, DMChannel } from 'discord.js';
export function isTextChannel(channel: Channel): channel is TextChannel {
return channel.type === 0; // ChannelType.GuildText
}
export function isDMChannel(channel: Channel): channel is DMChannel {
return channel.type === 1; // ChannelType.DM
}
// Usage
if (isTextChannel(message.channel)) {
// message.channel is now TextChannel
const perms = message.channel.permissionsFor(client.user!);
}
Anti-Patterns
Constants Anti-Patterns
// ❌ BAD - Magic number
await delay(300000);
// ✅ GOOD - Named constant
await delay(TIMEOUTS.CACHE_TTL);
// ❌ BAD - Too deeply nested
CONFIG.AI.PROVIDERS.OPENROUTER.TIMEOUTS.DEFAULT;
// ✅ GOOD - Flat structure
AI_TIMEOUTS.OPENROUTER_DEFAULT;
Types Anti-Patterns
// ❌ BAD - Trusts external data
const data = req.body as MyType; // Unsafe cast!
// ✅ GOOD - Validate at boundary
const data = MySchema.parse(req.body);
// ❌ BAD - Duplicate types across services
// bot-client/types.ts AND ai-worker/types.ts
// ✅ GOOD - Single source in common-types
import { MyType } from '@tzurot/common-types';
// ❌ BAD - Using 'any'
function process(data: any) {}
// ✅ GOOD - Proper typing
function process(data: ValidatedType) {}
Adding New Constants
- Determine domain (
timing.ts,queue.ts,discord.ts,ai.ts) - Add with JSDoc documentation
- Export from
constants/index.ts - Import via
@tzurot/common-types
// packages/common-types/src/constants/timing.ts
export const TIMEOUTS = {
/** Description of why this value */
MY_NEW_TIMEOUT: 60000,
} as const;
Adding New Schemas
- Define Zod schema in
types/schemas.ts - Export inferred TypeScript type
- Use
.parse()at service boundaries - Handle
z.ZodErrorappropriately
// packages/common-types/src/types/schemas.ts
export const MyNewSchema = z.object({
/* ... */
});
export type MyNewType = z.infer<typeof MyNewSchema>;
Related Skills
- tzurot-code-quality - no-explicit-any, type safety enforcement
- tzurot-testing - Type-safe test fixtures
- tzurot-async-flow - BullMQ job data types
- tzurot-db-vector - Prisma schema types
- tzurot-architecture - Service boundaries
References
- Constants:
packages/common-types/src/constants/ - Types:
packages/common-types/src/types/ - Zod docs: https://zod.dev/
Examples
Read the usage examples in the source repository.
View source ↗Source history
- Indexed on
- 2026-01-20
- Index updated
- 2026-01-26
- Branch
- main
Index and sync dates describe this directory. View the source repository for code history.
GitHub ↗chat Comments (0)
Sign in to join the discussion and leave a comment.
No comments yet. Be the first to share your thoughts!