Skip to content

Scoped Service - Scope-Based Instance

Scoped services that share the same instance within a specific scope.

🎯 What is it?

Scoped scope ensures that the service has a single instance within a specific scope. Different instances are created in different scopes.

📦 Usage

typescript
import { xscoped } from '@xcons/widget';

@xscoped()
export class RequestService {
  private requestId = Date.now();

  getRequestId() {
    return this.requestId;
  }
}

💡 When to Use?

  • Request Context: Separate context for each request
  • Session Management: Session-based data
  • Transaction: Transaction-based scope
  • User Context: User-based context
  • Temporary State: Temporary state management

📋 Examples

Request Context

typescript
@xscoped()
export class RequestContext {
  private context = {
    requestId: Date.now(),
    userId: null,
    timestamp: new Date()
  };

  setUserId(userId: string) {
    this.context.userId = userId;
  }

  getContext() {
    return this.context;
  }
}

Transaction Service

typescript
@xscoped()
export class TransactionService {
  private transactionId = `tx-${Date.now()}`;
  private operations: string[] = [];

  addOperation(op: string) {
    this.operations.push(op);
  }

  commit() {
    console.log(`Committing ${this.transactionId}:`, this.operations);
    this.operations = [];
  }

  rollback() {
    console.log(`Rolling back ${this.transactionId}`);
    this.operations = [];
  }
}

User Session

typescript
@xscoped()
export class UserSession {
  private sessionData = {
    userId: null,
    permissions: [],
    loginTime: Date.now()
  };

  setUser(userId: string, permissions: string[]) {
    this.sessionData.userId = userId;
    this.sessionData.permissions = permissions;
  }

  hasPermission(permission: string) {
    return this.sessionData.permissions.includes(permission);
  }

  getSessionDuration() {
    return Date.now() - this.sessionData.loginTime;
  }
}

Scoped Cache

typescript
@xscoped()
export class ScopedCache {
  private cache = new Map<string, any>();
  private scopeId = Math.random();

  set(key: string, value: any) {
    this.cache.set(key, value);
  }

  get(key: string) {
    return this.cache.get(key);
  }

  getScopeId() {
    return this.scopeId;
  }

  clear() {
    this.cache.clear();
  }
}

🔧 Scope Management

Scope Cleanup

typescript
import { ServiceRegistry } from '@xcons/widget';

const registry = ServiceRegistry.getInstance();

// Clear scoped services
registry.clearScope('scoped');

// onServiceDestroy is called automatically

Usage with Lifecycle

typescript
@xscoped()
export class ScopedResource implements OnServiceInit, OnServiceDestroy {
  private resourceId = `resource-${Date.now()}`;

  onServiceInit() {
    console.log(`${this.resourceId} initialized`);
  }

  onServiceDestroy() {
    console.log(`${this.resourceId} cleaning up`);
  }
}

📊 Behavior

typescript
@xscoped()
class MyService {
  value = Math.random();
}

// Same instance within the same scope
const service1 = injector.inject(MyService);
const service2 = injector.inject(MyService);
console.log(service1 === service2); // true

// Clear scope
registry.clearScope('scoped');

// New instance in new scope
const service3 = injector.inject(MyService);
console.log(service1 === service3); // false

🔄 Usage Scenario

HTTP Request Pipeline

typescript
// New scope for each request
@xscoped()
export class RequestPipeline {
  private steps: string[] = [];

  addStep(step: string) {
    this.steps.push(step);
  }

  async execute() {
    for (const step of this.steps) {
      console.log(`Executing: ${step}`);
      await this.executeStep(step);
    }
  }

  private async executeStep(step: string) {
    // Step execution logic
  }
}

// Usage in middleware
app.use((req, res, next) => {
  // New scope at request start
  const pipeline = injector.inject(RequestPipeline);
  pipeline.addStep('auth');
  pipeline.addStep('validate');
  
  // Clear scope at request end
  res.on('finish', () => {
    registry.clearScope('scoped');
  });
  
  next();
});

⚠️ Points to Consider

  • Scope must be manually cleared
  • Same instance within each scope
  • onServiceDestroy is called when scope is cleared
  • Requires more control than Singleton and Transient

✨ Summary

  • Same instance scope-based
  • ✅ Manual scope management
  • ✅ Ideal for Request/Session context
  • ✅ Isolated state managemen