Skip to main content

GraphQL API Design Patterns - Building Scalable and Efficient APIs

Muhammad Ubaid Raza
Friday, March 8, 2024
GraphQLAPI DesignBackend
GraphQL API architecture and design patterns

GraphQL API Design Patterns: Building Scalable and Efficient APIs

GraphQL has revolutionized how we think about API design, offering unprecedented flexibility and efficiency. After building and scaling GraphQL APIs serving millions of requests, I'm sharing the patterns, optimizations, and best practices that ensure your GraphQL implementation is both powerful and performant.

Schema Design Fundamentals

Type-First Design Approach

# schema.graphql - Start with clear, well-defined types
type User {
  id: ID!
  email: String!
  profile: UserProfile
  posts(first: Int, after: String): PostConnection!
  followers(first: Int, after: String): UserConnection!
  following(first: Int, after: String): UserConnection!
  createdAt: DateTime!
  updatedAt: DateTime!
}

type UserProfile {
  firstName: String!
  lastName: String!
  bio: String
  avatar: Image
  website: URL
  location: String
  birthDate: Date
}

type Post {
  id: ID!
  title: String!
  content: String!
  excerpt: String
  author: User!
  tags: [Tag!]!
  comments(first: Int, after: String): CommentConnection!
  likes: Int!
  isLiked: Boolean!
  publishedAt: DateTime
  createdAt: DateTime!
  updatedAt: DateTime!
}

# Relay-style connections for pagination
type PostConnection {
  edges: [PostEdge!]!
  pageInfo: PageInfo!
  totalCount: Int!
}

type PostEdge {
  node: Post!
  cursor: String!
}

type PageInfo {
  hasNextPage: Boolean!
  hasPreviousPage: Boolean!
  startCursor: String
  endCursor: String
}

Interface and Union Patterns

# Interfaces for shared behavior
interface Node {
  id: ID!
}

interface Timestamped {
  createdAt: DateTime!
  updatedAt: DateTime!
}

interface Authored {
  author: User!
}

# Implement interfaces
type Post implements Node & Timestamped & Authored {
  id: ID!
  title: String!
  content: String!
  author: User!
  createdAt: DateTime!
  updatedAt: DateTime!
}

type Comment implements Node & Timestamped & Authored {
  id: ID!
  content: String!
  post: Post!
  author: User!
  createdAt: DateTime!
  updatedAt: DateTime!
}

# Union types for polymorphic results
union SearchResult = Post | User | Tag

type Query {
  search(query: String!, type: SearchType): [SearchResult!]!
  node(id: ID!): Node
}

enum SearchType {
  ALL
  POSTS
  USERS
  TAGS
}

Advanced Resolver Patterns

DataLoader for N+1 Problem Resolution

// dataloaders/userLoader.js
const DataLoader = require("dataloader")
const { User } = require("../models")

const createUserLoader = () => {
  return new DataLoader(async (userIds) => {
    const users = await User.findByIds(userIds)

    // Return users in the same order as requested IDs
    const userMap = new Map(users.map((user) => [user.id, user]))
    return userIds.map((id) => userMap.get(id) || null)
  })
}

// dataloaders/postLoader.js
const createPostsByUserLoader = () => {
  return new DataLoader(async (userIds) => {
    const posts = await Post.findByUserIds(userIds)

    // Group posts by user ID
    const postsByUser = userIds.map((userId) =>
      posts.filter((post) => post.authorId === userId),
    )

    return postsByUser
  })
}

// Context setup
const createContext = ({ req }) => ({
  user: req.user,
  dataloaders: {
    userLoader: createUserLoader(),
    postsByUserLoader: createPostsByUserLoader(),
    commentsByPostLoader: createCommentsByPostLoader(),
  },
})

Resolver Implementation with DataLoaders

// resolvers/user.js
const userResolvers = {
  Query: {
    user: async (parent, { id }, { dataloaders }) => {
      return dataloaders.userLoader.load(id)
    },

    users: async (parent, { first, after }, { dataloaders }) => {
      const result = await User.findMany({ first, after })

      // Prime the loader cache
      result.edges.forEach((edge) => {
        dataloaders.userLoader.prime(edge.node.id, edge.node)
      })

      return result
    },
  },

  User: {
    posts: async (user, { first, after }, { dataloaders }) => {
      return dataloaders.postsByUserLoader.load(user.id)
    },

    followers: async (user, args, { dataloaders }) => {
      const followerIds = await dataloaders.followerIdsByUserLoader.load(
        user.id,
      )
      const followers = await dataloaders.userLoader.loadMany(followerIds)

      return {
        edges: followers.map((follower) => ({
          node: follower,
          cursor: Buffer.from(follower.id).toString("base64"),
        })),
        pageInfo: {
          hasNextPage: false, // Implement proper pagination logic
          hasPreviousPage: false,
        },
        totalCount: followers.length,
      }
    },
  },

  Post: {
    author: async (post, args, { dataloaders }) => {
      return dataloaders.userLoader.load(post.authorId)
    },

    comments: async (post, { first, after }, { dataloaders }) => {
      return dataloaders.commentsByPostLoader.load(post.id)
    },

    isLiked: async (post, args, { user, dataloaders }) => {
      if (!user) return false
      return dataloaders.isLikedLoader.load({
        postId: post.id,
        userId: user.id,
      })
    },
  },
}

Field-Level Authorization

// directives/auth.js
const { SchemaDirectiveVisitor } = require("apollo-server-express")
const { defaultFieldResolver } = require("graphql")

class AuthDirective extends SchemaDirectiveVisitor {
  visitFieldDefinition(field) {
    const { resolve = defaultFieldResolver } = field
    const requiredRole = this.args.requires

    field.resolve = async function (parent, args, context, info) {
      const { user } = context

      if (!user) {
        throw new AuthenticationError("You must be logged in")
      }

      if (requiredRole && !user.roles.includes(requiredRole)) {
        throw new ForbiddenError(`You need ${requiredRole} role`)
      }

      return resolve.call(this, parent, args, context, info)
    }
  }
}

// Schema with directives
const typeDefs = `
  directive @auth(requires: Role = USER) on FIELD_DEFINITION

  enum Role {
    USER
    ADMIN
    MODERATOR
  }

  type User {
    id: ID!
    email: String! @auth
    profile: UserProfile!
    adminNotes: String @auth(requires: ADMIN)
  }

  type Mutation {
    deleteUser(id: ID!): Boolean! @auth(requires: ADMIN)
    updateProfile(input: UpdateProfileInput!): User! @auth
  }
`

Performance Optimization Strategies

Query Complexity Analysis

// complexity/rules.js
const depthLimit = require("graphql-depth-limit")
const costAnalysis = require("graphql-cost-analysis")

const complexityLimitRule = costAnalysis({
  maximumCost: 1000,
  defaultCost: 1,
  scalarCost: 1,
  objectCost: 2,
  listFactor: 10,
  introspectionCost: 1000,
  fieldExtensions: {
    complexity: {
      // Custom complexity for expensive fields
      User: {
        posts: { complexity: ({ args }) => args.first * 2 },
        followers: { complexity: ({ args }) => args.first * 3 },
      },
      Post: {
        comments: { complexity: ({ args }) => args.first * 2 },
      },
    },
  },
})

// Apollo Server setup
const server = new ApolloServer({
  typeDefs,
  resolvers,
  validationRules: [
    depthLimit(10), // Limit query depth
    complexityLimitRule,
  ],
  plugins: [
    {
      requestDidStart() {
        return {
          didResolveOperation({ request, document }) {
            const complexity = getComplexity({
              estimators: [
                fieldExtensionsEstimator(),
                simpleEstimator({ defaultComplexity: 1 }),
              ],
              schema,
              query: document,
              variables: request.variables,
            })

            if (complexity > 1000) {
              throw new Error(
                `Query complexity ${complexity} exceeds limit of 1000`,
              )
            }
          },
        }
      },
    },
  ],
})

Query Caching and Persisted Queries

// cache/redis.js
const Redis = require("ioredis")
const redis = new Redis(process.env.REDIS_URL)

class QueryCache {
  constructor() {
    this.redis = redis
    this.defaultTTL = 300 // 5 minutes
  }

  generateKey(query, variables, user) {
    const hash = crypto
      .createHash("sha256")
      .update(JSON.stringify({ query, variables, userId: user?.id }))
      .digest("hex")
    return `gql:${hash}`
  }

  async get(query, variables, user) {
    const key = this.generateKey(query, variables, user)
    const cached = await this.redis.get(key)
    return cached ? JSON.parse(cached) : null
  }

  async set(query, variables, user, result, ttl = this.defaultTTL) {
    const key = this.generateKey(query, variables, user)
    await this.redis.setex(key, ttl, JSON.stringify(result))
  }

  async invalidatePattern(pattern) {
    const keys = await this.redis.keys(pattern)
    if (keys.length > 0) {
      await this.redis.del(...keys)
    }
  }
}

// Caching plugin
const cachePlugin = {
  requestDidStart() {
    return {
      async willSendResponse({ request, response, context }) {
        const { query, variables } = request
        const { user } = context

        // Only cache successful queries
        if (response.errors) return

        // Don't cache mutations
        if (query.includes("mutation")) return

        await queryCache.set(query, variables, user, response.data)
      },
    }
  },
}

Subscription Optimization

// subscriptions/setup.js
const { RedisPubSub } = require("graphql-redis-subscriptions")
const { withFilter } = require("graphql-subscriptions")

const pubsub = new RedisPubSub({
  connection: {
    host: process.env.REDIS_HOST,
    port: process.env.REDIS_PORT,
    retryDelayOnFailover: 100,
    enableReadyCheck: false,
    maxRetriesPerRequest: null,
  },
})

// Subscription resolvers
const subscriptionResolvers = {
  Subscription: {
    postAdded: {
      subscribe: withFilter(
        () => pubsub.asyncIterator(["POST_ADDED"]),
        (payload, variables, context) => {
          // Filter subscriptions based on user permissions
          const { user } = context
          const { post } = payload.postAdded

          // Only send public posts or posts from followed users
          return (
            post.isPublic || (user && user.following.includes(post.authorId))
          )
        },
      ),
    },

    commentAdded: {
      subscribe: withFilter(
        () => pubsub.asyncIterator(["COMMENT_ADDED"]),
        (payload, variables) => {
          return payload.commentAdded.postId === variables.postId
        },
      ),
    },

    userOnline: {
      subscribe: withFilter(
        () => pubsub.asyncIterator(["USER_STATUS_CHANGED"]),
        (payload, variables, context) => {
          const { user } = context
          return user && user.following.includes(payload.userOnline.id)
        },
      ),
    },
  },
}

// Publishing events
const publishPostAdded = async (post) => {
  await pubsub.publish("POST_ADDED", { postAdded: post })
}

const publishCommentAdded = async (comment) => {
  await pubsub.publish("COMMENT_ADDED", { commentAdded: comment })
}

Security Best Practices

Input Validation and Sanitization

// validation/schemas.js
const Joi = require("joi")

const validationSchemas = {
  createPost: Joi.object({
    title: Joi.string().min(1).max(200).required(),
    content: Joi.string().min(1).max(10000).required(),
    tags: Joi.array().items(Joi.string().max(50)).max(10),
    isPublic: Joi.boolean().default(true),
  }),

  updateUser: Joi.object({
    firstName: Joi.string().min(1).max(50),
    lastName: Joi.string().min(1).max(50),
    bio: Joi.string().max(500),
    website: Joi.string().uri(),
  }),

  searchQuery: Joi.object({
    query: Joi.string().min(1).max(100).required(),
    type: Joi.string().valid("ALL", "POSTS", "USERS", "TAGS").default("ALL"),
    first: Joi.number().integer().min(1).max(50).default(10),
  }),
}

// Validation middleware
const validateInput =
  (schema) => (resolve) => async (parent, args, context, info) => {
    const { error, value } = schema.validate(args.input || args)

    if (error) {
      throw new UserInputError("Invalid input", {
        validationErrors: error.details.map((detail) => ({
          field: detail.path.join("."),
          message: detail.message,
        })),
      })
    }

    // Replace args with validated values
    const newArgs = { ...args, ...(args.input ? { input: value } : value) }
    return resolve(parent, newArgs, context, info)
  }

// Usage in resolvers
const mutationResolvers = {
  Mutation: {
    createPost: validateInput(validationSchemas.createPost)(
      async (parent, { input }, { user, dataloaders }) => {
        if (!user) throw new AuthenticationError("Must be logged in")

        const post = await Post.create({
          ...input,
          authorId: user.id,
        })

        await publishPostAdded(post)
        return post
      },
    ),
  },
}

Rate Limiting

// middleware/rateLimiting.js
const { RateLimiterRedis } = require("rate-limiter-flexible")
const Redis = require("ioredis")

const redis = new Redis(process.env.REDIS_URL)

// Different limits for different operations
const rateLimiters = {
  query: new RateLimiterRedis({
    storeClient: redis,
    keyPrefix: "rl_query",
    points: 100, // Number of requests
    duration: 60, // Per 60 seconds
  }),

  mutation: new RateLimiterRedis({
    storeClient: redis,
    keyPrefix: "rl_mutation",
    points: 10, // Number of mutations
    duration: 60, // Per 60 seconds
  }),

  subscription: new RateLimiterRedis({
    storeClient: redis,
    keyPrefix: "rl_subscription",
    points: 5, // Number of subscriptions
    duration: 60, // Per 60 seconds
  }),
}

const rateLimitPlugin = {
  requestDidStart() {
    return {
      async didResolveOperation({ request, context }) {
        const { user } = context
        const userId = user?.id || request.ip

        const operationType = request.operationName?.toLowerCase() || "query"
        const limiter = rateLimiters[operationType] || rateLimiters.query

        try {
          await limiter.consume(userId)
        } catch (rejRes) {
          throw new Error(
            `Rate limit exceeded. Try again in ${rejRes.msBeforeNext}ms`,
          )
        }
      },
    }
  },
}

Query Whitelisting for Production

// security/queryWhitelist.js
const approvedQueries = new Map([
  [
    "GetUser",
    `
    query GetUser($id: ID!) {
      user(id: $id) {
        id
        profile {
          firstName
          lastName
          avatar
        }
      }
    }
  `,
  ],
  [
    "GetPosts",
    `
    query GetPosts($first: Int, $after: String) {
      posts(first: $first, after: $after) {
        edges {
          node {
            id
            title
            excerpt
            author {
              id
              profile {
                firstName
                lastName
              }
            }
          }
        }
        pageInfo {
          hasNextPage
          endCursor
        }
      }
    }
  `,
  ],
])

const queryWhitelistPlugin = {
  requestDidStart() {
    return {
      async didResolveOperation({ request }) {
        if (process.env.NODE_ENV === "production") {
          const { operationName, query } = request

          if (!operationName) {
            throw new Error("Operation name is required in production")
          }

          const approvedQuery = approvedQueries.get(operationName)
          if (!approvedQuery) {
            throw new Error(`Query ${operationName} is not approved`)
          }

          // Optionally validate that the query matches exactly
          const normalizedQuery = query.replace(/\s+/g, " ").trim()
          const normalizedApproved = approvedQuery.replace(/\s+/g, " ").trim()

          if (normalizedQuery !== normalizedApproved) {
            throw new Error("Query does not match approved version")
          }
        }
      },
    }
  },
}

Testing Strategies

Unit Testing Resolvers

// tests/resolvers/user.test.js
const { createTestClient } = require("apollo-server-testing")
const { ApolloServer } = require("apollo-server-express")
const { typeDefs, resolvers } = require("../../src/schema")

describe("User Resolvers", () => {
  let server, query, mutate

  beforeEach(() => {
    server = new ApolloServer({
      typeDefs,
      resolvers,
      context: () => ({
        user: { id: "1", email: "test@example.com" },
        dataloaders: {
          userLoader: {
            load: jest.fn().mockResolvedValue({
              id: "1",
              email: "test@example.com",
              profile: { firstName: "John", lastName: "Doe" },
            }),
          },
        },
      }),
    })

    const testClient = createTestClient(server)
    query = testClient.query
    mutate = testClient.mutate
  })

  it("should fetch user by ID", async () => {
    const GET_USER = `
      query GetUser($id: ID!) {
        user(id: $id) {
          id
          email
          profile {
            firstName
            lastName
          }
        }
      }
    `

    const result = await query({
      query: GET_USER,
      variables: { id: "1" },
    })

    expect(result.errors).toBeUndefined()
    expect(result.data.user).toEqual({
      id: "1",
      email: "test@example.com",
      profile: {
        firstName: "John",
        lastName: "Doe",
      },
    })
  })

  it("should handle authentication errors", async () => {
    server = new ApolloServer({
      typeDefs,
      resolvers,
      context: () => ({ user: null }), // No authenticated user
    })

    const testClient = createTestClient(server)

    const UPDATE_PROFILE = `
      mutation UpdateProfile($input: UpdateProfileInput!) {
        updateProfile(input: $input) {
          id
          profile {
            firstName
          }
        }
      }
    `

    const result = await testClient.mutate({
      mutation: UPDATE_PROFILE,
      variables: {
        input: { firstName: "Jane" },
      },
    })

    expect(result.errors).toBeDefined()
    expect(result.errors[0].message).toContain("authentication")
  })
})

Integration Testing

// tests/integration/api.test.js
const request = require("supertest")
const { createApp } = require("../../src/app")

describe("GraphQL API Integration", () => {
  let app, authToken

  beforeAll(async () => {
    app = await createApp()

    // Create test user and get auth token
    const loginResponse = await request(app)
      .post("/graphql")
      .send({
        query: `
          mutation Login($email: String!, $password: String!) {
            login(email: $email, password: $password) {
              token
              user {
                id
                email
              }
            }
          }
        `,
        variables: {
          email: "test@example.com",
          password: "password123",
        },
      })

    authToken = loginResponse.body.data.login.token
  })

  it("should create and fetch a post", async () => {
    // Create post
    const createResponse = await request(app)
      .post("/graphql")
      .set("Authorization", `Bearer ${authToken}`)
      .send({
        query: `
          mutation CreatePost($input: CreatePostInput!) {
            createPost(input: $input) {
              id
              title
              content
              author {
                id
              }
            }
          }
        `,
        variables: {
          input: {
            title: "Test Post",
            content: "This is a test post content",
            isPublic: true,
          },
        },
      })

    expect(createResponse.body.errors).toBeUndefined()
    const postId = createResponse.body.data.createPost.id

    // Fetch post
    const fetchResponse = await request(app)
      .post("/graphql")
      .send({
        query: `
          query GetPost($id: ID!) {
            post(id: $id) {
              id
              title
              content
              author {
                profile {
                  firstName
                  lastName
                }
              }
            }
          }
        `,
        variables: { id: postId },
      })

    expect(fetchResponse.body.errors).toBeUndefined()
    expect(fetchResponse.body.data.post.title).toBe("Test Post")
  })
})

Monitoring and Analytics

Performance Monitoring

// monitoring/apollo.js
const { ApolloServerPluginUsageReporting } = require("apollo-server-core")

const performancePlugin = {
  requestDidStart() {
    return {
      willSendResponse({ response, context, request }) {
        const { operationName, query } = request
        const { user } = context

        // Log slow queries
        const duration = Date.now() - context.startTime
        if (duration > 1000) {
          console.warn("Slow GraphQL Query", {
            operationName,
            duration,
            userId: user?.id,
            query: query.substring(0, 200),
          })
        }

        // Track metrics
        metrics.graphqlRequestDuration
          .labels(operationName || "unknown")
          .observe(duration / 1000)

        metrics.graphqlRequestTotal
          .labels(
            operationName || "unknown",
            response.errors ? "error" : "success",
          )
          .inc()
      },
    }
  },
}

// Apollo Studio integration
const server = new ApolloServer({
  typeDefs,
  resolvers,
  plugins: [
    ApolloServerPluginUsageReporting({
      sendVariableValues: { all: true },
      sendHeaders: { all: true },
    }),
    performancePlugin,
  ],
})

Conclusion

Building scalable GraphQL APIs requires careful attention to:

  1. Schema Design - Well-structured types, interfaces, and connections
  2. Performance - DataLoaders, caching, and query optimization
  3. Security - Authentication, authorization, and input validation
  4. Monitoring - Performance tracking and error reporting
  5. Testing - Comprehensive unit and integration tests

GraphQL's flexibility is both its strength and potential weakness. The patterns and practices outlined here help you harness that flexibility while maintaining performance, security, and maintainability.

Start with a solid schema foundation, implement proper data loading patterns, and gradually add advanced features like subscriptions and caching as your API grows.

What GraphQL challenges are you facing in your projects? Are there specific performance or security concerns you'd like me to address? I'm here to help with any GraphQL questions you might have.

Full-stack engineer leading teams to build scalable systems & tools, with solid DevOps expertise.

Muhammad Ubaid R.

