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.

Ir para a instalação

Informações da origem

Repositório
recca0120/code-quest
Última atividade na origem
13 de maio de 2026 às 16:19
Idioma detectado do SKILL.md
inglês
Estrelas
11
Forks
2

Opções de instalação

Por padrão, está selecionado o prompt que primeiro revisa a origem. Você pode mudar para um comando direto ou baixar uma cópia local.

Revise os arquivos de origem

Leia o SKILL.md e os arquivos complementares exibidos pelo SkillsMP antes de decidir se vai instalar.

Exibindo SKILL.md

SKILL.md
Instruções da origem · Visualização somente leitura
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`.
Ver no GitHub