File size: 3,086 Bytes
35743bd
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
/**
 * Simple DI Container — Factory-pattern service locator
 *
 * Provides a lightweight dependency injection container using factory
 * functions (no heavy frameworks). Services are lazily instantiated
 * and cached as singletons.
 *
 * Usage:
 *   import { container } from '@/lib/container';
 *   const settings = container.resolve('settings');
 *
 * Registration:
 *   container.register('myService', () => new MyService());
 *
 * @module lib/container
 */

import { evaluateFirstAllowed, evaluateRequest, PolicyEngine } from "../domain/policyEngine.ts";
import { getDbInstance } from "./db/core.ts";
import {
  decrypt,
  decryptConnectionFields,
  encrypt,
  encryptConnectionFields,
} from "./db/encryption.ts";
import { getSettings } from "./localDb.ts";
import { getCircuitBreaker } from "../shared/utils/circuitBreaker.ts";
import { recordTelemetry, RequestTelemetry } from "../shared/utils/requestTelemetry.ts";

type Factory<T = any> = () => T;

class Container {
  private _factories = new Map<string, Factory>();
  private _instances = new Map<string, any>();

  /**
   * Register a factory for a service. Does NOT instantiate until resolve().
   */
  register<T>(name: string, factory: Factory<T>): void {
    this._factories.set(name, factory);
    // Clear cached instance if re-registering (useful for testing)
    this._instances.delete(name);
  }

  /**
   * Resolve a service by name. Lazy-creates via factory on first call,
   * then returns the cached singleton.
   */
  resolve<T = any>(name: string): T {
    if (this._instances.has(name)) {
      return this._instances.get(name) as T;
    }

    const factory = this._factories.get(name);
    if (!factory) {
      throw new Error(`[Container] No factory registered for "${name}"`);
    }

    const instance = factory();
    this._instances.set(name, instance);
    return instance as T;
  }

  /**
   * Check if a service is registered (factory exists).
   */
  has(name: string): boolean {
    return this._factories.has(name);
  }

  /**
   * List all registered service names.
   */
  list(): string[] {
    return Array.from(this._factories.keys());
  }

  /**
   * Reset all factories and instances (for testing).
   */
  reset(): void {
    this._factories.clear();
    this._instances.clear();
  }
}

// ── Singleton container instance ──
export const container = new Container();

// ── Default registrations ──
// Services are still lazily instantiated on first resolve().

container.register("settings", () => {
  return { get: getSettings };
});

container.register("db", () => {
  return getDbInstance();
});

container.register("encryption", () => {
  return {
    encrypt,
    decrypt,
    encryptConnectionFields,
    decryptConnectionFields,
  };
});

container.register("policyEngine", () => {
  return { evaluateRequest, evaluateFirstAllowed, PolicyEngine };
});

container.register("circuitBreaker", () => {
  return { get: getCircuitBreaker };
});

container.register("telemetry", () => {
  return { RequestTelemetry, recordTelemetry };
});

export default container;