ADR 0003: @arachnejs/core kernel design
- Status: Accepted
- Date: 2026-09-27
- Deciders: Arachne core
Context #
Every higher-level package needs shared primitives for dependency injection, module lifecycle, events, and logging — without importing concrete servers, databases, or UI.
Decision #
@arachnejs/core provides:
- Tokens + Container — symbol/string tokens, singleton and transient
scopes, constructor and factory providers, child containers for request
scope. Resolution is synchronous; async factories are supported via
resolveAsync. - Modules —
defineModule({ name, providers, imports, setup, dispose }). Modules are composable; the app boots modules in topological order and disposes in reverse. - Events — typed
EventBuswithon/once/emit/off. No global singleton; the bus is a container provider. - Logger —
Loggerinterface (trace|debug|info|warn|error|child). DefaultconsoleLogger; adapters (Pino, OTel) live elsewhere. - App —
createApp({ modules, logger? })wires container + bus + lifecycle (boot/dispose).
@arachnejs/core has zero runtime dependencies and must not import any other
@arachnejs/* package.
Alternatives considered #
- tsyringe / inversify — heavy, decorator-centric, less tree-shakeable.
- Effect Context — powerful, but couples the kernel to Effect's runtime.
- No DI — module-level singletons fight testing and multi-tenancy.
Consequences #
- All framework services register through providers.
- Request-scoped children enable per-request services without globals.
- Later packages depend on interfaces from core, not concrete adapters.