or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

application.mdbase-classes.mdconfiguration.mdcontext.mdhttp-client.mdindex.mdloaders-errors.mdstartup.md
tile.json

base-classes.mddocs/

Base Classes & Components

Foundation classes for building controllers, services, subscriptions, and utility components in Egg.js applications.

Capabilities

BaseContextClass

Base class that provides context-aware functionality for controllers, services, and other context-bound components.

/**
 * BaseContextClass is a base class that can be extended for context-aware components
 * It's instantiated at the context level and provides access to app and ctx
 */
class BaseContextClass extends EggCoreBaseContextClass {
  /** Request context instance */
  ctx: Context;
  
  /** Application instance */
  app: EggApplicationCore;
  
  /** Service container */
  service: BaseContextClass;
  
  /** Component path name for logging */
  pathName?: string;
  
  /** Context-aware logger */
  get logger(): BaseContextLogger;
}

Usage Examples:

// Controller example
export default class UserController extends BaseContextClass {
  async show() {
    const { ctx, app } = this;
    const userId = ctx.params.id;
    
    // Access services through context
    const user = await ctx.service.user.findById(userId);
    
    // Use logger with automatic context information
    this.logger.info('User viewed: %s', userId);
    
    ctx.body = { user };
  }
}

// Service example
export default class UserService extends BaseContextClass {
  async findById(id: string) {
    const { ctx } = this;
    
    // Access database through app
    const user = await this.app.mysql.get('users', { id });
    
    if (!user) {
      this.logger.warn('User not found: %s', id);
      ctx.throw(404, 'User not found');
    }
    
    return user;
  }
  
  async create(userData: CreateUserData) {
    const { ctx, app } = this;
    
    // Validate using context helpers
    ctx.validate(userCreateRule, userData);
    
    // Use logger with service context
    this.logger.info('Creating user: %s', userData.email);
    
    const user = await app.mysql.insert('users', userData);
    return user;
  }
}

Controller Class

Alias for BaseContextClass specifically for controllers.

/**
 * Controller class - alias for BaseContextClass
 * Used for handling HTTP requests and responses
 */
const Controller = BaseContextClass;

Usage Examples:

import { Controller } from 'egg';

export default class HomeController extends Controller {
  async index() {
    const { ctx } = this;
    
    // Access request data
    const { page = 1, limit = 10 } = ctx.query;
    
    // Use services
    const posts = await ctx.service.post.list({ page, limit });
    
    // Set response
    ctx.body = {
      posts,
      pagination: {
        page: Number(page),
        limit: Number(limit),
        total: posts.length
      }
    };
    
    // Log request
    this.logger.info('Home page requested with page=%s, limit=%s', page, limit);
  }
}

Service Class

Alias for BaseContextClass specifically for services.

/**
 * Service class - alias for BaseContextClass
 * Used for business logic and data access
 */
const Service = BaseContextClass;

Usage Examples:

import { Service } from 'egg';

export default class PostService extends Service {
  async list(options: { page: number; limit: number }) {
    const { ctx, app } = this;
    const { page, limit } = options;
    
    // Calculate offset
    const offset = (page - 1) * limit;
    
    // Database query
    const posts = await app.mysql.select('posts', {
      where: { status: 'published' },
      orders: [['created_at', 'desc']],
      limit,
      offset
    });
    
    // Log operation
    this.logger.info('Listed %d posts (page %d)', posts.length, page);
    
    return posts;
  }
  
  async create(postData: CreatePostData) {
    const { ctx, app } = this;
    
    // Validate data
    const errors = await ctx.validate(postCreateRule, postData);
    if (errors) {
      ctx.throw(422, 'Validation failed', { errors });
    }
    
    // Create post
    const result = await app.mysql.insert('posts', {
      ...postData,
      created_at: new Date(),
      updated_at: new Date()
    });
    
    this.logger.info('Created post: %s', result.insertId);
    return result;
  }
}

Subscription Class

Alias for BaseContextClass specifically for scheduled tasks and subscriptions.

/**
 * Subscription class - alias for BaseContextClass
 * Used for scheduled tasks and background subscriptions
 */
