@mytechtoday/augment-extensions 0.1.0 → 0.1.1

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.
Files changed (102) hide show
  1. package/AGENTS.md +83 -3
  2. package/README.md +6 -5
  3. package/augment-extensions/coding-standards/python/README.md +44 -0
  4. package/augment-extensions/coding-standards/python/module.json +26 -0
  5. package/augment-extensions/coding-standards/python/rules/best-practices.md +232 -0
  6. package/augment-extensions/coding-standards/python/rules/code-organization.md +220 -0
  7. package/augment-extensions/coding-standards/python/rules/error-handling.md +221 -0
  8. package/augment-extensions/coding-standards/python/rules/naming-conventions.md +172 -0
  9. package/augment-extensions/coding-standards/python/rules/type-hints.md +188 -0
  10. package/augment-extensions/coding-standards/react/README.md +45 -0
  11. package/augment-extensions/coding-standards/react/module.json +27 -0
  12. package/augment-extensions/coding-standards/react/rules/component-patterns.md +214 -0
  13. package/augment-extensions/coding-standards/react/rules/hooks-best-practices.md +235 -0
  14. package/augment-extensions/coding-standards/react/rules/performance.md +300 -0
  15. package/augment-extensions/coding-standards/react/rules/state-management.md +265 -0
  16. package/augment-extensions/coding-standards/react/rules/typescript-react.md +271 -0
  17. package/augment-extensions/domain-rules/api-design/README.md +41 -0
  18. package/augment-extensions/domain-rules/api-design/module.json +27 -0
  19. package/augment-extensions/domain-rules/api-design/rules/authentication.md +263 -0
  20. package/augment-extensions/domain-rules/api-design/rules/documentation.md +395 -0
  21. package/augment-extensions/domain-rules/api-design/rules/error-handling.md +290 -0
  22. package/augment-extensions/domain-rules/api-design/rules/graphql-api.md +313 -0
  23. package/augment-extensions/domain-rules/api-design/rules/rest-api.md +214 -0
  24. package/augment-extensions/domain-rules/api-design/rules/versioning.md +268 -0
  25. package/augment-extensions/domain-rules/security/README.md +41 -0
  26. package/augment-extensions/domain-rules/security/module.json +28 -0
  27. package/augment-extensions/domain-rules/security/rules/authentication-security.md +361 -0
  28. package/augment-extensions/domain-rules/security/rules/encryption.md +208 -0
  29. package/augment-extensions/domain-rules/security/rules/input-validation.md +294 -0
  30. package/augment-extensions/domain-rules/security/rules/owasp-top-10.md +339 -0
  31. package/augment-extensions/domain-rules/security/rules/secure-coding.md +293 -0
  32. package/augment-extensions/domain-rules/security/rules/web-security.md +268 -0
  33. package/augment-extensions/examples/design-patterns/README.md +37 -0
  34. package/augment-extensions/examples/design-patterns/examples/behavioral-patterns.md +370 -0
  35. package/augment-extensions/examples/design-patterns/examples/creational-patterns.md +250 -0
  36. package/augment-extensions/examples/design-patterns/examples/structural-patterns.md +264 -0
  37. package/augment-extensions/examples/design-patterns/module.json +27 -0
  38. package/{modules → augment-extensions}/workflows/beads/examples/complete-workflow-example.md +5 -5
  39. package/{modules → augment-extensions}/workflows/beads/rules/file-format.md +45 -1
  40. package/{modules → augment-extensions}/workflows/beads/rules/workflow.md +41 -0
  41. package/{modules → augment-extensions}/workflows/openspec/examples/complete-change-example.md +14 -0
  42. package/{modules → augment-extensions}/workflows/openspec/rules/spec-format.md +44 -1
  43. package/{modules → augment-extensions}/workflows/openspec/rules/workflow.md +25 -0
  44. package/cli/dist/cli.js +64 -0
  45. package/cli/dist/cli.js.map +1 -1
  46. package/cli/dist/commands/coord.d.ts +30 -0
  47. package/cli/dist/commands/coord.d.ts.map +1 -0
  48. package/cli/dist/commands/coord.js +150 -0
  49. package/cli/dist/commands/coord.js.map +1 -0
  50. package/cli/dist/commands/link.js +1 -1
  51. package/cli/dist/commands/link.js.map +1 -1
  52. package/cli/dist/commands/list.js +1 -1
  53. package/cli/dist/commands/list.js.map +1 -1
  54. package/cli/dist/commands/search.d.ts.map +1 -1
  55. package/cli/dist/commands/search.js +107 -5
  56. package/cli/dist/commands/search.js.map +1 -1
  57. package/cli/dist/commands/show.js +1 -1
  58. package/cli/dist/commands/show.js.map +1 -1
  59. package/cli/dist/commands/sync.d.ts +26 -0
  60. package/cli/dist/commands/sync.d.ts.map +1 -0
  61. package/cli/dist/commands/sync.js +106 -0
  62. package/cli/dist/commands/sync.js.map +1 -0
  63. package/cli/dist/commands/update.d.ts.map +1 -1
  64. package/cli/dist/commands/update.js +132 -7
  65. package/cli/dist/commands/update.js.map +1 -1
  66. package/cli/dist/utils/auto-sync.d.ts +34 -0
  67. package/cli/dist/utils/auto-sync.d.ts.map +1 -0
  68. package/cli/dist/utils/auto-sync.js +172 -0
  69. package/cli/dist/utils/auto-sync.js.map +1 -0
  70. package/cli/dist/utils/beads-sync.d.ts +51 -0
  71. package/cli/dist/utils/beads-sync.d.ts.map +1 -0
  72. package/cli/dist/utils/beads-sync.js +171 -0
  73. package/cli/dist/utils/beads-sync.js.map +1 -0
  74. package/cli/dist/utils/coordination-queries.d.ts +79 -0
  75. package/cli/dist/utils/coordination-queries.d.ts.map +1 -0
  76. package/cli/dist/utils/coordination-queries.js +155 -0
  77. package/cli/dist/utils/coordination-queries.js.map +1 -0
  78. package/cli/dist/utils/file-tracking.d.ts +42 -0
  79. package/cli/dist/utils/file-tracking.d.ts.map +1 -0
  80. package/cli/dist/utils/file-tracking.js +155 -0
  81. package/cli/dist/utils/file-tracking.js.map +1 -0
  82. package/cli/dist/utils/migrate.d.ts +25 -0
  83. package/cli/dist/utils/migrate.d.ts.map +1 -0
  84. package/cli/dist/utils/migrate.js +204 -0
  85. package/cli/dist/utils/migrate.js.map +1 -0
  86. package/cli/dist/utils/openspec-sync.d.ts +48 -0
  87. package/cli/dist/utils/openspec-sync.d.ts.map +1 -0
  88. package/cli/dist/utils/openspec-sync.js +167 -0
  89. package/cli/dist/utils/openspec-sync.js.map +1 -0
  90. package/{MODULES.md → modules.md} +1 -1
  91. package/package.json +9 -7
  92. /package/{modules → augment-extensions}/coding-standards/typescript/README.md +0 -0
  93. /package/{modules → augment-extensions}/coding-standards/typescript/module.json +0 -0
  94. /package/{modules → augment-extensions}/coding-standards/typescript/rules/naming-conventions.md +0 -0
  95. /package/{modules → augment-extensions}/workflows/beads/README.md +0 -0
  96. /package/{modules → augment-extensions}/workflows/beads/module.json +0 -0
  97. /package/{modules → augment-extensions}/workflows/beads/rules/best-practices.md +0 -0
  98. /package/{modules → augment-extensions}/workflows/beads/rules/manual-setup.md +0 -0
  99. /package/{modules → augment-extensions}/workflows/openspec/README.md +0 -0
  100. /package/{modules → augment-extensions}/workflows/openspec/module.json +0 -0
  101. /package/{modules → augment-extensions}/workflows/openspec/rules/best-practices.md +0 -0
  102. /package/{modules → augment-extensions}/workflows/openspec/rules/manual-setup.md +0 -0
