Connect modules through interfaces
Overview
@antelopejs/interface-core lets one module call a contract implemented by another. The caller imports the interface rather than the provider, so the runtime can connect modules and replace a provider without changing the caller's imports.
If you only need application logs, start with logging. If you are using HTTP routes or authentication, start with those interfaces; you do not need to build a proxy first.
Start with your role
| You are… | Start here | You own… |
|---|---|---|
| Calling an existing interface | Its package documentation, then connection lookup | The consuming module and its provider binding. |
| Defining a new contract | How interfaces work, then proxies | Typed declarations shared by consumers and providers. |
| Implementing a contract | ImplementInterface | Every declared function and registration callback. |
| Integrating a module loader | Runtime and module lifecycle | Ownership contexts, generations, and cleanup. |
Application modules normally import an existing interface rather than construct proxies themselves. The AntelopeJS runtime supplies module context and connections; these primitives do not configure a project or choose a provider for you.
The package exports several key categories of functionality:
- Proxies -
AsyncProxy,EventProxy, andRegisteringProxymanage cross-module function calls, events, and registrations with automatic cleanup when modules are unloaded. - Interface functions -
InterfaceFunctionandImplementInterfacewire up interface declarations to their concrete implementations. - Decorator factories - Utilities for building type-safe TypeScript decorators that target classes, properties, methods, and parameters.
- Metadata -
GetMetadataprovides reflection-based metadata retrieval with inheritance support. - Module lifecycle - Events and functions for managing module construction, startup, shutdown, and destruction.
- Logging - A structured, channel-based logging system with multiple severity levels.
- Configuration - TypeScript types and helpers for defining AntelopeJS project configurations.
Import paths
The package exposes several entry points:
// Main entry - proxies, InterfaceFunction, GetMetadata, ImplementInterface, GetInterfaceInstances
import {
AsyncProxy,
InterfaceFunction,
GetMetadata,
} from "@antelopejs/interface-core";
// Decorator factories
import {
MakeClassDecorator,
MakeMethodDecorator,
} from "@antelopejs/interface-core/decorators";
// Module lifecycle events and management
import {
Events,
ListModules,
LoadModule,
} from "@antelopejs/interface-core/modules";
// Logging system
import { Logging } from "@antelopejs/interface-core/logging";
// Configuration types and helpers
import { defineConfig } from "@antelopejs/interface-core/config";
How interfaces work
AntelopeJS interfaces act as contracts between modules. One module declares an interface using proxy objects and InterfaceFunction, while another module provides the implementation using ImplementInterface. The proxy layer handles queuing, lifecycle management, and automatic cleanup.
// Declaration side: define what the interface looks like
import { InterfaceFunction, EventProxy } from "@antelopejs/interface-core";
export const GetUser = InterfaceFunction<(id: string) => { name: string }>();
export const OnUserCreated = new EventProxy<(userId: string) => void>();
// Implementation side: provide the concrete behavior
import { ImplementInterface } from "@antelopejs/interface-core";
import * as UserInterface from "./declaration";
ImplementInterface(UserInterface, {
GetUser(id: string) {
return { name: "Alice" };
},
});
The proxy queues calls to GetUser until an implementation attaches. When the implementing module unloads, the proxy detaches and queues new calls again. The queue is bounded (1,000 pending calls by default), and test stub mode rejects missing providers instead of waiting. See proxy failure modes before relying on this behavior during startup.
Choose a communication primitive
| Need | Primitive | Without an attached provider or listener |
|---|---|---|
| Ask for a result | InterfaceFunction / AsyncProxy | Calls queue, subject to the queue limit and stub mode. |
| Notify current listeners | EventProxy | Emissions are not retained for future listeners. |
| Keep declarations available across reloads | RegisteringProxy | Entries remain available for replay when handlers attach. |
Do not use an event for a registration that a replacement provider must recover. Use the registering proxy's paired onHandlers attachment when replay needs both registration and unregistration callbacks.
Next steps
- Proxies - Deep dive into
AsyncProxy,EventProxy, andRegisteringProxy - Decorators - Build type-safe decorator factories
- Modules - Understand module lifecycle events
- Logging - Use the structured logging system
- Metadata - Read inherited metadata
- Configuration - Define project configuration
- Runtime - Integrate ownership and loader behavior
Require authentication in controllers
Use a parameter decorator when one handler needs the payload, a property decorator when several methods need it, or a class decorator when every route must authenticate without receiving the payload. These are alternative scopes, not three steps you must combine.
Proxies