javi-forge 1.2.0 → 1.3.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/ci-local/ci-local.sh +20 -8
- package/package.json +1 -1
- package/ai-config/.skillignore +0 -15
- package/ai-config/AUTO_INVOKE.md +0 -300
- package/ai-config/agents/_TEMPLATE.md +0 -93
- package/ai-config/agents/business/api-designer.md +0 -1657
- package/ai-config/agents/business/business-analyst.md +0 -1331
- package/ai-config/agents/business/product-strategist.md +0 -206
- package/ai-config/agents/business/project-manager.md +0 -178
- package/ai-config/agents/business/requirements-analyst.md +0 -1277
- package/ai-config/agents/business/technical-writer.md +0 -1679
- package/ai-config/agents/creative/ux-designer.md +0 -205
- package/ai-config/agents/data-ai/ai-engineer.md +0 -487
- package/ai-config/agents/data-ai/analytics-engineer.md +0 -953
- package/ai-config/agents/data-ai/data-engineer.md +0 -173
- package/ai-config/agents/data-ai/data-scientist.md +0 -672
- package/ai-config/agents/data-ai/mlops-engineer.md +0 -814
- package/ai-config/agents/data-ai/prompt-engineer.md +0 -772
- package/ai-config/agents/development/angular-expert.md +0 -620
- package/ai-config/agents/development/backend-architect.md +0 -795
- package/ai-config/agents/development/database-specialist.md +0 -212
- package/ai-config/agents/development/frontend-specialist.md +0 -686
- package/ai-config/agents/development/fullstack-engineer.md +0 -668
- package/ai-config/agents/development/golang-pro.md +0 -338
- package/ai-config/agents/development/java-enterprise.md +0 -400
- package/ai-config/agents/development/javascript-pro.md +0 -422
- package/ai-config/agents/development/nextjs-pro.md +0 -474
- package/ai-config/agents/development/python-pro.md +0 -570
- package/ai-config/agents/development/react-pro.md +0 -487
- package/ai-config/agents/development/rust-pro.md +0 -246
- package/ai-config/agents/development/spring-boot-4-expert.md +0 -326
- package/ai-config/agents/development/typescript-pro.md +0 -336
- package/ai-config/agents/development/vue-specialist.md +0 -605
- package/ai-config/agents/infrastructure/cloud-architect.md +0 -472
- package/ai-config/agents/infrastructure/deployment-manager.md +0 -358
- package/ai-config/agents/infrastructure/devops-engineer.md +0 -455
- package/ai-config/agents/infrastructure/incident-responder.md +0 -519
- package/ai-config/agents/infrastructure/kubernetes-expert.md +0 -705
- package/ai-config/agents/infrastructure/monitoring-specialist.md +0 -674
- package/ai-config/agents/infrastructure/performance-engineer.md +0 -658
- package/ai-config/agents/orchestrator.md +0 -241
- package/ai-config/agents/quality/accessibility-auditor.md +0 -1204
- package/ai-config/agents/quality/code-reviewer-compact.md +0 -123
- package/ai-config/agents/quality/code-reviewer.md +0 -363
- package/ai-config/agents/quality/dependency-manager.md +0 -743
- package/ai-config/agents/quality/e2e-test-specialist.md +0 -1005
- package/ai-config/agents/quality/performance-tester.md +0 -1086
- package/ai-config/agents/quality/security-auditor.md +0 -133
- package/ai-config/agents/quality/test-engineer.md +0 -453
- package/ai-config/agents/specialists/api-designer.md +0 -87
- package/ai-config/agents/specialists/backend-architect.md +0 -73
- package/ai-config/agents/specialists/code-reviewer.md +0 -77
- package/ai-config/agents/specialists/db-optimizer.md +0 -75
- package/ai-config/agents/specialists/devops-engineer.md +0 -83
- package/ai-config/agents/specialists/documentation-writer.md +0 -78
- package/ai-config/agents/specialists/frontend-developer.md +0 -75
- package/ai-config/agents/specialists/performance-analyst.md +0 -82
- package/ai-config/agents/specialists/refactor-specialist.md +0 -74
- package/ai-config/agents/specialists/security-auditor.md +0 -74
- package/ai-config/agents/specialists/test-engineer.md +0 -81
- package/ai-config/agents/specialists/ux-consultant.md +0 -76
- package/ai-config/agents/specialized/agent-generator.md +0 -1190
- package/ai-config/agents/specialized/blockchain-developer.md +0 -149
- package/ai-config/agents/specialized/code-migrator.md +0 -892
- package/ai-config/agents/specialized/context-manager.md +0 -978
- package/ai-config/agents/specialized/documentation-writer.md +0 -1078
- package/ai-config/agents/specialized/ecommerce-expert.md +0 -1756
- package/ai-config/agents/specialized/embedded-engineer.md +0 -1714
- package/ai-config/agents/specialized/error-detective.md +0 -1034
- package/ai-config/agents/specialized/fintech-specialist.md +0 -1659
- package/ai-config/agents/specialized/freelance-project-planner-v2.md +0 -1988
- package/ai-config/agents/specialized/freelance-project-planner-v3.md +0 -2136
- package/ai-config/agents/specialized/freelance-project-planner-v4.md +0 -4503
- package/ai-config/agents/specialized/freelance-project-planner.md +0 -722
- package/ai-config/agents/specialized/game-developer.md +0 -1963
- package/ai-config/agents/specialized/healthcare-dev.md +0 -1620
- package/ai-config/agents/specialized/mobile-developer.md +0 -188
- package/ai-config/agents/specialized/parallel-plan-executor.md +0 -506
- package/ai-config/agents/specialized/plan-executor.md +0 -485
- package/ai-config/agents/specialized/solo-dev-planner-modular/00-INDEX.md +0 -485
- package/ai-config/agents/specialized/solo-dev-planner-modular/01-CORE.md +0 -3493
- package/ai-config/agents/specialized/solo-dev-planner-modular/02-SELF-CORRECTION.md +0 -778
- package/ai-config/agents/specialized/solo-dev-planner-modular/03-PROGRESSIVE-SETUP.md +0 -918
- package/ai-config/agents/specialized/solo-dev-planner-modular/04-DEPLOYMENT.md +0 -1537
- package/ai-config/agents/specialized/solo-dev-planner-modular/05-TESTING.md +0 -2633
- package/ai-config/agents/specialized/solo-dev-planner-modular/06-OPERATIONS.md +0 -5610
- package/ai-config/agents/specialized/solo-dev-planner-modular/INSTALL.md +0 -335
- package/ai-config/agents/specialized/solo-dev-planner-modular/QUICK-REFERENCE.txt +0 -215
- package/ai-config/agents/specialized/solo-dev-planner-modular/README.md +0 -260
- package/ai-config/agents/specialized/solo-dev-planner-modular/START-HERE.md +0 -379
- package/ai-config/agents/specialized/solo-dev-planner-modular/WORKFLOW-DIAGRAM.md +0 -355
- package/ai-config/agents/specialized/solo-dev-planner-modular/solo-dev-planner.md +0 -279
- package/ai-config/agents/specialized/template-writer.md +0 -347
- package/ai-config/agents/specialized/test-runner.md +0 -99
- package/ai-config/agents/specialized/vibekanban-smart-worker.md +0 -244
- package/ai-config/agents/specialized/wave-executor.md +0 -138
- package/ai-config/agents/specialized/workflow-optimizer.md +0 -1114
- package/ai-config/commands/git/changelog.md +0 -32
- package/ai-config/commands/git/ci-local.md +0 -70
- package/ai-config/commands/git/commit.md +0 -35
- package/ai-config/commands/git/fix-issue.md +0 -23
- package/ai-config/commands/git/pr-create.md +0 -42
- package/ai-config/commands/git/pr-review.md +0 -50
- package/ai-config/commands/git/worktree.md +0 -39
- package/ai-config/commands/refactoring/cleanup.md +0 -24
- package/ai-config/commands/refactoring/dead-code.md +0 -40
- package/ai-config/commands/refactoring/extract.md +0 -31
- package/ai-config/commands/testing/e2e.md +0 -30
- package/ai-config/commands/testing/tdd.md +0 -36
- package/ai-config/commands/testing/test-coverage.md +0 -30
- package/ai-config/commands/testing/test-fix.md +0 -24
- package/ai-config/commands/workflow/generate-agents-md.md +0 -85
- package/ai-config/commands/workflow/planning.md +0 -47
- package/ai-config/commands/workflows/compound.md +0 -89
- package/ai-config/commands/workflows/diagnose.md +0 -70
- package/ai-config/commands/workflows/discover.md +0 -86
- package/ai-config/commands/workflows/plan.md +0 -77
- package/ai-config/commands/workflows/review.md +0 -78
- package/ai-config/commands/workflows/work.md +0 -75
- package/ai-config/config.yaml +0 -18
- package/ai-config/hooks/_TEMPLATE.md +0 -96
- package/ai-config/hooks/block-dangerous-commands.md +0 -75
- package/ai-config/hooks/commit-guard.md +0 -90
- package/ai-config/hooks/context-loader.md +0 -73
- package/ai-config/hooks/improve-prompt.md +0 -91
- package/ai-config/hooks/learning-log.md +0 -72
- package/ai-config/hooks/model-router.md +0 -86
- package/ai-config/hooks/secret-scanner.md +0 -64
- package/ai-config/hooks/skill-validator.md +0 -102
- package/ai-config/hooks/task-artifact.md +0 -114
- package/ai-config/hooks/validate-workflow.md +0 -100
- package/ai-config/prompts/base.md +0 -71
- package/ai-config/prompts/modes/debug.md +0 -34
- package/ai-config/prompts/modes/deploy.md +0 -40
- package/ai-config/prompts/modes/research.md +0 -32
- package/ai-config/prompts/modes/review.md +0 -33
- package/ai-config/prompts/review-policy.md +0 -79
- package/ai-config/skills/_TEMPLATE.md +0 -157
- package/ai-config/skills/backend/api-gateway/SKILL.md +0 -254
- package/ai-config/skills/backend/bff-concepts/SKILL.md +0 -239
- package/ai-config/skills/backend/bff-spring/SKILL.md +0 -364
- package/ai-config/skills/backend/chi-router/SKILL.md +0 -396
- package/ai-config/skills/backend/error-handling/SKILL.md +0 -255
- package/ai-config/skills/backend/exceptions-spring/SKILL.md +0 -323
- package/ai-config/skills/backend/fastapi/SKILL.md +0 -302
- package/ai-config/skills/backend/gateway-spring/SKILL.md +0 -390
- package/ai-config/skills/backend/go-backend/SKILL.md +0 -457
- package/ai-config/skills/backend/gradle-multimodule/SKILL.md +0 -274
- package/ai-config/skills/backend/graphql-concepts/SKILL.md +0 -352
- package/ai-config/skills/backend/graphql-spring/SKILL.md +0 -398
- package/ai-config/skills/backend/grpc-concepts/SKILL.md +0 -283
- package/ai-config/skills/backend/grpc-spring/SKILL.md +0 -445
- package/ai-config/skills/backend/jwt-auth/SKILL.md +0 -412
- package/ai-config/skills/backend/notifications-concepts/SKILL.md +0 -259
- package/ai-config/skills/backend/recommendations-concepts/SKILL.md +0 -261
- package/ai-config/skills/backend/search-concepts/SKILL.md +0 -263
- package/ai-config/skills/backend/search-spring/SKILL.md +0 -375
- package/ai-config/skills/backend/spring-boot-4/SKILL.md +0 -172
- package/ai-config/skills/backend/websockets/SKILL.md +0 -532
- package/ai-config/skills/data-ai/ai-ml/SKILL.md +0 -423
- package/ai-config/skills/data-ai/analytics-concepts/SKILL.md +0 -195
- package/ai-config/skills/data-ai/analytics-spring/SKILL.md +0 -340
- package/ai-config/skills/data-ai/duckdb-analytics/SKILL.md +0 -440
- package/ai-config/skills/data-ai/langchain/SKILL.md +0 -238
- package/ai-config/skills/data-ai/mlflow/SKILL.md +0 -302
- package/ai-config/skills/data-ai/onnx-inference/SKILL.md +0 -290
- package/ai-config/skills/data-ai/powerbi/SKILL.md +0 -352
- package/ai-config/skills/data-ai/pytorch/SKILL.md +0 -274
- package/ai-config/skills/data-ai/scikit-learn/SKILL.md +0 -321
- package/ai-config/skills/data-ai/vector-db/SKILL.md +0 -301
- package/ai-config/skills/database/graph-databases/SKILL.md +0 -218
- package/ai-config/skills/database/graph-spring/SKILL.md +0 -361
- package/ai-config/skills/database/pgx-postgres/SKILL.md +0 -512
- package/ai-config/skills/database/redis-cache/SKILL.md +0 -343
- package/ai-config/skills/database/sqlite-embedded/SKILL.md +0 -388
- package/ai-config/skills/database/timescaledb/SKILL.md +0 -320
- package/ai-config/skills/docs/api-documentation/SKILL.md +0 -293
- package/ai-config/skills/docs/docs-spring/SKILL.md +0 -377
- package/ai-config/skills/docs/mustache-templates/SKILL.md +0 -190
- package/ai-config/skills/docs/technical-docs/SKILL.md +0 -447
- package/ai-config/skills/frontend/astro-ssr/SKILL.md +0 -441
- package/ai-config/skills/frontend/frontend-design/SKILL.md +0 -54
- package/ai-config/skills/frontend/frontend-web/SKILL.md +0 -368
- package/ai-config/skills/frontend/mantine-ui/SKILL.md +0 -396
- package/ai-config/skills/frontend/tanstack-query/SKILL.md +0 -439
- package/ai-config/skills/frontend/zod-validation/SKILL.md +0 -417
- package/ai-config/skills/frontend/zustand-state/SKILL.md +0 -350
- package/ai-config/skills/infrastructure/chaos-engineering/SKILL.md +0 -244
- package/ai-config/skills/infrastructure/chaos-spring/SKILL.md +0 -378
- package/ai-config/skills/infrastructure/devops-infra/SKILL.md +0 -435
- package/ai-config/skills/infrastructure/docker-containers/SKILL.md +0 -420
- package/ai-config/skills/infrastructure/kubernetes/SKILL.md +0 -456
- package/ai-config/skills/infrastructure/opentelemetry/SKILL.md +0 -546
- package/ai-config/skills/infrastructure/traefik-proxy/SKILL.md +0 -474
- package/ai-config/skills/infrastructure/woodpecker-ci/SKILL.md +0 -315
- package/ai-config/skills/mobile/ionic-capacitor/SKILL.md +0 -504
- package/ai-config/skills/mobile/mobile-ionic/SKILL.md +0 -448
- package/ai-config/skills/prompt-improver/SKILL.md +0 -125
- package/ai-config/skills/quality/ghagga-review/SKILL.md +0 -216
- package/ai-config/skills/references/hooks-patterns/SKILL.md +0 -238
- package/ai-config/skills/references/mcp-servers/SKILL.md +0 -275
- package/ai-config/skills/references/plugins-reference/SKILL.md +0 -110
- package/ai-config/skills/references/skills-reference/SKILL.md +0 -420
- package/ai-config/skills/references/subagent-templates/SKILL.md +0 -193
- package/ai-config/skills/systems-iot/modbus-protocol/SKILL.md +0 -410
- package/ai-config/skills/systems-iot/mqtt-rumqttc/SKILL.md +0 -408
- package/ai-config/skills/systems-iot/rust-systems/SKILL.md +0 -386
- package/ai-config/skills/systems-iot/tokio-async/SKILL.md +0 -324
- package/ai-config/skills/testing/playwright-e2e/SKILL.md +0 -289
- package/ai-config/skills/testing/testcontainers/SKILL.md +0 -299
- package/ai-config/skills/testing/vitest-testing/SKILL.md +0 -381
- package/ai-config/skills/workflow/ci-local-guide/SKILL.md +0 -118
- package/ai-config/skills/workflow/claude-automation-recommender/SKILL.md +0 -299
- package/ai-config/skills/workflow/claude-md-improver/SKILL.md +0 -158
- package/ai-config/skills/workflow/finishing-a-development-branch/SKILL.md +0 -117
- package/ai-config/skills/workflow/git-github/SKILL.md +0 -334
- package/ai-config/skills/workflow/git-github/references/examples.md +0 -160
- package/ai-config/skills/workflow/git-workflow/SKILL.md +0 -214
- package/ai-config/skills/workflow/ide-plugins/SKILL.md +0 -277
- package/ai-config/skills/workflow/ide-plugins-intellij/SKILL.md +0 -401
- package/ai-config/skills/workflow/obsidian-brain-workflow/SKILL.md +0 -199
- package/ai-config/skills/workflow/using-git-worktrees/SKILL.md +0 -100
- package/ai-config/skills/workflow/verification-before-completion/SKILL.md +0 -73
- package/ai-config/skills/workflow/wave-workflow/SKILL.md +0 -178
- package/schemas/agent.schema.json +0 -34
- package/schemas/ai-config.schema.json +0 -28
- package/schemas/plugin.schema.json +0 -62
- package/schemas/skill.schema.json +0 -44
|
@@ -1,417 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: zod-validation
|
|
3
|
-
description: >
|
|
4
|
-
Zod schema validation for TypeScript with runtime type checking, form validation, and API contracts.
|
|
5
|
-
Trigger: zod, validation, schema, typescript types, form validation, api contracts
|
|
6
|
-
tools:
|
|
7
|
-
- Read
|
|
8
|
-
- Write
|
|
9
|
-
- Grep
|
|
10
|
-
metadata:
|
|
11
|
-
author: plataforma-industrial
|
|
12
|
-
version: "2.0"
|
|
13
|
-
tags: [zod, validation, typescript, schemas, forms]
|
|
14
|
-
updated: "2026-02"
|
|
15
|
-
---
|
|
16
|
-
|
|
17
|
-
# Zod Schema Validation
|
|
18
|
-
|
|
19
|
-
## Stack
|
|
20
|
-
```json
|
|
21
|
-
{ "zod": "3.22.x" }
|
|
22
|
-
```
|
|
23
|
-
|
|
24
|
-
## Primitive Types
|
|
25
|
-
|
|
26
|
-
```typescript
|
|
27
|
-
import { z } from 'zod';
|
|
28
|
-
|
|
29
|
-
// Strings
|
|
30
|
-
const name = z.string().min(1, 'Required').max(100);
|
|
31
|
-
const email = z.string().email('Invalid email');
|
|
32
|
-
const uuid = z.string().uuid('Invalid ID');
|
|
33
|
-
|
|
34
|
-
// Numbers
|
|
35
|
-
const port = z.number().int().min(1).max(65535);
|
|
36
|
-
const percentage = z.number().min(0).max(100);
|
|
37
|
-
|
|
38
|
-
// Dates
|
|
39
|
-
const date = z.coerce.date(); // Converts strings to Date
|
|
40
|
-
const isoDate = z.string().datetime(); // Validates ISO format
|
|
41
|
-
|
|
42
|
-
// Enums
|
|
43
|
-
const status = z.enum(['active', 'inactive', 'pending']);
|
|
44
|
-
const role = z.enum(['admin', 'user', 'guest']);
|
|
45
|
-
|
|
46
|
-
// Boolean with default
|
|
47
|
-
const enabled = z.boolean().default(true);
|
|
48
|
-
|
|
49
|
-
// Nullable & Optional
|
|
50
|
-
const optionalStr = z.string().optional(); // string | undefined
|
|
51
|
-
const nullableStr = z.string().nullable(); // string | null
|
|
52
|
-
const nullishStr = z.string().nullish(); // string | null | undefined
|
|
53
|
-
```
|
|
54
|
-
|
|
55
|
-
## Domain Schema Example
|
|
56
|
-
|
|
57
|
-
```typescript
|
|
58
|
-
// lib/schemas/item.ts
|
|
59
|
-
import { z } from 'zod';
|
|
60
|
-
|
|
61
|
-
export const ItemTypeSchema = z.enum(['typeA', 'typeB', 'typeC']);
|
|
62
|
-
export const ItemStatusSchema = z.enum(['active', 'inactive', 'pending']);
|
|
63
|
-
|
|
64
|
-
export const ItemSchema = z.object({
|
|
65
|
-
id: z.string().uuid(),
|
|
66
|
-
name: z.string().min(1).max(100),
|
|
67
|
-
type: ItemTypeSchema,
|
|
68
|
-
status: ItemStatusSchema,
|
|
69
|
-
value: z.number().nullable(),
|
|
70
|
-
minValue: z.number(),
|
|
71
|
-
maxValue: z.number(),
|
|
72
|
-
parentId: z.string().uuid(),
|
|
73
|
-
createdAt: z.string().datetime(),
|
|
74
|
-
updatedAt: z.string().datetime(),
|
|
75
|
-
}).refine(
|
|
76
|
-
(data) => data.minValue < data.maxValue,
|
|
77
|
-
{ message: 'minValue must be less than maxValue', path: ['minValue'] }
|
|
78
|
-
);
|
|
79
|
-
|
|
80
|
-
export type Item = z.infer<typeof ItemSchema>;
|
|
81
|
-
export type ItemType = z.infer<typeof ItemTypeSchema>;
|
|
82
|
-
export type ItemStatus = z.infer<typeof ItemStatusSchema>;
|
|
83
|
-
|
|
84
|
-
// Create schema (omit auto-generated fields)
|
|
85
|
-
export const CreateItemSchema = ItemSchema.omit({
|
|
86
|
-
id: true,
|
|
87
|
-
status: true,
|
|
88
|
-
value: true,
|
|
89
|
-
createdAt: true,
|
|
90
|
-
updatedAt: true,
|
|
91
|
-
});
|
|
92
|
-
|
|
93
|
-
export type CreateItemInput = z.infer<typeof CreateItemSchema>;
|
|
94
|
-
|
|
95
|
-
// Update schema (all optional)
|
|
96
|
-
export const UpdateItemSchema = CreateItemSchema.partial();
|
|
97
|
-
export type UpdateItemInput = z.infer<typeof UpdateItemSchema>;
|
|
98
|
-
```
|
|
99
|
-
|
|
100
|
-
## User/Auth Schemas
|
|
101
|
-
|
|
102
|
-
```typescript
|
|
103
|
-
export const LoginSchema = z.object({
|
|
104
|
-
email: z.string().email('Invalid email'),
|
|
105
|
-
password: z.string().min(8, 'Minimum 8 characters'),
|
|
106
|
-
});
|
|
107
|
-
|
|
108
|
-
export const RegisterSchema = z.object({
|
|
109
|
-
email: z.string().email('Invalid email'),
|
|
110
|
-
password: z.string()
|
|
111
|
-
.min(8, 'Minimum 8 characters')
|
|
112
|
-
.regex(/[A-Z]/, 'Must contain uppercase')
|
|
113
|
-
.regex(/[a-z]/, 'Must contain lowercase')
|
|
114
|
-
.regex(/[0-9]/, 'Must contain number'),
|
|
115
|
-
confirmPassword: z.string(),
|
|
116
|
-
name: z.string().min(2, 'Name required'),
|
|
117
|
-
}).refine(
|
|
118
|
-
(data) => data.password === data.confirmPassword,
|
|
119
|
-
{ message: 'Passwords do not match', path: ['confirmPassword'] }
|
|
120
|
-
);
|
|
121
|
-
|
|
122
|
-
export type LoginInput = z.infer<typeof LoginSchema>;
|
|
123
|
-
export type RegisterInput = z.infer<typeof RegisterSchema>;
|
|
124
|
-
```
|
|
125
|
-
|
|
126
|
-
## API Response Schemas
|
|
127
|
-
|
|
128
|
-
```typescript
|
|
129
|
-
// Generic response wrapper
|
|
130
|
-
export function createDataResponse<T extends z.ZodTypeAny>(dataSchema: T) {
|
|
131
|
-
return z.object({ data: dataSchema });
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
// Paginated response
|
|
135
|
-
export function createPaginatedResponse<T extends z.ZodTypeAny>(dataSchema: T) {
|
|
136
|
-
return z.object({
|
|
137
|
-
data: z.array(dataSchema),
|
|
138
|
-
meta: z.object({
|
|
139
|
-
total: z.number(),
|
|
140
|
-
page: z.number(),
|
|
141
|
-
limit: z.number(),
|
|
142
|
-
totalPages: z.number(),
|
|
143
|
-
}),
|
|
144
|
-
});
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
// Error response
|
|
148
|
-
export const ApiErrorSchema = z.object({
|
|
149
|
-
error: z.string(),
|
|
150
|
-
code: z.string().optional(),
|
|
151
|
-
details: z.record(z.string(), z.string()).optional(),
|
|
152
|
-
});
|
|
153
|
-
|
|
154
|
-
// Usage
|
|
155
|
-
const ItemResponseSchema = createDataResponse(ItemSchema);
|
|
156
|
-
const ItemsListResponseSchema = createPaginatedResponse(ItemSchema);
|
|
157
|
-
```
|
|
158
|
-
|
|
159
|
-
## Filter/Query Schemas
|
|
160
|
-
|
|
161
|
-
```typescript
|
|
162
|
-
export const PaginationSchema = z.object({
|
|
163
|
-
page: z.coerce.number().int().min(1).default(1),
|
|
164
|
-
limit: z.coerce.number().int().min(1).max(100).default(20),
|
|
165
|
-
});
|
|
166
|
-
|
|
167
|
-
export const SortSchema = z.object({
|
|
168
|
-
sortBy: z.string().optional(),
|
|
169
|
-
sortOrder: z.enum(['asc', 'desc']).default('asc'),
|
|
170
|
-
});
|
|
171
|
-
|
|
172
|
-
export const ItemFiltersSchema = PaginationSchema.merge(SortSchema).extend({
|
|
173
|
-
status: ItemStatusSchema.optional(),
|
|
174
|
-
type: ItemTypeSchema.optional(),
|
|
175
|
-
parentId: z.string().uuid().optional(),
|
|
176
|
-
search: z.string().max(100).optional(),
|
|
177
|
-
});
|
|
178
|
-
|
|
179
|
-
export type ItemFilters = z.infer<typeof ItemFiltersSchema>;
|
|
180
|
-
|
|
181
|
-
// Date range with validation
|
|
182
|
-
export const DateRangeSchema = z.object({
|
|
183
|
-
from: z.coerce.date(),
|
|
184
|
-
to: z.coerce.date(),
|
|
185
|
-
}).refine(
|
|
186
|
-
(data) => data.from <= data.to,
|
|
187
|
-
{ message: 'from must be before or equal to to', path: ['from'] }
|
|
188
|
-
);
|
|
189
|
-
```
|
|
190
|
-
|
|
191
|
-
## Form Integration (Mantine)
|
|
192
|
-
|
|
193
|
-
```tsx
|
|
194
|
-
import { useForm, zodResolver } from '@mantine/form';
|
|
195
|
-
import { CreateItemSchema, type CreateItemInput } from '@/lib/schemas/item';
|
|
196
|
-
|
|
197
|
-
export function ItemForm() {
|
|
198
|
-
const form = useForm<CreateItemInput>({
|
|
199
|
-
validate: zodResolver(CreateItemSchema),
|
|
200
|
-
initialValues: {
|
|
201
|
-
name: '',
|
|
202
|
-
type: 'typeA',
|
|
203
|
-
minValue: 0,
|
|
204
|
-
maxValue: 100,
|
|
205
|
-
parentId: '',
|
|
206
|
-
},
|
|
207
|
-
});
|
|
208
|
-
|
|
209
|
-
return (
|
|
210
|
-
<form onSubmit={form.onSubmit(handleSubmit)}>
|
|
211
|
-
<TextInput label="Name" {...form.getInputProps('name')} />
|
|
212
|
-
{/* more fields */}
|
|
213
|
-
</form>
|
|
214
|
-
);
|
|
215
|
-
}
|
|
216
|
-
```
|
|
217
|
-
|
|
218
|
-
## Runtime Validation
|
|
219
|
-
|
|
220
|
-
```typescript
|
|
221
|
-
// API client with validation
|
|
222
|
-
export const itemsApi = {
|
|
223
|
-
list: async (filters?: ItemFilters) => {
|
|
224
|
-
const response = await api.get('items', { searchParams: filters }).json();
|
|
225
|
-
return ItemsListResponseSchema.parse(response);
|
|
226
|
-
},
|
|
227
|
-
|
|
228
|
-
get: async (id: string) => {
|
|
229
|
-
const response = await api.get(`items/${id}`).json();
|
|
230
|
-
return createDataResponse(ItemSchema).parse(response).data;
|
|
231
|
-
},
|
|
232
|
-
|
|
233
|
-
create: async (input: CreateItemInput) => {
|
|
234
|
-
const validated = CreateItemSchema.parse(input); // Validate before sending
|
|
235
|
-
const response = await api.post('items', { json: validated }).json();
|
|
236
|
-
return createDataResponse(ItemSchema).parse(response).data;
|
|
237
|
-
},
|
|
238
|
-
};
|
|
239
|
-
|
|
240
|
-
// Safe parse (no throw)
|
|
241
|
-
const result = ItemSchema.safeParse(data);
|
|
242
|
-
if (result.success) {
|
|
243
|
-
console.log(result.data.name);
|
|
244
|
-
} else {
|
|
245
|
-
console.error(result.error.issues);
|
|
246
|
-
}
|
|
247
|
-
```
|
|
248
|
-
|
|
249
|
-
## Advanced Patterns
|
|
250
|
-
|
|
251
|
-
### Discriminated Unions
|
|
252
|
-
```typescript
|
|
253
|
-
const EmailNotification = z.object({
|
|
254
|
-
type: z.literal('email'),
|
|
255
|
-
to: z.string().email(),
|
|
256
|
-
subject: z.string(),
|
|
257
|
-
body: z.string(),
|
|
258
|
-
});
|
|
259
|
-
|
|
260
|
-
const SmsNotification = z.object({
|
|
261
|
-
type: z.literal('sms'),
|
|
262
|
-
phone: z.string().regex(/^\+?[1-9]\d{1,14}$/),
|
|
263
|
-
message: z.string().max(160),
|
|
264
|
-
});
|
|
265
|
-
|
|
266
|
-
export const NotificationSchema = z.discriminatedUnion('type', [
|
|
267
|
-
EmailNotification,
|
|
268
|
-
SmsNotification,
|
|
269
|
-
]);
|
|
270
|
-
|
|
271
|
-
export type Notification = z.infer<typeof NotificationSchema>;
|
|
272
|
-
```
|
|
273
|
-
|
|
274
|
-
### Recursive Types
|
|
275
|
-
```typescript
|
|
276
|
-
interface TreeNode {
|
|
277
|
-
id: string;
|
|
278
|
-
name: string;
|
|
279
|
-
children?: TreeNode[];
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
const TreeNodeSchema: z.ZodType<TreeNode> = z.lazy(() =>
|
|
283
|
-
z.object({
|
|
284
|
-
id: z.string().uuid(),
|
|
285
|
-
name: z.string(),
|
|
286
|
-
children: z.array(TreeNodeSchema).optional(),
|
|
287
|
-
})
|
|
288
|
-
);
|
|
289
|
-
```
|
|
290
|
-
|
|
291
|
-
### Branded Types
|
|
292
|
-
```typescript
|
|
293
|
-
const ItemId = z.string().uuid().brand<'ItemId'>();
|
|
294
|
-
const UserId = z.string().uuid().brand<'UserId'>();
|
|
295
|
-
|
|
296
|
-
type ItemId = z.infer<typeof ItemId>;
|
|
297
|
-
type UserId = z.infer<typeof UserId>;
|
|
298
|
-
|
|
299
|
-
// Now ItemId and UserId are distinct types
|
|
300
|
-
function getItem(id: ItemId) { /* ... */ }
|
|
301
|
-
// getItem(userId) // Type error!
|
|
302
|
-
```
|
|
303
|
-
|
|
304
|
-
### Preprocessing
|
|
305
|
-
```typescript
|
|
306
|
-
// Clean data before validation
|
|
307
|
-
const SearchQuery = z.preprocess(
|
|
308
|
-
(val) => typeof val === 'string' ? val.trim().toLowerCase() : val,
|
|
309
|
-
z.string().min(2).max(100)
|
|
310
|
-
);
|
|
311
|
-
|
|
312
|
-
// Convert empty string to undefined
|
|
313
|
-
const OptionalString = z.preprocess(
|
|
314
|
-
(val) => (val === '' ? undefined : val),
|
|
315
|
-
z.string().optional()
|
|
316
|
-
);
|
|
317
|
-
```
|
|
318
|
-
|
|
319
|
-
### Transformations
|
|
320
|
-
```typescript
|
|
321
|
-
const CreateItemForm = z.object({
|
|
322
|
-
name: z.string().min(1).transform(s => s.trim()),
|
|
323
|
-
address: z.string().transform((val, ctx) => {
|
|
324
|
-
const num = parseInt(val, 10);
|
|
325
|
-
if (isNaN(num)) {
|
|
326
|
-
ctx.addIssue({ code: z.ZodIssueCode.custom, message: 'Must be a number' });
|
|
327
|
-
return z.NEVER;
|
|
328
|
-
}
|
|
329
|
-
return num;
|
|
330
|
-
}),
|
|
331
|
-
});
|
|
332
|
-
```
|
|
333
|
-
|
|
334
|
-
### Extending & Composing
|
|
335
|
-
```typescript
|
|
336
|
-
const BaseItem = z.object({ name: z.string(), type: ItemTypeSchema });
|
|
337
|
-
const FullItem = BaseItem.extend({
|
|
338
|
-
id: z.string().uuid(),
|
|
339
|
-
createdAt: z.string().datetime(),
|
|
340
|
-
});
|
|
341
|
-
|
|
342
|
-
// Pick & Omit
|
|
343
|
-
const ItemSummary = ItemSchema.pick({ id: true, name: true, status: true });
|
|
344
|
-
const ItemPublic = ItemSchema.omit({ internalField: true });
|
|
345
|
-
```
|
|
346
|
-
|
|
347
|
-
## Environment Variables
|
|
348
|
-
|
|
349
|
-
```typescript
|
|
350
|
-
// lib/env.ts
|
|
351
|
-
const EnvSchema = z.object({
|
|
352
|
-
DATABASE_URL: z.string().url(),
|
|
353
|
-
JWT_SECRET: z.string().min(32),
|
|
354
|
-
API_URL: z.string().url(),
|
|
355
|
-
PORT: z.coerce.number().default(3000),
|
|
356
|
-
NODE_ENV: z.enum(['development', 'production', 'test']).default('development'),
|
|
357
|
-
SENTRY_DSN: z.string().url().optional(),
|
|
358
|
-
});
|
|
359
|
-
|
|
360
|
-
export type Env = z.infer<typeof EnvSchema>;
|
|
361
|
-
|
|
362
|
-
export function validateEnv(): Env {
|
|
363
|
-
const result = EnvSchema.safeParse(process.env);
|
|
364
|
-
if (!result.success) {
|
|
365
|
-
console.error('Invalid environment variables:', result.error.flatten().fieldErrors);
|
|
366
|
-
process.exit(1);
|
|
367
|
-
}
|
|
368
|
-
return result.data;
|
|
369
|
-
}
|
|
370
|
-
|
|
371
|
-
export const env = validateEnv();
|
|
372
|
-
```
|
|
373
|
-
|
|
374
|
-
## Error Formatting
|
|
375
|
-
|
|
376
|
-
```typescript
|
|
377
|
-
import { ZodError } from 'zod';
|
|
378
|
-
|
|
379
|
-
export function formatZodError(error: ZodError): Record<string, string> {
|
|
380
|
-
const errors: Record<string, string> = {};
|
|
381
|
-
for (const issue of error.issues) {
|
|
382
|
-
const path = issue.path.join('.');
|
|
383
|
-
if (!errors[path]) errors[path] = issue.message;
|
|
384
|
-
}
|
|
385
|
-
return errors;
|
|
386
|
-
}
|
|
387
|
-
|
|
388
|
-
// API route error handling
|
|
389
|
-
export const POST: APIRoute = async ({ request }) => {
|
|
390
|
-
const body = await request.json();
|
|
391
|
-
const result = CreateItemSchema.safeParse(body);
|
|
392
|
-
|
|
393
|
-
if (!result.success) {
|
|
394
|
-
return new Response(JSON.stringify({
|
|
395
|
-
error: 'Validation failed',
|
|
396
|
-
details: result.error.flatten().fieldErrors,
|
|
397
|
-
}), { status: 400 });
|
|
398
|
-
}
|
|
399
|
-
|
|
400
|
-
// Continue with result.data...
|
|
401
|
-
};
|
|
402
|
-
```
|
|
403
|
-
|
|
404
|
-
## Best Practices
|
|
405
|
-
|
|
406
|
-
1. **Schemas near usage**: Keep schema in same file as type
|
|
407
|
-
2. **Derive from base**: `CreateSchema = Schema.omit({...})`, `UpdateSchema = CreateSchema.partial()`
|
|
408
|
-
3. **Validate at boundaries**: API responses, user input, env vars, query params
|
|
409
|
-
4. **Use safeParse for expected errors**: Form validation, user input
|
|
410
|
-
5. **Use parse for unexpected errors**: Trusted internal data
|
|
411
|
-
|
|
412
|
-
## Related Skills
|
|
413
|
-
|
|
414
|
-
- `tanstack-query`: API response validation
|
|
415
|
-
- `mantine-ui`: Form validation integration
|
|
416
|
-
- `fastapi`: Pydantic-like validation patterns
|
|
417
|
-
- `jwt-auth`: Token payload validation
|