@girardmedia/bootspring 1.2.0 → 2.0.3
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/README.md +107 -14
- package/bin/bootspring.js +166 -27
- package/cli/agent.js +189 -17
- package/cli/analyze.js +499 -0
- package/cli/audit.js +557 -0
- package/cli/auth.js +495 -38
- package/cli/billing.js +302 -0
- package/cli/build.js +695 -0
- package/cli/business.js +109 -26
- package/cli/checkpoint-utils.js +168 -0
- package/cli/checkpoint.js +639 -0
- package/cli/cloud-sync.js +447 -0
- package/cli/content.js +198 -0
- package/cli/context.js +1 -1
- package/cli/deploy.js +543 -0
- package/cli/fundraise.js +112 -50
- package/cli/github-cmd.js +435 -0
- package/cli/health.js +477 -0
- package/cli/init.js +84 -13
- package/cli/legal.js +107 -95
- package/cli/log.js +2 -2
- package/cli/loop.js +976 -73
- package/cli/manager.js +711 -0
- package/cli/metrics.js +480 -0
- package/cli/monitor.js +812 -0
- package/cli/onboard.js +521 -0
- package/cli/orchestrator.js +12 -24
- package/cli/prd.js +594 -0
- package/cli/preseed-start.js +1483 -0
- package/cli/preseed.js +2302 -0
- package/cli/project.js +436 -0
- package/cli/quality.js +233 -0
- package/cli/security.js +913 -0
- package/cli/seed.js +1441 -5
- package/cli/skill.js +273 -211
- package/cli/suggest.js +989 -0
- package/cli/switch.js +453 -0
- package/cli/visualize.js +527 -0
- package/cli/watch.js +769 -0
- package/cli/workspace.js +607 -0
- package/core/analyze-workflow.js +1134 -0
- package/core/api-client.js +535 -22
- package/core/audit-workflow.js +1350 -0
- package/core/build-orchestrator.js +480 -0
- package/core/build-state.js +577 -0
- package/core/checkpoint-engine.js +408 -0
- package/core/config.js +1109 -26
- package/core/context-loader.js +21 -1
- package/core/deploy-workflow.js +836 -0
- package/core/entitlements.js +93 -22
- package/core/github-sync.js +610 -0
- package/core/index.js +8 -1
- package/core/ingest.js +1111 -0
- package/core/metrics-engine.js +768 -0
- package/core/onboard-workflow.js +1007 -0
- package/core/preseed-workflow.js +934 -0
- package/core/preseed.js +1617 -0
- package/core/project-context.js +325 -0
- package/core/project-state.js +694 -0
- package/core/r2-sync.js +583 -0
- package/core/scaffold.js +525 -7
- package/core/session.js +258 -0
- package/core/task-extractor.js +758 -0
- package/core/telemetry.js +28 -6
- package/core/tier-enforcement.js +737 -0
- package/core/utils.js +38 -14
- package/generators/questionnaire.js +15 -12
- package/generators/sections/ai.js +7 -7
- package/generators/sections/content.js +300 -0
- package/generators/sections/index.js +3 -0
- package/generators/sections/plugins.js +7 -6
- package/generators/templates/build-planning.template.js +596 -0
- package/generators/templates/content.template.js +819 -0
- package/generators/templates/index.js +2 -1
- package/hooks/git-autopilot.js +1250 -0
- package/hooks/index.js +9 -0
- package/intelligence/agent-collab.js +2057 -0
- package/intelligence/auto-suggest.js +634 -0
- package/intelligence/content-gen.js +1589 -0
- package/intelligence/cross-project.js +1647 -0
- package/intelligence/index.js +184 -0
- package/intelligence/learning/insights.json +517 -7
- package/intelligence/learning/pattern-learner.js +1008 -14
- package/intelligence/memory/decision-tracker.js +1431 -31
- package/intelligence/memory/decisions.jsonl +0 -0
- package/intelligence/orchestrator.js +2896 -1
- package/intelligence/prd.js +92 -1
- package/intelligence/recommendation-weights.json +14 -2
- package/intelligence/recommendations.js +463 -9
- package/intelligence/workflow-composer.js +1451 -0
- package/marketplace/index.d.ts +324 -0
- package/marketplace/index.js +1921 -0
- package/mcp/contracts/mcp-contract.v1.json +342 -4
- package/mcp/registry.js +680 -3
- package/mcp/response-formatter.js +23 -0
- package/mcp/tools/assist-tool.js +78 -4
- package/mcp/tools/autopilot-tool.js +408 -0
- package/mcp/tools/content-tool.js +571 -0
- package/mcp/tools/dashboard-tool.js +251 -5
- package/mcp/tools/mvp-tool.js +344 -0
- package/mcp/tools/plugin-tool.js +23 -1
- package/mcp/tools/prd-tool.js +579 -0
- package/mcp/tools/seed-tool.js +447 -0
- package/mcp/tools/skill-tool.js +43 -14
- package/mcp/tools/suggest-tool.js +147 -0
- package/package.json +15 -6
- package/agents/README.md +0 -93
- package/agents/ai-integration-expert/context.md +0 -386
- package/agents/api-expert/context.md +0 -416
- package/agents/architecture-expert/context.md +0 -454
- package/agents/auth-expert/context.md +0 -399
- package/agents/backend-expert/context.md +0 -483
- package/agents/business-strategy-expert/context.md +0 -180
- package/agents/code-review-expert/context.md +0 -365
- package/agents/competitive-analysis-expert/context.md +0 -239
- package/agents/data-modeling-expert/context.md +0 -352
- package/agents/database-expert/context.md +0 -250
- package/agents/devops-expert/context.md +0 -446
- package/agents/email-expert/context.md +0 -379
- package/agents/financial-expert/context.md +0 -213
- package/agents/frontend-expert/context.md +0 -364
- package/agents/fundraising-expert/context.md +0 -257
- package/agents/growth-expert/context.md +0 -249
- package/agents/index.js +0 -140
- package/agents/investor-relations-expert/context.md +0 -266
- package/agents/legal-expert/context.md +0 -284
- package/agents/marketing-expert/context.md +0 -236
- package/agents/monitoring-expert/context.md +0 -362
- package/agents/operations-expert/context.md +0 -279
- package/agents/partnerships-expert/context.md +0 -286
- package/agents/payment-expert/context.md +0 -340
- package/agents/performance-expert/context.md +0 -377
- package/agents/private-equity-expert/context.md +0 -246
- package/agents/railway-expert/context.md +0 -284
- package/agents/research-expert/context.md +0 -245
- package/agents/sales-expert/context.md +0 -241
- package/agents/security-expert/context.md +0 -343
- package/agents/testing-expert/context.md +0 -414
- package/agents/ui-ux-expert/context.md +0 -448
- package/agents/vercel-expert/context.md +0 -426
- package/skills/index.js +0 -787
- package/skills/patterns/README.md +0 -163
- package/skills/patterns/ai/agents.md +0 -281
- package/skills/patterns/ai/claude.md +0 -138
- package/skills/patterns/ai/embeddings.md +0 -150
- package/skills/patterns/ai/rag.md +0 -266
- package/skills/patterns/ai/streaming.md +0 -170
- package/skills/patterns/ai/structured-output.md +0 -162
- package/skills/patterns/ai/tools.md +0 -154
- package/skills/patterns/analytics/tracking.md +0 -220
- package/skills/patterns/api/errors.md +0 -296
- package/skills/patterns/api/graphql.md +0 -440
- package/skills/patterns/api/middleware.md +0 -279
- package/skills/patterns/api/openapi.md +0 -285
- package/skills/patterns/api/rate-limiting.md +0 -231
- package/skills/patterns/api/route-handler.md +0 -217
- package/skills/patterns/api/server-action.md +0 -249
- package/skills/patterns/api/versioning.md +0 -443
- package/skills/patterns/api/webhooks.md +0 -247
- package/skills/patterns/auth/clerk.md +0 -132
- package/skills/patterns/auth/mfa.md +0 -313
- package/skills/patterns/auth/nextauth.md +0 -140
- package/skills/patterns/auth/oauth.md +0 -237
- package/skills/patterns/auth/rbac.md +0 -152
- package/skills/patterns/auth/session-management.md +0 -367
- package/skills/patterns/auth/session.md +0 -120
- package/skills/patterns/database/audit.md +0 -177
- package/skills/patterns/database/migrations.md +0 -177
- package/skills/patterns/database/pagination.md +0 -230
- package/skills/patterns/database/pooling.md +0 -357
- package/skills/patterns/database/prisma.md +0 -180
- package/skills/patterns/database/relations.md +0 -187
- package/skills/patterns/database/seeding.md +0 -246
- package/skills/patterns/database/soft-delete.md +0 -153
- package/skills/patterns/database/transactions.md +0 -162
- package/skills/patterns/deployment/ci-cd.md +0 -231
- package/skills/patterns/deployment/docker.md +0 -188
- package/skills/patterns/deployment/monitoring.md +0 -387
- package/skills/patterns/deployment/vercel.md +0 -160
- package/skills/patterns/email/resend.md +0 -143
- package/skills/patterns/email/templates.md +0 -245
- package/skills/patterns/email/transactional.md +0 -503
- package/skills/patterns/email/verification.md +0 -176
- package/skills/patterns/files/download.md +0 -243
- package/skills/patterns/files/upload.md +0 -239
- package/skills/patterns/i18n/nextintl.md +0 -188
- package/skills/patterns/logging/structured.md +0 -292
- package/skills/patterns/notifications/email-queue.md +0 -248
- package/skills/patterns/notifications/push.md +0 -279
- package/skills/patterns/payments/checkout.md +0 -303
- package/skills/patterns/payments/invoices.md +0 -287
- package/skills/patterns/payments/portal.md +0 -245
- package/skills/patterns/payments/stripe.md +0 -272
- package/skills/patterns/payments/subscriptions.md +0 -300
- package/skills/patterns/payments/usage.md +0 -279
- package/skills/patterns/performance/caching.md +0 -276
- package/skills/patterns/performance/code-splitting.md +0 -233
- package/skills/patterns/performance/edge.md +0 -254
- package/skills/patterns/performance/isr.md +0 -266
- package/skills/patterns/performance/lazy-loading.md +0 -281
- package/skills/patterns/realtime/sse.md +0 -327
- package/skills/patterns/realtime/websockets.md +0 -336
- package/skills/patterns/search/filtering.md +0 -329
- package/skills/patterns/search/fulltext.md +0 -260
- package/skills/patterns/security/audit-logging.md +0 -444
- package/skills/patterns/security/csrf.md +0 -234
- package/skills/patterns/security/headers.md +0 -252
- package/skills/patterns/security/sanitization.md +0 -258
- package/skills/patterns/security/secrets.md +0 -261
- package/skills/patterns/security/validation.md +0 -268
- package/skills/patterns/security/xss.md +0 -229
- package/skills/patterns/seo/metadata.md +0 -252
- package/skills/patterns/state/context.md +0 -349
- package/skills/patterns/state/react-query.md +0 -313
- package/skills/patterns/state/url-state.md +0 -482
- package/skills/patterns/state/zustand.md +0 -262
- package/skills/patterns/testing/api.md +0 -259
- package/skills/patterns/testing/component.md +0 -233
- package/skills/patterns/testing/coverage.md +0 -207
- package/skills/patterns/testing/fixtures.md +0 -225
- package/skills/patterns/testing/integration.md +0 -436
- package/skills/patterns/testing/mocking.md +0 -177
- package/skills/patterns/testing/playwright.md +0 -162
- package/skills/patterns/testing/snapshot.md +0 -175
- package/skills/patterns/testing/vitest.md +0 -307
- package/skills/patterns/ui/accordions.md +0 -395
- package/skills/patterns/ui/cards.md +0 -299
- package/skills/patterns/ui/dropdowns.md +0 -476
- package/skills/patterns/ui/empty-states.md +0 -320
- package/skills/patterns/ui/forms.md +0 -405
- package/skills/patterns/ui/inputs.md +0 -319
- package/skills/patterns/ui/layouts.md +0 -282
- package/skills/patterns/ui/loading.md +0 -291
- package/skills/patterns/ui/modals.md +0 -338
- package/skills/patterns/ui/navigation.md +0 -374
- package/skills/patterns/ui/tables.md +0 -407
- package/skills/patterns/ui/toasts.md +0 -300
- package/skills/patterns/ui/tooltips.md +0 -396
- package/skills/patterns/utils/dates.md +0 -435
- package/skills/patterns/utils/errors.md +0 -451
- package/skills/patterns/utils/formatting.md +0 -345
- package/skills/patterns/utils/validation.md +0 -434
- package/templates/bootspring.config.js +0 -83
- package/templates/business/business-model-canvas.md +0 -246
- package/templates/business/business-plan.md +0 -266
- package/templates/business/competitive-analysis.md +0 -312
- package/templates/fundraising/data-room-checklist.md +0 -300
- package/templates/fundraising/investor-research.md +0 -243
- package/templates/fundraising/pitch-deck-outline.md +0 -253
- package/templates/legal/gdpr-checklist.md +0 -339
- package/templates/legal/privacy-policy.md +0 -285
- package/templates/legal/terms-of-service.md +0 -222
- package/templates/mcp.json +0 -9
|
@@ -1,434 +0,0 @@
|
|
|
1
|
-
# Validation Patterns
|
|
2
|
-
|
|
3
|
-
Patterns for input validation with Zod.
|
|
4
|
-
|
|
5
|
-
## Basic Schemas
|
|
6
|
-
|
|
7
|
-
```typescript
|
|
8
|
-
// lib/validations/common.ts
|
|
9
|
-
import { z } from 'zod'
|
|
10
|
-
|
|
11
|
-
// Email validation
|
|
12
|
-
export const emailSchema = z
|
|
13
|
-
.string()
|
|
14
|
-
.email('Invalid email address')
|
|
15
|
-
.toLowerCase()
|
|
16
|
-
.trim()
|
|
17
|
-
|
|
18
|
-
// Password validation
|
|
19
|
-
export const passwordSchema = z
|
|
20
|
-
.string()
|
|
21
|
-
.min(8, 'Password must be at least 8 characters')
|
|
22
|
-
.regex(/[A-Z]/, 'Password must contain an uppercase letter')
|
|
23
|
-
.regex(/[a-z]/, 'Password must contain a lowercase letter')
|
|
24
|
-
.regex(/[0-9]/, 'Password must contain a number')
|
|
25
|
-
|
|
26
|
-
// Username validation
|
|
27
|
-
export const usernameSchema = z
|
|
28
|
-
.string()
|
|
29
|
-
.min(3, 'Username must be at least 3 characters')
|
|
30
|
-
.max(20, 'Username must be at most 20 characters')
|
|
31
|
-
.regex(/^[a-zA-Z0-9_]+$/, 'Username can only contain letters, numbers, and underscores')
|
|
32
|
-
|
|
33
|
-
// URL validation
|
|
34
|
-
export const urlSchema = z
|
|
35
|
-
.string()
|
|
36
|
-
.url('Invalid URL')
|
|
37
|
-
.or(z.literal(''))
|
|
38
|
-
|
|
39
|
-
// Phone number
|
|
40
|
-
export const phoneSchema = z
|
|
41
|
-
.string()
|
|
42
|
-
.regex(/^\+?[1-9]\d{1,14}$/, 'Invalid phone number')
|
|
43
|
-
|
|
44
|
-
// Slug validation
|
|
45
|
-
export const slugSchema = z
|
|
46
|
-
.string()
|
|
47
|
-
.min(1)
|
|
48
|
-
.max(100)
|
|
49
|
-
.regex(/^[a-z0-9]+(?:-[a-z0-9]+)*$/, 'Invalid slug format')
|
|
50
|
-
|
|
51
|
-
// UUID validation
|
|
52
|
-
export const uuidSchema = z.string().uuid('Invalid ID format')
|
|
53
|
-
|
|
54
|
-
// Date string (ISO format)
|
|
55
|
-
export const dateStringSchema = z
|
|
56
|
-
.string()
|
|
57
|
-
.datetime({ message: 'Invalid date format' })
|
|
58
|
-
|
|
59
|
-
// Positive number
|
|
60
|
-
export const positiveNumberSchema = z
|
|
61
|
-
.number()
|
|
62
|
-
.positive('Must be a positive number')
|
|
63
|
-
|
|
64
|
-
// Non-empty string
|
|
65
|
-
export const nonEmptyStringSchema = z
|
|
66
|
-
.string()
|
|
67
|
-
.min(1, 'This field is required')
|
|
68
|
-
.trim()
|
|
69
|
-
```
|
|
70
|
-
|
|
71
|
-
## Form Schemas
|
|
72
|
-
|
|
73
|
-
```typescript
|
|
74
|
-
// lib/validations/auth.ts
|
|
75
|
-
import { z } from 'zod'
|
|
76
|
-
import { emailSchema, passwordSchema } from './common'
|
|
77
|
-
|
|
78
|
-
export const loginSchema = z.object({
|
|
79
|
-
email: emailSchema,
|
|
80
|
-
password: z.string().min(1, 'Password is required'),
|
|
81
|
-
rememberMe: z.boolean().optional()
|
|
82
|
-
})
|
|
83
|
-
|
|
84
|
-
export const registerSchema = z
|
|
85
|
-
.object({
|
|
86
|
-
name: z.string().min(2, 'Name must be at least 2 characters'),
|
|
87
|
-
email: emailSchema,
|
|
88
|
-
password: passwordSchema,
|
|
89
|
-
confirmPassword: z.string()
|
|
90
|
-
})
|
|
91
|
-
.refine(data => data.password === data.confirmPassword, {
|
|
92
|
-
message: 'Passwords do not match',
|
|
93
|
-
path: ['confirmPassword']
|
|
94
|
-
})
|
|
95
|
-
|
|
96
|
-
export const forgotPasswordSchema = z.object({
|
|
97
|
-
email: emailSchema
|
|
98
|
-
})
|
|
99
|
-
|
|
100
|
-
export const resetPasswordSchema = z
|
|
101
|
-
.object({
|
|
102
|
-
token: z.string().min(1),
|
|
103
|
-
password: passwordSchema,
|
|
104
|
-
confirmPassword: z.string()
|
|
105
|
-
})
|
|
106
|
-
.refine(data => data.password === data.confirmPassword, {
|
|
107
|
-
message: 'Passwords do not match',
|
|
108
|
-
path: ['confirmPassword']
|
|
109
|
-
})
|
|
110
|
-
|
|
111
|
-
export type LoginInput = z.infer<typeof loginSchema>
|
|
112
|
-
export type RegisterInput = z.infer<typeof registerSchema>
|
|
113
|
-
```
|
|
114
|
-
|
|
115
|
-
## API Input Validation
|
|
116
|
-
|
|
117
|
-
```typescript
|
|
118
|
-
// lib/validations/api.ts
|
|
119
|
-
import { z } from 'zod'
|
|
120
|
-
|
|
121
|
-
// Pagination params
|
|
122
|
-
export const paginationSchema = z.object({
|
|
123
|
-
page: z.coerce.number().int().positive().default(1),
|
|
124
|
-
limit: z.coerce.number().int().min(1).max(100).default(20),
|
|
125
|
-
sort: z.string().optional(),
|
|
126
|
-
order: z.enum(['asc', 'desc']).default('desc')
|
|
127
|
-
})
|
|
128
|
-
|
|
129
|
-
// Search params
|
|
130
|
-
export const searchSchema = z.object({
|
|
131
|
-
q: z.string().min(1).max(100).optional(),
|
|
132
|
-
filters: z.record(z.string()).optional()
|
|
133
|
-
})
|
|
134
|
-
|
|
135
|
-
// ID param
|
|
136
|
-
export const idParamSchema = z.object({
|
|
137
|
-
id: z.string().cuid()
|
|
138
|
-
})
|
|
139
|
-
|
|
140
|
-
// Create post
|
|
141
|
-
export const createPostSchema = z.object({
|
|
142
|
-
title: z.string().min(1).max(200),
|
|
143
|
-
content: z.string().min(1),
|
|
144
|
-
excerpt: z.string().max(500).optional(),
|
|
145
|
-
slug: z.string().regex(/^[a-z0-9-]+$/).optional(),
|
|
146
|
-
published: z.boolean().default(false),
|
|
147
|
-
categoryId: z.string().cuid().optional(),
|
|
148
|
-
tags: z.array(z.string()).max(10).optional()
|
|
149
|
-
})
|
|
150
|
-
|
|
151
|
-
// Update post (partial)
|
|
152
|
-
export const updatePostSchema = createPostSchema.partial()
|
|
153
|
-
|
|
154
|
-
// Validate in API route
|
|
155
|
-
import { NextRequest, NextResponse } from 'next/server'
|
|
156
|
-
|
|
157
|
-
export async function POST(request: NextRequest) {
|
|
158
|
-
const body = await request.json()
|
|
159
|
-
|
|
160
|
-
const result = createPostSchema.safeParse(body)
|
|
161
|
-
|
|
162
|
-
if (!result.success) {
|
|
163
|
-
return NextResponse.json(
|
|
164
|
-
{
|
|
165
|
-
error: 'Validation failed',
|
|
166
|
-
details: result.error.flatten().fieldErrors
|
|
167
|
-
},
|
|
168
|
-
{ status: 400 }
|
|
169
|
-
)
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
// result.data is typed and validated
|
|
173
|
-
const post = await prisma.post.create({ data: result.data })
|
|
174
|
-
|
|
175
|
-
return NextResponse.json(post, { status: 201 })
|
|
176
|
-
}
|
|
177
|
-
```
|
|
178
|
-
|
|
179
|
-
## Validation Helper
|
|
180
|
-
|
|
181
|
-
```typescript
|
|
182
|
-
// lib/validations/validate.ts
|
|
183
|
-
import { z } from 'zod'
|
|
184
|
-
import { NextRequest, NextResponse } from 'next/server'
|
|
185
|
-
|
|
186
|
-
export class ValidationError extends Error {
|
|
187
|
-
constructor(
|
|
188
|
-
public errors: z.ZodError,
|
|
189
|
-
message = 'Validation failed'
|
|
190
|
-
) {
|
|
191
|
-
super(message)
|
|
192
|
-
this.name = 'ValidationError'
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
export function validate<T extends z.ZodSchema>(
|
|
197
|
-
schema: T,
|
|
198
|
-
data: unknown
|
|
199
|
-
): z.infer<T> {
|
|
200
|
-
const result = schema.safeParse(data)
|
|
201
|
-
|
|
202
|
-
if (!result.success) {
|
|
203
|
-
throw new ValidationError(result.error)
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
return result.data
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
// Middleware wrapper
|
|
210
|
-
type Handler<T> = (
|
|
211
|
-
req: NextRequest,
|
|
212
|
-
validated: T,
|
|
213
|
-
context?: any
|
|
214
|
-
) => Promise<NextResponse>
|
|
215
|
-
|
|
216
|
-
export function withValidation<T extends z.ZodSchema>(
|
|
217
|
-
schema: T,
|
|
218
|
-
handler: Handler<z.infer<T>>
|
|
219
|
-
) {
|
|
220
|
-
return async (req: NextRequest, context?: any) => {
|
|
221
|
-
try {
|
|
222
|
-
const body = await req.json()
|
|
223
|
-
const validated = validate(schema, body)
|
|
224
|
-
return handler(req, validated, context)
|
|
225
|
-
} catch (error) {
|
|
226
|
-
if (error instanceof ValidationError) {
|
|
227
|
-
return NextResponse.json(
|
|
228
|
-
{
|
|
229
|
-
error: 'Validation failed',
|
|
230
|
-
details: error.errors.flatten().fieldErrors
|
|
231
|
-
},
|
|
232
|
-
{ status: 400 }
|
|
233
|
-
)
|
|
234
|
-
}
|
|
235
|
-
throw error
|
|
236
|
-
}
|
|
237
|
-
}
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
// Usage
|
|
241
|
-
export const POST = withValidation(createPostSchema, async (req, data) => {
|
|
242
|
-
const post = await prisma.post.create({ data })
|
|
243
|
-
return NextResponse.json(post, { status: 201 })
|
|
244
|
-
})
|
|
245
|
-
```
|
|
246
|
-
|
|
247
|
-
## Custom Validators
|
|
248
|
-
|
|
249
|
-
```typescript
|
|
250
|
-
// lib/validations/custom.ts
|
|
251
|
-
import { z } from 'zod'
|
|
252
|
-
import { prisma } from '@/lib/db'
|
|
253
|
-
|
|
254
|
-
// Unique email check
|
|
255
|
-
export const uniqueEmailSchema = z
|
|
256
|
-
.string()
|
|
257
|
-
.email()
|
|
258
|
-
.refine(
|
|
259
|
-
async email => {
|
|
260
|
-
const existing = await prisma.user.findUnique({
|
|
261
|
-
where: { email },
|
|
262
|
-
select: { id: true }
|
|
263
|
-
})
|
|
264
|
-
return !existing
|
|
265
|
-
},
|
|
266
|
-
{ message: 'Email already in use' }
|
|
267
|
-
)
|
|
268
|
-
|
|
269
|
-
// Existing resource check
|
|
270
|
-
export function existsInDatabase(
|
|
271
|
-
table: 'user' | 'post' | 'team',
|
|
272
|
-
field: 'id' | 'slug' = 'id'
|
|
273
|
-
) {
|
|
274
|
-
return z.string().refine(
|
|
275
|
-
async value => {
|
|
276
|
-
const record = await (prisma as any)[table].findUnique({
|
|
277
|
-
where: { [field]: value },
|
|
278
|
-
select: { id: true }
|
|
279
|
-
})
|
|
280
|
-
return !!record
|
|
281
|
-
},
|
|
282
|
-
{ message: `${table} not found` }
|
|
283
|
-
)
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
// File validation
|
|
287
|
-
export const fileSchema = z.object({
|
|
288
|
-
name: z.string(),
|
|
289
|
-
size: z.number().max(5 * 1024 * 1024, 'File must be less than 5MB'),
|
|
290
|
-
type: z.string().refine(
|
|
291
|
-
type => ['image/jpeg', 'image/png', 'image/webp'].includes(type),
|
|
292
|
-
'Invalid file type'
|
|
293
|
-
)
|
|
294
|
-
})
|
|
295
|
-
|
|
296
|
-
// Credit card (basic format)
|
|
297
|
-
export const creditCardSchema = z
|
|
298
|
-
.string()
|
|
299
|
-
.regex(/^\d{13,19}$/, 'Invalid card number')
|
|
300
|
-
.refine(luhnCheck, 'Invalid card number')
|
|
301
|
-
|
|
302
|
-
function luhnCheck(cardNumber: string): boolean {
|
|
303
|
-
let sum = 0
|
|
304
|
-
let isEven = false
|
|
305
|
-
|
|
306
|
-
for (let i = cardNumber.length - 1; i >= 0; i--) {
|
|
307
|
-
let digit = parseInt(cardNumber[i], 10)
|
|
308
|
-
|
|
309
|
-
if (isEven) {
|
|
310
|
-
digit *= 2
|
|
311
|
-
if (digit > 9) digit -= 9
|
|
312
|
-
}
|
|
313
|
-
|
|
314
|
-
sum += digit
|
|
315
|
-
isEven = !isEven
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
return sum % 10 === 0
|
|
319
|
-
}
|
|
320
|
-
```
|
|
321
|
-
|
|
322
|
-
## Form Validation Hook
|
|
323
|
-
|
|
324
|
-
```tsx
|
|
325
|
-
// hooks/useFormValidation.ts
|
|
326
|
-
'use client'
|
|
327
|
-
|
|
328
|
-
import { useState, useCallback } from 'react'
|
|
329
|
-
import { z } from 'zod'
|
|
330
|
-
|
|
331
|
-
interface UseFormValidationOptions<T extends z.ZodSchema> {
|
|
332
|
-
schema: T
|
|
333
|
-
onSubmit: (data: z.infer<T>) => Promise<void>
|
|
334
|
-
}
|
|
335
|
-
|
|
336
|
-
export function useFormValidation<T extends z.ZodSchema>({
|
|
337
|
-
schema,
|
|
338
|
-
onSubmit
|
|
339
|
-
}: UseFormValidationOptions<T>) {
|
|
340
|
-
const [errors, setErrors] = useState<Record<string, string>>({})
|
|
341
|
-
const [isSubmitting, setIsSubmitting] = useState(false)
|
|
342
|
-
|
|
343
|
-
const validate = useCallback(
|
|
344
|
-
(data: unknown): z.infer<T> | null => {
|
|
345
|
-
const result = schema.safeParse(data)
|
|
346
|
-
|
|
347
|
-
if (!result.success) {
|
|
348
|
-
const fieldErrors: Record<string, string> = {}
|
|
349
|
-
result.error.errors.forEach(err => {
|
|
350
|
-
const path = err.path.join('.')
|
|
351
|
-
if (!fieldErrors[path]) {
|
|
352
|
-
fieldErrors[path] = err.message
|
|
353
|
-
}
|
|
354
|
-
})
|
|
355
|
-
setErrors(fieldErrors)
|
|
356
|
-
return null
|
|
357
|
-
}
|
|
358
|
-
|
|
359
|
-
setErrors({})
|
|
360
|
-
return result.data
|
|
361
|
-
},
|
|
362
|
-
[schema]
|
|
363
|
-
)
|
|
364
|
-
|
|
365
|
-
const handleSubmit = useCallback(
|
|
366
|
-
async (data: unknown) => {
|
|
367
|
-
const validated = validate(data)
|
|
368
|
-
if (!validated) return
|
|
369
|
-
|
|
370
|
-
setIsSubmitting(true)
|
|
371
|
-
try {
|
|
372
|
-
await onSubmit(validated)
|
|
373
|
-
} finally {
|
|
374
|
-
setIsSubmitting(false)
|
|
375
|
-
}
|
|
376
|
-
},
|
|
377
|
-
[validate, onSubmit]
|
|
378
|
-
)
|
|
379
|
-
|
|
380
|
-
const getFieldError = useCallback(
|
|
381
|
-
(field: string) => errors[field],
|
|
382
|
-
[errors]
|
|
383
|
-
)
|
|
384
|
-
|
|
385
|
-
const clearErrors = useCallback(() => setErrors({}), [])
|
|
386
|
-
|
|
387
|
-
return {
|
|
388
|
-
errors,
|
|
389
|
-
isSubmitting,
|
|
390
|
-
validate,
|
|
391
|
-
handleSubmit,
|
|
392
|
-
getFieldError,
|
|
393
|
-
clearErrors
|
|
394
|
-
}
|
|
395
|
-
}
|
|
396
|
-
```
|
|
397
|
-
|
|
398
|
-
## Error Display Component
|
|
399
|
-
|
|
400
|
-
```tsx
|
|
401
|
-
// components/FormError.tsx
|
|
402
|
-
interface FormErrorProps {
|
|
403
|
-
error?: string
|
|
404
|
-
}
|
|
405
|
-
|
|
406
|
-
export function FormError({ error }: FormErrorProps) {
|
|
407
|
-
if (!error) return null
|
|
408
|
-
|
|
409
|
-
return (
|
|
410
|
-
<p className="mt-1 text-sm text-red-600" role="alert">
|
|
411
|
-
{error}
|
|
412
|
-
</p>
|
|
413
|
-
)
|
|
414
|
-
}
|
|
415
|
-
|
|
416
|
-
// Usage
|
|
417
|
-
<div>
|
|
418
|
-
<label htmlFor="email">Email</label>
|
|
419
|
-
<input
|
|
420
|
-
id="email"
|
|
421
|
-
type="email"
|
|
422
|
-
aria-invalid={!!errors.email}
|
|
423
|
-
aria-describedby={errors.email ? 'email-error' : undefined}
|
|
424
|
-
/>
|
|
425
|
-
<FormError error={errors.email} />
|
|
426
|
-
</div>
|
|
427
|
-
```
|
|
428
|
-
|
|
429
|
-
## When to Use
|
|
430
|
-
|
|
431
|
-
- Form validation
|
|
432
|
-
- API input validation
|
|
433
|
-
- Data sanitization
|
|
434
|
-
- Type safety
|
|
@@ -1,83 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Bootspring Configuration
|
|
3
|
-
* Copy this file to your project root and customize
|
|
4
|
-
*/
|
|
5
|
-
module.exports = {
|
|
6
|
-
// Project information
|
|
7
|
-
project: {
|
|
8
|
-
name: 'My Project',
|
|
9
|
-
description: 'A modern web application',
|
|
10
|
-
version: '0.1.0'
|
|
11
|
-
},
|
|
12
|
-
|
|
13
|
-
// Technology stack
|
|
14
|
-
stack: {
|
|
15
|
-
framework: 'nextjs', // nextjs, remix, astro
|
|
16
|
-
language: 'typescript', // typescript, javascript
|
|
17
|
-
database: 'postgresql', // postgresql, mysql, mongodb
|
|
18
|
-
hosting: 'vercel' // vercel, aws, railway
|
|
19
|
-
},
|
|
20
|
-
|
|
21
|
-
// Enabled plugins
|
|
22
|
-
plugins: {
|
|
23
|
-
auth: {
|
|
24
|
-
enabled: true,
|
|
25
|
-
provider: 'clerk', // clerk, nextauth, auth0, supabase
|
|
26
|
-
features: ['social_login', 'email_password']
|
|
27
|
-
},
|
|
28
|
-
payments: {
|
|
29
|
-
enabled: false,
|
|
30
|
-
provider: 'stripe', // stripe, paddle, lemonsqueezy
|
|
31
|
-
features: ['checkout', 'subscriptions']
|
|
32
|
-
},
|
|
33
|
-
database: {
|
|
34
|
-
enabled: true,
|
|
35
|
-
provider: 'prisma', // prisma, drizzle, typeorm
|
|
36
|
-
features: ['migrations', 'transactions']
|
|
37
|
-
},
|
|
38
|
-
testing: {
|
|
39
|
-
enabled: true,
|
|
40
|
-
provider: 'vitest', // vitest, jest, playwright
|
|
41
|
-
features: ['unit', 'integration']
|
|
42
|
-
},
|
|
43
|
-
security: {
|
|
44
|
-
enabled: true,
|
|
45
|
-
features: ['input_validation', 'rate_limiting']
|
|
46
|
-
},
|
|
47
|
-
ai: {
|
|
48
|
-
enabled: false,
|
|
49
|
-
provider: 'anthropic', // anthropic, openai, google
|
|
50
|
-
features: ['streaming', 'tool_use']
|
|
51
|
-
}
|
|
52
|
-
},
|
|
53
|
-
|
|
54
|
-
// Dashboard settings
|
|
55
|
-
dashboard: {
|
|
56
|
-
port: 3456,
|
|
57
|
-
autoOpen: false
|
|
58
|
-
},
|
|
59
|
-
|
|
60
|
-
// Context generation options
|
|
61
|
-
context: {
|
|
62
|
-
includeEnvVars: true,
|
|
63
|
-
includeTechStack: true,
|
|
64
|
-
includePlugins: true,
|
|
65
|
-
customSections: []
|
|
66
|
-
},
|
|
67
|
-
|
|
68
|
-
// Quality gate settings
|
|
69
|
-
quality: {
|
|
70
|
-
preCommit: {
|
|
71
|
-
enabled: true,
|
|
72
|
-
checks: ['lint', 'typecheck']
|
|
73
|
-
},
|
|
74
|
-
prePush: {
|
|
75
|
-
enabled: true,
|
|
76
|
-
checks: ['test', 'build']
|
|
77
|
-
},
|
|
78
|
-
preDeploy: {
|
|
79
|
-
enabled: true,
|
|
80
|
-
checks: ['security', 'coverage']
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
};
|