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.

Zur Installation springen

Quellinformationen

Repository
recca0120/code-quest
Letzte Quellaktivität
13. Mai 2026 um 16:19
Erkannte Sprache von SKILL.md
Englisch
Sterne
11
Forks
2

Installationsoptionen

Standardmäßig ist der Prompt ausgewählt, der zuerst die Quelle prüft. Sie können zu einem direkten Befehl wechseln oder eine lokale Kopie herunterladen.

Quelldateien prüfen

Lesen Sie SKILL.md und alle von SkillsMP angezeigten Begleitdateien, bevor Sie sich für eine Installation entscheiden.

SKILL.md wird angezeigt

SKILL.md
Quellanweisungen · Schreibgeschützte Vorschau
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`.
Auf GitHub ansehen