@@ -0,0 +1,208 @@
1
+ # Encryption and Data Protection
2
+
3
+ Best practices for encrypting and protecting sensitive data.
4
+
5
+ ## Data at Rest Encryption
6
+
7
+ ### Symmetric Encryption (AES-256-GCM)
8
+
9
+ ```typescript
10
+ import crypto from 'crypto';
11
+
12
+ // Encrypt data
13
+ const encrypt = (data: string, key: Buffer): { encrypted: string; iv: string; authTag: string } => {
14
+ const iv = crypto.randomBytes(16);
15
+ const cipher = crypto.createCipheriv('aes-256-gcm', key, iv);
16
+
17
+ let encrypted = cipher.update(data, 'utf8', 'hex');
18
+ encrypted += cipher.final('hex');
19
+
20
+ return {
21
+ encrypted,
22
+ iv: iv.toString('hex'),
23
+ authTag: cipher.getAuthTag().toString('hex')
24
+ };
25
+ };
26
+
27
+ // Decrypt data
28
+ const decrypt = (encrypted: string, key: Buffer, iv: string, authTag: string): string => {
29
+ const decipher = crypto.createDecipheriv('aes-256-gcm', key, Buffer.from(iv, 'hex'));
30
+ decipher.setAuthTag(Buffer.from(authTag, 'hex'));
31
+
32
+ let decrypted = decipher.update(encrypted, 'hex', 'utf8');
33
+ decrypted += decipher.final('utf8');
34
+
35
+ return decrypted;
36
+ };
37
+
38
+ // Generate encryption key
39
+ const key = crypto.randomBytes(32); // 256 bits
40
+ // Store key securely (e.g., AWS KMS, Azure Key Vault, environment variable)
41
+ ```
42
+
43
+ ### Database Encryption
44
+
45
+ ```typescript
46
+ // Good - Encrypt sensitive fields
47
+ const encryptedData = encrypt(user.ssn, encryptionKey);
48
+
49
+ await db.users.create({
50
+ email: user.email,
51
+ ssn: encryptedData.encrypted,
52
+ ssnIv: encryptedData.iv,
53
+ ssnAuthTag: encryptedData.authTag
54
+ });
55
+
56
+ // Decrypt when needed
57
+ const user = await db.users.findOne(userId);
58
+ const ssn = decrypt(user.ssn, encryptionKey, user.ssnIv, user.ssnAuthTag);
59
+ ```
60
+
61
+ ## Data in Transit Encryption
62
+
63
+ ### HTTPS/TLS
64
+
65
+ ```typescript
66
+ // Good - Force HTTPS
67
+ app.use((req, res, next) => {
68
+ if (!req.secure && process.env.NODE_ENV === 'production') {
69
+ return res.redirect(301, `https://${req.headers.host}${req.url}`);
70
+ }
71
+ next();
72
+ });
73
+
74
+ // Good - HSTS header
75
+ app.use((req, res, next) => {
76
+ res.setHeader('Strict-Transport-Security', 'max-age=31536000; includeSubDomains; preload');
77
+ next();
78
+ });
79
+
80
+ // Good - TLS configuration
81
+ import https from 'https';
82
+ import fs from 'fs';
83
+
84
+ const options = {
85
+ key: fs.readFileSync('private-key.pem'),
86
+ cert: fs.readFileSync('certificate.pem'),
87
+ minVersion: 'TLSv1.2', // Minimum TLS 1.2
88
+ ciphers: 'ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384'
89
+ };
90
+
91
+ https.createServer(options, app).listen(443);
92
+ ```
93
+
94
+ ## Key Management
95
+
96
+ ### Environment Variables
97
+
98
+ ```bash
99
+ # .env (never commit to git)
100
+ ENCRYPTION_KEY=hex_encoded_32_byte_key
101
+ JWT_SECRET=strong_random_secret
102
+ DATABASE_PASSWORD=strong_password
103
+
104
+ # .gitignore
105
+ .env
106
+ .env.local
107
+ ```
108
+
109
+ ### Key Rotation
110
+
111
+ ```typescript
112
+ // Support multiple encryption keys for rotation
113
+ const ENCRYPTION_KEYS = {
114
+ current: process.env.ENCRYPTION_KEY_V2,
115
+ previous: process.env.ENCRYPTION_KEY_V1
116
+ };
117
+
118
+ // Encrypt with current key
119
+ const encrypted = encrypt(data, Buffer.from(ENCRYPTION_KEYS.current, 'hex'));
120
+
121
+ // Decrypt with appropriate key version
122
+ const decrypt = (encrypted: string, keyVersion: string, iv: string, authTag: string): string => {
123
+ const key = ENCRYPTION_KEYS[keyVersion];
124
+ // ... decrypt logic
125
+ };
126
+
127
+ // Re-encrypt old data with new key
128
+ const migrateEncryption = async () => {
129
+ const users = await db.users.findMany({ keyVersion: 'previous' });
130
+
131
+ for (const user of users) {
132
+ const decrypted = decrypt(user.ssn, 'previous', user.ssnIv, user.ssnAuthTag);
133
+ const reencrypted = encrypt(decrypted, Buffer.from(ENCRYPTION_KEYS.current, 'hex'));
134
+
135
+ await db.users.update(user.id, {
136
+ ssn: reencrypted.encrypted,
137
+ ssnIv: reencrypted.iv,
138
+ ssnAuthTag: reencrypted.authTag,
139
+ keyVersion: 'current'
140
+ });
141
+ }
142
+ };
143
+ ```
144
+
145
+ ## Hashing
146
+
147
+ ### One-Way Hashing
148
+
149
+ ```typescript
150
+ import crypto from 'crypto';
151
+
152
+ // Good - SHA-256 for non-password data
153
+ const hash = crypto.createHash('sha256').update(data).digest('hex');
154
+
155
+ // Good - HMAC for message authentication
156
+ const hmac = crypto.createHmac('sha256', secret).update(data).digest('hex');
157
+
158
+ // Verify HMAC
159
+ const isValid = crypto.timingSafeEqual(
160
+ Buffer.from(receivedHmac, 'hex'),
161
+ Buffer.from(expectedHmac, 'hex')
162
+ );
163
+ ```
164
+
165
+ ## Secure Random Generation
166
+
167
+ ```typescript
168
+ // Good - Cryptographically secure random
169
+ const token = crypto.randomBytes(32).toString('hex');
170
+ const uuid = crypto.randomUUID();
171
+
172
+ // Bad - Not cryptographically secure
173
+ const token = Math.random().toString(36); // ❌ Don't use for security
174
+ ```
175
+
176
+ ## Data Masking
177
+
178
+ ```typescript
179
+ // Mask sensitive data in logs
180
+ const maskEmail = (email: string): string => {
181
+ const [local, domain] = email.split('@');
182
+ return `${local.slice(0, 2)}***@${domain}`;
183
+ };
184
+
185
+ const maskCreditCard = (card: string): string => {
186
+ return `****-****-****-${card.slice(-4)}`;
187
+ };
188
+
189
+ // Log with masked data
190
+ logger.info('User registered', {
191
+ email: maskEmail(user.email),
192
+ ip: req.ip
193
+ });
194
+ ```
195
+
196
+ ## Best Practices
197
+
198
+ 1. **Use AES-256-GCM** - For symmetric encryption
199
+ 2. **Always use HTTPS** - Encrypt data in transit
200
+ 3. **Secure key storage** - Use key management services
201
+ 4. **Rotate keys** - Periodically change encryption keys
202
+ 5. **Hash passwords** - Use bcrypt/Argon2, not encryption
203
+ 6. **Use crypto.randomBytes** - For secure random generation
204
+ 7. **Encrypt at rest** - Sensitive database fields
205
+ 8. **Mask in logs** - Don't log sensitive data
206
+ 9. **Use HSTS** - Force HTTPS
207
+ 10. **TLS 1.2+** - Minimum TLS version
208
+
@@ -0,0 +1,294 @@
1
+ # Input Validation and Sanitization
2
+
3
+ Best practices for validating and sanitizing user input.
4
+
5
+ ## Validation Libraries
6
+
7
+ ### Zod (TypeScript)
8
+
9
+ ```typescript
10
+ import { z } from 'zod';
11
+
12
+ // Define schema
13
+ const userSchema = z.object({
14
+ email: z.string().email(),
15
+ password: z.string().min(12).max(100),
16
+ age: z.number().int().min(18).max(120),
17
+ role: z.enum(['admin', 'user', 'guest']),
18
+ website: z.string().url().optional()
19
+ });
20
+
21
+ // Validate input
22
+ app.post('/users', async (req, res) => {
23
+ try {
24
+ const validatedData = userSchema.parse(req.body);
25
+ // Use validatedData (type-safe)
26
+ } catch (error) {
27
+ if (error instanceof z.ZodError) {
28
+ return res.status(422).json({
29
+ error: 'Validation failed',
30
+ details: error.errors
31
+ });
32
+ }
33
+ }
34
+ });
35
+ ```
36
+
37
+ ### Joi (JavaScript)
38
+
39
+ ```javascript
40
+ const Joi = require('joi');
41
+
42
+ const schema = Joi.object({
43
+ email: Joi.string().email().required(),
44
+ password: Joi.string().min(12).max(100).required(),
45
+ age: Joi.number().integer().min(18).max(120),
46
+ tags: Joi.array().items(Joi.string()).max(10)
47
+ });
48
+
49
+ const { error, value } = schema.validate(req.body);
50
+ if (error) {
51
+ return res.status(422).json({ error: error.details });
52
+ }
53
+ ```
54
+
55
+ ## SQL Injection Prevention
56
+
57
+ ```typescript
58
+ // Bad - SQL injection vulnerability
59
+ const query = `SELECT * FROM users WHERE email = '${req.body.email}'`; // ❌
60
+
61
+ // Good - Parameterized query
62
+ const query = 'SELECT * FROM users WHERE email = $1';
63
+ const result = await db.query(query, [req.body.email]);
64
+
65
+ // Good - ORM (Prisma)
66
+ const user = await prisma.user.findUnique({
67
+ where: { email: req.body.email }
68
+ });
69
+
70
+ // Good - Query builder (Knex)
71
+ const users = await knex('users')
72
+ .where('email', req.body.email)
73
+ .select('*');
74
+ ```
75
+
76
+ ## NoSQL Injection Prevention
77
+
78
+ ```typescript
79
+ // Bad - NoSQL injection
80
+ const user = await db.users.findOne({
81
+ email: req.body.email, // Could be: { $ne: null }
82
+ password: req.body.password
83
+ });
84
+
85
+ // Good - Validate input type
86
+ if (typeof req.body.email !== 'string' || typeof req.body.password !== 'string') {
87
+ return res.status(400).json({ error: 'Invalid input' });
88
+ }
89
+
90
+ const user = await db.users.findOne({
91
+ email: req.body.email,
92
+ password: req.body.password
93
+ });
94
+
95
+ // Good - Use schema validation
96
+ const loginSchema = z.object({
97
+ email: z.string().email(),
98
+ password: z.string()
99
+ });
100
+
101
+ const { email, password } = loginSchema.parse(req.body);
102
+ ```
103
+
104
+ ## XSS Prevention
105
+
106
+ ```typescript
107
+ // Bad - Rendering user input directly
108
+ res.send(`<h1>Welcome ${req.query.name}</h1>`); // ❌ XSS vulnerability
109
+
110
+ // Good - Use template engine with auto-escaping
111
+ res.render('welcome', { name: req.query.name }); // Handlebars, EJS, etc.
112
+
113
+ // Good - Sanitize HTML
114
+ import DOMPurify from 'isomorphic-dompurify';
115
+
116
+ const clean = DOMPurify.sanitize(req.body.html);
117
+
118
+ // Good - Content Security Policy
119
+ app.use((req, res, next) => {
120
+ res.setHeader(
121
+ 'Content-Security-Policy',
122
+ "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'"
123
+ );
124
+ next();
125
+ });
126
+ ```
127
+
128
+ ## Command Injection Prevention
129
+
130
+ ```typescript
131
+ // Bad - Command injection
132
+ const { exec } = require('child_process');
133
+ exec(`ping ${req.query.host}`); // ❌ Vulnerable
134
+
135
+ // Good - Validate input
136
+ const host = req.query.host;
137
+ if (!/^[a-zA-Z0-9.-]+$/.test(host)) {
138
+ return res.status(400).json({ error: 'Invalid host' });
139
+ }
140
+
141
+ // Better - Use safe library
142
+ import { ping } from 'ping';
143
+ const result = await ping.promise.probe(req.query.host);
144
+
145
+ // Good - Use execFile with array
146
+ import { execFile } from 'child_process';
147
+ execFile('ping', ['-c', '4', host], (error, stdout) => {
148
+ // ...
149
+ });
150
+ ```
151
+
152
+ ## Path Traversal Prevention
153
+
154
+ ```typescript
155
+ // Bad - Path traversal vulnerability
156
+ const filePath = path.join(__dirname, 'uploads', req.query.file); // ❌
157
+ res.sendFile(filePath);
158
+
159
+ // Good - Validate filename
160
+ import path from 'path';
161
+
162
+ const filename = path.basename(req.query.file); // Remove directory components
163
+ const filePath = path.join(__dirname, 'uploads', filename);
164
+
165
+ // Ensure file is within uploads directory
166
+ const realPath = fs.realpathSync(filePath);
167
+ const uploadsPath = fs.realpathSync(path.join(__dirname, 'uploads'));
168
+
169
+ if (!realPath.startsWith(uploadsPath)) {
170
+ return res.status(400).json({ error: 'Invalid file path' });
171
+ }
172
+
173
+ res.sendFile(realPath);
174
+ ```
175
+
176
+ ## Email Validation
177
+
178
+ ```typescript
179
+ // Good - Email validation
180
+ const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
181
+
182
+ if (!emailRegex.test(email)) {
183
+ return res.status(400).json({ error: 'Invalid email' });
184
+ }
185
+
186
+ // Better - Use validation library
187
+ import { z } from 'zod';
188
+ const email = z.string().email().parse(req.body.email);
189
+
190
+ // Best - Verify email ownership
191
+ const verificationToken = crypto.randomBytes(32).toString('hex');
192
+ await sendVerificationEmail(email, verificationToken);
193
+ ```
194
+
195
+ ## URL Validation
196
+
197
+ ```typescript
198
+ // Good - URL validation
199
+ const validateUrl = (url: string): boolean => {
200
+ try {
201
+ const parsed = new URL(url);
202
+ return ['http:', 'https:'].includes(parsed.protocol);
203
+ } catch {
204
+ return false;
205
+ }
206
+ };
207
+
208
+ // Good - Whitelist domains
209
+ const allowedDomains = ['example.com', 'api.example.com'];
210
+
211
+ const url = new URL(req.body.url);
212
+ if (!allowedDomains.includes(url.hostname)) {
213
+ return res.status(400).json({ error: 'Domain not allowed' });
214
+ }
215
+ ```
216
+
217
+ ## File Upload Validation
218
+
219
+ ```typescript
220
+ import multer from 'multer';
221
+ import path from 'path';
222
+
223
+ // Good - Validate file type and size
224
+ const upload = multer({
225
+ storage: multer.diskStorage({
226
+ destination: 'uploads/',
227
+ filename: (req, file, cb) => {
228
+ const uniqueSuffix = Date.now() + '-' + crypto.randomBytes(6).toString('hex');
229
+ cb(null, uniqueSuffix + path.extname(file.originalname));
230
+ }
231
+ }),
232
+ limits: {
233
+ fileSize: 5 * 1024 * 1024 // 5MB
234
+ },
235
+ fileFilter: (req, file, cb) => {
236
+ const allowedTypes = ['image/jpeg', 'image/png', 'image/gif'];
237
+
238
+ if (!allowedTypes.includes(file.mimetype)) {
239
+ return cb(new Error('Invalid file type'));
240
+ }
241
+
242
+ cb(null, true);
243
+ }
244
+ });
245
+
246
+ // Verify file content (not just extension)
247
+ import fileType from 'file-type';
248
+
249
+ const type = await fileType.fromFile(filePath);
250
+ if (!type || !['image/jpeg', 'image/png'].includes(type.mime)) {
251
+ fs.unlinkSync(filePath);
252
+ return res.status(400).json({ error: 'Invalid file type' });
253
+ }
254
+ ```
255
+
256
+ ## Integer Validation
257
+
258
+ ```typescript
259
+ // Good - Validate integers
260
+ const validateInteger = (value: any, min?: number, max?: number): number => {
261
+ const num = parseInt(value, 10);
262
+
263
+ if (isNaN(num) || !Number.isInteger(num)) {
264
+ throw new Error('Must be an integer');
265
+ }
266
+
267
+ if (min !== undefined && num < min) {
268
+ throw new Error(`Must be at least ${min}`);
269
+ }
270
+
271
+ if (max !== undefined && num > max) {
272
+ throw new Error(`Must be at most ${max}`);
273
+ }
274
+
275
+ return num;
276
+ };
277
+
278
+ // Usage
279
+ const age = validateInteger(req.body.age, 18, 120);
280
+ ```
281
+
282
+ ## Best Practices
283
+
284
+ 1. **Validate all input** - Never trust user input
285
+ 2. **Use validation libraries** - Zod, Joi, etc.
286
+ 3. **Whitelist, don't blacklist** - Define what's allowed
287
+ 4. **Parameterized queries** - Prevent SQL injection
288
+ 5. **Type checking** - Prevent NoSQL injection
289
+ 6. **Sanitize HTML** - Use DOMPurify
290
+ 7. **Validate file uploads** - Type, size, content
291
+ 8. **Validate URLs** - Check protocol and domain
292
+ 9. **Prevent path traversal** - Use path.basename
293
+ 10. **Fail securely** - Reject invalid input
294
+