memory-journal-mcp 7.0.1 → 7.2.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.
Files changed (124) hide show
  1. package/README.md +75 -66
  2. package/dist/{chunk-6J4RPJ4I.js → chunk-GR4T3SRW.js} +146 -105
  3. package/dist/{chunk-ARLH46WS.js → chunk-IWKLHSPU.js} +89 -3
  4. package/dist/{chunk-2BJHLTYP.js → chunk-ORV7ZZOE.js} +1086 -86
  5. package/dist/cli.js +30 -4
  6. package/dist/github-integration-2TFMXHIJ.js +1 -0
  7. package/dist/index.d.ts +6 -2
  8. package/dist/index.js +3 -3
  9. package/dist/{tools-FFFGXIKN.js → tools-CXR2FEB2.js} +2 -2
  10. package/package.json +2 -2
  11. package/skills/README.md +77 -0
  12. package/skills/autonomous-dev/SKILL.md +56 -0
  13. package/skills/bin/sync.js +50 -0
  14. package/skills/bun/SKILL.md +156 -0
  15. package/skills/github-commander/SKILL.md +1 -1
  16. package/skills/github-commander/workflows/code-quality-audit.md +7 -5
  17. package/skills/github-commander/workflows/issue-triage.md +13 -4
  18. package/skills/github-commander/workflows/milestone-sprint.md +9 -1
  19. package/skills/github-commander/workflows/perf-audit.md +2 -0
  20. package/skills/github-commander/workflows/pr-review.md +9 -3
  21. package/skills/github-commander/workflows/roadmap-kickoff.md +79 -0
  22. package/skills/github-commander/workflows/security-audit.md +3 -3
  23. package/skills/github-commander/workflows/update-deps.md +2 -2
  24. package/skills/gitlab/SKILL.md +115 -0
  25. package/skills/gitlab/package-lock.json +392 -0
  26. package/skills/gitlab/package.json +14 -0
  27. package/skills/gitlab/scripts/gitlab-client.ts +125 -0
  28. package/skills/gitlab/scripts/gitlab-helper.ts +80 -0
  29. package/skills/golang/SKILL.md +54 -0
  30. package/skills/mysql/SKILL.md +30 -0
  31. package/skills/package.json +48 -0
  32. package/skills/playwright-standard/SKILL.md +58 -0
  33. package/skills/playwright-standard/examples/fixtures.ts +66 -0
  34. package/skills/playwright-standard/examples/type-stubs.d.ts +10 -0
  35. package/skills/playwright-standard/references/advanced-scenarios.md +59 -0
  36. package/skills/playwright-standard/references/infrastructure.md +43 -0
  37. package/skills/postgres/SKILL.md +33 -0
  38. package/skills/react-best-practices/AGENTS.md +2883 -0
  39. package/skills/react-best-practices/README.md +127 -0
  40. package/skills/react-best-practices/SKILL.md +138 -0
  41. package/skills/react-best-practices/metadata.json +17 -0
  42. package/skills/react-best-practices/rules/_sections.md +46 -0
  43. package/skills/react-best-practices/rules/_template.md +28 -0
  44. package/skills/react-best-practices/rules/advanced-event-handler-refs.md +55 -0
  45. package/skills/react-best-practices/rules/advanced-init-once.md +42 -0
  46. package/skills/react-best-practices/rules/advanced-use-latest.md +39 -0
  47. package/skills/react-best-practices/rules/async-api-routes.md +35 -0
  48. package/skills/react-best-practices/rules/async-defer-await.md +80 -0
  49. package/skills/react-best-practices/rules/async-dependencies.md +48 -0
  50. package/skills/react-best-practices/rules/async-parallel.md +24 -0
  51. package/skills/react-best-practices/rules/async-suspense-boundaries.md +99 -0
  52. package/skills/react-best-practices/rules/bundle-barrel-imports.md +59 -0
  53. package/skills/react-best-practices/rules/bundle-conditional.md +37 -0
  54. package/skills/react-best-practices/rules/bundle-defer-third-party.md +48 -0
  55. package/skills/react-best-practices/rules/bundle-dynamic-imports.md +34 -0
  56. package/skills/react-best-practices/rules/bundle-preload.md +44 -0
  57. package/skills/react-best-practices/rules/client-event-listeners.md +78 -0
  58. package/skills/react-best-practices/rules/client-localstorage-schema.md +74 -0
  59. package/skills/react-best-practices/rules/client-passive-event-listeners.md +48 -0
  60. package/skills/react-best-practices/rules/client-swr-dedup.md +56 -0
  61. package/skills/react-best-practices/rules/js-batch-dom-css.md +110 -0
  62. package/skills/react-best-practices/rules/js-cache-function-results.md +80 -0
  63. package/skills/react-best-practices/rules/js-cache-property-access.md +28 -0
  64. package/skills/react-best-practices/rules/js-cache-storage.md +68 -0
  65. package/skills/react-best-practices/rules/js-combine-iterations.md +32 -0
  66. package/skills/react-best-practices/rules/js-early-exit.md +50 -0
  67. package/skills/react-best-practices/rules/js-hoist-regexp.md +45 -0
  68. package/skills/react-best-practices/rules/js-index-maps.md +37 -0
  69. package/skills/react-best-practices/rules/js-length-check-first.md +50 -0
  70. package/skills/react-best-practices/rules/js-min-max-loop.md +82 -0
  71. package/skills/react-best-practices/rules/js-set-map-lookups.md +24 -0
  72. package/skills/react-best-practices/rules/js-tosorted-immutable.md +57 -0
  73. package/skills/react-best-practices/rules/rendering-activity.md +24 -0
  74. package/skills/react-best-practices/rules/rendering-animate-svg-wrapper.md +38 -0
  75. package/skills/react-best-practices/rules/rendering-conditional-render.md +32 -0
  76. package/skills/react-best-practices/rules/rendering-content-visibility.md +38 -0
  77. package/skills/react-best-practices/rules/rendering-hoist-jsx.md +36 -0
  78. package/skills/react-best-practices/rules/rendering-hydration-no-flicker.md +72 -0
  79. package/skills/react-best-practices/rules/rendering-hydration-suppress-warning.md +26 -0
  80. package/skills/react-best-practices/rules/rendering-svg-precision.md +28 -0
  81. package/skills/react-best-practices/rules/rendering-usetransition-loading.md +75 -0
  82. package/skills/react-best-practices/rules/rerender-defer-reads.md +39 -0
  83. package/skills/react-best-practices/rules/rerender-dependencies.md +45 -0
  84. package/skills/react-best-practices/rules/rerender-derived-state-no-effect.md +40 -0
  85. package/skills/react-best-practices/rules/rerender-derived-state.md +29 -0
  86. package/skills/react-best-practices/rules/rerender-functional-setstate.md +77 -0
  87. package/skills/react-best-practices/rules/rerender-lazy-state-init.md +56 -0
  88. package/skills/react-best-practices/rules/rerender-memo-with-default-value.md +36 -0
  89. package/skills/react-best-practices/rules/rerender-memo.md +44 -0
  90. package/skills/react-best-practices/rules/rerender-move-effect-to-event.md +45 -0
  91. package/skills/react-best-practices/rules/rerender-simple-expression-in-memo.md +35 -0
  92. package/skills/react-best-practices/rules/rerender-transitions.md +40 -0
  93. package/skills/react-best-practices/rules/rerender-use-ref-transient-values.md +73 -0
  94. package/skills/react-best-practices/rules/server-after-nonblocking.md +73 -0
  95. package/skills/react-best-practices/rules/server-auth-actions.md +96 -0
  96. package/skills/react-best-practices/rules/server-cache-lru.md +41 -0
  97. package/skills/react-best-practices/rules/server-cache-react.md +76 -0
  98. package/skills/react-best-practices/rules/server-dedup-props.md +65 -0
  99. package/skills/react-best-practices/rules/server-parallel-fetching.md +83 -0
  100. package/skills/react-best-practices/rules/server-serialization.md +38 -0
  101. package/skills/rust/SKILL.md +86 -0
  102. package/skills/shadcn-ui/SKILL.md +72 -0
  103. package/skills/skill-builder/SKILL.md +457 -0
  104. package/skills/skill-builder/checklist.md +65 -0
  105. package/skills/sqlite/SKILL.md +38 -0
  106. package/skills/typescript/SKILL.md +453 -0
  107. package/skills/typescript/assets/eslint-template.js +102 -0
  108. package/skills/typescript/assets/tsconfig-template.json +45 -0
  109. package/skills/typescript/references/enterprise-patterns.md +531 -0
  110. package/skills/typescript/references/generics.md +493 -0
  111. package/skills/typescript/references/nestjs-integration.md +579 -0
  112. package/skills/typescript/references/react-integration.md +616 -0
  113. package/skills/typescript/references/toolchain.md +547 -0
  114. package/skills/typescript/references/type-system.md +481 -0
  115. package/skills/vitest-standard/SKILL.md +82 -0
  116. package/skills/vitest-standard/examples/service-mock.ts +60 -0
  117. package/skills/vitest-standard/examples/tdd-calculator.ts +41 -0
  118. package/skills/vitest-standard/examples/type-stubs.d.ts +18 -0
  119. package/skills/vitest-standard/references/async-and-errors.md +58 -0
  120. package/skills/vitest-standard/references/coverage-and-config.md +53 -0
  121. package/skills/vitest-standard/references/mocking.md +61 -0
  122. package/skills/vitest-standard/references/tdd-patterns.md +60 -0
  123. package/dist/github-integration-PDRLXKGM.js +0 -1
  124. package/skills/github-commander/workflows/full-audit.md +0 -134
