Skip to main content

inversify-di

Inversify dependency injection patterns for the server. Use when creating or modifying DI container bindings, adding injectable services, writing tests with dependency overrides, or managing TYPES symbols.

الانتقال إلى التثبيت

معلومات المصدر

المستودع
recca0120/code-quest
آخر نشاط في المصدر
١٣ مايو ٢٠٢٦ في ١٦:١٩
لغة SKILL.md المكتشفة
الإنجليزية
النجوم
١١
التفرعات
٢

خيارات التثبيت

يُحدَّد Prompt الذي يراجع المصدر أولًا بشكل افتراضي. يمكنك التبديل إلى أمر مباشر أو تنزيل نسخة محلية.

مراجعة ملفات المصدر

اقرأ SKILL.md وأي ملفات مرافقة يعرضها SkillsMP قبل أن تقرر التثبيت.

عرض SKILL.md

SKILL.md
تعليمات المصدر · معاينة للقراءة فقط
name
inversify-di
description
Inversify dependency injection patterns for the server. Use when creating or modifying DI container bindings, adding injectable services, writing tests with dependency overrides, or managing TYPES symbols.
# Inversify DI ## TYPES Registry **File:** `apps/server/src/types.ts` ```typescript export const TYPES = { RunnerFactory: Symbol.for('RunnerFactory'), SessionStore: Symbol.for('SessionStore'), RawEventStore: Symbol.for('RawEventStore'), ChatHandler: Symbol.for('ChatHandler'), Database: Symbol.for('Database'), UsageTracker: Symbol.for('UsageTracker'), SettingsStore: Symbol.for('SettingsStore'), ChannelManager: Symbol.for('ChannelManager'), } as const; ``` ## Container Setup **File:** `apps/server/src/container.ts` — `createContainer(options)` All bindings are inline (no ContainerModule pattern): | Symbol | Binding | Scope | |--------|---------|-------| | RunnerFactory | `.toConstantValue(factory)` | — | | Database | `.toConstantValue(db)` | — | | SessionStore | `.toConstantValue(store)` | — | | RawEventStore | `.toConstantValue(store)` | — | | SettingsStore | `.toConstantValue(store)` | — | | ChannelManager | `.toConstantValue(mgr)` | — | | UsageTracker | `.to(UsageTracker).inSingletonScope()` | Singleton | | ChatHandler | `.to(ChatHandler).inSingletonScope()` | Singleton | Only `ChatHandler` and `UsageTracker` use `@injectable()` + `@inject()`. ## Injectable Services ```typescript // apps/server/src/socket/chat-handler.ts @injectable() export class ChatHandler implements HandlerContext { constructor( @inject(TYPES.RunnerFactory) public runnerFactory: RunnerFactory, @inject(TYPES.RawEventStore) public rawEventStore: RawEventStore, @inject(TYPES.SessionStore) public sessionStore: SessionStore, @inject(TYPES.UsageTracker) public usageTracker: UsageTracker, @inject(TYPES.ChannelManager) public channelManager: ChannelManager, @inject(TYPES.SettingsStore) @optional() settingsStore?: SettingsStore, ) {} } ``` ## HandlerContext Interface **File:** `apps/server/src/socket/handler-context.ts` Aggregates all injected services. Socket handlers access dependencies through this interface. ## Composite Store Pattern `buildStores()` in container.ts creates stores based on `StoreConfig`, wrapping multiple backends in `CompositeRawStore` / `CompositeSessionStore` when needed. ## Testing **File:** `apps/server/src/test/create-test-container.ts` ```typescript export function createTestContainer(overrides): Container { const container = createContainer({ ...overrides, storeConfig: { sqlite: true } }); const db = container.get<DrizzleDatabase>(TYPES.Database); migrate(db, { migrationsFolder }); container.rebindSync<SettingsStore>(TYPES.SettingsStore) .toConstantValue(new InMemorySettingsStore()); return container; } ``` Key test methods: - `container.get<T>(TYPES.X)` — retrieve service - `container.rebindSync<T>(TYPES.X).toConstantValue(mock)` — replace binding ## Adding a New Service 1. Add symbol to `TYPES` in `apps/server/src/types.ts` 2. If constructor-injectable: add `@injectable()` + `@inject()` decorators 3. If constant-bound: instantiate and `.bind(TYPES.X).toConstantValue(instance)` 4. Add to test container if tests need it --- ## Inversify v8 Breaking Changes > Reference: https://inversify.io/docs/guides/migrating-from-v7/ ### API Renames | v7 | v8 | |----|----| | `container.loadSync(module)` | `container.load(module)` | | `container.load(module)` | `container.loadAsync(module)` | | `container.rebindSync<T>(id)` | `container.rebind<T>(id)` (now sync by default) | | `container.isBoundNamed(id, name)` | `container.isBound({ serviceIdentifier: id, named: name })` | | `container.isBoundTagged(id, key, val)` | `container.isBound({ serviceIdentifier: id, tag: { key, value: val } })` | ### Removed APIs - **`rebindSync`** is gone — `rebind` is now synchronous by default in v8; update all call sites. - **`toProvider()`** is removed — replace with `toFactory()` using an async inner function if you need a promise-returning factory. ### Module System - v8 is **ESM-only**. CommonJS (`require`) is no longer supported. ### Service Identifiers - **Plain functions are no longer valid service identifiers.** Use `string` or `Symbol` (e.g., `Symbol.for('MyService')`) instead. Abstract classes are still valid. ### Migration Tip for This Project The test container currently calls `container.rebindSync` (v7). When upgrading to v8, rename all `rebindSync` calls to `rebind`.
عرض على GitHub