const Subscription = BaseContextClass;

Usage Examples:

import { Subscription } from 'egg';

export default class CleanupSubscription extends Subscription {
  // Subscription configuration
  static get schedule() {
    return {
      cron: '0 2 * * *', // Run at 2 AM daily
      type: 'worker',    // Run on all workers
      env: ['prod']      // Only in production
    };
  }
  
  async subscribe() {
    const { ctx, app } = this;
    
    this.logger.info('Starting cleanup job');
    
    try {
      // Clean expired sessions
      await app.redis.del('session:*:expired');
      
      // Clean old logs
      const cutoffDate = new Date(Date.now() - 30 * 24 * 60 * 60 * 1000);
      await app.mysql.delete('logs', {
        created_at: { $lt: cutoffDate }
      });
      
      this.logger.info('Cleanup job completed successfully');
    } catch (error) {
      this.logger.error('Cleanup job failed:', error);
      throw error;
    }
  }
}

Helper Class

Utility class providing common helper functions accessible via context.

/**
 * Helper class providing utility functions
 * Available as ctx.helper in all context-aware components
 */
class Helper extends BaseContextClass {
  /**
   * Generate URL path for route name and parameters
   * @param name - Router route name
   * @param params - Route parameters and query string
   * @returns URL path without host
   */
  pathFor(name: string, params: Record<string, any>): string;
  
  /**
   * Generate full URL for route name and parameters
   * @param name - Router route name
   * @param params - Route parameters and query string
   * @returns Full URL with host
   */
  urlFor(name: string, params: Record<string, any>): string;
}

Usage Examples:

// In controller
export default class LinkController extends Controller {
  async generateLinks() {
    const { ctx } = this;
    
    // Generate path (relative URL)
    const profilePath = ctx.helper.pathFor('user.profile', {
      id: 123,
      tab: 'settings'
    });
    // Result: /user/123/profile?tab=settings
    
    // Generate full URL
    const profileUrl = ctx.helper.urlFor('user.profile', {
      id: 123,
      tab: 'settings'
    });
    // Result: http://localhost:7001/user/123/profile?tab=settings
    
    ctx.body = {
      profilePath,
      profileUrl
    };
  }
}

// In service or other components
export default class EmailService extends Service {
  async sendPasswordReset(user: User) {
    const { ctx } = this;
    
    // Generate reset link
    const resetUrl = ctx.helper.urlFor('auth.reset', {
      token: user.resetToken
    });
    
    await this.sendEmail(user.email, 'Password Reset', {
      resetUrl,
      userName: user.name
    });
    
    this.logger.info('Sent password reset email to %s', user.email);
  }
}

Custom Helper Extensions

Helpers can be extended in your application for project-specific utilities.

Usage Examples:

// app/extend/helper.js - Application helper extensions
export default {
  // Format currency
  formatCurrency(amount: number, currency = 'USD') {
    return new Intl.NumberFormat('en-US', {
      style: 'currency',
      currency
    }).format(amount);
  },
  
  // Generate secure token
  generateToken(length = 32) {
    const { ctx } = this;
    return ctx.app.crypto.randomBytes(length).toString('hex');
  },
  
  // Sanitize HTML
  sanitizeHtml(html: string) {
    // Use sanitization library
    return sanitize(html);
  }
};

// Usage in controllers
export default class ProductController extends Controller {
  async show() {
    const { ctx } = this;
    const product = await ctx.service.product.findById(ctx.params.id);
    
    ctx.body = {
      ...product,
      formattedPrice: ctx.helper.formatCurrency(product.price),
      safeDescription: ctx.helper.sanitizeHtml(product.description)
    };
  }
}

Types

interface BaseContextLogger {
  info(message: string, ...args: any[]): void;
  warn(message: string, ...args: any[]): void;
  error(message: string, ...args: any[]): void;
  debug(message: string, ...args: any[]): void;
}

interface CreateUserData {
  name: string;
  email: string;
  password: string;
}

interface CreatePostData {
  title: string;
  content: string;
  status: 'draft' | 'published';
  author_id: number;
}