\n",[124,5748,5749,5754,5773,5795,5815,5819,5824,5865,5877,5881,5885,5890,5918,5927,5936,5960,5971,5975,5979,5994,6025,6029,6035],{"__ignoreMap":122},[127,5750,5751],{"class":129,"line":130},[127,5752,5753],{"class":4433},"// app/pages/users.vue\n",[127,5755,5756,5758,5761,5763,5765,5768,5770],{"class":129,"line":136},[127,5757,5359],{"class":4514},[127,5759,5760],{"class":4518},"script setup lang",[127,5762,4615],{"class":4514},[127,5764,4624],{"class":4514},[127,5766,5767],{"class":4547},"ts",[127,5769,4624],{"class":4514},[127,5771,5772],{"class":4514},">\n",[127,5774,5775,5777,5779,5782,5784,5786,5789,5792],{"class":129,"line":16},[127,5776,4511],{"class":4510},[127,5778,4515],{"class":4514},[127,5780,5781],{"class":4518}," usersApi",[127,5783,4538],{"class":4514},[127,5785,4541],{"class":4510},[127,5787,5788],{"class":4514}," '",[127,5790,5791],{"class":4547},"@/lib/api/client",[127,5793,5794],{"class":4514},"'\n",[127,5796,5797,5799,5801,5803,5805,5807,5809,5811,5813],{"class":129,"line":147},[127,5798,4511],{"class":4510},[127,5800,4839],{"class":4510},[127,5802,4515],{"class":4514},[127,5804,4843],{"class":4518},[127,5806,4538],{"class":4514},[127,5808,4541],{"class":4510},[127,5810,5788],{"class":4514},[127,5812,4954],{"class":4547},[127,5814,5794],{"class":4514},[127,5816,5817],{"class":129,"line":153},[127,5818,199],{"emptyLinePlaceholder":198},[127,5820,5821],{"class":129,"line":159},[127,5822,5823],{"class":4433},"// Fully typed with inference\n",[127,5825,5826,5828,5830,5832,5834,5836,5838,5841,5843,5845,5847,5850,5852,5855,5857,5859,5861,5863],{"class":129,"line":165},[127,5827,4965],{"class":4608},[127,5829,4515],{"class":4514},[127,5831,5051],{"class":4639},[127,5833,4643],{"class":4514},[127,5835,4852],{"class":4518},[127,5837,4522],{"class":4514},[127,5839,5840],{"class":4518}," error ",[127,5842,4780],{"class":4514},[127,5844,4846],{"class":4514},[127,5846,5097],{"class":4510},[127,5848,5849],{"class":4618}," useAsyncData",[127,5851,4621],{"class":4518},[127,5853,5854],{"class":4514},"'",[127,5856,4627],{"class":4547},[127,5858,5854],{"class":4514},[127,5860,4522],{"class":4514},[127,5862,5548],{"class":4514},[127,5864,5639],{"class":4608},[127,5866,5867,5870,5872,5875],{"class":129,"line":171},[127,5868,5869],{"class":4518}," usersApi",[127,5871,4660],{"class":4514},[127,5873,5874],{"class":4618},"getAll",[127,5876,4978],{"class":4518},[127,5878,5879],{"class":129,"line":177},[127,5880,4783],{"class":4518},[127,5882,5883],{"class":129,"line":183},[127,5884,199],{"emptyLinePlaceholder":198},[127,5886,5887],{"class":129,"line":189},[127,5888,5889],{"class":4433},"// Type-safe component\n",[127,5891,5892,5894,5897,5899,5902,5905,5907,5909,5911,5914,5916],{"class":129,"line":195},[127,5893,4965],{"class":4608},[127,5895,5896],{"class":4518}," UserCard ",[127,5898,4615],{"class":4514},[127,5900,5901],{"class":4618}," defineComponent",[127,5903,5904],{"class":4514},"<{",[127,5906,5092],{"class":4639},[127,5908,4643],{"class":4514},[127,5910,4843],{"class":4842},[127,5912,5913],{"class":4514}," }>",[127,5915,4621],{"class":4518},[127,5917,5150],{"class":4514},[127,5919,5920,5923,5925],{"class":129,"line":29},[127,5921,5922],{"class":4639}," props",[127,5924,4643],{"class":4514},[127,5926,4634],{"class":4514},[127,5928,5929,5932,5934],{"class":129,"line":207},[127,5930,5931],{"class":4639}," user",[127,5933,4643],{"class":4514},[127,5935,4634],{"class":4514},[127,5937,5938,5941,5943,5946,5949,5952,5954,5957],{"class":129,"line":213},[127,5939,5940],{"class":4639}," type",[127,5942,4643],{"class":4514},[127,5944,5945],{"class":4518}," Object ",[127,5947,5948],{"class":4510},"as",[127,5950,5951],{"class":4842}," PropType",[127,5953,5359],{"class":4514},[127,5955,5956],{"class":4842},"User",[127,5958,5959],{"class":4514},">,\n",[127,5961,5962,5965,5967],{"class":129,"line":219},[127,5963,5964],{"class":4639}," required",[127,5966,4643],{"class":4514},[127,5968,5970],{"class":5969},"sfNiH"," true\n",[127,5972,5973],{"class":129,"line":225},[127,5974,1267],{"class":4514},[127,5976,5977],{"class":129,"line":231},[127,5978,844],{"class":4514},[127,5980,5981,5984,5987,5989,5992],{"class":129,"line":237},[127,5982,5983],{"class":4639}," setup",[127,5985,5986],{"class":4514},"({",[127,5988,5092],{"class":5035},[127,5990,5991],{"class":4514}," })",[127,5993,4634],{"class":4514},[127,5995,5996,5999,6001,6003,6006,6008,6010,6013,6015,6017,6019,6021,6023],{"class":129,"line":243},[127,5997,5998],{"class":4510}," return",[127,6000,5548],{"class":4514},[127,6002,5041],{"class":4608},[127,6004,6005],{"class":4618}," h",[127,6007,4621],{"class":4639},[127,6009,5854],{"class":4514},[127,6011,6012],{"class":4547},"div",[127,6014,5854],{"class":4514},[127,6016,4522],{"class":4514},[127,6018,5092],{"class":4518},[127,6020,4660],{"class":4514},[127,6022,4728],{"class":4518},[127,6024,4783],{"class":4639},[127,6026,6027],{"class":129,"line":249},[127,6028,1272],{"class":4514},[127,6030,6031,6033],{"class":129,"line":254},[127,6032,4780],{"class":4514},[127,6034,4783],{"class":4518},[127,6036,6037,6040,6043],{"class":129,"line":259},[127,6038,6039],{"class":4514},"(dataSchema: T) =>\n z.object({\n data: dataSchema,\n meta: z.object({\n timestamp: z.string().datetime(),\n version: z.string(),\n requestId: z.string().uuid(),\n }),\n })\n\nexport type ApiResponse = z.infer>>\n",[124,6057,6058,6063,6081,6085,6090,6130,6144,6155,6171,6195,6211,6235,6243,6249,6253],{"__ignoreMap":122},[127,6059,6060],{"class":129,"line":130},[127,6061,6062],{"class":4433},"// shared/types/common.ts\n",[127,6064,6065,6067,6069,6071,6073,6075,6077,6079],{"class":129,"line":136},[127,6066,4511],{"class":4510},[127,6068,4515],{"class":4514},[127,6070,4585],{"class":4518},[127,6072,4538],{"class":4514},[127,6074,4541],{"class":4510},[127,6076,4544],{"class":4514},[127,6078,4594],{"class":4547},[127,6080,4551],{"class":4514},[127,6082,6083],{"class":129,"line":16},[127,6084,199],{"emptyLinePlaceholder":198},[127,6086,6087],{"class":129,"line":147},[127,6088,6089],{"class":4433},"// Common response structure\n",[127,6091,6092,6094,6096,6099,6101,6104,6106,6109,6111,6113,6116,6118,6121,6123,6126,6128],{"class":129,"line":153},[127,6093,4605],{"class":4510},[127,6095,4609],{"class":4608},[127,6097,6098],{"class":4518}," apiResponseSchema ",[127,6100,4615],{"class":4514},[127,6102,6103],{"class":4514}," <",[127,6105,5362],{"class":4842},[127,6107,6108],{"class":4608}," extends",[127,6110,4585],{"class":4842},[127,6112,4660],{"class":4514},[127,6114,6115],{"class":4842},"ZodType",[127,6117,5365],{"class":4514},[127,6119,6120],{"class":5035},"dataSchema",[127,6122,4643],{"class":4514},[127,6124,6125],{"class":4842}," T",[127,6127,4657],{"class":4514},[127,6129,5639],{"class":4608},[127,6131,6132,6135,6137,6140,6142],{"class":129,"line":159},[127,6133,6134],{"class":4518}," z",[127,6136,4660],{"class":4514},[127,6138,6139],{"class":4618},"object",[127,6141,4621],{"class":4518},[127,6143,5150],{"class":4514},[127,6145,6146,6148,6150,6153],{"class":129,"line":165},[127,6147,5155],{"class":4639},[127,6149,4643],{"class":4514},[127,6151,6152],{"class":4518}," dataSchema",[127,6154,4676],{"class":4514},[127,6156,6157,6159,6161,6163,6165,6167,6169],{"class":129,"line":171},[127,6158,5176],{"class":4639},[127,6160,4643],{"class":4514},[127,6162,4585],{"class":4518},[127,6164,4660],{"class":4514},[127,6166,6139],{"class":4618},[127,6168,4621],{"class":4518},[127,6170,5150],{"class":4514},[127,6172,6173,6175,6177,6179,6181,6184,6186,6188,6191,6193],{"class":129,"line":177},[127,6174,5185],{"class":4639},[127,6176,4643],{"class":4514},[127,6178,4585],{"class":4518},[127,6180,4660],{"class":4514},[127,6182,6183],{"class":4618},"string",[127,6185,4666],{"class":4518},[127,6187,4660],{"class":4514},[127,6189,6190],{"class":4618},"datetime",[127,6192,4666],{"class":4518},[127,6194,4676],{"class":4514},[127,6196,6197,6199,6201,6203,6205,6207,6209],{"class":129,"line":183},[127,6198,5208],{"class":4639},[127,6200,4643],{"class":4514},[127,6202,4585],{"class":4518},[127,6204,4660],{"class":4514},[127,6206,6183],{"class":4618},[127,6208,4666],{"class":4518},[127,6210,4676],{"class":4514},[127,6212,6213,6216,6218,6220,6222,6224,6226,6228,6231,6233],{"class":129,"line":189},[127,6214,6215],{"class":4639}," requestId",[127,6217,4643],{"class":4514},[127,6219,4585],{"class":4518},[127,6221,4660],{"class":4514},[127,6223,6183],{"class":4618},[127,6225,4666],{"class":4518},[127,6227,4660],{"class":4514},[127,6229,6230],{"class":4618},"uuid",[127,6232,4666],{"class":4518},[127,6234,4676],{"class":4514},[127,6236,6237,6239,6241],{"class":129,"line":195},[127,6238,5731],{"class":4514},[127,6240,4657],{"class":4518},[127,6242,4676],{"class":4514},[127,6244,6245,6247],{"class":129,"line":29},[127,6246,5228],{"class":4514},[127,6248,4783],{"class":4518},[127,6250,6251],{"class":129,"line":207},[127,6252,199],{"emptyLinePlaceholder":198},[127,6254,6255,6257,6259,6262,6264,6266,6268,6270,6272,6274,6277,6279,6282,6285,6288,6290,6292],{"class":129,"line":213},[127,6256,4605],{"class":4510},[127,6258,4839],{"class":4608},[127,6260,6261],{"class":4842}," ApiResponse",[127,6263,5359],{"class":4514},[127,6265,5362],{"class":4842},[127,6267,5397],{"class":4514},[127,6269,4846],{"class":4514},[127,6271,4585],{"class":4842},[127,6273,4660],{"class":4514},[127,6275,6276],{"class":4842},"infer",[127,6278,5359],{"class":4514},[127,6280,6281],{"class":4842},"ReturnType",[127,6283,6284],{"class":4514},">>\n",[112,6296,6298],{"id":6297},"_2-type-safe-environment-variables","2. Type-Safe Environment Variables",[117,6300,6302],{"className":4424,"code":6301,"language":4426,"meta":122,"style":122},"// lib/env.ts\nimport { z } from \"zod\"\n\nconst envSchema = z.object({\n DATABASE_URL: z.string().url(),\n API_KEY: z.string().min(1),\n NODE_ENV: z.enum([\"development\", \"production\", \"test\"]),\n})\n\nexport const env = envSchema.parse(process.env)\nexport type Env = z.infer\n",[124,6303,6304,6309,6327,6331,6350,6374,6403,6450,6456,6460,6487],{"__ignoreMap":122},[127,6305,6306],{"class":129,"line":130},[127,6307,6308],{"class":4433},"// lib/env.ts\n",[127,6310,6311,6313,6315,6317,6319,6321,6323,6325],{"class":129,"line":136},[127,6312,4511],{"class":4510},[127,6314,4515],{"class":4514},[127,6316,4585],{"class":4518},[127,6318,4538],{"class":4514},[127,6320,4541],{"class":4510},[127,6322,4544],{"class":4514},[127,6324,4594],{"class":4547},[127,6326,4551],{"class":4514},[127,6328,6329],{"class":129,"line":16},[127,6330,199],{"emptyLinePlaceholder":198},[127,6332,6333,6335,6338,6340,6342,6344,6346,6348],{"class":129,"line":147},[127,6334,4965],{"class":4608},[127,6336,6337],{"class":4518}," envSchema ",[127,6339,4615],{"class":4514},[127,6341,4585],{"class":4518},[127,6343,4660],{"class":4514},[127,6345,6139],{"class":4618},[127,6347,4621],{"class":4518},[127,6349,5150],{"class":4514},[127,6351,6352,6355,6357,6359,6361,6363,6365,6367,6370,6372],{"class":129,"line":153},[127,6353,6354],{"class":4639}," DATABASE_URL",[127,6356,4643],{"class":4514},[127,6358,4585],{"class":4518},[127,6360,4660],{"class":4514},[127,6362,6183],{"class":4618},[127,6364,4666],{"class":4518},[127,6366,4660],{"class":4514},[127,6368,6369],{"class":4618},"url",[127,6371,4666],{"class":4518},[127,6373,4676],{"class":4514},[127,6375,6376,6379,6381,6383,6385,6387,6389,6391,6394,6396,6399,6401],{"class":129,"line":159},[127,6377,6378],{"class":4639}," API_KEY",[127,6380,4643],{"class":4514},[127,6382,4585],{"class":4518},[127,6384,4660],{"class":4514},[127,6386,6183],{"class":4618},[127,6388,4666],{"class":4518},[127,6390,4660],{"class":4514},[127,6392,6393],{"class":4618},"min",[127,6395,4621],{"class":4518},[127,6397,6398],{"class":5165},"1",[127,6400,4657],{"class":4518},[127,6402,4676],{"class":4514},[127,6404,6405,6408,6410,6412,6414,6417,6420,6422,6425,6427,6429,6431,6434,6436,6438,6440,6443,6445,6448],{"class":129,"line":165},[127,6406,6407],{"class":4639}," NODE_ENV",[127,6409,4643],{"class":4514},[127,6411,4585],{"class":4518},[127,6413,4660],{"class":4514},[127,6415,6416],{"class":4618},"enum",[127,6418,6419],{"class":4518},"([",[127,6421,4624],{"class":4514},[127,6423,6424],{"class":4547},"development",[127,6426,4624],{"class":4514},[127,6428,4522],{"class":4514},[127,6430,4544],{"class":4514},[127,6432,6433],{"class":4547},"production",[127,6435,4624],{"class":4514},[127,6437,4522],{"class":4514},[127,6439,4544],{"class":4514},[127,6441,6442],{"class":4547},"test",[127,6444,4624],{"class":4514},[127,6446,6447],{"class":4518},"])",[127,6449,4676],{"class":4514},[127,6451,6452,6454],{"class":129,"line":171},[127,6453,4780],{"class":4514},[127,6455,4783],{"class":4518},[127,6457,6458],{"class":129,"line":177},[127,6459,199],{"emptyLinePlaceholder":198},[127,6461,6462,6464,6466,6469,6471,6474,6476,6479,6482,6484],{"class":129,"line":183},[127,6463,4605],{"class":4510},[127,6465,4609],{"class":4608},[127,6467,6468],{"class":4518}," env ",[127,6470,4615],{"class":4514},[127,6472,6473],{"class":4518}," envSchema",[127,6475,4660],{"class":4514},[127,6477,6478],{"class":4618},"parse",[127,6480,6481],{"class":4518},"(process",[127,6483,4660],{"class":4514},[127,6485,6486],{"class":4518},"env)\n",[127,6488,6489,6491,6493,6496,6498,6500,6502,6504,6506,6508],{"class":129,"line":189},[127,6490,4605],{"class":4510},[127,6492,4839],{"class":4608},[127,6494,6495],{"class":4842}," Env",[127,6497,4846],{"class":4514},[127,6499,4585],{"class":4842},[127,6501,4660],{"class":4514},[127,6503,6276],{"class":4842},[127,6505,6284],{"class":4514},[127,6507,6473],{"class":4518},[127,6509,5772],{"class":4514},[112,6511,6513],{"id":6512},"_3-database-migrations-with-type-safety","3. Database Migrations with Type Safety",[117,6515,6517],{"className":4424,"code":6516,"language":4426,"meta":122,"style":122},"// db/migrations/001_create_users.ts\nimport { sql } from \"drizzle-orm\"\n\nexport async function up() {\n await sql`\n CREATE TABLE users (\n id UUID PRIMARY KEY DEFAULT gen_random_uuid(),\n email TEXT NOT NULL UNIQUE,\n name TEXT NOT NULL,\n created_at TIMESTAMPTZ DEFAULT NOW()\n )\n `\n}\n\nexport async function down() {\n await sql`DROP TABLE users`\n}\n",[124,6518,6519,6524,6544,6548,6563,6572,6577,6582,6587,6592,6597,6601,6606,6610,6614,6629,6642],{"__ignoreMap":122},[127,6520,6521],{"class":129,"line":130},[127,6522,6523],{"class":4433},"// db/migrations/001_create_users.ts\n",[127,6525,6526,6528,6530,6533,6535,6537,6539,6542],{"class":129,"line":136},[127,6527,4511],{"class":4510},[127,6529,4515],{"class":4514},[127,6531,6532],{"class":4518}," sql",[127,6534,4538],{"class":4514},[127,6536,4541],{"class":4510},[127,6538,4544],{"class":4514},[127,6540,6541],{"class":4547},"drizzle-orm",[127,6543,4551],{"class":4514},[127,6545,6546],{"class":129,"line":16},[127,6547,199],{"emptyLinePlaceholder":198},[127,6549,6550,6552,6554,6556,6559,6561],{"class":129,"line":147},[127,6551,4605],{"class":4510},[127,6553,5029],{"class":4608},[127,6555,5353],{"class":4608},[127,6557,6558],{"class":4618}," up",[127,6560,4666],{"class":4514},[127,6562,4634],{"class":4514},[127,6564,6565,6568,6570],{"class":129,"line":153},[127,6566,6567],{"class":4510}," await",[127,6569,6532],{"class":4618},[127,6571,1384],{"class":4514},[127,6573,6574],{"class":129,"line":159},[127,6575,6576],{"class":4547}," CREATE TABLE users (\n",[127,6578,6579],{"class":129,"line":165},[127,6580,6581],{"class":4547}," id UUID PRIMARY KEY DEFAULT gen_random_uuid(),\n",[127,6583,6584],{"class":129,"line":171},[127,6585,6586],{"class":4547}," email TEXT NOT NULL UNIQUE,\n",[127,6588,6589],{"class":129,"line":177},[127,6590,6591],{"class":4547}," name TEXT NOT NULL,\n",[127,6593,6594],{"class":129,"line":183},[127,6595,6596],{"class":4547}," created_at TIMESTAMPTZ DEFAULT NOW()\n",[127,6598,6599],{"class":129,"line":189},[127,6600,783],{"class":4547},[127,6602,6603],{"class":129,"line":195},[127,6604,6605],{"class":4514}," `\n",[127,6607,6608],{"class":129,"line":29},[127,6609,192],{"class":4514},[127,6611,6612],{"class":129,"line":207},[127,6613,199],{"emptyLinePlaceholder":198},[127,6615,6616,6618,6620,6622,6625,6627],{"class":129,"line":213},[127,6617,4605],{"class":4510},[127,6619,5029],{"class":4608},[127,6621,5353],{"class":4608},[127,6623,6624],{"class":4618}," down",[127,6626,4666],{"class":4514},[127,6628,4634],{"class":4514},[127,6630,6631,6633,6635,6637,6640],{"class":129,"line":219},[127,6632,6567],{"class":4510},[127,6634,6532],{"class":4618},[127,6636,5418],{"class":4514},[127,6638,6639],{"class":4547},"DROP TABLE users",[127,6641,1384],{"class":4514},[127,6643,6644],{"class":129,"line":225},[127,6645,192],{"class":4514},[99,6647,6649],{"id":6648},"real-world-example-e-commerce-product-api","Real-World Example: E-Commerce Product API",[112,6651,6653],{"id":6652},"database-schema","Database Schema",[117,6655,6657],{"className":4424,"code":6656,"language":4426,"meta":122,"style":122},"// db/schema/products.ts\nexport const products = pgTable(\"products\", {\n id: uuid(\"id\").primaryKey(),\n name: text(\"name\").notNull(),\n description: text(\"description\"),\n price: numeric(\"price\").notNull(),\n inventory: integer(\"inventory\").default(0),\n categoryId: uuid(\"category_id\").references(() => categories.id),\n})\n",[124,6658,6659,6664,6690,6716,6742,6764,6793,6827,6868],{"__ignoreMap":122},[127,6660,6661],{"class":129,"line":130},[127,6662,6663],{"class":4433},"// db/schema/products.ts\n",[127,6665,6666,6668,6670,6673,6675,6677,6679,6681,6684,6686,6688],{"class":129,"line":136},[127,6667,4605],{"class":4510},[127,6669,4609],{"class":4608},[127,6671,6672],{"class":4518}," products ",[127,6674,4615],{"class":4514},[127,6676,4519],{"class":4618},[127,6678,4621],{"class":4518},[127,6680,4624],{"class":4514},[127,6682,6683],{"class":4547},"products",[127,6685,4624],{"class":4514},[127,6687,4522],{"class":4514},[127,6689,4634],{"class":4514},[127,6691,6692,6694,6696,6698,6700,6702,6704,6706,6708,6710,6712,6714],{"class":129,"line":16},[127,6693,4640],{"class":4639},[127,6695,4643],{"class":4514},[127,6697,4535],{"class":4618},[127,6699,4621],{"class":4518},[127,6701,4624],{"class":4514},[127,6703,4652],{"class":4547},[127,6705,4624],{"class":4514},[127,6707,4657],{"class":4518},[127,6709,4660],{"class":4514},[127,6711,4663],{"class":4618},[127,6713,4666],{"class":4518},[127,6715,4676],{"class":4514},[127,6717,6718,6720,6722,6724,6726,6728,6730,6732,6734,6736,6738,6740],{"class":129,"line":147},[127,6719,4717],{"class":4639},[127,6721,4643],{"class":4514},[127,6723,4525],{"class":4618},[127,6725,4621],{"class":4518},[127,6727,4624],{"class":4514},[127,6729,4728],{"class":4547},[127,6731,4624],{"class":4514},[127,6733,4657],{"class":4518},[127,6735,4660],{"class":4514},[127,6737,4701],{"class":4618},[127,6739,4666],{"class":4518},[127,6741,4676],{"class":4514},[127,6743,6744,6747,6749,6751,6753,6755,6758,6760,6762],{"class":129,"line":153},[127,6745,6746],{"class":4639}," description",[127,6748,4643],{"class":4514},[127,6750,4525],{"class":4618},[127,6752,4621],{"class":4518},[127,6754,4624],{"class":4514},[127,6756,6757],{"class":4547},"description",[127,6759,4624],{"class":4514},[127,6761,4657],{"class":4518},[127,6763,4676],{"class":4514},[127,6765,6766,6769,6771,6774,6776,6778,6781,6783,6785,6787,6789,6791],{"class":129,"line":159},[127,6767,6768],{"class":4639}," price",[127,6770,4643],{"class":4514},[127,6772,6773],{"class":4618}," numeric",[127,6775,4621],{"class":4518},[127,6777,4624],{"class":4514},[127,6779,6780],{"class":4547},"price",[127,6782,4624],{"class":4514},[127,6784,4657],{"class":4518},[127,6786,4660],{"class":4514},[127,6788,4701],{"class":4618},[127,6790,4666],{"class":4518},[127,6792,4676],{"class":4514},[127,6794,6795,6798,6800,6803,6805,6807,6810,6812,6814,6816,6819,6821,6823,6825],{"class":129,"line":165},[127,6796,6797],{"class":4639}," inventory",[127,6799,4643],{"class":4514},[127,6801,6802],{"class":4618}," integer",[127,6804,4621],{"class":4518},[127,6806,4624],{"class":4514},[127,6808,6809],{"class":4547},"inventory",[127,6811,4624],{"class":4514},[127,6813,4657],{"class":4518},[127,6815,4660],{"class":4514},[127,6817,6818],{"class":4618},"default",[127,6820,4621],{"class":4518},[127,6822,5166],{"class":5165},[127,6824,4657],{"class":4518},[127,6826,4676],{"class":4514},[127,6828,6829,6832,6834,6836,6838,6840,6843,6845,6847,6849,6852,6854,6856,6858,6861,6863,6866],{"class":129,"line":171},[127,6830,6831],{"class":4639}," categoryId",[127,6833,4643],{"class":4514},[127,6835,4535],{"class":4618},[127,6837,4621],{"class":4518},[127,6839,4624],{"class":4514},[127,6841,6842],{"class":4547},"category_id",[127,6844,4624],{"class":4514},[127,6846,4657],{"class":4518},[127,6848,4660],{"class":4514},[127,6850,6851],{"class":4618},"references",[127,6853,4621],{"class":4518},[127,6855,4666],{"class":4514},[127,6857,5041],{"class":4608},[127,6859,6860],{"class":4518}," categories",[127,6862,4660],{"class":4514},[127,6864,6865],{"class":4518},"id)",[127,6867,4676],{"class":4514},[127,6869,6870,6872],{"class":129,"line":177},[127,6871,4780],{"class":4514},[127,6873,4783],{"class":4518},[112,6875,6877],{"id":6876},"api-route","API Route",[117,6879,6881],{"className":4424,"code":6880,"language":4426,"meta":122,"style":122},"// server/routes/api/products.ts\napp.get(\n \"/products/:id\",\n zValidator(\"param\", z.object({ id: z.string().uuid() })),\n async (c) => {\n const { id } = c.req.valid(\"param\")\n\n const product = await db.query.products.findFirst({\n where: eq(products.id, id),\n with: {\n category: true,\n images: true,\n },\n })\n\n if (!product) {\n return c.json({ error: \"Product not found\" }, 404)\n }\n\n return c.json({ data: product })\n },\n)\n",[124,6882,6883,6888,6900,6912,6966,6981,7014,7018,7049,7075,7084,7096,7107,7111,7117,7121,7137,7172,7176,7180,7204,7208],{"__ignoreMap":122},[127,6884,6885],{"class":129,"line":130},[127,6886,6887],{"class":4433},"// server/routes/api/products.ts\n",[127,6889,6890,6892,6894,6897],{"class":129,"line":136},[127,6891,4992],{"class":4518},[127,6893,4660],{"class":4514},[127,6895,6896],{"class":4618},"get",[127,6898,6899],{"class":4518},"(\n",[127,6901,6902,6905,6908,6910],{"class":129,"line":16},[127,6903,6904],{"class":4514}," \"",[127,6906,6907],{"class":4547},"/products/:id",[127,6909,4624],{"class":4514},[127,6911,4676],{"class":4514},[127,6913,6914,6917,6919,6921,6924,6926,6928,6930,6932,6934,6936,6939,6942,6944,6946,6948,6950,6952,6954,6956,6959,6961,6964],{"class":129,"line":147},[127,6915,6916],{"class":4618}," zValidator",[127,6918,4621],{"class":4518},[127,6920,4624],{"class":4514},[127,6922,6923],{"class":4547},"param",[127,6925,4624],{"class":4514},[127,6927,4522],{"class":4514},[127,6929,4585],{"class":4518},[127,6931,4660],{"class":4514},[127,6933,6139],{"class":4618},[127,6935,4621],{"class":4518},[127,6937,6938],{"class":4514},"{",[127,6940,6941],{"class":4639}," id",[127,6943,4643],{"class":4514},[127,6945,4585],{"class":4518},[127,6947,4660],{"class":4514},[127,6949,6183],{"class":4618},[127,6951,4666],{"class":4518},[127,6953,4660],{"class":4514},[127,6955,6230],{"class":4618},[127,6957,6958],{"class":4518},"() ",[127,6960,4780],{"class":4514},[127,6962,6963],{"class":4518},"))",[127,6965,4676],{"class":4514},[127,6967,6968,6971,6973,6975,6977,6979],{"class":129,"line":153},[127,6969,6970],{"class":4608}," async",[127,6972,5032],{"class":4514},[127,6974,5036],{"class":5035},[127,6976,4657],{"class":4514},[127,6978,5041],{"class":4608},[127,6980,4634],{"class":4514},[127,6982,6983,6986,6988,6990,6992,6994,6996,6998,7000,7002,7004,7006,7008,7010,7012],{"class":129,"line":159},[127,6984,6985],{"class":4608}," const",[127,6987,4515],{"class":4514},[127,6989,6941],{"class":4518},[127,6991,4538],{"class":4514},[127,6993,4846],{"class":4514},[127,6995,5056],{"class":4518},[127,6997,4660],{"class":4514},[127,6999,5061],{"class":4518},[127,7001,4660],{"class":4514},[127,7003,5066],{"class":4618},[127,7005,4621],{"class":4639},[127,7007,4624],{"class":4514},[127,7009,6923],{"class":4547},[127,7011,4624],{"class":4514},[127,7013,4783],{"class":4639},[127,7015,7016],{"class":129,"line":165},[127,7017,199],{"emptyLinePlaceholder":198},[127,7019,7020,7022,7025,7027,7029,7031,7033,7036,7038,7040,7042,7045,7047],{"class":129,"line":171},[127,7021,6985],{"class":4608},[127,7023,7024],{"class":4518}," product",[127,7026,4846],{"class":4514},[127,7028,5097],{"class":4510},[127,7030,5100],{"class":4518},[127,7032,4660],{"class":4514},[127,7034,7035],{"class":4518},"query",[127,7037,4660],{"class":4514},[127,7039,6683],{"class":4518},[127,7041,4660],{"class":4514},[127,7043,7044],{"class":4618},"findFirst",[127,7046,4621],{"class":4639},[127,7048,5150],{"class":4514},[127,7050,7051,7054,7056,7059,7061,7063,7065,7067,7069,7071,7073],{"class":129,"line":177},[127,7052,7053],{"class":4639}," where",[127,7055,4643],{"class":4514},[127,7057,7058],{"class":4618}," eq",[127,7060,4621],{"class":4639},[127,7062,6683],{"class":4518},[127,7064,4660],{"class":4514},[127,7066,4652],{"class":4518},[127,7068,4522],{"class":4514},[127,7070,6941],{"class":4518},[127,7072,4657],{"class":4639},[127,7074,4676],{"class":4514},[127,7076,7077,7080,7082],{"class":129,"line":183},[127,7078,7079],{"class":4639}," with",[127,7081,4643],{"class":4514},[127,7083,4634],{"class":4514},[127,7085,7086,7089,7091,7094],{"class":129,"line":189},[127,7087,7088],{"class":4639}," category",[127,7090,4643],{"class":4514},[127,7092,7093],{"class":5969}," true",[127,7095,4676],{"class":4514},[127,7097,7098,7101,7103,7105],{"class":129,"line":195},[127,7099,7100],{"class":4639}," images",[127,7102,4643],{"class":4514},[127,7104,7093],{"class":5969},[127,7106,4676],{"class":4514},[127,7108,7109],{"class":129,"line":29},[127,7110,1486],{"class":4514},[127,7112,7113,7115],{"class":129,"line":207},[127,7114,5731],{"class":4514},[127,7116,4783],{"class":4639},[127,7118,7119],{"class":129,"line":213},[127,7120,199],{"emptyLinePlaceholder":198},[127,7122,7123,7126,7128,7130,7133,7135],{"class":129,"line":219},[127,7124,7125],{"class":4510}," if",[127,7127,5032],{"class":4639},[127,7129,5449],{"class":4514},[127,7131,7132],{"class":4518},"product",[127,7134,5460],{"class":4639},[127,7136,5150],{"class":4514},[127,7138,7139,7142,7144,7146,7148,7150,7152,7155,7157,7159,7162,7164,7167,7170],{"class":129,"line":225},[127,7140,7141],{"class":4510}," return",[127,7143,5056],{"class":4518},[127,7145,4660],{"class":4514},[127,7147,5017],{"class":4618},[127,7149,4621],{"class":4639},[127,7151,6938],{"class":4514},[127,7153,7154],{"class":4639}," error",[127,7156,4643],{"class":4514},[127,7158,4544],{"class":4514},[127,7160,7161],{"class":4547},"Product not found",[127,7163,4624],{"class":4514},[127,7165,7166],{"class":4514}," },",[127,7168,7169],{"class":5165}," 404",[127,7171,4783],{"class":4639},[127,7173,7174],{"class":129,"line":231},[127,7175,1267],{"class":4514},[127,7177,7178],{"class":129,"line":237},[127,7179,199],{"emptyLinePlaceholder":198},[127,7181,7182,7184,7186,7188,7190,7192,7194,7196,7198,7200,7202],{"class":129,"line":243},[127,7183,5998],{"class":4510},[127,7185,5056],{"class":4518},[127,7187,4660],{"class":4514},[127,7189,5017],{"class":4618},[127,7191,4621],{"class":4639},[127,7193,6938],{"class":4514},[127,7195,5051],{"class":4639},[127,7197,4643],{"class":4514},[127,7199,7024],{"class":4518},[127,7201,4538],{"class":4514},[127,7203,4783],{"class":4639},[127,7205,7206],{"class":129,"line":249},[127,7207,844],{"class":4514},[127,7209,7210],{"class":129,"line":254},[127,7211,4783],{"class":4518},[112,7213,7215],{"id":7214},"frontend-component","Frontend Component",[117,7217,7221],{"className":7218,"code":7219,"language":7220,"meta":122,"style":122},"language-vue shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","\n\n\n\n","vue",[124,7222,7223,7228,7250,7271,7275,7290,7300,7307,7311,7329,7355,7371,7386,7416,7420,7428,7432,7441,7462,7480,7497,7506],{"__ignoreMap":122},[127,7224,7225],{"class":129,"line":130},[127,7226,7227],{"class":4433},"\n",[127,7229,7230,7232,7234,7237,7240,7242,7244,7246,7248],{"class":129,"line":136},[127,7231,5359],{"class":4514},[127,7233,6042],{"class":4639},[127,7235,7236],{"class":4608}," setup",[127,7238,7239],{"class":4608}," lang",[127,7241,4615],{"class":4514},[127,7243,4624],{"class":4514},[127,7245,5767],{"class":4547},[127,7247,4624],{"class":4514},[127,7249,5772],{"class":4514},[127,7251,7252,7254,7256,7258,7261,7263,7265,7267,7269],{"class":129,"line":16},[127,7253,4511],{"class":4510},[127,7255,4839],{"class":4510},[127,7257,4515],{"class":4514},[127,7259,7260],{"class":4518}," Product",[127,7262,4538],{"class":4514},[127,7264,4541],{"class":4510},[127,7266,4544],{"class":4514},[127,7268,4954],{"class":4547},[127,7270,4551],{"class":4514},[127,7272,7273],{"class":129,"line":147},[127,7274,199],{"emptyLinePlaceholder":198},[127,7276,7277,7279,7282,7284,7287],{"class":129,"line":153},[127,7278,4965],{"class":4608},[127,7280,7281],{"class":4518}," props ",[127,7283,4615],{"class":4514},[127,7285,7286],{"class":4618}," defineProps",[127,7288,7289],{"class":4514},"<{\n",[127,7291,7292,7295,7297],{"class":129,"line":159},[127,7293,7294],{"class":4639}," product",[127,7296,4643],{"class":4514},[127,7298,7299],{"class":4842}," Product\n",[127,7301,7302,7305],{"class":129,"line":165},[127,7303,7304],{"class":4514},"}>",[127,7306,4978],{"class":4518},[127,7308,7309],{"class":129,"line":171},[127,7310,199],{"emptyLinePlaceholder":198},[127,7312,7313,7315,7318,7320,7323,7325,7327],{"class":129,"line":177},[127,7314,4965],{"class":4608},[127,7316,7317],{"class":4518}," formattedPrice ",[127,7319,4615],{"class":4514},[127,7321,7322],{"class":4618}," computed",[127,7324,4621],{"class":4518},[127,7326,4666],{"class":4514},[127,7328,5639],{"class":4608},[127,7330,7331,7334,7337,7339,7342,7344,7346,7349,7351,7353],{"class":129,"line":183},[127,7332,7333],{"class":4514}," new",[127,7335,7336],{"class":4518}," Intl",[127,7338,4660],{"class":4514},[127,7340,7341],{"class":4618},"NumberFormat",[127,7343,4621],{"class":4518},[127,7345,4624],{"class":4514},[127,7347,7348],{"class":4547},"en-US",[127,7350,4624],{"class":4514},[127,7352,4522],{"class":4514},[127,7354,4634],{"class":4514},[127,7356,7357,7360,7362,7364,7367,7369],{"class":129,"line":189},[127,7358,7359],{"class":4639}," style",[127,7361,4643],{"class":4514},[127,7363,4544],{"class":4514},[127,7365,7366],{"class":4547},"currency",[127,7368,4624],{"class":4514},[127,7370,4676],{"class":4514},[127,7372,7373,7376,7378,7380,7382,7384],{"class":129,"line":195},[127,7374,7375],{"class":4639}," currency",[127,7377,4643],{"class":4514},[127,7379,4544],{"class":4514},[127,7381,41],{"class":4547},[127,7383,4624],{"class":4514},[127,7385,4676],{"class":4514},[127,7387,7388,7390,7392,7394,7397,7399,7402,7405,7407,7409,7411,7414],{"class":129,"line":29},[127,7389,5228],{"class":4514},[127,7391,4657],{"class":4518},[127,7393,4660],{"class":4514},[127,7395,7396],{"class":4618},"format",[127,7398,4621],{"class":4518},[127,7400,7401],{"class":4618},"Number",[127,7403,7404],{"class":4518},"(props",[127,7406,4660],{"class":4514},[127,7408,7132],{"class":4518},[127,7410,4660],{"class":4514},[127,7412,7413],{"class":4518},"price))",[127,7415,4676],{"class":4514},[127,7417,7418],{"class":129,"line":207},[127,7419,4783],{"class":4518},[127,7421,7422,7424,7426],{"class":129,"line":213},[127,7423,6039],{"class":4514},[127,7425,6042],{"class":4639},[127,7427,5772],{"class":4514},[127,7429,7430],{"class":129,"line":219},[127,7431,199],{"emptyLinePlaceholder":198},[127,7433,7434,7436,7439],{"class":129,"line":225},[127,7435,5359],{"class":4514},[127,7437,7438],{"class":4639},"template",[127,7440,5772],{"class":4514},[127,7442,7443,7446,7448,7451,7453,7455,7458,7460],{"class":129,"line":231},[127,7444,7445],{"class":4514}," <",[127,7447,6012],{"class":4639},[127,7449,7450],{"class":4608}," class",[127,7452,4615],{"class":4514},[127,7454,4624],{"class":4514},[127,7456,7457],{"class":4547},"product-card",[127,7459,4624],{"class":4514},[127,7461,5772],{"class":4514},[127,7463,7464,7467,7469,7471,7474,7476,7478],{"class":129,"line":237},[127,7465,7466],{"class":4514}," <",[127,7468,112],{"class":4639},[127,7470,5397],{"class":4514},[127,7472,7473],{"class":4518},"{{ product.name }}",[127,7475,6039],{"class":4514},[127,7477,112],{"class":4639},[127,7479,5772],{"class":4514},[127,7481,7482,7484,7486,7488,7491,7493,7495],{"class":129,"line":243},[127,7483,7466],{"class":4514},[127,7485,104],{"class":4639},[127,7487,5397],{"class":4514},[127,7489,7490],{"class":4518},"{{ formattedPrice }}",[127,7492,6039],{"class":4514},[127,7494,104],{"class":4639},[127,7496,5772],{"class":4514},[127,7498,7499,7502,7504],{"class":129,"line":249},[127,7500,7501],{"class":4514}," {\n expectTypeOf(usersApi.getAll()).resolves.toEqualTypeOf()\n})\n\ntest(\"usersApi.create accepts NewUser\", () => {\n expectTypeOf(usersApi.create).parameter(0).toEqualTypeOf()\n})\n",[124,7990,7991,7996,8016,8034,8038,8059,8096,8102,8106,8127,8166],{"__ignoreMap":122},[127,7992,7993],{"class":129,"line":130},[127,7994,7995],{"class":4433},"// tests/types.test.ts\n",[127,7997,7998,8000,8002,8005,8007,8009,8011,8014],{"class":129,"line":136},[127,7999,4511],{"class":4510},[127,8001,4515],{"class":4514},[127,8003,8004],{"class":4518}," expectTypeOf",[127,8006,4538],{"class":4514},[127,8008,4541],{"class":4510},[127,8010,4544],{"class":4514},[127,8012,8013],{"class":4547},"expect-type",[127,8015,4551],{"class":4514},[127,8017,8018,8020,8022,8024,8026,8028,8030,8032],{"class":129,"line":16},[127,8019,4511],{"class":4510},[127,8021,4515],{"class":4514},[127,8023,5781],{"class":4518},[127,8025,4538],{"class":4514},[127,8027,4541],{"class":4510},[127,8029,4544],{"class":4514},[127,8031,5791],{"class":4547},[127,8033,4551],{"class":4514},[127,8035,8036],{"class":129,"line":147},[127,8037,199],{"emptyLinePlaceholder":198},[127,8039,8040,8042,8044,8046,8049,8051,8053,8055,8057],{"class":129,"line":153},[127,8041,6442],{"class":4618},[127,8043,4621],{"class":4518},[127,8045,4624],{"class":4514},[127,8047,8048],{"class":4547},"usersApi.getAll returns User[]",[127,8050,4624],{"class":4514},[127,8052,4522],{"class":4514},[127,8054,5548],{"class":4514},[127,8056,5041],{"class":4608},[127,8058,4634],{"class":4514},[127,8060,8061,8064,8066,8069,8071,8073,8076,8078,8081,8083,8086,8088,8090,8092,8094],{"class":129,"line":159},[127,8062,8063],{"class":4618}," expectTypeOf",[127,8065,4621],{"class":4639},[127,8067,8068],{"class":4518},"usersApi",[127,8070,4660],{"class":4514},[127,8072,5874],{"class":4618},[127,8074,8075],{"class":4639},"())",[127,8077,4660],{"class":4514},[127,8079,8080],{"class":4518},"resolves",[127,8082,4660],{"class":4514},[127,8084,8085],{"class":4618},"toEqualTypeOf",[127,8087,5359],{"class":4514},[127,8089,5956],{"class":4842},[127,8091,5560],{"class":4639},[127,8093,5397],{"class":4514},[127,8095,4978],{"class":4639},[127,8097,8098,8100],{"class":129,"line":165},[127,8099,4780],{"class":4514},[127,8101,4783],{"class":4518},[127,8103,8104],{"class":129,"line":171},[127,8105,199],{"emptyLinePlaceholder":198},[127,8107,8108,8110,8112,8114,8117,8119,8121,8123,8125],{"class":129,"line":177},[127,8109,6442],{"class":4618},[127,8111,4621],{"class":4518},[127,8113,4624],{"class":4514},[127,8115,8116],{"class":4547},"usersApi.create accepts NewUser",[127,8118,4624],{"class":4514},[127,8120,4522],{"class":4514},[127,8122,5548],{"class":4514},[127,8124,5041],{"class":4608},[127,8126,4634],{"class":4514},[127,8128,8129,8131,8133,8135,8137,8140,8142,8144,8147,8149,8151,8153,8155,8157,8159,8162,8164],{"class":129,"line":183},[127,8130,8063],{"class":4618},[127,8132,4621],{"class":4639},[127,8134,8068],{"class":4518},[127,8136,4660],{"class":4514},[127,8138,8139],{"class":4518},"create",[127,8141,4657],{"class":4639},[127,8143,4660],{"class":4514},[127,8145,8146],{"class":4618},"parameter",[127,8148,4621],{"class":4639},[127,8150,5166],{"class":5165},[127,8152,4657],{"class":4639},[127,8154,4660],{"class":4514},[127,8156,8085],{"class":4618},[127,8158,5359],{"class":4514},[127,8160,8161],{"class":4842},"NewUser",[127,8163,5397],{"class":4514},[127,8165,4978],{"class":4639},[127,8167,8168,8170],{"class":129,"line":189},[127,8169,4780],{"class":4514},[127,8171,4783],{"class":4518},[99,8173,8175],{"id":8174},"performance-considerations","Performance Considerations",[104,8177,8178],{},"Type safety doesn't have to impact performance:",[4266,8180,8181,8187,8197,8206],{},[4269,8182,8183,8186],{},[4272,8184,8185],{},"Tree-shaking",": Unused types are removed in production",[4269,8188,8189,8192,8193,8196],{},[4272,8190,8191],{},"Type-only imports",": Use ",[124,8194,8195],{},"import type"," to avoid runtime overhead",[4269,8198,8199,8192,8202,8205],{},[4272,8200,8201],{},"Zod optimization",[124,8203,8204],{},"z.safeParse()"," for better performance",[4269,8207,8208,8211],{},[4272,8209,8210],{},"Code splitting",": Split types by feature/route",[99,8213,4261],{"id":4260},[104,8215,8216],{},"End-to-end type safety is no longer optional in 2026—it's a fundamental requirement for building reliable, maintainable applications. By leveraging modern tools like TypeScript, Zod, and type-safe frameworks, you can catch errors before they reach production and provide a better developer experience.",[104,8218,8219],{},"Start small by adding types to your most critical paths, then gradually expand coverage. The investment pays dividends in reduced bugs, better documentation, and improved developer confidence.",[8221,8222],"hr",{},[104,8224,8225,8228],{},[4272,8226,8227],{},"Ready to implement end-to-end type safety?"," Start with your database schema and work outward. Each layer builds on the previous one, creating a solid foundation for your entire application.",[4310,8230,8231],{},"html pre.shiki code .sHwdD, html code.shiki .sHwdD{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#546E7A;--shiki-default-font-style:italic;--shiki-dark:#676E95;--shiki-dark-font-style:italic}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .s7zQu, html code.shiki .s7zQu{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#89DDFF;--shiki-default-font-style:italic;--shiki-dark:#89DDFF;--shiki-dark-font-style:italic}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}html pre.shiki code .swJcz, html code.shiki .swJcz{--shiki-light:#E53935;--shiki-default:#F07178;--shiki-dark:#F07178}html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .sHdIc, html code.shiki .sHdIc{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#EEFFFF;--shiki-default-font-style:italic;--shiki-dark:#BABED8;--shiki-dark-font-style:italic}html pre.shiki code .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}html pre.shiki code .sfNiH, html code.shiki .sfNiH{--shiki-light:#FF5370;--shiki-default:#FF9CAC;--shiki-dark:#FF9CAC}",{"title":122,"searchDepth":136,"depth":136,"links":8233},[8234,8235,8236,8240,8246,8251,8256,8261,8266,8267,8268],{"id":4374,"depth":136,"text":4368},{"id":4380,"depth":136,"text":4381},{"id":4416,"depth":136,"text":4417,"children":8237},[8238,8239],{"id":4420,"depth":16,"text":4421},{"id":4457,"depth":16,"text":4458},{"id":4487,"depth":136,"text":4488,"children":8241},[8242,8243,8244,8245],{"id":4491,"depth":16,"text":4492},{"id":4880,"depth":16,"text":4881},{"id":5264,"depth":16,"text":5265},{"id":5742,"depth":16,"text":5743},{"id":6047,"depth":136,"text":6048,"children":8247},[8248,8249,8250],{"id":6051,"depth":16,"text":6052},{"id":6297,"depth":16,"text":6298},{"id":6512,"depth":16,"text":6513},{"id":6648,"depth":136,"text":6649,"children":8252},[8253,8254,8255],{"id":6652,"depth":16,"text":6653},{"id":6876,"depth":16,"text":6877},{"id":7214,"depth":16,"text":7215},{"id":7516,"depth":136,"text":7517,"children":8257},[8258,8259,8260],{"id":7520,"depth":16,"text":7521},{"id":7587,"depth":16,"text":7588},{"id":7813,"depth":16,"text":7814},{"id":7902,"depth":136,"text":7903,"children":8262},[8263,8264,8265],{"id":7906,"depth":16,"text":7907},{"id":7936,"depth":16,"text":7937},{"id":7960,"depth":16,"text":7961},{"id":7984,"depth":136,"text":7985},{"id":8174,"depth":136,"text":8175},{"id":4260,"depth":136,"text":4261},"2026-02-22","Master end-to-end type safety in 2026 with TypeScript, Zod, and modern tools that eliminate runtime errors across your entire stack.",{"readingTime":8272},"11 min read","/blog/27-end-to-end-type-safety-guide-2026",{"title":4368,"description":8270},"TypeScript Mastery","Advanced TypeScript patterns for full-stack development",{"src":8278,"mime":4355,"alt":8279,"width":4357,"height":4358},"/img/blog/27-end-to-end-type-safety-guide-2026/banner.svg","End-to-End Type Safety - Connected type chain from database to frontend on blue gradient","blog/27-end-to-end-type-safety-guide-2026",[8282,8283,8284,7944,4362],"TypeScript","Type Safety","Full-Stack","N8RnEQivPlHqHoUy1OdwWQLnfChWlNh-gR5oMZhHnsA",{"id":8287,"title":8288,"abstract":4345,"author":4369,"authorUrl":4345,"body":8289,"date":12445,"dateUpdated":12445,"description":12446,"excerpt":4345,"extension":4346,"featured":198,"headline":4345,"image":12447,"meta":12448,"navigation":198,"ogImage":4345,"path":12390,"seo":12450,"series":8275,"seriesDescription":12451,"seriesOrder":136,"socialImage":4345,"stem":12452,"tags":12453,"__hash__":12456},"blog/blog/6-typescript-nodejs-production-guide.md","TypeScript + Node.js in Production: A Complete Guide",{"type":96,"value":8290,"toc":12410},[8291,8294,8297,8301,8305,8528,8532,8903,8907,8911,9083,9087,9240,9244,9248,9563,9567,9935,9939,9943,10101,10105,10487,10491,10495,10670,10674,11189,11193,11197,11304,11308,11449,11453,11457,11835,11839,11843,12332,12334,12337,12340,12357,12360,12362,12366,12372,12407],[99,8292,8288],{"id":8293},"typescript-nodejs-in-production-a-complete-guide",[104,8295,8296],{},"Running TypeScript in production requires careful consideration of build processes, performance, and maintainability. After deploying dozens of TypeScript Node.js applications, here's everything you need to know.",[99,8298,8300],{"id":8299},"project-setup-and-configuration","Project Setup and Configuration",[112,8302,8304],{"id":8303},"essential-dependencies","Essential Dependencies",[117,8306,8309],{"className":8307,"code":8308,"language":5017,"meta":122,"style":122},"language-json shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","{\n \"devDependencies\": {\n \"@types/node\": \"^20.0.0\",\n \"typescript\": \"^5.0.0\",\n \"ts-node\": \"^10.9.0\",\n \"nodemon\": \"^3.0.0\",\n \"@typescript-eslint/eslint-plugin\": \"^6.0.0\",\n \"@typescript-eslint/parser\": \"^6.0.0\"\n },\n \"dependencies\": {\n \"dotenv\": \"^16.0.0\",\n \"express\": \"^4.18.0\",\n \"@types/express\": \"^4.17.0\"\n }\n}\n",[124,8310,8311,8315,8328,8349,8368,8388,8408,8428,8445,8449,8462,8482,8502,8520,8524],{"__ignoreMap":122},[127,8312,8313],{"class":129,"line":130},[127,8314,5150],{"class":4514},[127,8316,8317,8319,8322,8324,8326],{"class":129,"line":136},[127,8318,6904],{"class":4514},[127,8320,8321],{"class":4608},"devDependencies",[127,8323,4624],{"class":4514},[127,8325,4643],{"class":4514},[127,8327,4634],{"class":4514},[127,8329,8330,8333,8336,8338,8340,8342,8345,8347],{"class":129,"line":16},[127,8331,8332],{"class":4514}," \"",[127,8334,8335],{"class":4842},"@types/node",[127,8337,4624],{"class":4514},[127,8339,4643],{"class":4514},[127,8341,4544],{"class":4514},[127,8343,8344],{"class":4547},"^20.0.0",[127,8346,4624],{"class":4514},[127,8348,4676],{"class":4514},[127,8350,8351,8353,8355,8357,8359,8361,8364,8366],{"class":129,"line":147},[127,8352,8332],{"class":4514},[127,8354,4426],{"class":4842},[127,8356,4624],{"class":4514},[127,8358,4643],{"class":4514},[127,8360,4544],{"class":4514},[127,8362,8363],{"class":4547},"^5.0.0",[127,8365,4624],{"class":4514},[127,8367,4676],{"class":4514},[127,8369,8370,8372,8375,8377,8379,8381,8384,8386],{"class":129,"line":153},[127,8371,8332],{"class":4514},[127,8373,8374],{"class":4842},"ts-node",[127,8376,4624],{"class":4514},[127,8378,4643],{"class":4514},[127,8380,4544],{"class":4514},[127,8382,8383],{"class":4547},"^10.9.0",[127,8385,4624],{"class":4514},[127,8387,4676],{"class":4514},[127,8389,8390,8392,8395,8397,8399,8401,8404,8406],{"class":129,"line":159},[127,8391,8332],{"class":4514},[127,8393,8394],{"class":4842},"nodemon",[127,8396,4624],{"class":4514},[127,8398,4643],{"class":4514},[127,8400,4544],{"class":4514},[127,8402,8403],{"class":4547},"^3.0.0",[127,8405,4624],{"class":4514},[127,8407,4676],{"class":4514},[127,8409,8410,8412,8415,8417,8419,8421,8424,8426],{"class":129,"line":165},[127,8411,8332],{"class":4514},[127,8413,8414],{"class":4842},"@typescript-eslint/eslint-plugin",[127,8416,4624],{"class":4514},[127,8418,4643],{"class":4514},[127,8420,4544],{"class":4514},[127,8422,8423],{"class":4547},"^6.0.0",[127,8425,4624],{"class":4514},[127,8427,4676],{"class":4514},[127,8429,8430,8432,8435,8437,8439,8441,8443],{"class":129,"line":171},[127,8431,8332],{"class":4514},[127,8433,8434],{"class":4842},"@typescript-eslint/parser",[127,8436,4624],{"class":4514},[127,8438,4643],{"class":4514},[127,8440,4544],{"class":4514},[127,8442,8423],{"class":4547},[127,8444,4551],{"class":4514},[127,8446,8447],{"class":129,"line":177},[127,8448,844],{"class":4514},[127,8450,8451,8453,8456,8458,8460],{"class":129,"line":183},[127,8452,6904],{"class":4514},[127,8454,8455],{"class":4608},"dependencies",[127,8457,4624],{"class":4514},[127,8459,4643],{"class":4514},[127,8461,4634],{"class":4514},[127,8463,8464,8466,8469,8471,8473,8475,8478,8480],{"class":129,"line":189},[127,8465,8332],{"class":4514},[127,8467,8468],{"class":4842},"dotenv",[127,8470,4624],{"class":4514},[127,8472,4643],{"class":4514},[127,8474,4544],{"class":4514},[127,8476,8477],{"class":4547},"^16.0.0",[127,8479,4624],{"class":4514},[127,8481,4676],{"class":4514},[127,8483,8484,8486,8489,8491,8493,8495,8498,8500],{"class":129,"line":195},[127,8485,8332],{"class":4514},[127,8487,8488],{"class":4842},"express",[127,8490,4624],{"class":4514},[127,8492,4643],{"class":4514},[127,8494,4544],{"class":4514},[127,8496,8497],{"class":4547},"^4.18.0",[127,8499,4624],{"class":4514},[127,8501,4676],{"class":4514},[127,8503,8504,8506,8509,8511,8513,8515,8518],{"class":129,"line":29},[127,8505,8332],{"class":4514},[127,8507,8508],{"class":4842},"@types/express",[127,8510,4624],{"class":4514},[127,8512,4643],{"class":4514},[127,8514,4544],{"class":4514},[127,8516,8517],{"class":4547},"^4.17.0",[127,8519,4551],{"class":4514},[127,8521,8522],{"class":129,"line":207},[127,8523,1272],{"class":4514},[127,8525,8526],{"class":129,"line":213},[127,8527,192],{"class":4514},[112,8529,8531],{"id":8530},"typescript-configuration","TypeScript Configuration",[117,8533,8535],{"className":8307,"code":8534,"language":5017,"meta":122,"style":122},"// tsconfig.json\n{\n \"compilerOptions\": {\n \"target\": \"ES2022\",\n \"module\": \"commonjs\",\n \"lib\": [\"ES2022\"],\n \"outDir\": \"./dist\",\n \"rootDir\": \"./src\",\n \"strict\": true,\n \"esModuleInterop\": true,\n \"skipLibCheck\": true,\n \"forceConsistentCasingInFileNames\": true,\n \"resolveJsonModule\": true,\n \"declaration\": true,\n \"declarationMap\": true,\n \"sourceMap\": true,\n \"removeComments\": true,\n \"noImplicitReturns\": true,\n \"noFallthroughCasesInSwitch\": true,\n \"noUncheckedIndexedAccess\": true,\n \"exactOptionalPropertyTypes\": true\n },\n \"include\": [\"src/**/*\"],\n \"exclude\": [\"node_modules\", \"dist\", \"**/*.test.ts\"]\n}\n",[124,8536,8537,8542,8546,8559,8579,8599,8622,8642,8662,8676,8689,8702,8715,8728,8741,8754,8767,8780,8793,8806,8819,8832,8836,8858,8899],{"__ignoreMap":122},[127,8538,8539],{"class":129,"line":130},[127,8540,8541],{"class":4433},"// tsconfig.json\n",[127,8543,8544],{"class":129,"line":136},[127,8545,5150],{"class":4514},[127,8547,8548,8550,8553,8555,8557],{"class":129,"line":16},[127,8549,6904],{"class":4514},[127,8551,8552],{"class":4608},"compilerOptions",[127,8554,4624],{"class":4514},[127,8556,4643],{"class":4514},[127,8558,4634],{"class":4514},[127,8560,8561,8563,8566,8568,8570,8572,8575,8577],{"class":129,"line":147},[127,8562,8332],{"class":4514},[127,8564,8565],{"class":4842},"target",[127,8567,4624],{"class":4514},[127,8569,4643],{"class":4514},[127,8571,4544],{"class":4514},[127,8573,8574],{"class":4547},"ES2022",[127,8576,4624],{"class":4514},[127,8578,4676],{"class":4514},[127,8580,8581,8583,8586,8588,8590,8592,8595,8597],{"class":129,"line":153},[127,8582,8332],{"class":4514},[127,8584,8585],{"class":4842},"module",[127,8587,4624],{"class":4514},[127,8589,4643],{"class":4514},[127,8591,4544],{"class":4514},[127,8593,8594],{"class":4547},"commonjs",[127,8596,4624],{"class":4514},[127,8598,4676],{"class":4514},[127,8600,8601,8603,8606,8608,8610,8613,8615,8617,8619],{"class":129,"line":159},[127,8602,8332],{"class":4514},[127,8604,8605],{"class":4842},"lib",[127,8607,4624],{"class":4514},[127,8609,4643],{"class":4514},[127,8611,8612],{"class":4514}," [",[127,8614,4624],{"class":4514},[127,8616,8574],{"class":4547},[127,8618,4624],{"class":4514},[127,8620,8621],{"class":4514},"],\n",[127,8623,8624,8626,8629,8631,8633,8635,8638,8640],{"class":129,"line":165},[127,8625,8332],{"class":4514},[127,8627,8628],{"class":4842},"outDir",[127,8630,4624],{"class":4514},[127,8632,4643],{"class":4514},[127,8634,4544],{"class":4514},[127,8636,8637],{"class":4547},"./dist",[127,8639,4624],{"class":4514},[127,8641,4676],{"class":4514},[127,8643,8644,8646,8649,8651,8653,8655,8658,8660],{"class":129,"line":171},[127,8645,8332],{"class":4514},[127,8647,8648],{"class":4842},"rootDir",[127,8650,4624],{"class":4514},[127,8652,4643],{"class":4514},[127,8654,4544],{"class":4514},[127,8656,8657],{"class":4547},"./src",[127,8659,4624],{"class":4514},[127,8661,4676],{"class":4514},[127,8663,8664,8666,8669,8671,8673],{"class":129,"line":177},[127,8665,8332],{"class":4514},[127,8667,8668],{"class":4842},"strict",[127,8670,4624],{"class":4514},[127,8672,4643],{"class":4514},[127,8674,8675],{"class":4514}," true,\n",[127,8677,8678,8680,8683,8685,8687],{"class":129,"line":183},[127,8679,8332],{"class":4514},[127,8681,8682],{"class":4842},"esModuleInterop",[127,8684,4624],{"class":4514},[127,8686,4643],{"class":4514},[127,8688,8675],{"class":4514},[127,8690,8691,8693,8696,8698,8700],{"class":129,"line":189},[127,8692,8332],{"class":4514},[127,8694,8695],{"class":4842},"skipLibCheck",[127,8697,4624],{"class":4514},[127,8699,4643],{"class":4514},[127,8701,8675],{"class":4514},[127,8703,8704,8706,8709,8711,8713],{"class":129,"line":195},[127,8705,8332],{"class":4514},[127,8707,8708],{"class":4842},"forceConsistentCasingInFileNames",[127,8710,4624],{"class":4514},[127,8712,4643],{"class":4514},[127,8714,8675],{"class":4514},[127,8716,8717,8719,8722,8724,8726],{"class":129,"line":29},[127,8718,8332],{"class":4514},[127,8720,8721],{"class":4842},"resolveJsonModule",[127,8723,4624],{"class":4514},[127,8725,4643],{"class":4514},[127,8727,8675],{"class":4514},[127,8729,8730,8732,8735,8737,8739],{"class":129,"line":207},[127,8731,8332],{"class":4514},[127,8733,8734],{"class":4842},"declaration",[127,8736,4624],{"class":4514},[127,8738,4643],{"class":4514},[127,8740,8675],{"class":4514},[127,8742,8743,8745,8748,8750,8752],{"class":129,"line":213},[127,8744,8332],{"class":4514},[127,8746,8747],{"class":4842},"declarationMap",[127,8749,4624],{"class":4514},[127,8751,4643],{"class":4514},[127,8753,8675],{"class":4514},[127,8755,8756,8758,8761,8763,8765],{"class":129,"line":219},[127,8757,8332],{"class":4514},[127,8759,8760],{"class":4842},"sourceMap",[127,8762,4624],{"class":4514},[127,8764,4643],{"class":4514},[127,8766,8675],{"class":4514},[127,8768,8769,8771,8774,8776,8778],{"class":129,"line":225},[127,8770,8332],{"class":4514},[127,8772,8773],{"class":4842},"removeComments",[127,8775,4624],{"class":4514},[127,8777,4643],{"class":4514},[127,8779,8675],{"class":4514},[127,8781,8782,8784,8787,8789,8791],{"class":129,"line":231},[127,8783,8332],{"class":4514},[127,8785,8786],{"class":4842},"noImplicitReturns",[127,8788,4624],{"class":4514},[127,8790,4643],{"class":4514},[127,8792,8675],{"class":4514},[127,8794,8795,8797,8800,8802,8804],{"class":129,"line":237},[127,8796,8332],{"class":4514},[127,8798,8799],{"class":4842},"noFallthroughCasesInSwitch",[127,8801,4624],{"class":4514},[127,8803,4643],{"class":4514},[127,8805,8675],{"class":4514},[127,8807,8808,8810,8813,8815,8817],{"class":129,"line":243},[127,8809,8332],{"class":4514},[127,8811,8812],{"class":4842},"noUncheckedIndexedAccess",[127,8814,4624],{"class":4514},[127,8816,4643],{"class":4514},[127,8818,8675],{"class":4514},[127,8820,8821,8823,8826,8828,8830],{"class":129,"line":249},[127,8822,8332],{"class":4514},[127,8824,8825],{"class":4842},"exactOptionalPropertyTypes",[127,8827,4624],{"class":4514},[127,8829,4643],{"class":4514},[127,8831,5970],{"class":4514},[127,8833,8834],{"class":129,"line":254},[127,8835,844],{"class":4514},[127,8837,8838,8840,8843,8845,8847,8849,8851,8854,8856],{"class":129,"line":259},[127,8839,6904],{"class":4514},[127,8841,8842],{"class":4608},"include",[127,8844,4624],{"class":4514},[127,8846,4643],{"class":4514},[127,8848,8612],{"class":4514},[127,8850,4624],{"class":4514},[127,8852,8853],{"class":4547},"src/**/*",[127,8855,4624],{"class":4514},[127,8857,8621],{"class":4514},[127,8859,8860,8862,8865,8867,8869,8871,8873,8876,8878,8880,8882,8885,8887,8889,8891,8894,8896],{"class":129,"line":265},[127,8861,6904],{"class":4514},[127,8863,8864],{"class":4608},"exclude",[127,8866,4624],{"class":4514},[127,8868,4643],{"class":4514},[127,8870,8612],{"class":4514},[127,8872,4624],{"class":4514},[127,8874,8875],{"class":4547},"node_modules",[127,8877,4624],{"class":4514},[127,8879,4522],{"class":4514},[127,8881,4544],{"class":4514},[127,8883,8884],{"class":4547},"dist",[127,8886,4624],{"class":4514},[127,8888,4522],{"class":4514},[127,8890,4544],{"class":4514},[127,8892,8893],{"class":4547},"**/*.test.ts",[127,8895,4624],{"class":4514},[127,8897,8898],{"class":4514},"]\n",[127,8900,8901],{"class":129,"line":270},[127,8902,192],{"class":4514},[99,8904,8906],{"id":8905},"build-and-deployment-strategies","Build and Deployment Strategies",[112,8908,8910],{"id":8909},"development-vs-production-builds","Development vs Production Builds",[117,8912,8914],{"className":8307,"code":8913,"language":5017,"meta":122,"style":122},"// package.json scripts\n{\n \"scripts\": {\n \"dev\": \"nodemon --exec ts-node src/index.ts\",\n \"build\": \"tsc\",\n \"start\": \"node dist/index.js\",\n \"start:prod\": \"NODE_ENV=production node dist/index.js\",\n \"type-check\": \"tsc --noEmit\",\n \"lint\": \"eslint src/**/*.ts\",\n \"test\": \"jest\"\n }\n}\n",[124,8915,8916,8921,8925,8938,8958,8978,8998,9018,9038,9058,9075,9079],{"__ignoreMap":122},[127,8917,8918],{"class":129,"line":130},[127,8919,8920],{"class":4433},"// package.json scripts\n",[127,8922,8923],{"class":129,"line":136},[127,8924,5150],{"class":4514},[127,8926,8927,8929,8932,8934,8936],{"class":129,"line":16},[127,8928,6904],{"class":4514},[127,8930,8931],{"class":4608},"scripts",[127,8933,4624],{"class":4514},[127,8935,4643],{"class":4514},[127,8937,4634],{"class":4514},[127,8939,8940,8942,8945,8947,8949,8951,8954,8956],{"class":129,"line":147},[127,8941,8332],{"class":4514},[127,8943,8944],{"class":4842},"dev",[127,8946,4624],{"class":4514},[127,8948,4643],{"class":4514},[127,8950,4544],{"class":4514},[127,8952,8953],{"class":4547},"nodemon --exec ts-node src/index.ts",[127,8955,4624],{"class":4514},[127,8957,4676],{"class":4514},[127,8959,8960,8962,8965,8967,8969,8971,8974,8976],{"class":129,"line":153},[127,8961,8332],{"class":4514},[127,8963,8964],{"class":4842},"build",[127,8966,4624],{"class":4514},[127,8968,4643],{"class":4514},[127,8970,4544],{"class":4514},[127,8972,8973],{"class":4547},"tsc",[127,8975,4624],{"class":4514},[127,8977,4676],{"class":4514},[127,8979,8980,8982,8985,8987,8989,8991,8994,8996],{"class":129,"line":159},[127,8981,8332],{"class":4514},[127,8983,8984],{"class":4842},"start",[127,8986,4624],{"class":4514},[127,8988,4643],{"class":4514},[127,8990,4544],{"class":4514},[127,8992,8993],{"class":4547},"node dist/index.js",[127,8995,4624],{"class":4514},[127,8997,4676],{"class":4514},[127,8999,9000,9002,9005,9007,9009,9011,9014,9016],{"class":129,"line":165},[127,9001,8332],{"class":4514},[127,9003,9004],{"class":4842},"start:prod",[127,9006,4624],{"class":4514},[127,9008,4643],{"class":4514},[127,9010,4544],{"class":4514},[127,9012,9013],{"class":4547},"NODE_ENV=production node dist/index.js",[127,9015,4624],{"class":4514},[127,9017,4676],{"class":4514},[127,9019,9020,9022,9025,9027,9029,9031,9034,9036],{"class":129,"line":171},[127,9021,8332],{"class":4514},[127,9023,9024],{"class":4842},"type-check",[127,9026,4624],{"class":4514},[127,9028,4643],{"class":4514},[127,9030,4544],{"class":4514},[127,9032,9033],{"class":4547},"tsc --noEmit",[127,9035,4624],{"class":4514},[127,9037,4676],{"class":4514},[127,9039,9040,9042,9045,9047,9049,9051,9054,9056],{"class":129,"line":177},[127,9041,8332],{"class":4514},[127,9043,9044],{"class":4842},"lint",[127,9046,4624],{"class":4514},[127,9048,4643],{"class":4514},[127,9050,4544],{"class":4514},[127,9052,9053],{"class":4547},"eslint src/**/*.ts",[127,9055,4624],{"class":4514},[127,9057,4676],{"class":4514},[127,9059,9060,9062,9064,9066,9068,9070,9073],{"class":129,"line":183},[127,9061,8332],{"class":4514},[127,9063,6442],{"class":4842},[127,9065,4624],{"class":4514},[127,9067,4643],{"class":4514},[127,9069,4544],{"class":4514},[127,9071,9072],{"class":4547},"jest",[127,9074,4551],{"class":4514},[127,9076,9077],{"class":129,"line":189},[127,9078,1272],{"class":4514},[127,9080,9081],{"class":129,"line":195},[127,9082,192],{"class":4514},[112,9084,9086],{"id":9085},"docker-configuration","Docker Configuration",[117,9088,9092],{"className":9089,"code":9090,"language":9091,"meta":122,"style":122},"language-dockerfile shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","# Multi-stage build for production\nFROM node:18-alpine AS builder\n\nWORKDIR /app\nCOPY package*.json ./\nRUN npm ci --only=production\n\nCOPY . .\nRUN npm run build\n\nFROM node:18-alpine AS production\n\nWORKDIR /app\nCOPY --from=builder /app/dist ./dist\nCOPY --from=builder /app/node_modules ./node_modules\nCOPY --from=builder /app/package*.json ./\n\nEXPOSE 3000\nCMD [\"npm\", \"run\", \"start:prod\"]\n","dockerfile",[124,9093,9094,9099,9113,9117,9125,9133,9141,9145,9152,9159,9163,9174,9178,9184,9191,9198,9205,9209,9217],{"__ignoreMap":122},[127,9095,9096],{"class":129,"line":130},[127,9097,9098],{"class":4433},"# Multi-stage build for production\n",[127,9100,9101,9104,9107,9110],{"class":129,"line":136},[127,9102,9103],{"class":5165},"FROM",[127,9105,9106],{"class":4518}," node:18-alpine ",[127,9108,9109],{"class":5165},"AS",[127,9111,9112],{"class":4518}," builder\n",[127,9114,9115],{"class":129,"line":16},[127,9116,199],{"emptyLinePlaceholder":198},[127,9118,9119,9122],{"class":129,"line":147},[127,9120,9121],{"class":5165},"WORKDIR",[127,9123,9124],{"class":4518}," /app\n",[127,9126,9127,9130],{"class":129,"line":153},[127,9128,9129],{"class":5165},"COPY",[127,9131,9132],{"class":4518}," package*.json ./\n",[127,9134,9135,9138],{"class":129,"line":159},[127,9136,9137],{"class":5165},"RUN",[127,9139,9140],{"class":4518}," npm ci --only=production\n",[127,9142,9143],{"class":129,"line":165},[127,9144,199],{"emptyLinePlaceholder":198},[127,9146,9147,9149],{"class":129,"line":171},[127,9148,9129],{"class":5165},[127,9150,9151],{"class":4518}," . .\n",[127,9153,9154,9156],{"class":129,"line":177},[127,9155,9137],{"class":5165},[127,9157,9158],{"class":4518}," npm run build\n",[127,9160,9161],{"class":129,"line":183},[127,9162,199],{"emptyLinePlaceholder":198},[127,9164,9165,9167,9169,9171],{"class":129,"line":189},[127,9166,9103],{"class":5165},[127,9168,9106],{"class":4518},[127,9170,9109],{"class":5165},[127,9172,9173],{"class":4518}," production\n",[127,9175,9176],{"class":129,"line":195},[127,9177,199],{"emptyLinePlaceholder":198},[127,9179,9180,9182],{"class":129,"line":29},[127,9181,9121],{"class":5165},[127,9183,9124],{"class":4518},[127,9185,9186,9188],{"class":129,"line":207},[127,9187,9129],{"class":5165},[127,9189,9190],{"class":4518}," --from=builder /app/dist ./dist\n",[127,9192,9193,9195],{"class":129,"line":213},[127,9194,9129],{"class":5165},[127,9196,9197],{"class":4518}," --from=builder /app/node_modules ./node_modules\n",[127,9199,9200,9202],{"class":129,"line":219},[127,9201,9129],{"class":5165},[127,9203,9204],{"class":4518}," --from=builder /app/package*.json ./\n",[127,9206,9207],{"class":129,"line":225},[127,9208,199],{"emptyLinePlaceholder":198},[127,9210,9211,9214],{"class":129,"line":231},[127,9212,9213],{"class":5165},"EXPOSE",[127,9215,9216],{"class":4518}," 3000\n",[127,9218,9219,9222,9224,9227,9230,9233,9235,9238],{"class":129,"line":237},[127,9220,9221],{"class":5165},"CMD",[127,9223,8612],{"class":4518},[127,9225,9226],{"class":4547},"\"npm\"",[127,9228,9229],{"class":4518},", ",[127,9231,9232],{"class":4547},"\"run\"",[127,9234,9229],{"class":4518},[127,9236,9237],{"class":4547},"\"start:prod\"",[127,9239,8898],{"class":4518},[99,9241,9243],{"id":9242},"error-handling-and-type-safety","Error Handling and Type Safety",[112,9245,9247],{"id":9246},"custom-error-classes","Custom Error Classes",[117,9249,9251],{"className":4424,"code":9250,"language":4426,"meta":122,"style":122},"// src/errors/AppError.ts\nexport class AppError extends Error {\n public readonly statusCode: number\n public readonly isOperational: boolean\n\n constructor(\n message: string,\n statusCode: number = 500,\n isOperational: boolean = true,\n ) {\n super(message)\n this.statusCode = statusCode\n this.isOperational = isOperational\n\n Error.captureStackTrace(this, this.constructor)\n }\n}\n\nexport class ValidationError extends AppError {\n constructor(message: string) {\n super(message, 400)\n }\n}\n\nexport class NotFoundError extends AppError {\n constructor(resource: string) {\n super(`${resource} not found`, 404)\n }\n}\n",[124,9252,9253,9258,9273,9289,9303,9307,9314,9325,9342,9358,9365,9377,9390,9402,9406,9429,9433,9437,9441,9456,9472,9487,9491,9495,9499,9514,9531,9555,9559],{"__ignoreMap":122},[127,9254,9255],{"class":129,"line":130},[127,9256,9257],{"class":4433},"// src/errors/AppError.ts\n",[127,9259,9260,9262,9264,9267,9269,9271],{"class":129,"line":136},[127,9261,4605],{"class":4510},[127,9263,7450],{"class":4608},[127,9265,9266],{"class":4842}," AppError",[127,9268,6108],{"class":4608},[127,9270,5472],{"class":4842},[127,9272,4634],{"class":4514},[127,9274,9275,9278,9281,9284,9286],{"class":129,"line":16},[127,9276,9277],{"class":4608}," public",[127,9279,9280],{"class":4608}," readonly",[127,9282,9283],{"class":4639}," statusCode",[127,9285,4643],{"class":4514},[127,9287,9288],{"class":4842}," number\n",[127,9290,9291,9293,9295,9298,9300],{"class":129,"line":147},[127,9292,9277],{"class":4608},[127,9294,9280],{"class":4608},[127,9296,9297],{"class":4639}," isOperational",[127,9299,4643],{"class":4514},[127,9301,9302],{"class":4842}," boolean\n",[127,9304,9305],{"class":129,"line":153},[127,9306,199],{"emptyLinePlaceholder":198},[127,9308,9309,9312],{"class":129,"line":159},[127,9310,9311],{"class":4608}," constructor",[127,9313,6899],{"class":4514},[127,9315,9316,9319,9321,9323],{"class":129,"line":165},[127,9317,9318],{"class":5035}," message",[127,9320,4643],{"class":4514},[127,9322,5373],{"class":4842},[127,9324,4676],{"class":4514},[127,9326,9327,9330,9332,9335,9337,9340],{"class":129,"line":171},[127,9328,9329],{"class":5035}," statusCode",[127,9331,4643],{"class":4514},[127,9333,9334],{"class":4842}," number",[127,9336,4846],{"class":4514},[127,9338,9339],{"class":5165}," 500",[127,9341,4676],{"class":4514},[127,9343,9344,9347,9349,9352,9354,9356],{"class":129,"line":177},[127,9345,9346],{"class":5035}," isOperational",[127,9348,4643],{"class":4514},[127,9350,9351],{"class":4842}," boolean",[127,9353,4846],{"class":4514},[127,9355,7093],{"class":5969},[127,9357,4676],{"class":4514},[127,9359,9360,9363],{"class":129,"line":183},[127,9361,9362],{"class":4514}," )",[127,9364,4634],{"class":4514},[127,9366,9367,9370,9372,9375],{"class":129,"line":189},[127,9368,9369],{"class":4518}," super",[127,9371,4621],{"class":4639},[127,9373,9374],{"class":4518},"message",[127,9376,4783],{"class":4639},[127,9378,9379,9382,9385,9387],{"class":129,"line":195},[127,9380,9381],{"class":4514}," this.",[127,9383,9384],{"class":4518},"statusCode",[127,9386,4846],{"class":4514},[127,9388,9389],{"class":4518}," statusCode\n",[127,9391,9392,9394,9397,9399],{"class":129,"line":29},[127,9393,9381],{"class":4514},[127,9395,9396],{"class":4518},"isOperational",[127,9398,4846],{"class":4514},[127,9400,9401],{"class":4518}," isOperational\n",[127,9403,9404],{"class":129,"line":207},[127,9405,199],{"emptyLinePlaceholder":198},[127,9407,9408,9411,9413,9416,9418,9421,9424,9427],{"class":129,"line":213},[127,9409,9410],{"class":4518}," Error",[127,9412,4660],{"class":4514},[127,9414,9415],{"class":4618},"captureStackTrace",[127,9417,4621],{"class":4639},[127,9419,9420],{"class":4514},"this,",[127,9422,9423],{"class":4514}," this.",[127,9425,9426],{"class":4518},"constructor",[127,9428,4783],{"class":4639},[127,9430,9431],{"class":129,"line":219},[127,9432,1272],{"class":4514},[127,9434,9435],{"class":129,"line":225},[127,9436,192],{"class":4514},[127,9438,9439],{"class":129,"line":231},[127,9440,199],{"emptyLinePlaceholder":198},[127,9442,9443,9445,9447,9450,9452,9454],{"class":129,"line":237},[127,9444,4605],{"class":4510},[127,9446,7450],{"class":4608},[127,9448,9449],{"class":4842}," ValidationError",[127,9451,6108],{"class":4608},[127,9453,9266],{"class":4842},[127,9455,4634],{"class":4514},[127,9457,9458,9460,9462,9464,9466,9468,9470],{"class":129,"line":243},[127,9459,9311],{"class":4608},[127,9461,4621],{"class":4514},[127,9463,9374],{"class":5035},[127,9465,4643],{"class":4514},[127,9467,5373],{"class":4842},[127,9469,4657],{"class":4514},[127,9471,4634],{"class":4514},[127,9473,9474,9476,9478,9480,9482,9485],{"class":129,"line":249},[127,9475,9369],{"class":4518},[127,9477,4621],{"class":4639},[127,9479,9374],{"class":4518},[127,9481,4522],{"class":4514},[127,9483,9484],{"class":5165}," 400",[127,9486,4783],{"class":4639},[127,9488,9489],{"class":129,"line":254},[127,9490,1272],{"class":4514},[127,9492,9493],{"class":129,"line":259},[127,9494,192],{"class":4514},[127,9496,9497],{"class":129,"line":265},[127,9498,199],{"emptyLinePlaceholder":198},[127,9500,9501,9503,9505,9508,9510,9512],{"class":129,"line":270},[127,9502,4605],{"class":4510},[127,9504,7450],{"class":4608},[127,9506,9507],{"class":4842}," NotFoundError",[127,9509,6108],{"class":4608},[127,9511,9266],{"class":4842},[127,9513,4634],{"class":4514},[127,9515,9516,9518,9520,9523,9525,9527,9529],{"class":129,"line":276},[127,9517,9311],{"class":4608},[127,9519,4621],{"class":4514},[127,9521,9522],{"class":5035},"resource",[127,9524,4643],{"class":4514},[127,9526,5373],{"class":4842},[127,9528,4657],{"class":4514},[127,9530,4634],{"class":4514},[127,9532,9533,9535,9537,9540,9542,9544,9547,9549,9551,9553],{"class":129,"line":282},[127,9534,9369],{"class":4518},[127,9536,4621],{"class":4639},[127,9538,9539],{"class":4514},"`${",[127,9541,9522],{"class":4518},[127,9543,4780],{"class":4514},[127,9545,9546],{"class":4547}," not found",[127,9548,5418],{"class":4514},[127,9550,4522],{"class":4514},[127,9552,7169],{"class":5165},[127,9554,4783],{"class":4639},[127,9556,9557],{"class":129,"line":288},[127,9558,1272],{"class":4514},[127,9560,9561],{"class":129,"line":294},[127,9562,192],{"class":4514},[112,9564,9566],{"id":9565},"global-error-handler","Global Error Handler",[117,9568,9570],{"className":4424,"code":9569,"language":4426,"meta":122,"style":122},"// src/middleware/errorHandler.ts\nimport { Request, Response, NextFunction } from \"express\"\nimport { AppError } from \"../errors/AppError\"\n\nexport const errorHandler = (\n error: Error,\n req: Request,\n res: Response,\n next: NextFunction,\n) => {\n if (error instanceof AppError) {\n return res.status(error.statusCode).json({\n status: \"error\",\n message: error.message,\n ...(process.env.NODE_ENV === \"development\" && { stack: error.stack }),\n })\n }\n\n // Log unexpected errors\n console.error(\"Unexpected error:\", error)\n\n res.status(500).json({\n status: \"error\",\n message: \"Internal server error\",\n })\n}\n",[124,9571,9572,9577,9606,9625,9629,9643,9654,9665,9676,9687,9696,9714,9743,9758,9773,9825,9831,9835,9839,9844,9868,9872,9895,9910,9925,9931],{"__ignoreMap":122},[127,9573,9574],{"class":129,"line":130},[127,9575,9576],{"class":4433},"// src/middleware/errorHandler.ts\n",[127,9578,9579,9581,9583,9586,9588,9591,9593,9596,9598,9600,9602,9604],{"class":129,"line":136},[127,9580,4511],{"class":4510},[127,9582,4515],{"class":4514},[127,9584,9585],{"class":4518}," Request",[127,9587,4522],{"class":4514},[127,9589,9590],{"class":4518}," Response",[127,9592,4522],{"class":4514},[127,9594,9595],{"class":4518}," NextFunction",[127,9597,4538],{"class":4514},[127,9599,4541],{"class":4510},[127,9601,4544],{"class":4514},[127,9603,8488],{"class":4547},[127,9605,4551],{"class":4514},[127,9607,9608,9610,9612,9614,9616,9618,9620,9623],{"class":129,"line":16},[127,9609,4511],{"class":4510},[127,9611,4515],{"class":4514},[127,9613,9266],{"class":4518},[127,9615,4538],{"class":4514},[127,9617,4541],{"class":4510},[127,9619,4544],{"class":4514},[127,9621,9622],{"class":4547},"../errors/AppError",[127,9624,4551],{"class":4514},[127,9626,9627],{"class":129,"line":147},[127,9628,199],{"emptyLinePlaceholder":198},[127,9630,9631,9633,9635,9638,9640],{"class":129,"line":153},[127,9632,4605],{"class":4510},[127,9634,4609],{"class":4608},[127,9636,9637],{"class":4518}," errorHandler ",[127,9639,4615],{"class":4514},[127,9641,9642],{"class":4518}," (\n",[127,9644,9645,9648,9650,9652],{"class":129,"line":159},[127,9646,9647],{"class":5035}," error",[127,9649,4643],{"class":4514},[127,9651,5472],{"class":4842},[127,9653,4676],{"class":4514},[127,9655,9656,9659,9661,9663],{"class":129,"line":165},[127,9657,9658],{"class":5035}," req",[127,9660,4643],{"class":4514},[127,9662,9585],{"class":4842},[127,9664,4676],{"class":4514},[127,9666,9667,9670,9672,9674],{"class":129,"line":171},[127,9668,9669],{"class":5035}," res",[127,9671,4643],{"class":4514},[127,9673,9590],{"class":4842},[127,9675,4676],{"class":4514},[127,9677,9678,9681,9683,9685],{"class":129,"line":177},[127,9679,9680],{"class":5035}," next",[127,9682,4643],{"class":4514},[127,9684,9595],{"class":4842},[127,9686,4676],{"class":4514},[127,9688,9689,9691,9694],{"class":129,"line":183},[127,9690,5460],{"class":4518},[127,9692,9693],{"class":4608},"=>",[127,9695,4634],{"class":4514},[127,9697,9698,9700,9702,9705,9708,9710,9712],{"class":129,"line":189},[127,9699,5444],{"class":4510},[127,9701,5032],{"class":4639},[127,9703,9704],{"class":4518},"error",[127,9706,9707],{"class":4514}," instanceof",[127,9709,9266],{"class":4842},[127,9711,5460],{"class":4639},[127,9713,5150],{"class":4514},[127,9715,9716,9718,9721,9723,9725,9727,9729,9731,9733,9735,9737,9739,9741],{"class":129,"line":195},[127,9717,5998],{"class":4510},[127,9719,9720],{"class":4518}," res",[127,9722,4660],{"class":4514},[127,9724,5488],{"class":4618},[127,9726,4621],{"class":4639},[127,9728,9704],{"class":4518},[127,9730,4660],{"class":4514},[127,9732,9384],{"class":4518},[127,9734,4657],{"class":4639},[127,9736,4660],{"class":4514},[127,9738,5017],{"class":4618},[127,9740,4621],{"class":4639},[127,9742,5150],{"class":4514},[127,9744,9745,9748,9750,9752,9754,9756],{"class":129,"line":29},[127,9746,9747],{"class":4639}," status",[127,9749,4643],{"class":4514},[127,9751,4544],{"class":4514},[127,9753,9704],{"class":4547},[127,9755,4624],{"class":4514},[127,9757,4676],{"class":4514},[127,9759,9760,9763,9765,9767,9769,9771],{"class":129,"line":207},[127,9761,9762],{"class":4639}," message",[127,9764,4643],{"class":4514},[127,9766,7154],{"class":4518},[127,9768,4660],{"class":4514},[127,9770,9374],{"class":4518},[127,9772,4676],{"class":4514},[127,9774,9775,9778,9780,9783,9785,9788,9790,9793,9796,9798,9800,9802,9805,9807,9810,9812,9814,9816,9819,9821,9823],{"class":129,"line":213},[127,9776,9777],{"class":4514}," ...",[127,9779,4621],{"class":4639},[127,9781,9782],{"class":4518},"process",[127,9784,4660],{"class":4514},[127,9786,9787],{"class":4518},"env",[127,9789,4660],{"class":4514},[127,9791,9792],{"class":4518},"NODE_ENV",[127,9794,9795],{"class":4514}," ===",[127,9797,4544],{"class":4514},[127,9799,6424],{"class":4547},[127,9801,4624],{"class":4514},[127,9803,9804],{"class":4514}," &&",[127,9806,4515],{"class":4514},[127,9808,9809],{"class":4639}," stack",[127,9811,4643],{"class":4514},[127,9813,7154],{"class":4518},[127,9815,4660],{"class":4514},[127,9817,9818],{"class":4518},"stack",[127,9820,4538],{"class":4514},[127,9822,4657],{"class":4639},[127,9824,4676],{"class":4514},[127,9826,9827,9829],{"class":129,"line":219},[127,9828,5731],{"class":4514},[127,9830,4783],{"class":4639},[127,9832,9833],{"class":129,"line":225},[127,9834,1272],{"class":4514},[127,9836,9837],{"class":129,"line":231},[127,9838,199],{"emptyLinePlaceholder":198},[127,9840,9841],{"class":129,"line":237},[127,9842,9843],{"class":4433}," // Log unexpected errors\n",[127,9845,9846,9849,9851,9853,9855,9857,9860,9862,9864,9866],{"class":129,"line":243},[127,9847,9848],{"class":4518}," console",[127,9850,4660],{"class":4514},[127,9852,9704],{"class":4618},[127,9854,4621],{"class":4639},[127,9856,4624],{"class":4514},[127,9858,9859],{"class":4547},"Unexpected error:",[127,9861,4624],{"class":4514},[127,9863,4522],{"class":4514},[127,9865,7154],{"class":4518},[127,9867,4783],{"class":4639},[127,9869,9870],{"class":129,"line":249},[127,9871,199],{"emptyLinePlaceholder":198},[127,9873,9874,9876,9878,9880,9882,9885,9887,9889,9891,9893],{"class":129,"line":254},[127,9875,9669],{"class":4518},[127,9877,4660],{"class":4514},[127,9879,5488],{"class":4618},[127,9881,4621],{"class":4639},[127,9883,9884],{"class":5165},"500",[127,9886,4657],{"class":4639},[127,9888,4660],{"class":4514},[127,9890,5017],{"class":4618},[127,9892,4621],{"class":4639},[127,9894,5150],{"class":4514},[127,9896,9897,9900,9902,9904,9906,9908],{"class":129,"line":259},[127,9898,9899],{"class":4639}," status",[127,9901,4643],{"class":4514},[127,9903,4544],{"class":4514},[127,9905,9704],{"class":4547},[127,9907,4624],{"class":4514},[127,9909,4676],{"class":4514},[127,9911,9912,9914,9916,9918,9921,9923],{"class":129,"line":265},[127,9913,9318],{"class":4639},[127,9915,4643],{"class":4514},[127,9917,4544],{"class":4514},[127,9919,9920],{"class":4547},"Internal server error",[127,9922,4624],{"class":4514},[127,9924,4676],{"class":4514},[127,9926,9927,9929],{"class":129,"line":270},[127,9928,5228],{"class":4514},[127,9930,4783],{"class":4639},[127,9932,9933],{"class":129,"line":276},[127,9934,192],{"class":4514},[99,9936,9938],{"id":9937},"database-integration-with-type-safety","Database Integration with Type Safety",[112,9940,9942],{"id":9941},"prisma-integration","Prisma Integration",[117,9944,9946],{"className":4424,"code":9945,"language":4426,"meta":122,"style":122},"// src/database/client.ts\nimport { PrismaClient } from \"@prisma/client\"\n\nconst globalForPrisma = globalThis as unknown as {\n prisma: PrismaClient | undefined\n}\n\nexport const prisma = globalForPrisma.prisma ?? new PrismaClient()\n\nif (process.env.NODE_ENV !== \"production\") {\n globalForPrisma.prisma = prisma\n}\n",[124,9947,9948,9953,9973,9977,9997,10012,10016,10020,10048,10052,10082,10097],{"__ignoreMap":122},[127,9949,9950],{"class":129,"line":130},[127,9951,9952],{"class":4433},"// src/database/client.ts\n",[127,9954,9955,9957,9959,9962,9964,9966,9968,9971],{"class":129,"line":136},[127,9956,4511],{"class":4510},[127,9958,4515],{"class":4514},[127,9960,9961],{"class":4518}," PrismaClient",[127,9963,4538],{"class":4514},[127,9965,4541],{"class":4510},[127,9967,4544],{"class":4514},[127,9969,9970],{"class":4547},"@prisma/client",[127,9972,4551],{"class":4514},[127,9974,9975],{"class":129,"line":16},[127,9976,199],{"emptyLinePlaceholder":198},[127,9978,9979,9981,9984,9986,9989,9991,9993,9995],{"class":129,"line":147},[127,9980,4965],{"class":4608},[127,9982,9983],{"class":4518}," globalForPrisma ",[127,9985,4615],{"class":4514},[127,9987,9988],{"class":4518}," globalThis ",[127,9990,5948],{"class":4510},[127,9992,7649],{"class":4842},[127,9994,7666],{"class":4510},[127,9996,4634],{"class":4514},[127,9998,9999,10002,10004,10006,10009],{"class":129,"line":153},[127,10000,10001],{"class":4639}," prisma",[127,10003,4643],{"class":4514},[127,10005,9961],{"class":4842},[127,10007,10008],{"class":4514}," |",[127,10010,10011],{"class":4842}," undefined\n",[127,10013,10014],{"class":129,"line":159},[127,10015,192],{"class":4514},[127,10017,10018],{"class":129,"line":165},[127,10019,199],{"emptyLinePlaceholder":198},[127,10021,10022,10024,10026,10029,10031,10034,10036,10039,10042,10044,10046],{"class":129,"line":171},[127,10023,4605],{"class":4510},[127,10025,4609],{"class":4608},[127,10027,10028],{"class":4518}," prisma ",[127,10030,4615],{"class":4514},[127,10032,10033],{"class":4518}," globalForPrisma",[127,10035,4660],{"class":4514},[127,10037,10038],{"class":4518},"prisma ",[127,10040,10041],{"class":4514},"??",[127,10043,4973],{"class":4514},[127,10045,9961],{"class":4618},[127,10047,4978],{"class":4518},[127,10049,10050],{"class":129,"line":177},[127,10051,199],{"emptyLinePlaceholder":198},[127,10053,10054,10057,10060,10062,10064,10066,10069,10072,10074,10076,10078,10080],{"class":129,"line":183},[127,10055,10056],{"class":4510},"if",[127,10058,10059],{"class":4518}," (process",[127,10061,4660],{"class":4514},[127,10063,9787],{"class":4518},[127,10065,4660],{"class":4514},[127,10067,10068],{"class":4518},"NODE_ENV ",[127,10070,10071],{"class":4514},"!==",[127,10073,4544],{"class":4514},[127,10075,6433],{"class":4547},[127,10077,4624],{"class":4514},[127,10079,5460],{"class":4518},[127,10081,5150],{"class":4514},[127,10083,10084,10087,10089,10092,10094],{"class":129,"line":189},[127,10085,10086],{"class":4518}," globalForPrisma",[127,10088,4660],{"class":4514},[127,10090,10091],{"class":4518},"prisma",[127,10093,4846],{"class":4514},[127,10095,10096],{"class":4518}," prisma\n",[127,10098,10099],{"class":129,"line":195},[127,10100,192],{"class":4514},[112,10102,10104],{"id":10103},"repository-pattern","Repository Pattern",[117,10106,10108],{"className":4424,"code":10107,"language":4426,"meta":122,"style":122},"// src/repositories/UserRepository.ts\nimport { User, Prisma } from \"@prisma/client\"\nimport { prisma } from \"../database/client\"\n\nexport class UserRepository {\n async findById(id: string): Promise {\n return prisma.user.findUnique({\n where: { id },\n })\n }\n\n async create(data: Prisma.UserCreateInput): Promise {\n return prisma.user.create({\n data,\n })\n }\n\n async update(id: string, data: Prisma.UserUpdateInput): Promise {\n return prisma.user.update({\n where: { id },\n data,\n })\n }\n\n async delete(id: string): Promise {\n await prisma.user.delete({\n where: { id },\n })\n }\n}\n",[124,10109,10110,10115,10138,10158,10162,10173,10205,10225,10237,10243,10247,10251,10283,10301,10308,10314,10318,10322,10362,10381,10393,10399,10405,10409,10413,10441,10461,10473,10479,10483],{"__ignoreMap":122},[127,10111,10112],{"class":129,"line":130},[127,10113,10114],{"class":4433},"// src/repositories/UserRepository.ts\n",[127,10116,10117,10119,10121,10123,10125,10128,10130,10132,10134,10136],{"class":129,"line":136},[127,10118,4511],{"class":4510},[127,10120,4515],{"class":4514},[127,10122,4843],{"class":4518},[127,10124,4522],{"class":4514},[127,10126,10127],{"class":4518}," Prisma",[127,10129,4538],{"class":4514},[127,10131,4541],{"class":4510},[127,10133,4544],{"class":4514},[127,10135,9970],{"class":4547},[127,10137,4551],{"class":4514},[127,10139,10140,10142,10144,10147,10149,10151,10153,10156],{"class":129,"line":16},[127,10141,4511],{"class":4510},[127,10143,4515],{"class":4514},[127,10145,10146],{"class":4518}," prisma",[127,10148,4538],{"class":4514},[127,10150,4541],{"class":4510},[127,10152,4544],{"class":4514},[127,10154,10155],{"class":4547},"../database/client",[127,10157,4551],{"class":4514},[127,10159,10160],{"class":129,"line":147},[127,10161,199],{"emptyLinePlaceholder":198},[127,10163,10164,10166,10168,10171],{"class":129,"line":153},[127,10165,4605],{"class":4510},[127,10167,7450],{"class":4608},[127,10169,10170],{"class":4842}," UserRepository",[127,10172,4634],{"class":4514},[127,10174,10175,10177,10180,10182,10184,10186,10188,10190,10192,10194,10196,10198,10201,10203],{"class":129,"line":159},[127,10176,6970],{"class":4608},[127,10178,10179],{"class":4639}," findById",[127,10181,4621],{"class":4514},[127,10183,4652],{"class":5035},[127,10185,4643],{"class":4514},[127,10187,5373],{"class":4842},[127,10189,5387],{"class":4514},[127,10191,5390],{"class":4842},[127,10193,5359],{"class":4514},[127,10195,5956],{"class":4842},[127,10197,10008],{"class":4514},[127,10199,10200],{"class":4842}," null",[127,10202,5397],{"class":4514},[127,10204,4634],{"class":4514},[127,10206,10207,10209,10211,10213,10216,10218,10221,10223],{"class":129,"line":165},[127,10208,5998],{"class":4510},[127,10210,10146],{"class":4518},[127,10212,4660],{"class":4514},[127,10214,10215],{"class":4518},"user",[127,10217,4660],{"class":4514},[127,10219,10220],{"class":4618},"findUnique",[127,10222,4621],{"class":4639},[127,10224,5150],{"class":4514},[127,10226,10227,10229,10231,10233,10235],{"class":129,"line":171},[127,10228,7053],{"class":4639},[127,10230,4643],{"class":4514},[127,10232,4515],{"class":4514},[127,10234,6941],{"class":4518},[127,10236,5726],{"class":4514},[127,10238,10239,10241],{"class":129,"line":177},[127,10240,5731],{"class":4514},[127,10242,4783],{"class":4639},[127,10244,10245],{"class":129,"line":183},[127,10246,1272],{"class":4514},[127,10248,10249],{"class":129,"line":189},[127,10250,199],{"emptyLinePlaceholder":198},[127,10252,10253,10255,10258,10260,10262,10264,10266,10268,10271,10273,10275,10277,10279,10281],{"class":129,"line":195},[127,10254,6970],{"class":4608},[127,10256,10257],{"class":4639}," create",[127,10259,4621],{"class":4514},[127,10261,5121],{"class":5035},[127,10263,4643],{"class":4514},[127,10265,10127],{"class":4842},[127,10267,4660],{"class":4514},[127,10269,10270],{"class":4842},"UserCreateInput",[127,10272,5387],{"class":4514},[127,10274,5390],{"class":4842},[127,10276,5359],{"class":4514},[127,10278,5956],{"class":4842},[127,10280,5397],{"class":4514},[127,10282,4634],{"class":4514},[127,10284,10285,10287,10289,10291,10293,10295,10297,10299],{"class":129,"line":29},[127,10286,5998],{"class":4510},[127,10288,10146],{"class":4518},[127,10290,4660],{"class":4514},[127,10292,10215],{"class":4518},[127,10294,4660],{"class":4514},[127,10296,8139],{"class":4618},[127,10298,4621],{"class":4639},[127,10300,5150],{"class":4514},[127,10302,10303,10306],{"class":129,"line":207},[127,10304,10305],{"class":4518}," data",[127,10307,4676],{"class":4514},[127,10309,10310,10312],{"class":129,"line":213},[127,10311,5731],{"class":4514},[127,10313,4783],{"class":4639},[127,10315,10316],{"class":129,"line":219},[127,10317,1272],{"class":4514},[127,10319,10320],{"class":129,"line":225},[127,10321,199],{"emptyLinePlaceholder":198},[127,10323,10324,10326,10329,10331,10333,10335,10337,10339,10341,10343,10345,10347,10350,10352,10354,10356,10358,10360],{"class":129,"line":231},[127,10325,6970],{"class":4608},[127,10327,10328],{"class":4639}," update",[127,10330,4621],{"class":4514},[127,10332,4652],{"class":5035},[127,10334,4643],{"class":4514},[127,10336,5373],{"class":4842},[127,10338,4522],{"class":4514},[127,10340,5051],{"class":5035},[127,10342,4643],{"class":4514},[127,10344,10127],{"class":4842},[127,10346,4660],{"class":4514},[127,10348,10349],{"class":4842},"UserUpdateInput",[127,10351,5387],{"class":4514},[127,10353,5390],{"class":4842},[127,10355,5359],{"class":4514},[127,10357,5956],{"class":4842},[127,10359,5397],{"class":4514},[127,10361,4634],{"class":4514},[127,10363,10364,10366,10368,10370,10372,10374,10377,10379],{"class":129,"line":237},[127,10365,5998],{"class":4510},[127,10367,10146],{"class":4518},[127,10369,4660],{"class":4514},[127,10371,10215],{"class":4518},[127,10373,4660],{"class":4514},[127,10375,10376],{"class":4618},"update",[127,10378,4621],{"class":4639},[127,10380,5150],{"class":4514},[127,10382,10383,10385,10387,10389,10391],{"class":129,"line":243},[127,10384,7053],{"class":4639},[127,10386,4643],{"class":4514},[127,10388,4515],{"class":4514},[127,10390,6941],{"class":4518},[127,10392,5726],{"class":4514},[127,10394,10395,10397],{"class":129,"line":249},[127,10396,10305],{"class":4518},[127,10398,4676],{"class":4514},[127,10400,10401,10403],{"class":129,"line":254},[127,10402,5731],{"class":4514},[127,10404,4783],{"class":4639},[127,10406,10407],{"class":129,"line":259},[127,10408,1272],{"class":4514},[127,10410,10411],{"class":129,"line":265},[127,10412,199],{"emptyLinePlaceholder":198},[127,10414,10415,10417,10420,10422,10424,10426,10428,10430,10432,10434,10437,10439],{"class":129,"line":270},[127,10416,6970],{"class":4608},[127,10418,10419],{"class":4639}," delete",[127,10421,4621],{"class":4514},[127,10423,4652],{"class":5035},[127,10425,4643],{"class":4514},[127,10427,5373],{"class":4842},[127,10429,5387],{"class":4514},[127,10431,5390],{"class":4842},[127,10433,5359],{"class":4514},[127,10435,10436],{"class":4842},"void",[127,10438,5397],{"class":4514},[127,10440,4634],{"class":4514},[127,10442,10443,10446,10448,10450,10452,10454,10457,10459],{"class":129,"line":276},[127,10444,10445],{"class":4510}," await",[127,10447,10146],{"class":4518},[127,10449,4660],{"class":4514},[127,10451,10215],{"class":4518},[127,10453,4660],{"class":4514},[127,10455,10456],{"class":4618},"delete",[127,10458,4621],{"class":4639},[127,10460,5150],{"class":4514},[127,10462,10463,10465,10467,10469,10471],{"class":129,"line":282},[127,10464,7053],{"class":4639},[127,10466,4643],{"class":4514},[127,10468,4515],{"class":4514},[127,10470,6941],{"class":4518},[127,10472,5726],{"class":4514},[127,10474,10475,10477],{"class":129,"line":288},[127,10476,5731],{"class":4514},[127,10478,4783],{"class":4639},[127,10480,10481],{"class":129,"line":294},[127,10482,1272],{"class":4514},[127,10484,10485],{"class":129,"line":300},[127,10486,192],{"class":4514},[99,10488,10490],{"id":10489},"api-design-with-strong-types","API Design with Strong Types",[112,10492,10494],{"id":10493},"requestresponse-types","Request/Response Types",[117,10496,10498],{"className":4424,"code":10497,"language":4426,"meta":122,"style":122},"// src/types/api.ts\nexport interface CreateUserRequest {\n email: string\n name: string\n password: string\n}\n\nexport interface UserResponse {\n id: string\n email: string\n name: string\n createdAt: string\n updatedAt: string\n}\n\nexport interface ApiResponse {\n success: boolean\n data?: T\n error?: string\n message?: string\n}\n",[124,10499,10500,10505,10517,10525,10533,10542,10546,10550,10561,10569,10577,10585,10593,10602,10606,10610,10630,10639,10649,10657,10666],{"__ignoreMap":122},[127,10501,10502],{"class":129,"line":130},[127,10503,10504],{"class":4433},"// src/types/api.ts\n",[127,10506,10507,10509,10512,10515],{"class":129,"line":136},[127,10508,4605],{"class":4510},[127,10510,10511],{"class":4608}," interface",[127,10513,10514],{"class":4842}," CreateUserRequest",[127,10516,4634],{"class":4514},[127,10518,10519,10521,10523],{"class":129,"line":16},[127,10520,4681],{"class":4639},[127,10522,4643],{"class":4514},[127,10524,7616],{"class":4842},[127,10526,10527,10529,10531],{"class":129,"line":147},[127,10528,4717],{"class":4639},[127,10530,4643],{"class":4514},[127,10532,7616],{"class":4842},[127,10534,10535,10538,10540],{"class":129,"line":153},[127,10536,10537],{"class":4639}," password",[127,10539,4643],{"class":4514},[127,10541,7616],{"class":4842},[127,10543,10544],{"class":129,"line":159},[127,10545,192],{"class":4514},[127,10547,10548],{"class":129,"line":165},[127,10549,199],{"emptyLinePlaceholder":198},[127,10551,10552,10554,10556,10559],{"class":129,"line":171},[127,10553,4605],{"class":4510},[127,10555,10511],{"class":4608},[127,10557,10558],{"class":4842}," UserResponse",[127,10560,4634],{"class":4514},[127,10562,10563,10565,10567],{"class":129,"line":177},[127,10564,4640],{"class":4639},[127,10566,4643],{"class":4514},[127,10568,7616],{"class":4842},[127,10570,10571,10573,10575],{"class":129,"line":183},[127,10572,4681],{"class":4639},[127,10574,4643],{"class":4514},[127,10576,7616],{"class":4842},[127,10578,10579,10581,10583],{"class":129,"line":189},[127,10580,4717],{"class":4639},[127,10582,4643],{"class":4514},[127,10584,7616],{"class":4842},[127,10586,10587,10589,10591],{"class":129,"line":195},[127,10588,4745],{"class":4639},[127,10590,4643],{"class":4514},[127,10592,7616],{"class":4842},[127,10594,10595,10598,10600],{"class":129,"line":29},[127,10596,10597],{"class":4639}," updatedAt",[127,10599,4643],{"class":4514},[127,10601,7616],{"class":4842},[127,10603,10604],{"class":129,"line":207},[127,10605,192],{"class":4514},[127,10607,10608],{"class":129,"line":213},[127,10609,199],{"emptyLinePlaceholder":198},[127,10611,10612,10614,10616,10618,10620,10622,10624,10626,10628],{"class":129,"line":219},[127,10613,4605],{"class":4510},[127,10615,10511],{"class":4608},[127,10617,6261],{"class":4842},[127,10619,5359],{"class":4514},[127,10621,5362],{"class":4842},[127,10623,4846],{"class":4514},[127,10625,7649],{"class":4842},[127,10627,5397],{"class":4514},[127,10629,4634],{"class":4514},[127,10631,10632,10635,10637],{"class":129,"line":225},[127,10633,10634],{"class":4639}," success",[127,10636,4643],{"class":4514},[127,10638,9302],{"class":4842},[127,10640,10641,10644,10646],{"class":129,"line":231},[127,10642,10643],{"class":4639}," data",[127,10645,5381],{"class":4514},[127,10647,10648],{"class":4842}," T\n",[127,10650,10651,10653,10655],{"class":129,"line":237},[127,10652,9647],{"class":4639},[127,10654,5381],{"class":4514},[127,10656,7616],{"class":4842},[127,10658,10659,10662,10664],{"class":129,"line":243},[127,10660,10661],{"class":4639}," message",[127,10663,5381],{"class":4514},[127,10665,7616],{"class":4842},[127,10667,10668],{"class":129,"line":249},[127,10669,192],{"class":4514},[112,10671,10673],{"id":10672},"validated-controllers","Validated Controllers",[117,10675,10677],{"className":4424,"code":10676,"language":4426,"meta":122,"style":122},"// src/controllers/UserController.ts\nimport { Request, Response, NextFunction } from \"express\"\nimport { z } from \"zod\"\nimport { UserService } from \"../services/UserService\"\nimport { ValidationError } from \"../errors/AppError\"\n\nconst createUserSchema = z.object({\n email: z.string().email(),\n name: z.string().min(2),\n password: z.string().min(8),\n})\n\nexport class UserController {\n constructor(private userService: UserService) {}\n\n async createUser(req: Request, res: Response, next: NextFunction) {\n try {\n const validatedData = createUserSchema.parse(req.body)\n const user = await this.userService.createUser(validatedData)\n\n res.status(201).json({\n success: true,\n data: user,\n })\n } catch (error) {\n if (error instanceof z.ZodError) {\n next(\n new ValidationError(error.errors[0]?.message || \"Validation failed\"),\n )\n } else {\n next(error)\n }\n }\n }\n}\n",[124,10678,10679,10684,10710,10728,10748,10766,10770,10789,10811,10838,10865,10871,10875,10886,10906,10910,10945,10952,10980,11007,11011,11035,11046,11057,11064,11079,11101,11108,11149,11154,11163,11173,11177,11181,11185],{"__ignoreMap":122},[127,10680,10681],{"class":129,"line":130},[127,10682,10683],{"class":4433},"// src/controllers/UserController.ts\n",[127,10685,10686,10688,10690,10692,10694,10696,10698,10700,10702,10704,10706,10708],{"class":129,"line":136},[127,10687,4511],{"class":4510},[127,10689,4515],{"class":4514},[127,10691,9585],{"class":4518},[127,10693,4522],{"class":4514},[127,10695,9590],{"class":4518},[127,10697,4522],{"class":4514},[127,10699,9595],{"class":4518},[127,10701,4538],{"class":4514},[127,10703,4541],{"class":4510},[127,10705,4544],{"class":4514},[127,10707,8488],{"class":4547},[127,10709,4551],{"class":4514},[127,10711,10712,10714,10716,10718,10720,10722,10724,10726],{"class":129,"line":16},[127,10713,4511],{"class":4510},[127,10715,4515],{"class":4514},[127,10717,4585],{"class":4518},[127,10719,4538],{"class":4514},[127,10721,4541],{"class":4510},[127,10723,4544],{"class":4514},[127,10725,4594],{"class":4547},[127,10727,4551],{"class":4514},[127,10729,10730,10732,10734,10737,10739,10741,10743,10746],{"class":129,"line":147},[127,10731,4511],{"class":4510},[127,10733,4515],{"class":4514},[127,10735,10736],{"class":4518}," UserService",[127,10738,4538],{"class":4514},[127,10740,4541],{"class":4510},[127,10742,4544],{"class":4514},[127,10744,10745],{"class":4547},"../services/UserService",[127,10747,4551],{"class":4514},[127,10749,10750,10752,10754,10756,10758,10760,10762,10764],{"class":129,"line":153},[127,10751,4511],{"class":4510},[127,10753,4515],{"class":4514},[127,10755,9449],{"class":4518},[127,10757,4538],{"class":4514},[127,10759,4541],{"class":4510},[127,10761,4544],{"class":4514},[127,10763,9622],{"class":4547},[127,10765,4551],{"class":4514},[127,10767,10768],{"class":129,"line":159},[127,10769,199],{"emptyLinePlaceholder":198},[127,10771,10772,10774,10777,10779,10781,10783,10785,10787],{"class":129,"line":165},[127,10773,4965],{"class":4608},[127,10775,10776],{"class":4518}," createUserSchema ",[127,10778,4615],{"class":4514},[127,10780,4585],{"class":4518},[127,10782,4660],{"class":4514},[127,10784,6139],{"class":4618},[127,10786,4621],{"class":4518},[127,10788,5150],{"class":4514},[127,10790,10791,10793,10795,10797,10799,10801,10803,10805,10807,10809],{"class":129,"line":171},[127,10792,4681],{"class":4639},[127,10794,4643],{"class":4514},[127,10796,4585],{"class":4518},[127,10798,4660],{"class":4514},[127,10800,6183],{"class":4618},[127,10802,4666],{"class":4518},[127,10804,4660],{"class":4514},[127,10806,4692],{"class":4618},[127,10808,4666],{"class":4518},[127,10810,4676],{"class":4514},[127,10812,10813,10815,10817,10819,10821,10823,10825,10827,10829,10831,10834,10836],{"class":129,"line":177},[127,10814,4717],{"class":4639},[127,10816,4643],{"class":4514},[127,10818,4585],{"class":4518},[127,10820,4660],{"class":4514},[127,10822,6183],{"class":4618},[127,10824,4666],{"class":4518},[127,10826,4660],{"class":4514},[127,10828,6393],{"class":4618},[127,10830,4621],{"class":4518},[127,10832,10833],{"class":5165},"2",[127,10835,4657],{"class":4518},[127,10837,4676],{"class":4514},[127,10839,10840,10842,10844,10846,10848,10850,10852,10854,10856,10858,10861,10863],{"class":129,"line":183},[127,10841,10537],{"class":4639},[127,10843,4643],{"class":4514},[127,10845,4585],{"class":4518},[127,10847,4660],{"class":4514},[127,10849,6183],{"class":4618},[127,10851,4666],{"class":4518},[127,10853,4660],{"class":4514},[127,10855,6393],{"class":4618},[127,10857,4621],{"class":4518},[127,10859,10860],{"class":5165},"8",[127,10862,4657],{"class":4518},[127,10864,4676],{"class":4514},[127,10866,10867,10869],{"class":129,"line":189},[127,10868,4780],{"class":4514},[127,10870,4783],{"class":4518},[127,10872,10873],{"class":129,"line":195},[127,10874,199],{"emptyLinePlaceholder":198},[127,10876,10877,10879,10881,10884],{"class":129,"line":29},[127,10878,4605],{"class":4510},[127,10880,7450],{"class":4608},[127,10882,10883],{"class":4842}," UserController",[127,10885,4634],{"class":4514},[127,10887,10888,10890,10892,10895,10898,10900,10902,10904],{"class":129,"line":207},[127,10889,9311],{"class":4608},[127,10891,4621],{"class":4514},[127,10893,10894],{"class":4608},"private",[127,10896,10897],{"class":5035}," userService",[127,10899,4643],{"class":4514},[127,10901,10736],{"class":4842},[127,10903,4657],{"class":4514},[127,10905,7584],{"class":4514},[127,10907,10908],{"class":129,"line":213},[127,10909,199],{"emptyLinePlaceholder":198},[127,10911,10912,10914,10916,10918,10920,10922,10924,10926,10928,10930,10932,10934,10937,10939,10941,10943],{"class":129,"line":219},[127,10913,6970],{"class":4608},[127,10915,7640],{"class":4639},[127,10917,4621],{"class":4514},[127,10919,5061],{"class":5035},[127,10921,4643],{"class":4514},[127,10923,9585],{"class":4842},[127,10925,4522],{"class":4514},[127,10927,9720],{"class":5035},[127,10929,4643],{"class":4514},[127,10931,9590],{"class":4842},[127,10933,4522],{"class":4514},[127,10935,10936],{"class":5035}," next",[127,10938,4643],{"class":4514},[127,10940,9595],{"class":4842},[127,10942,4657],{"class":4514},[127,10944,4634],{"class":4514},[127,10946,10947,10950],{"class":129,"line":225},[127,10948,10949],{"class":4510}," try",[127,10951,4634],{"class":4514},[127,10953,10954,10957,10960,10962,10965,10967,10969,10971,10973,10975,10978],{"class":129,"line":231},[127,10955,10956],{"class":4608}," const",[127,10958,10959],{"class":4518}," validatedData",[127,10961,4846],{"class":4514},[127,10963,10964],{"class":4518}," createUserSchema",[127,10966,4660],{"class":4514},[127,10968,6478],{"class":4618},[127,10970,4621],{"class":4639},[127,10972,5061],{"class":4518},[127,10974,4660],{"class":4514},[127,10976,10977],{"class":4518},"body",[127,10979,4783],{"class":4639},[127,10981,10982,10984,10986,10988,10990,10992,10995,10997,11000,11002,11005],{"class":129,"line":237},[127,10983,10956],{"class":4608},[127,10985,5092],{"class":4518},[127,10987,4846],{"class":4514},[127,10989,5097],{"class":4510},[127,10991,9423],{"class":4514},[127,10993,10994],{"class":4518},"userService",[127,10996,4660],{"class":4514},[127,10998,10999],{"class":4618},"createUser",[127,11001,4621],{"class":4639},[127,11003,11004],{"class":4518},"validatedData",[127,11006,4783],{"class":4639},[127,11008,11009],{"class":129,"line":243},[127,11010,199],{"emptyLinePlaceholder":198},[127,11012,11013,11016,11018,11020,11022,11025,11027,11029,11031,11033],{"class":129,"line":249},[127,11014,11015],{"class":4518}," res",[127,11017,4660],{"class":4514},[127,11019,5488],{"class":4618},[127,11021,4621],{"class":4639},[127,11023,11024],{"class":5165},"201",[127,11026,4657],{"class":4639},[127,11028,4660],{"class":4514},[127,11030,5017],{"class":4618},[127,11032,4621],{"class":4639},[127,11034,5150],{"class":4514},[127,11036,11037,11040,11042,11044],{"class":129,"line":254},[127,11038,11039],{"class":4639}," success",[127,11041,4643],{"class":4514},[127,11043,7093],{"class":5969},[127,11045,4676],{"class":4514},[127,11047,11048,11051,11053,11055],{"class":129,"line":259},[127,11049,11050],{"class":4639}," data",[127,11052,4643],{"class":4514},[127,11054,5092],{"class":4518},[127,11056,4676],{"class":4514},[127,11058,11059,11062],{"class":129,"line":265},[127,11060,11061],{"class":4514}," }",[127,11063,4783],{"class":4639},[127,11065,11066,11068,11071,11073,11075,11077],{"class":129,"line":270},[127,11067,5731],{"class":4514},[127,11069,11070],{"class":4510}," catch",[127,11072,5032],{"class":4639},[127,11074,9704],{"class":4518},[127,11076,5460],{"class":4639},[127,11078,5150],{"class":4514},[127,11080,11081,11084,11086,11088,11090,11092,11094,11097,11099],{"class":129,"line":276},[127,11082,11083],{"class":4510}," if",[127,11085,5032],{"class":4639},[127,11087,9704],{"class":4518},[127,11089,9707],{"class":4514},[127,11091,4585],{"class":4842},[127,11093,4660],{"class":4514},[127,11095,11096],{"class":4842},"ZodError",[127,11098,5460],{"class":4639},[127,11100,5150],{"class":4514},[127,11102,11103,11106],{"class":129,"line":282},[127,11104,11105],{"class":4618}," next",[127,11107,6899],{"class":4639},[127,11109,11110,11113,11115,11117,11119,11121,11124,11126,11128,11130,11133,11135,11138,11140,11143,11145,11147],{"class":129,"line":288},[127,11111,11112],{"class":4514}," new",[127,11114,9449],{"class":4618},[127,11116,4621],{"class":4639},[127,11118,9704],{"class":4518},[127,11120,4660],{"class":4514},[127,11122,11123],{"class":4518},"errors",[127,11125,5162],{"class":4639},[127,11127,5166],{"class":5165},[127,11129,5169],{"class":4639},[127,11131,11132],{"class":4514},"?.",[127,11134,9374],{"class":4518},[127,11136,11137],{"class":4514}," ||",[127,11139,4544],{"class":4514},[127,11141,11142],{"class":4547},"Validation failed",[127,11144,4624],{"class":4514},[127,11146,4657],{"class":4639},[127,11148,4676],{"class":4514},[127,11150,11151],{"class":129,"line":294},[127,11152,11153],{"class":4639}," )\n",[127,11155,11156,11158,11161],{"class":129,"line":300},[127,11157,11061],{"class":4514},[127,11159,11160],{"class":4510}," else",[127,11162,4634],{"class":4514},[127,11164,11165,11167,11169,11171],{"class":129,"line":306},[127,11166,11105],{"class":4618},[127,11168,4621],{"class":4639},[127,11170,9704],{"class":4518},[127,11172,4783],{"class":4639},[127,11174,11175],{"class":129,"line":312},[127,11176,1054],{"class":4514},[127,11178,11179],{"class":129,"line":318},[127,11180,1267],{"class":4514},[127,11182,11183],{"class":129,"line":324},[127,11184,1272],{"class":4514},[127,11186,11187],{"class":129,"line":329},[127,11188,192],{"class":4514},[99,11190,11192],{"id":11191},"performance-optimization","Performance Optimization",[112,11194,11196],{"id":11195},"compilation-speed","Compilation Speed",[117,11198,11200],{"className":8307,"code":11199,"language":5017,"meta":122,"style":122},"// tsconfig.json - for faster builds\n{\n \"compilerOptions\": {\n \"incremental\": true,\n \"tsBuildInfoFile\": \".tsbuildinfo\"\n },\n \"ts-node\": {\n \"transpileOnly\": true,\n \"files\": true\n }\n}\n",[124,11201,11202,11207,11211,11223,11236,11254,11258,11270,11283,11296,11300],{"__ignoreMap":122},[127,11203,11204],{"class":129,"line":130},[127,11205,11206],{"class":4433},"// tsconfig.json - for faster builds\n",[127,11208,11209],{"class":129,"line":136},[127,11210,5150],{"class":4514},[127,11212,11213,11215,11217,11219,11221],{"class":129,"line":16},[127,11214,6904],{"class":4514},[127,11216,8552],{"class":4608},[127,11218,4624],{"class":4514},[127,11220,4643],{"class":4514},[127,11222,4634],{"class":4514},[127,11224,11225,11227,11230,11232,11234],{"class":129,"line":147},[127,11226,8332],{"class":4514},[127,11228,11229],{"class":4842},"incremental",[127,11231,4624],{"class":4514},[127,11233,4643],{"class":4514},[127,11235,8675],{"class":4514},[127,11237,11238,11240,11243,11245,11247,11249,11252],{"class":129,"line":153},[127,11239,8332],{"class":4514},[127,11241,11242],{"class":4842},"tsBuildInfoFile",[127,11244,4624],{"class":4514},[127,11246,4643],{"class":4514},[127,11248,4544],{"class":4514},[127,11250,11251],{"class":4547},".tsbuildinfo",[127,11253,4551],{"class":4514},[127,11255,11256],{"class":129,"line":159},[127,11257,844],{"class":4514},[127,11259,11260,11262,11264,11266,11268],{"class":129,"line":165},[127,11261,6904],{"class":4514},[127,11263,8374],{"class":4608},[127,11265,4624],{"class":4514},[127,11267,4643],{"class":4514},[127,11269,4634],{"class":4514},[127,11271,11272,11274,11277,11279,11281],{"class":129,"line":171},[127,11273,8332],{"class":4514},[127,11275,11276],{"class":4842},"transpileOnly",[127,11278,4624],{"class":4514},[127,11280,4643],{"class":4514},[127,11282,8675],{"class":4514},[127,11284,11285,11287,11290,11292,11294],{"class":129,"line":177},[127,11286,8332],{"class":4514},[127,11288,11289],{"class":4842},"files",[127,11291,4624],{"class":4514},[127,11293,4643],{"class":4514},[127,11295,5970],{"class":4514},[127,11297,11298],{"class":129,"line":183},[127,11299,1272],{"class":4514},[127,11301,11302],{"class":129,"line":189},[127,11303,192],{"class":4514},[112,11305,11307],{"id":11306},"runtime-performance","Runtime Performance",[117,11309,11311],{"className":4424,"code":11310,"language":4426,"meta":122,"style":122},"// Use type assertions carefully\nconst user = data as User // Fast but unsafe\nconst user = data satisfies User // Type-safe validation\n\n// Prefer interfaces over types for objects\ninterface User {\n id: string\n name: string\n}\n\n// Use const assertions for immutable data\nconst config = {\n port: 3000,\n host: \"localhost\",\n} as const\n",[124,11312,11313,11318,11337,11355,11359,11364,11372,11380,11388,11392,11396,11401,11412,11424,11440],{"__ignoreMap":122},[127,11314,11315],{"class":129,"line":130},[127,11316,11317],{"class":4433},"// Use type assertions carefully\n",[127,11319,11320,11322,11325,11327,11330,11332,11334],{"class":129,"line":136},[127,11321,4965],{"class":4608},[127,11323,11324],{"class":4518}," user ",[127,11326,4615],{"class":4514},[127,11328,11329],{"class":4518}," data ",[127,11331,5948],{"class":4510},[127,11333,4843],{"class":4842},[127,11335,11336],{"class":4433}," // Fast but unsafe\n",[127,11338,11339,11341,11343,11345,11347,11350,11352],{"class":129,"line":16},[127,11340,4965],{"class":4608},[127,11342,11324],{"class":4518},[127,11344,4615],{"class":4514},[127,11346,11329],{"class":4518},[127,11348,11349],{"class":4510},"satisfies",[127,11351,4843],{"class":4842},[127,11353,11354],{"class":4433}," // Type-safe validation\n",[127,11356,11357],{"class":129,"line":147},[127,11358,199],{"emptyLinePlaceholder":198},[127,11360,11361],{"class":129,"line":153},[127,11362,11363],{"class":4433},"// Prefer interfaces over types for objects\n",[127,11365,11366,11368,11370],{"class":129,"line":159},[127,11367,7603],{"class":4608},[127,11369,4843],{"class":4842},[127,11371,4634],{"class":4514},[127,11373,11374,11376,11378],{"class":129,"line":165},[127,11375,4640],{"class":4639},[127,11377,4643],{"class":4514},[127,11379,7616],{"class":4842},[127,11381,11382,11384,11386],{"class":129,"line":171},[127,11383,4717],{"class":4639},[127,11385,4643],{"class":4514},[127,11387,7616],{"class":4842},[127,11389,11390],{"class":129,"line":177},[127,11391,192],{"class":4514},[127,11393,11394],{"class":129,"line":183},[127,11395,199],{"emptyLinePlaceholder":198},[127,11397,11398],{"class":129,"line":189},[127,11399,11400],{"class":4433},"// Use const assertions for immutable data\n",[127,11402,11403,11405,11408,11410],{"class":129,"line":195},[127,11404,4965],{"class":4608},[127,11406,11407],{"class":4518}," config ",[127,11409,4615],{"class":4514},[127,11411,4634],{"class":4514},[127,11413,11414,11417,11419,11422],{"class":129,"line":29},[127,11415,11416],{"class":4639}," port",[127,11418,4643],{"class":4514},[127,11420,11421],{"class":5165}," 3000",[127,11423,4676],{"class":4514},[127,11425,11426,11429,11431,11433,11436,11438],{"class":129,"line":207},[127,11427,11428],{"class":4639}," host",[127,11430,4643],{"class":4514},[127,11432,4544],{"class":4514},[127,11434,11435],{"class":4547},"localhost",[127,11437,4624],{"class":4514},[127,11439,4676],{"class":4514},[127,11441,11442,11444,11446],{"class":129,"line":213},[127,11443,4780],{"class":4514},[127,11445,7666],{"class":4510},[127,11447,11448],{"class":4608}," const\n",[99,11450,11452],{"id":11451},"monitoring-and-logging","Monitoring and Logging",[112,11454,11456],{"id":11455},"structured-logging","Structured Logging",[117,11458,11460],{"className":4424,"code":11459,"language":4426,"meta":122,"style":122},"// src/utils/logger.ts\nimport winston from \"winston\"\n\nexport const logger = winston.createLogger({\n level: process.env.LOG_LEVEL || \"info\",\n format: winston.format.combine(\n winston.format.timestamp(),\n winston.format.errors({ stack: true }),\n winston.format.json(),\n ),\n transports: [\n new winston.transports.File({ filename: \"error.log\", level: \"error\" }),\n new winston.transports.File({ filename: \"combined.log\" }),\n ...(process.env.NODE_ENV !== \"production\"\n ? [\n new winston.transports.Console({\n format: winston.format.simple(),\n }),\n ]\n : []),\n ],\n})\n",[124,11461,11462,11467,11484,11488,11511,11542,11562,11580,11608,11624,11630,11640,11692,11727,11750,11757,11776,11798,11807,11812,11822,11829],{"__ignoreMap":122},[127,11463,11464],{"class":129,"line":130},[127,11465,11466],{"class":4433},"// src/utils/logger.ts\n",[127,11468,11469,11471,11474,11477,11479,11482],{"class":129,"line":136},[127,11470,4511],{"class":4510},[127,11472,11473],{"class":4518}," winston ",[127,11475,11476],{"class":4510},"from",[127,11478,4544],{"class":4514},[127,11480,11481],{"class":4547},"winston",[127,11483,4551],{"class":4514},[127,11485,11486],{"class":129,"line":16},[127,11487,199],{"emptyLinePlaceholder":198},[127,11489,11490,11492,11494,11497,11499,11502,11504,11507,11509],{"class":129,"line":147},[127,11491,4605],{"class":4510},[127,11493,4609],{"class":4608},[127,11495,11496],{"class":4518}," logger ",[127,11498,4615],{"class":4514},[127,11500,11501],{"class":4518}," winston",[127,11503,4660],{"class":4514},[127,11505,11506],{"class":4618},"createLogger",[127,11508,4621],{"class":4518},[127,11510,5150],{"class":4514},[127,11512,11513,11516,11518,11521,11523,11525,11527,11530,11533,11535,11538,11540],{"class":129,"line":153},[127,11514,11515],{"class":4639}," level",[127,11517,4643],{"class":4514},[127,11519,11520],{"class":4518}," process",[127,11522,4660],{"class":4514},[127,11524,9787],{"class":4518},[127,11526,4660],{"class":4514},[127,11528,11529],{"class":4518},"LOG_LEVEL ",[127,11531,11532],{"class":4514},"||",[127,11534,4544],{"class":4514},[127,11536,11537],{"class":4547},"info",[127,11539,4624],{"class":4514},[127,11541,4676],{"class":4514},[127,11543,11544,11547,11549,11551,11553,11555,11557,11560],{"class":129,"line":159},[127,11545,11546],{"class":4639}," format",[127,11548,4643],{"class":4514},[127,11550,11501],{"class":4518},[127,11552,4660],{"class":4514},[127,11554,7396],{"class":4518},[127,11556,4660],{"class":4514},[127,11558,11559],{"class":4618},"combine",[127,11561,6899],{"class":4518},[127,11563,11564,11567,11569,11571,11573,11576,11578],{"class":129,"line":165},[127,11565,11566],{"class":4518}," winston",[127,11568,4660],{"class":4514},[127,11570,7396],{"class":4518},[127,11572,4660],{"class":4514},[127,11574,11575],{"class":4618},"timestamp",[127,11577,4666],{"class":4518},[127,11579,4676],{"class":4514},[127,11581,11582,11584,11586,11588,11590,11592,11594,11596,11598,11600,11602,11604,11606],{"class":129,"line":171},[127,11583,11566],{"class":4518},[127,11585,4660],{"class":4514},[127,11587,7396],{"class":4518},[127,11589,4660],{"class":4514},[127,11591,11123],{"class":4618},[127,11593,4621],{"class":4518},[127,11595,6938],{"class":4514},[127,11597,9809],{"class":4639},[127,11599,4643],{"class":4514},[127,11601,7093],{"class":5969},[127,11603,4538],{"class":4514},[127,11605,4657],{"class":4518},[127,11607,4676],{"class":4514},[127,11609,11610,11612,11614,11616,11618,11620,11622],{"class":129,"line":177},[127,11611,11566],{"class":4518},[127,11613,4660],{"class":4514},[127,11615,7396],{"class":4518},[127,11617,4660],{"class":4514},[127,11619,5017],{"class":4618},[127,11621,4666],{"class":4518},[127,11623,4676],{"class":4514},[127,11625,11626,11628],{"class":129,"line":183},[127,11627,9362],{"class":4518},[127,11629,4676],{"class":4514},[127,11631,11632,11635,11637],{"class":129,"line":189},[127,11633,11634],{"class":4639}," transports",[127,11636,4643],{"class":4514},[127,11638,11639],{"class":4518}," [\n",[127,11641,11642,11645,11647,11649,11652,11654,11657,11659,11661,11664,11666,11668,11671,11673,11675,11678,11680,11682,11684,11686,11688,11690],{"class":129,"line":195},[127,11643,11644],{"class":4514}," new",[127,11646,11501],{"class":4518},[127,11648,4660],{"class":4514},[127,11650,11651],{"class":4518},"transports",[127,11653,4660],{"class":4514},[127,11655,11656],{"class":4618},"File",[127,11658,4621],{"class":4518},[127,11660,6938],{"class":4514},[127,11662,11663],{"class":4639}," filename",[127,11665,4643],{"class":4514},[127,11667,4544],{"class":4514},[127,11669,11670],{"class":4547},"error.log",[127,11672,4624],{"class":4514},[127,11674,4522],{"class":4514},[127,11676,11677],{"class":4639}," level",[127,11679,4643],{"class":4514},[127,11681,4544],{"class":4514},[127,11683,9704],{"class":4547},[127,11685,4624],{"class":4514},[127,11687,4538],{"class":4514},[127,11689,4657],{"class":4518},[127,11691,4676],{"class":4514},[127,11693,11694,11696,11698,11700,11702,11704,11706,11708,11710,11712,11714,11716,11719,11721,11723,11725],{"class":129,"line":29},[127,11695,11644],{"class":4514},[127,11697,11501],{"class":4518},[127,11699,4660],{"class":4514},[127,11701,11651],{"class":4518},[127,11703,4660],{"class":4514},[127,11705,11656],{"class":4618},[127,11707,4621],{"class":4518},[127,11709,6938],{"class":4514},[127,11711,11663],{"class":4639},[127,11713,4643],{"class":4514},[127,11715,4544],{"class":4514},[127,11717,11718],{"class":4547},"combined.log",[127,11720,4624],{"class":4514},[127,11722,4538],{"class":4514},[127,11724,4657],{"class":4518},[127,11726,4676],{"class":4514},[127,11728,11729,11732,11734,11736,11738,11740,11742,11744,11746,11748],{"class":129,"line":207},[127,11730,11731],{"class":4514}," ...",[127,11733,6481],{"class":4518},[127,11735,4660],{"class":4514},[127,11737,9787],{"class":4518},[127,11739,4660],{"class":4514},[127,11741,10068],{"class":4518},[127,11743,10071],{"class":4514},[127,11745,4544],{"class":4514},[127,11747,6433],{"class":4547},[127,11749,4551],{"class":4514},[127,11751,11752,11755],{"class":129,"line":213},[127,11753,11754],{"class":4514}," ?",[127,11756,11639],{"class":4518},[127,11758,11759,11761,11763,11765,11767,11769,11772,11774],{"class":129,"line":219},[127,11760,11112],{"class":4514},[127,11762,11501],{"class":4518},[127,11764,4660],{"class":4514},[127,11766,11651],{"class":4518},[127,11768,4660],{"class":4514},[127,11770,11771],{"class":4618},"Console",[127,11773,4621],{"class":4518},[127,11775,5150],{"class":4514},[127,11777,11778,11781,11783,11785,11787,11789,11791,11794,11796],{"class":129,"line":225},[127,11779,11780],{"class":4639}," format",[127,11782,4643],{"class":4514},[127,11784,11501],{"class":4518},[127,11786,4660],{"class":4514},[127,11788,7396],{"class":4518},[127,11790,4660],{"class":4514},[127,11792,11793],{"class":4618},"simple",[127,11795,4666],{"class":4518},[127,11797,4676],{"class":4514},[127,11799,11800,11803,11805],{"class":129,"line":231},[127,11801,11802],{"class":4514}," }",[127,11804,4657],{"class":4518},[127,11806,4676],{"class":4514},[127,11808,11809],{"class":129,"line":237},[127,11810,11811],{"class":4518}," ]\n",[127,11813,11814,11817,11820],{"class":129,"line":243},[127,11815,11816],{"class":4514}," :",[127,11818,11819],{"class":4518}," [])",[127,11821,4676],{"class":4514},[127,11823,11824,11827],{"class":129,"line":249},[127,11825,11826],{"class":4518}," ]",[127,11828,4676],{"class":4514},[127,11830,11831,11833],{"class":129,"line":254},[127,11832,4780],{"class":4514},[127,11834,4783],{"class":4518},[99,11836,11838],{"id":11837},"testing-strategy","Testing Strategy",[112,11840,11842],{"id":11841},"unit-tests-with-jest","Unit Tests with Jest",[117,11844,11846],{"className":4424,"code":11845,"language":4426,"meta":122,"style":122},"// src/services/__tests__/UserService.test.ts\nimport { UserService } from \"../UserService\"\nimport { UserRepository } from \"../../repositories/UserRepository\"\n\njest.mock(\"../../repositories/UserRepository\")\n\ndescribe(\"UserService\", () => {\n let userService: UserService\n let mockUserRepository: jest.Mocked\n\n beforeEach(() => {\n mockUserRepository = new UserRepository() as jest.Mocked\n userService = new UserService(mockUserRepository)\n })\n\n it(\"should create user successfully\", async () => {\n const userData = {\n email: \"test@example.com\",\n name: \"Test User\",\n password: \"password123\",\n }\n\n mockUserRepository.create.mockResolvedValue({\n id: \"1\",\n ...userData,\n createdAt: new Date(),\n updatedAt: new Date(),\n })\n\n const result = await userService.createUser(userData)\n\n expect(result).toBeDefined()\n expect(result.email).toBe(userData.email)\n expect(mockUserRepository.create).toHaveBeenCalledWith(userData)\n })\n})\n",[124,11847,11848,11853,11872,11891,11895,11914,11918,11940,11952,11976,11980,11993,12020,12038,12044,12048,12072,12083,12099,12115,12131,12135,12139,12156,12171,12180,12195,12210,12216,12220,12243,12247,12266,12295,12320,12326],{"__ignoreMap":122},[127,11849,11850],{"class":129,"line":130},[127,11851,11852],{"class":4433},"// src/services/__tests__/UserService.test.ts\n",[127,11854,11855,11857,11859,11861,11863,11865,11867,11870],{"class":129,"line":136},[127,11856,4511],{"class":4510},[127,11858,4515],{"class":4514},[127,11860,10736],{"class":4518},[127,11862,4538],{"class":4514},[127,11864,4541],{"class":4510},[127,11866,4544],{"class":4514},[127,11868,11869],{"class":4547},"../UserService",[127,11871,4551],{"class":4514},[127,11873,11874,11876,11878,11880,11882,11884,11886,11889],{"class":129,"line":16},[127,11875,4511],{"class":4510},[127,11877,4515],{"class":4514},[127,11879,10170],{"class":4518},[127,11881,4538],{"class":4514},[127,11883,4541],{"class":4510},[127,11885,4544],{"class":4514},[127,11887,11888],{"class":4547},"../../repositories/UserRepository",[127,11890,4551],{"class":4514},[127,11892,11893],{"class":129,"line":147},[127,11894,199],{"emptyLinePlaceholder":198},[127,11896,11897,11899,11901,11904,11906,11908,11910,11912],{"class":129,"line":153},[127,11898,9072],{"class":4518},[127,11900,4660],{"class":4514},[127,11902,11903],{"class":4618},"mock",[127,11905,4621],{"class":4518},[127,11907,4624],{"class":4514},[127,11909,11888],{"class":4547},[127,11911,4624],{"class":4514},[127,11913,4783],{"class":4518},[127,11915,11916],{"class":129,"line":159},[127,11917,199],{"emptyLinePlaceholder":198},[127,11919,11920,11923,11925,11927,11930,11932,11934,11936,11938],{"class":129,"line":165},[127,11921,11922],{"class":4618},"describe",[127,11924,4621],{"class":4518},[127,11926,4624],{"class":4514},[127,11928,11929],{"class":4547},"UserService",[127,11931,4624],{"class":4514},[127,11933,4522],{"class":4514},[127,11935,5548],{"class":4514},[127,11937,5041],{"class":4608},[127,11939,4634],{"class":4514},[127,11941,11942,11945,11947,11949],{"class":129,"line":171},[127,11943,11944],{"class":4608}," let",[127,11946,10897],{"class":4518},[127,11948,4643],{"class":4514},[127,11950,11951],{"class":4842}," UserService\n",[127,11953,11954,11956,11959,11961,11964,11966,11969,11971,11974],{"class":129,"line":177},[127,11955,11944],{"class":4608},[127,11957,11958],{"class":4518}," mockUserRepository",[127,11960,4643],{"class":4514},[127,11962,11963],{"class":4842}," jest",[127,11965,4660],{"class":4514},[127,11967,11968],{"class":4842},"Mocked",[127,11970,5359],{"class":4514},[127,11972,11973],{"class":4842},"UserRepository",[127,11975,5772],{"class":4514},[127,11977,11978],{"class":129,"line":183},[127,11979,199],{"emptyLinePlaceholder":198},[127,11981,11982,11985,11987,11989,11991],{"class":129,"line":189},[127,11983,11984],{"class":4618}," beforeEach",[127,11986,4621],{"class":4639},[127,11988,4666],{"class":4514},[127,11990,5041],{"class":4608},[127,11992,4634],{"class":4514},[127,11994,11995,11998,12000,12002,12004,12006,12008,12010,12012,12014,12016,12018],{"class":129,"line":195},[127,11996,11997],{"class":4518}," mockUserRepository",[127,11999,4846],{"class":4514},[127,12001,4973],{"class":4514},[127,12003,10170],{"class":4618},[127,12005,6958],{"class":4639},[127,12007,5948],{"class":4510},[127,12009,11963],{"class":4842},[127,12011,4660],{"class":4514},[127,12013,11968],{"class":4842},[127,12015,5359],{"class":4514},[127,12017,11973],{"class":4842},[127,12019,5772],{"class":4514},[127,12021,12022,12025,12027,12029,12031,12033,12036],{"class":129,"line":29},[127,12023,12024],{"class":4518}," userService",[127,12026,4846],{"class":4514},[127,12028,4973],{"class":4514},[127,12030,10736],{"class":4618},[127,12032,4621],{"class":4639},[127,12034,12035],{"class":4518},"mockUserRepository",[127,12037,4783],{"class":4639},[127,12039,12040,12042],{"class":129,"line":207},[127,12041,5228],{"class":4514},[127,12043,4783],{"class":4639},[127,12045,12046],{"class":129,"line":213},[127,12047,199],{"emptyLinePlaceholder":198},[127,12049,12050,12053,12055,12057,12060,12062,12064,12066,12068,12070],{"class":129,"line":219},[127,12051,12052],{"class":4618}," it",[127,12054,4621],{"class":4639},[127,12056,4624],{"class":4514},[127,12058,12059],{"class":4547},"should create user successfully",[127,12061,4624],{"class":4514},[127,12063,4522],{"class":4514},[127,12065,5029],{"class":4608},[127,12067,5548],{"class":4514},[127,12069,5041],{"class":4608},[127,12071,4634],{"class":4514},[127,12073,12074,12076,12079,12081],{"class":129,"line":225},[127,12075,6985],{"class":4608},[127,12077,12078],{"class":4518}," userData",[127,12080,4846],{"class":4514},[127,12082,4634],{"class":4514},[127,12084,12085,12088,12090,12092,12095,12097],{"class":129,"line":231},[127,12086,12087],{"class":4639}," email",[127,12089,4643],{"class":4514},[127,12091,4544],{"class":4514},[127,12093,12094],{"class":4547},"test@example.com",[127,12096,4624],{"class":4514},[127,12098,4676],{"class":4514},[127,12100,12101,12104,12106,12108,12111,12113],{"class":129,"line":237},[127,12102,12103],{"class":4639}," name",[127,12105,4643],{"class":4514},[127,12107,4544],{"class":4514},[127,12109,12110],{"class":4547},"Test User",[127,12112,4624],{"class":4514},[127,12114,4676],{"class":4514},[127,12116,12117,12120,12122,12124,12127,12129],{"class":129,"line":243},[127,12118,12119],{"class":4639}," password",[127,12121,4643],{"class":4514},[127,12123,4544],{"class":4514},[127,12125,12126],{"class":4547},"password123",[127,12128,4624],{"class":4514},[127,12130,4676],{"class":4514},[127,12132,12133],{"class":129,"line":249},[127,12134,1267],{"class":4514},[127,12136,12137],{"class":129,"line":254},[127,12138,199],{"emptyLinePlaceholder":198},[127,12140,12141,12143,12145,12147,12149,12152,12154],{"class":129,"line":259},[127,12142,11997],{"class":4518},[127,12144,4660],{"class":4514},[127,12146,8139],{"class":4518},[127,12148,4660],{"class":4514},[127,12150,12151],{"class":4618},"mockResolvedValue",[127,12153,4621],{"class":4639},[127,12155,5150],{"class":4514},[127,12157,12158,12161,12163,12165,12167,12169],{"class":129,"line":265},[127,12159,12160],{"class":4639}," id",[127,12162,4643],{"class":4514},[127,12164,4544],{"class":4514},[127,12166,6398],{"class":4547},[127,12168,4624],{"class":4514},[127,12170,4676],{"class":4514},[127,12172,12173,12175,12178],{"class":129,"line":270},[127,12174,9777],{"class":4514},[127,12176,12177],{"class":4518},"userData",[127,12179,4676],{"class":4514},[127,12181,12182,12185,12187,12189,12191,12193],{"class":129,"line":276},[127,12183,12184],{"class":4639}," createdAt",[127,12186,4643],{"class":4514},[127,12188,4973],{"class":4514},[127,12190,5192],{"class":4618},[127,12192,4666],{"class":4639},[127,12194,4676],{"class":4514},[127,12196,12197,12200,12202,12204,12206,12208],{"class":129,"line":282},[127,12198,12199],{"class":4639}," updatedAt",[127,12201,4643],{"class":4514},[127,12203,4973],{"class":4514},[127,12205,5192],{"class":4618},[127,12207,4666],{"class":4639},[127,12209,4676],{"class":4514},[127,12211,12212,12214],{"class":129,"line":288},[127,12213,5731],{"class":4514},[127,12215,4783],{"class":4639},[127,12217,12218],{"class":129,"line":294},[127,12219,199],{"emptyLinePlaceholder":198},[127,12221,12222,12224,12227,12229,12231,12233,12235,12237,12239,12241],{"class":129,"line":300},[127,12223,6985],{"class":4608},[127,12225,12226],{"class":4518}," result",[127,12228,4846],{"class":4514},[127,12230,5097],{"class":4510},[127,12232,10897],{"class":4518},[127,12234,4660],{"class":4514},[127,12236,10999],{"class":4618},[127,12238,4621],{"class":4639},[127,12240,12177],{"class":4518},[127,12242,4783],{"class":4639},[127,12244,12245],{"class":129,"line":306},[127,12246,199],{"emptyLinePlaceholder":198},[127,12248,12249,12252,12254,12257,12259,12261,12264],{"class":129,"line":312},[127,12250,12251],{"class":4618}," expect",[127,12253,4621],{"class":4639},[127,12255,12256],{"class":4518},"result",[127,12258,4657],{"class":4639},[127,12260,4660],{"class":4514},[127,12262,12263],{"class":4618},"toBeDefined",[127,12265,4978],{"class":4639},[127,12267,12268,12270,12272,12274,12276,12278,12280,12282,12285,12287,12289,12291,12293],{"class":129,"line":318},[127,12269,12251],{"class":4618},[127,12271,4621],{"class":4639},[127,12273,12256],{"class":4518},[127,12275,4660],{"class":4514},[127,12277,4692],{"class":4518},[127,12279,4657],{"class":4639},[127,12281,4660],{"class":4514},[127,12283,12284],{"class":4618},"toBe",[127,12286,4621],{"class":4639},[127,12288,12177],{"class":4518},[127,12290,4660],{"class":4514},[127,12292,4692],{"class":4518},[127,12294,4783],{"class":4639},[127,12296,12297,12299,12301,12303,12305,12307,12309,12311,12314,12316,12318],{"class":129,"line":324},[127,12298,12251],{"class":4618},[127,12300,4621],{"class":4639},[127,12302,12035],{"class":4518},[127,12304,4660],{"class":4514},[127,12306,8139],{"class":4518},[127,12308,4657],{"class":4639},[127,12310,4660],{"class":4514},[127,12312,12313],{"class":4618},"toHaveBeenCalledWith",[127,12315,4621],{"class":4639},[127,12317,12177],{"class":4518},[127,12319,4783],{"class":4639},[127,12321,12322,12324],{"class":129,"line":329},[127,12323,5228],{"class":4514},[127,12325,4783],{"class":4639},[127,12327,12328,12330],{"class":129,"line":334},[127,12329,4780],{"class":4514},[127,12331,4783],{"class":4518},[99,12333,4261],{"id":4260},[104,12335,12336],{},"TypeScript in Node.js production environments requires attention to build processes, error handling, and type safety. The investment in proper setup pays dividends in maintainability, developer experience, and runtime reliability.",[104,12338,12339],{},"Key takeaways:",[4386,12341,12342,12345,12348,12351,12354],{},[4269,12343,12344],{},"Use strict TypeScript configuration",[4269,12346,12347],{},"Implement proper error handling with custom error classes",[4269,12349,12350],{},"Leverage type-safe database access patterns",[4269,12352,12353],{},"Optimize for both development and production builds",[4269,12355,12356],{},"Maintain comprehensive testing coverage",[104,12358,12359],{},"With these practices, you'll build robust, scalable Node.js applications that are a joy to maintain and extend.",[8221,12361],{},[99,12363,12365],{"id":12364},"continue-your-typescript-journey","Continue Your TypeScript Journey",[104,12367,12368,12369,12371],{},"This post is part 2 of the ",[4272,12370,8275],{}," series. Continue learning:",[4266,12373,12374,12384,12398],{},[4269,12375,12376,12383],{},[4272,12377,12378],{},[12379,12380,12382],"a",{"href":12381},"/blog/2-my-vscode-setup","My VSCode Setup"," - Development environment setup",[4269,12385,12386,12392,12393,12397],{},[4272,12387,12388],{},[12379,12389,12391],{"href":12390},"/blog/6-typescript-nodejs-production-guide","TypeScript + Node.js in Production"," ",[12394,12395,12396],"em",{},"(You are here)"," - Building production-ready TypeScript applications",[4269,12399,12400,12406],{},[4272,12401,12402],{},[12379,12403,12405],{"href":12404},"/blog/11-typescript-advanced-patterns","Advanced TypeScript Patterns"," - Enterprise-level TypeScript patterns and techniques",[4310,12408,12409],{},"html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sHwdD, html code.shiki .sHwdD{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#546E7A;--shiki-default-font-style:italic;--shiki-dark:#676E95;--shiki-dark-font-style:italic}html pre.shiki code .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .s7zQu, html code.shiki .s7zQu{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#89DDFF;--shiki-default-font-style:italic;--shiki-dark:#89DDFF;--shiki-dark-font-style:italic}html pre.shiki code .swJcz, html code.shiki .swJcz{--shiki-light:#E53935;--shiki-default:#F07178;--shiki-dark:#F07178}html pre.shiki code .sHdIc, html code.shiki .sHdIc{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#EEFFFF;--shiki-default-font-style:italic;--shiki-dark:#BABED8;--shiki-dark-font-style:italic}html pre.shiki code .sfNiH, html code.shiki .sfNiH{--shiki-light:#FF5370;--shiki-default:#FF9CAC;--shiki-dark:#FF9CAC}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}",{"title":122,"searchDepth":136,"depth":136,"links":12411},[12412,12413,12417,12421,12425,12429,12433,12437,12440,12443,12444],{"id":8293,"depth":136,"text":8288},{"id":8299,"depth":136,"text":8300,"children":12414},[12415,12416],{"id":8303,"depth":16,"text":8304},{"id":8530,"depth":16,"text":8531},{"id":8905,"depth":136,"text":8906,"children":12418},[12419,12420],{"id":8909,"depth":16,"text":8910},{"id":9085,"depth":16,"text":9086},{"id":9242,"depth":136,"text":9243,"children":12422},[12423,12424],{"id":9246,"depth":16,"text":9247},{"id":9565,"depth":16,"text":9566},{"id":9937,"depth":136,"text":9938,"children":12426},[12427,12428],{"id":9941,"depth":16,"text":9942},{"id":10103,"depth":16,"text":10104},{"id":10489,"depth":136,"text":10490,"children":12430},[12431,12432],{"id":10493,"depth":16,"text":10494},{"id":10672,"depth":16,"text":10673},{"id":11191,"depth":136,"text":11192,"children":12434},[12435,12436],{"id":11195,"depth":16,"text":11196},{"id":11306,"depth":16,"text":11307},{"id":11451,"depth":136,"text":11452,"children":12438},[12439],{"id":11455,"depth":16,"text":11456},{"id":11837,"depth":136,"text":11838,"children":12441},[12442],{"id":11841,"depth":16,"text":11842},{"id":4260,"depth":136,"text":4261},{"id":12364,"depth":136,"text":12365},"2024-02-28","Learn how to build, deploy, and maintain TypeScript Node.js applications in production environments with best practices and real-world examples.","/img/blog/6-typescript-nodejs-production-guide/banner.svg",{"readingTime":12449},"18 min read",{"title":8288,"description":12446},"Master TypeScript from development setup to advanced enterprise patterns","blog/6-typescript-nodejs-production-guide",[8282,12454,4363,12455],"Node.js","Production","qfyychSTx6Wbs307TObROpK4RV8jhDc7CO-J4T2fblw",["Reactive",12458],{"$scolor-mode":12459,"$snuxt-seo-utils:routeRules":12461,"$stoasts":12462,"$ssite-config":12463},{"preference":12460,"value":12460,"unknown":198,"forced":4347},"system",{"head":-1,"seoMeta":-1},[],{"_priority":12464,"defaultLocale":12467,"description":12468,"env":6433,"indexable":198,"name":12469,"url":12470},{"env":12465,"indexable":12466,"url":12466,"name":12466,"description":12466,"defaultLocale":12466},-15,-3,"en","Senior Software Engineer specializing in modern web technologies. Crafting scalable web applications and browser extensions for startups and founders.","Muhammad Ubaid Raza - Full Stack Engineer","https://mubaidr.js.org",["Set"],["ShallowReactive",12473],{"blog-post-/blog/13-graphql-api-design-patterns":-1,"profile-data":-1,"related-posts-/blog/13-graphql-api-design-patterns":-1}]