Full-Stack Demo: User Service

A complete backend service with typed endpoints - save this first!

TjsCompat
/#
## User Service

A complete backend service running in the browser.
Save this module as "user-service", then run the client example.

Features:
- Type-safe endpoints with validation
- In-memory data store
- Full CRUD operations
#/

// In-memory store (would be a real DB in production)
const users = new Map()
let nextId = 1

// Create a new user
export function createUser(input: {
  name: 'Alice',
  email: 'alice@example.com'
}):! { id: 0, name: '', email: '', createdAt: '' } {
  const user = {
    id: nextId++,
    name: input.name,
    email: input.email,
    createdAt: new Date().toISOString()
  }
  users.set(user.id, user)
  return user
}

// Get user by ID (returns empty object if not found - union types not yet supported)
export function getUser(input: { id: 1 }):! { id: 0, name: '', email: '', createdAt: '' } {
  return users.get(input.id) || { id: 0, name: '', email: '', createdAt: '' }
}

// Update a user (returns empty object if not found - union types not yet supported)
export function updateUser(input: {
  id: 1,
  name: 'Alice',
  email: 'alice@example.com'
}):! { id: 0, name: '', email: '', createdAt: '' } {
  const existing = users.get(input.id)
  if (!existing) return { id: 0, name: '', email: '', createdAt: '' }

  const updated = { ...existing, name: input.name, email: input.email }
  users.set(input.id, updated)
  return updated
}

// Delete a user
export function deleteUser(input: { id: 1 }):! { success: true, deleted: 0 } {
  const existed = users.has(input.id)
  users.delete(input.id)
  return { success: existed, deleted: existed ? input.id : 0 }
}

// List all users
export function listUsers(input: { limit: 10, offset: 0 }):! { users: [{ id: 0, name: '', email: '', createdAt: '' }], total: 0 } {
  const all = [...users.values()]
  const slice = all.slice(input.offset, input.offset + input.limit)
  return { users: slice, total: all.length }
}

// Search users by name
export function searchUsers(input: { query: '' }):! { users: [{ id: 0, name: '', email: '', createdAt: '' }] } {
  const query = input.query.toLowerCase()
  const matches = [...users.values()].filter(u =>
    u.name.toLowerCase().includes(query)
  )
  return { users: matches }
}

// Test the service
test('createUser creates user with ID') {
  const user = createUser({ name: 'Test', email: 'test@test.com' })
  expect(user.id).toBeGreaterThan(0)
  expect(user.name).toBe('Test')
}

test('getUser returns created user') {
  const created = createUser({ name: 'Bob', email: 'bob@test.com' })
  const fetched = getUser({ id: created.id })
  expect(fetched?.name).toBe('Bob')
}

test('updateUser modifies user') {
  const user = createUser({ name: 'Original', email: 'orig@test.com' })
  const updated = updateUser({ id: user.id, name: 'Updated', email: 'new@test.com' })
  expect(updated?.name).toBe('Updated')
}

test('deleteUser removes user') {
  const user = createUser({ name: 'ToDelete', email: 'del@test.com' })
  const result = deleteUser({ id: user.id })
  expect(result.success).toBe(true)
  // getUser returns empty object when not found (not null)
  expect(getUser({ id: user.id }).name).toBe('')
}

// Demo
console.log('=== User Service Demo ===\\n')

const alice = createUser({ name: 'Alice', email: 'alice@company.com' })
console.log('Created:', alice)

const bob = createUser({ name: 'Bob', email: 'bob@company.com' })
console.log('Created:', bob)

const carol = createUser({ name: 'Carol', email: 'carol@company.com' })
console.log('Created:', carol)

console.log('\\nAll users:', listUsers({ limit: 10, offset: 0 }))
console.log('\\nSearch "ob":', searchUsers({ query: 'ob' }))

// Type validation in action (safe mode catches wrong types)
console.log('\\nType validation test:')
console.log('createUser({ name: 123 }) would return a type error in safe mode')