
Product
Introducing Repository Access Permissions and Custom Roles
Socket now supports Custom Roles and Repository Access Permissions so organizations can control who can access specific repositories and actions.
@fluojs/core
Advanced tools
Shared contracts, decorators, and metadata helpers that form the foundation of every Fluo package.
English 한국어
Shared contracts, standard decorators, and metadata primitives that every fluo package builds on.
npm install @fluojs/core
Use this package when you are:
Every fluo application starts with module metadata declared through @fluojs/core.
import { Global, Inject, Module, Scope } from '@fluojs/core';
@Global()
@Module({
providers: [DatabaseService],
exports: [DatabaseService],
})
class CoreModule {}
@Module({
imports: [CoreModule],
providers: [UserService],
})
class AppModule {}
@Inject(DatabaseService)
@Scope('singleton')
class UserService {
constructor(private readonly db: DatabaseService) {}
}
fluo uses TC39 standard decorators. You do not need experimentalDecorators: true or emitDecoratorMetadata: true to use @Module, @Inject, @Global, or @Scope.
Core metadata is written through fluo-owned stores and TC39 Symbol.metadata integration points, never through reflect-metadata or compiler-emitted design types. Importing @fluojs/core does not install a global Symbol.metadata polyfill. Call ensureMetadataSymbol() at test or bootstrap boundaries when a runtime needs the polyfill installed before evaluating custom standard decorators.
import { ensureMetadataSymbol } from '@fluojs/core';
ensureMetadataSymbol();
@Inject(...) keeps dependency wiring visible in code instead of relying on emitted reflection metadata. It is a standard class decorator: place it on the class whose constructor tokens you are declaring, not on constructor parameters or properties. Call @Inject() when you want to record an explicit empty override for inherited constructor tokens.
const CONFIG_TOKEN = Symbol('CONFIG_TOKEN');
@Inject(CONFIG_TOKEN)
class UsesConfigValue {
constructor(private readonly config: Config) {}
}
Pass multiple constructor tokens as variadic arguments, such as @Inject(A, B), so dependency metadata stays aligned with standard decorator usage. The array form @Inject([A, B]) is also accepted, but new code should prefer the variadic form. If a token is unavailable at decoration time, wrap that one token with forwardRef(...); if a dependency may be absent, wrap that token with optional(...). The wrapper helpers are runtime DI helpers from @fluojs/di; @fluojs/core only exports the shared wrapper types accepted by @Inject(...).
import { Inject } from '@fluojs/core';
import { forwardRef, optional } from '@fluojs/di';
@Inject(forwardRef(() => AuditLogger), optional(CacheClient))
class UsesDeferredAndOptionalDeps {}
getModuleMetadata() is available from the public root entrypoint for read-only module inspection in tests and tooling. Broader internal readers and writers live under @fluojs/core/internal, which is how packages like @fluojs/di, @fluojs/http, and @fluojs/runtime consume the same metadata model.
Application code should import public decorators, ensureMetadataSymbol(), and read-only module metadata inspection from @fluojs/core. The @fluojs/core/internal subpath is reserved for fluo packages that need metadata records, controller/route helpers, injection and validation helpers, or clone utilities. Standard metadata bag helpers handle mixed-era lookups across current/native Symbol.metadata and the fallback symbol: own metadata from either era overrides inherited metadata from either era for the same key, while inherited keys from parent constructors remain visible when the child owns a different key. To reduce DI and module-graph hot-path allocations, getModuleMetadata(), getOwnClassDiMetadata(), getInheritedClassDiMetadata(), and getClassDiMetadata() return frozen snapshots and may reuse the same reference between writes. Treat those results, their collection fields, module provider descriptor wrappers, and middleware route-config wrappers (including their routes arrays) as immutable. useValue payload objects and runtime middleware/guard/interceptor instances remain mutable references and are not frozen by these snapshots. Other metadata readers keep their existing defensive-read behavior unless their own tests document stable-reference reuse.
import { getModuleMetadata } from '@fluojs/core';
const metadata = getModuleMetadata(AppModule);
console.log(metadata.providers);
AsyncModuleOptions<T> is the standard contract for modules that require asynchronous initialization, such as those relying on an external ConfigService.
import { AsyncModuleOptions, MaybePromise, Token } from '@fluojs/core';
interface Config {
apiKey: string;
}
class EmailModule {
static forRootAsync(options: AsyncModuleOptions<Config>) {
return {
module: EmailModule,
providers: [
{
provide: 'CONFIG',
useFactory: options.useFactory,
inject: options.inject,
},
],
};
}
}
The @Scope decorator controls the lifetime of a provider instance. fluo supports three distinct levels:
singleton (default): A single instance is shared across the entire application.request: A new instance is created for every incoming HTTP request.transient: A new instance is created every time it is injected into a consumer.import { Scope } from '@fluojs/core';
@Scope('request')
class TransactionContext {}
@Scope('transient')
class Logger {}
Ensure you are using standard TC39 decorators. fluo does not use reflect-metadata. If you are migrating from NestJS, remove experimentalDecorators and emitDecoratorMetadata from your tsconfig.json to prevent conflicts with standard decorator behavior.
If two modules import each other, the module graph cannot be compiled. Use a shared "Common" or "Core" module to house providers that both modules depend on, or refactor the shared logic into a separate package.
Standard decorators cannot automatically infer types for abstract classes or interfaces. Always use @Inject(TOKEN) when injecting anything that is not a concrete class constructor.
Module, Global, Inject, ScopeFluoError, InvariantError, FluoCodeError, FluoErrorOptions, formatTokenNameensureMetadataSymbol, getModuleMetadataConstructor<T>, Token<T>, InjectionToken<T>, ForwardRefToken<T>, OptionalInjectToken<T>, MaybePromise<T>, AsyncModuleOptions, MetadataPropertyKey, MetadataSource@fluojs/core/internal@fluojs/di: resolves the tokens and scopes defined here into live instances@fluojs/runtime: compiles the module graph from @Module metadata@fluojs/http: consumes controller and route metadata built on the same primitivespackages/core/src/index.tspackages/core/src/decorators.tspackages/core/src/metadata.tsFAQs
Shared contracts, decorators, and metadata helpers that form the foundation of every Fluo package.
We found that @fluojs/core demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Product
Socket now supports Custom Roles and Repository Access Permissions so organizations can control who can access specific repositories and actions.

Product
Socket MCP now lets AI assistants review org alerts, investigate threats using the Socket threat feed, and inspect package files in addition to dependency scoring.

Product
Socket Firewall blocks malicious VS Code and Open VSX extensions before install, protecting developers from compromised editor marketplaces.