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
최근 소스 활동
2026년 5월 13일 16:19
감지된 SKILL.md 언어
영어
스타
11
포크
2

설치 방법

기본적으로 소스를 먼저 확인하는 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에서 보기