@@ -0,0 +1,531 @@
1
+ # Enterprise Patterns Reference
2
+
3
+ > **Load when:** User asks about error handling, validation, project architecture, migration strategies, or large-scale TypeScript patterns.
4
+
5
+ Proven patterns for building maintainable TypeScript applications.
6
+
7
+ ## Contents
8
+
9
+ - [Error Handling](#error-handling)
10
+ - [Validation Patterns](#validation-patterns)
11
+ - [Project Organization](#project-organization)
12
+ - [Migration Strategies](#migration-strategies)
13
+ - [Security Patterns](#security-patterns)
14
+
15
+ ---
16
+
17
+ ## Error Handling
18
+
19
+ ### Result Type Pattern
20
+
21
+ Instead of throwing exceptions, return typed results:
22
+
23
+ ```typescript
24
+ // Define Result type
25
+ type Result<T, E = Error> = { success: true; data: T } | { success: false; error: E }
26
+
27
+ // Helper functions
28
+ function ok<T>(data: T): Result<T, never> {
29
+ return { success: true, data }
30
+ }
31
+
32
+ function err<E>(error: E): Result<never, E> {
33
+ return { success: false, error }
34
+ }
35
+
36
+ // Usage
37
+ interface ValidationError {
38
+ field: string
39
+ message: string
40
+ }
41
+
42
+ function parseEmail(input: string): Result<string, ValidationError> {
43
+ const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/
44
+
45
+ if (!emailRegex.test(input)) {
46
+ return err({ field: 'email', message: 'Invalid email format' })
47
+ }
48
+
49
+ return ok(input.toLowerCase())
50
+ }
51
+
52
+ // Consuming Result
53
+ const result = parseEmail(userInput)
54
+
55
+ if (result.success) {
56
+ console.log(`Valid email: ${result.data}`)
57
+ } else {
58
+ console.error(`Error in ${result.error.field}: ${result.error.message}`)
59
+ }
60
+ ```
61
+
62
+ ### Typed Error Classes
63
+
64
+ ```typescript
65
+ // Base application error
66
+ abstract class AppError extends Error {
67
+ abstract readonly code: string
68
+ abstract readonly statusCode: number
69
+
70
+ constructor(message: string) {
71
+ super(message)
72
+ this.name = this.constructor.name
73
+ Error.captureStackTrace(this, this.constructor)
74
+ }
75
+ }
76
+
77
+ // Specific error types
78
+ class NotFoundError extends AppError {
79
+ readonly code = 'NOT_FOUND'
80
+ readonly statusCode = 404
81
+
82
+ constructor(resource: string, id: string) {
83
+ super(`${resource} with id ${id} not found`)
84
+ }
85
+ }
86
+
87
+ class ValidationError extends AppError {
88
+ readonly code = 'VALIDATION_ERROR'
89
+ readonly statusCode = 400
90
+
91
+ constructor(
92
+ message: string,
93
+ public readonly fields: Record<string, string[]>
94
+ ) {
95
+ super(message)
96
+ }
97
+ }
98
+
99
+ class UnauthorizedError extends AppError {
100
+ readonly code = 'UNAUTHORIZED'
101
+ readonly statusCode = 401
102
+
103
+ constructor(message = 'Authentication required') {
104
+ super(message)
105
+ }
106
+ }
107
+
108
+ // Type guard for app errors
109
+ function isAppError(error: unknown): error is AppError {
110
+ return error instanceof AppError
111
+ }
112
+
113
+ // Error handler
114
+ function handleError(error: unknown): { status: number; body: object } {
115
+ if (isAppError(error)) {
116
+ return {
117
+ status: error.statusCode,
118
+ body: {
119
+ code: error.code,
120
+ message: error.message,
121
+ ...(error instanceof ValidationError && { fields: error.fields }),
122
+ },
123
+ }
124
+ }
125
+
126
+ console.error('Unexpected error:', error)
127
+ return {
128
+ status: 500,
129
+ body: { code: 'INTERNAL_ERROR', message: 'Internal server error' },
130
+ }
131
+ }
132
+ ```
133
+
134
+ ---
135
+
136
+ ## Validation Patterns
137
+
138
+ ### Zod Schema Validation
139
+
140
+ ```typescript
141
+ import { z } from 'zod'
142
+
143
+ // Define schemas
144
+ const UserSchema = z.object({
145
+ id: z.string().uuid(),
146
+ name: z.string().min(1).max(100),
147
+ email: z.string().email(),
148
+ age: z.number().int().min(0).max(150).optional(),
149
+ role: z.enum(['user', 'admin', 'moderator']),
150
+ metadata: z.record(z.string()).optional(),
151
+ })
152
+
153
+ // Infer TypeScript type
154
+ type User = z.infer<typeof UserSchema>
155
+
156
+ // Create DTO schemas
157
+ const CreateUserSchema = UserSchema.omit({ id: true })
158
+ type CreateUserDto = z.infer<typeof CreateUserSchema>
159
+
160
+ const UpdateUserSchema = UserSchema.partial().omit({ id: true })
161
+ type UpdateUserDto = z.infer<typeof UpdateUserSchema>
162
+
163
+ // Validation functions
164
+ function validateCreateUser(data: unknown): Result<CreateUserDto, z.ZodError> {
165
+ const result = CreateUserSchema.safeParse(data)
166
+
167
+ if (result.success) {
168
+ return ok(result.data)
169
+ }
170
+
171
+ return err(result.error)
172
+ }
173
+
174
+ // Transform Zod errors to user-friendly format
175
+ function formatZodError(error: z.ZodError): Record<string, string[]> {
176
+ const formatted: Record<string, string[]> = {}
177
+
178
+ for (const issue of error.issues) {
179
+ const path = issue.path.join('.')
180
+ if (!formatted[path]) {
181
+ formatted[path] = []
182
+ }
183
+ formatted[path].push(issue.message)
184
+ }
185
+
186
+ return formatted
187
+ }
188
+ ```
189
+
190
+ ### Branded Types for Validation
191
+
192
+ ```typescript
193
+ // Branded/Nominal types
194
+ declare const EmailBrand: unique symbol
195
+ type Email = string & { readonly [EmailBrand]: true }
196
+
197
+ declare const UserIdBrand: unique symbol
198
+ type UserId = string & { readonly [UserIdBrand]: true }
199
+
200
+ // Validation functions that return branded types
201
+ function validateEmail(input: string): Email {
202
+ const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/
203
+ if (!emailRegex.test(input)) {
204
+ throw new ValidationError('Invalid email', { email: ['Invalid format'] })
205
+ }
206
+ return input as Email
207
+ }
208
+
209
+ function validateUserId(input: string): UserId {
210
+ const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i
211
+ if (!uuidRegex.test(input)) {
212
+ throw new ValidationError('Invalid user ID', { id: ['Must be UUID'] })
213
+ }
214
+ return input as UserId
215
+ }
216
+
217
+ // Usage: Functions require validated types
218
+ function sendEmail(to: Email, subject: string): void {
219
+ // to is guaranteed to be valid email
220
+ }
221
+
222
+ function getUser(id: UserId): Promise<User> {
223
+ // id is guaranteed to be valid UUID
224
+ }
225
+
226
+ // Compiler enforces validation
227
+ sendEmail('invalid', 'Hello') // Error: string not assignable to Email
228
+ sendEmail(validateEmail('a@b.com'), 'Hello') // OK
229
+ ```
230
+
231
+ ---
232
+
233
+ ## Project Organization
234
+
235
+ ### Feature-Based Structure
236
+
237
+ ```
238
+ src/
239
+ ├── features/
240
+ │ ├── users/
241
+ │ │ ├── index.ts # Public exports (barrel)
242
+ │ │ ├── user.types.ts # Types and interfaces
243
+ │ │ ├── user.schema.ts # Zod schemas
244
+ │ │ ├── user.service.ts # Business logic
245
+ │ │ ├── user.repository.ts # Data access
246
+ │ │ ├── user.controller.ts # HTTP handlers
247
+ │ │ └── __tests__/
248
+ │ │ ├── user.service.test.ts
249
+ │ │ └── user.controller.test.ts
250
+ │ ├── auth/
251
+ │ │ ├── index.ts
252
+ │ │ ├── auth.types.ts
253
+ │ │ └── ...
254
+ │ └── posts/
255
+ │ └── ...
256
+ ├── shared/
257
+ │ ├── types/
258
+ │ │ ├── result.ts
259
+ │ │ └── pagination.ts
260
+ │ ├── utils/
261
+ │ │ ├── validation.ts
262
+ │ │ └── date.ts
263
+ │ └── errors/
264
+ │ └── app-error.ts
265
+ ├── infrastructure/
266
+ │ ├── database/
267
+ │ │ └── client.ts
268
+ │ ├── cache/
269
+ │ │ └── redis.ts
270
+ │ └── logging/
271
+ │ └── logger.ts
272
+ └── config/
273
+ ├── index.ts
274
+ └── env.ts
275
+ ```
276
+
277
+ ### Barrel Exports
278
+
279
+ ```typescript
280
+ // features/users/index.ts
281
+ export type { User, CreateUserDto, UpdateUserDto } from './user.types'
282
+ export { UserSchema, CreateUserSchema } from './user.schema'
283
+ export { UserService } from './user.service'
284
+ export { UserController } from './user.controller'
285
+
286
+ // Don't export repository (internal detail)
287
+ // Don't export internal helper functions
288
+
289
+ // Usage in other modules
290
+ import { User, UserService } from '@/features/users'
291
+ ```
292
+
293
+ ### Path Aliases
294
+
295
+ ```json
296
+ // tsconfig.json
297
+ {
298
+ "compilerOptions": {
299
+ "baseUrl": ".",
300
+ "paths": {
301
+ "@/*": ["src/*"],
302
+ "@features/*": ["src/features/*"],
303
+ "@shared/*": ["src/shared/*"],
304
+ "@config/*": ["src/config/*"]
305
+ }
306
+ }
307
+ }
308
+ ```
309
+
310
+ ---
311
+
312
+ ## Migration Strategies
313
+
314
+ ### Incremental Migration from JavaScript
315
+
316
+ **Phase 1: Enable TypeScript alongside JavaScript**
317
+
318
+ ```json
319
+ // tsconfig.json
320
+ {
321
+ "compilerOptions": {
322
+ "allowJs": true,
323
+ "checkJs": false,
324
+ "outDir": "./dist",
325
+ "target": "ES2022",
326
+ "module": "ESNext",
327
+ "moduleResolution": "bundler",
328
+ "strict": false,
329
+ "noImplicitAny": false
330
+ },
331
+ "include": ["src/**/*"]
332
+ }
333
+ ```
334
+
335
+ **Phase 2: Rename files gradually**
336
+
337
+ ```bash
338
+ # Convert one file at a time
339
+ mv src/utils/helpers.js src/utils/helpers.ts
340
+
341
+ # Add minimal type annotations
342
+ # Fix any type errors
343
+ # Run tests to verify
344
+ ```
345
+
346
+ **Phase 3: Enable stricter checks incrementally**
347
+
348
+ ```json
349
+ // Progression of strict options
350
+ {
351
+ "compilerOptions": {
352
+ // Step 1: Basic strictness
353
+ "noImplicitAny": true,
354
+
355
+ // Step 2: Null safety
356
+ "strictNullChecks": true,
357
+
358
+ // Step 3: Full strict mode
359
+ "strict": true,
360
+
361
+ // Step 4: Extra safety (optional)
362
+ "noUncheckedIndexedAccess": true,
363
+ "exactOptionalPropertyTypes": true
364
+ }
365
+ }
366
+ ```
367
+
368
+ ### JSDoc for Gradual Typing
369
+
370
+ ```javascript
371
+ // Before full migration, use JSDoc
372
+ /**
373
+ * @typedef {Object} User
374
+ * @property {string} id
375
+ * @property {string} name
376
+ * @property {string} email
377
+ */
378
+
379
+ /**
380
+ * Find user by ID
381
+ * @param {string} id - User ID
382
+ * @returns {Promise<User | null>}
383
+ */
384
+ async function findUser(id) {
385
+ // implementation
386
+ }
387
+
388
+ /**
389
+ * @template T
390
+ * @param {T[]} items
391
+ * @returns {T | undefined}
392
+ */
393
+ function first(items) {
394
+ return items[0]
395
+ }
396
+ ```
397
+
398
+ ### CommonJS to ESM Migration
399
+
400
+ ```json
401
+ // package.json
402
+ {
403
+ "type": "module"
404
+ }
405
+ ```
406
+
407
+ ```typescript
408
+ // Before (CommonJS)
409
+ const express = require('express')
410
+ const { UserService } = require('./user.service')
411
+ module.exports = { router }
412
+
413
+ // After (ESM)
414
+ import express from 'express'
415
+ import { UserService } from './user.service.js' // Note .js extension
416
+ export { router }
417
+ ```
418
+
419
+ ---
420
+
421
+ ## Security Patterns
422
+
423
+ ### Input Sanitization
424
+
425
+ ```typescript
426
+ import { z } from 'zod'
427
+ import DOMPurify from 'isomorphic-dompurify'
428
+
429
+ // Sanitized string schema
430
+ const SanitizedString = z.string().transform((val) => {
431
+ return DOMPurify.sanitize(val.trim())
432
+ })
433
+
434
+ // HTML content schema (for rich text)
435
+ const HtmlContentSchema = z.string().transform((val) => {
436
+ return DOMPurify.sanitize(val, {
437
+ ALLOWED_TAGS: ['b', 'i', 'em', 'strong', 'a', 'p', 'br'],
438
+ ALLOWED_ATTR: ['href', 'target'],
439
+ })
440
+ })
441
+
442
+ // SQL-safe identifier
443
+ const SafeIdentifierSchema = z.string().regex(/^[a-zA-Z_][a-zA-Z0-9_]*$/, 'Invalid identifier')
444
+ ```
445
+
446
+ ### Type-Safe Environment Variables
447
+
448
+ ```typescript
449
+ import { z } from 'zod'
450
+
451
+ const EnvSchema = z.object({
452
+ NODE_ENV: z.enum(['development', 'production', 'test']),
453
+ PORT: z.coerce.number().default(3000),
454
+ DATABASE_URL: z.string().url(),
455
+ JWT_SECRET: z.string().min(32),
456
+ REDIS_URL: z.string().url().optional(),
457
+ })
458
+
459
+ // Validate on startup
460
+ function loadEnv() {
461
+ const result = EnvSchema.safeParse(process.env)
462
+
463
+ if (!result.success) {
464
+ console.error('Invalid environment variables:')
465
+ console.error(result.error.format())
466
+ process.exit(1)
467
+ }
468
+
469
+ return result.data
470
+ }
471
+
472
+ export const env = loadEnv()
473
+
474
+ // Usage: fully typed
475
+ env.PORT // number
476
+ env.NODE_ENV // "development" | "production" | "test"
477
+ env.REDIS_URL // string | undefined
478
+ ```
479
+
480
+ ### Secure API Response Types
481
+
482
+ ```typescript
483
+ // Never expose internal fields
484
+ interface InternalUser {
485
+ id: string
486
+ name: string
487
+ email: string
488
+ passwordHash: string
489
+ internalNotes: string
490
+ }
491
+
492
+ // Public API response (Pick only safe fields)
493
+ type PublicUser = Pick<InternalUser, 'id' | 'name' | 'email'>
494
+
495
+ // Or explicitly define
496
+ interface UserResponse {
497
+ id: string
498
+ name: string
499
+ email: string
500
+ }
501
+
502
+ // Transform function
503
+ function toPublicUser(user: InternalUser): UserResponse {
504
+ return {
505
+ id: user.id,
506
+ name: user.name,
507
+ email: user.email,
508
+ }
509
+ }
510
+ ```
511
+
512
+ ### Rate Limiting Types
513
+
514
+ ```typescript
515
+ interface RateLimitConfig {
516
+ windowMs: number
517
+ maxRequests: number
518
+ }
519
+
520
+ interface RateLimitResult {
521
+ allowed: boolean
522
+ remaining: number
523
+ resetAt: Date
524
+ }
525
+
526
+ const rateLimits: Record<string, RateLimitConfig> = {
527
+ api: { windowMs: 60000, maxRequests: 100 },
528
+ auth: { windowMs: 300000, maxRequests: 5 },
529
+ upload: { windowMs: 3600000, maxRequests: 10 },
530
+ } as const satisfies Record<string, RateLimitConfig>
531
+ ```