English 한국어
@fluojs/openapi exposes OpenApiModule.forRoot(...) / forRootAsync(...) for live documentation and OpenApiDocumentBuilder.build(...) for offline documents; legacy builder functions and registries are not public. Legacy nullable and boolean exclusive bounds are rejected in favor of OpenAPI 3.1 null unions and finite numeric bounds. See OpenAPI 3 Migration Guide.
@fluojs/platform-cloudflare-workers exposes no host-invoked shutdown callback through its exported fetch handler. CloudflareWorkerApplicationHost owns lazy bootstrap sharing, first-environment configuration reuse, retry, generation replacement, and drain recovery; direct applications instead use the adapter Factory and no-socket app.listen(). A trigger outside worker.fetch may call await worker.close() directly. A management route inside that fetch must return its current response, then use executionContext.waitUntil(worker.close()) or an equivalent non-self-awaiting mechanism; awaiting it waits for its own active request to drain and reaches the shutdown timeout. A successful host close is restartable: the next fetch(...) creates a fresh application, reruns bootstrap lifecycle hooks, and reconstructs application singleton providers.
| family | description | packages |
|---|---|---|
| Core | Shared contracts and DI. | @fluojs/core, @fluojs/di, @fluojs/config, @fluojs/i18n, @fluojs/runtime |
| HTTP | Web API execution, routing, and structured access logging. | @fluojs/http, @fluojs/graphql, @fluojs/validation, @fluojs/serialization, @fluojs/openapi |
| Auth | Authentication and authorization. | @fluojs/jwt, @fluojs/passport |
| Platform | Runtime adapters. | @fluojs/platform-fastify, @fluojs/platform-nodejs, @fluojs/platform-express, @fluojs/platform-nextjs, @fluojs/platform-bun, @fluojs/platform-deno, @fluojs/platform-cloudflare-workers |
| Realtime | WebSocket and Socket.IO. | @fluojs/websockets, @fluojs/socket.io |
| Persistence | Database and cache. | @fluojs/prisma, @fluojs/drizzle, @fluojs/mongoose, @fluojs/redis, @fluojs/cache-manager |
| Patterns | Messaging and architecture. | @fluojs/microservices, @fluojs/cqrs, @fluojs/event-bus, @fluojs/cron, @fluojs/queue, @fluojs/notifications, @fluojs/email, @fluojs/slack, @fluojs/discord |
| Operations | Health and monitoring. | @fluojs/metrics, @fluojs/terminus, @fluojs/throttler |
| UI | React integration. | @fluojs/react |
| Tooling | CLI inspection export, CLI-launched Studio sidecar/viewer diagnostics, inspect artifact rendering, testing diagnostics, and Vite build integration. | @fluojs/cli, @fluojs/studio, @fluojs/testing, @fluojs/vite |
@fluojs/graphql exposes GraphqlModule.forRootAsync({ inject, useFactory }) alongside
GraphqlModule.forRoot(...). GraphqlAsyncModuleOptions<TTokens> ties each explicit inject
token to its ordered useFactory parameter and models an optional token's value as
T | undefined. This is not NestJS dynamic-module
compatibility: imports, useClass, useExisting, and implicit provider discovery are rejected.
| runtime target | adapter package | notes |
|---|---|---|
| Node.js (Default) | @fluojs/platform-fastify |
Recommended starter path for high performance on Node.js >=24.0.0 <27. The package declares that exact engines.node range, owns the Fastify-backed Node http/https listener, and accepts Node.js https server options through FastifyHttpApplicationAdapter.create(options) when the process terminates TLS directly. This bounded range excludes Node versions below 24 and Node 27+ so listener-level RFC QUERY requests reach Fastify wildcard fallback and fluo dispatch. |
| Node.js (Bare) | @fluojs/platform-nodejs |
Use when you need direct control over the Node HTTP listener. The package targets Node.js >=24.0.0 <27 and declares that exact engines.node range so listener-level RFC QUERY requests reach fluo dispatch. |
| Node.js (Express) | @fluojs/platform-express |
Express host adapter for Node.js >=24.0.0 <27, with the same exact engines.node range. Use it when existing Express hosting or server integrations must remain at the platform boundary. The adapter constructs and owns its Express application; adopting or reusing an existing Express application is unsupported. Replacing the host does not preserve NestJS legacy decorator or reflection-metadata semantics; complete the TC39 standard decorator and explicit DI/module wiring migration first. Application-level middleware still uses fluo's Middleware contract; native Express/Connect (req, res, next) functions are not portable fluo middleware and must be supplied through the adapter's explicit pre-router nativeMiddleware option at construction time when a migration must retain them. After bootstrap, calling use(...) to append to the native stack is not supported. Prefer rewriting portable behavior as fluo Middleware. |
| Next.js (Node.js) | @fluojs/platform-nextjs |
App Router Route Handlers and Pages Router API Routes on Next.js 16.x (peer >=16.0.0 <17), Node.js >=24.0.0 <27, and @fluojs/runtime >=3.0.0 <4. Request-lazy Fluo bootstrap binds the dispatcher without opening a socket; Next.js owns the server and process lifecycle. No Edge Runtime or raw WebSocket upgrade seam; HTTP methods remain bounded by Next.js routing. Packaged decorator integration is Turbopack-only. Hybrid App/Pages server bundles use separate Fluo applications with the default per-closure lazy recipe. Consumers explicitly using defineNextApplication with the same key share one application Promise only within the same JS global (globalThis). Different processes, workers, serverless instances, and JS globals remain isolated. |
| Bun | @fluojs/platform-bun |
Official Bun-native fetch-style startup path with native-route registration that preserves observer-compatible dispatcher fallback. |
| Deno | @fluojs/platform-deno |
Official managed Deno.serve() startup path plus createDenoFetchHandler(...) for hosts that bootstrap fluo but own server startup, shutdown, signals, and websocket upgrades. |
| Cloudflare Workers | @fluojs/platform-cloudflare-workers |
Stateless isolate lifecycle built on the fetch-style adapter seam. CloudflareWorkerHttpApplicationAdapter.create(...) plus FluoFactory.create(...) is the direct path; CloudflareWorkerApplicationHost.create(...) owns lazy lifecycle. listen() binds the dispatcher without opening a socket, Worker fetch() registers active work with executionContext.waitUntil(...), SSE (text/event-stream) drains follow the response body until completion or cancellation, WebSocket upgrades use a binding frozen before the first listen boundary, and shutdown returns JSON 503 for new HTTP/WebSocket ingress while active work drains for the bounded close window. If a lazy host close() times out, it keeps the shutdown gate until the underlying drain settles, then clears the temporary gate so a later request can bootstrap a fresh application. |
The normal runtime dispatch pipeline retains buffered multipart materialization so its existing
FrameworkRequest.body and files contract stays stable. Applications select streaming explicitly
with multipart: { strategy: 'stream' }; supported adapters then expose
RequestContext.request.body as an AsyncIterable<MultipartPart> without pre-reading or buffering
the iterator. File bytes are pulled only while its file stream is consumed, and one request body
cannot be consumed through both modes.
| adapter family | portable input to parseMultipartStream(...) |
buffered mode | streaming mode |
|---|---|---|---|
| Node.js, Express, Fastify | Native async-iterable request directly or as MultipartRequestLike |
Supported by the runtime request pipeline. | Supported by the shared parser with typed parts and Web streams. |
| Bun, Deno, Cloudflare Workers | Native Fetch Request |
Supported by the runtime request pipeline. | Supported by the shared parser with typed parts and Web streams. |
Both rows enforce the same maxFieldSize, maxFileSize, maxTotalSize, maxFields, maxFiles,
and maxHeaderSize limits. Request abort, parser failure, and file-stream cancellation cancel the
active source; MultipartBodyConsumedError rejects buffered/streaming double consumption.
@fluojs/core: Metadata helpers and TC39-standard decorator support, including the@fluojs/core/request-pipelinepackage-integration seam for first-party request-pipeline DTO validation, binding, and standard metadata-bag access.@fluojs/di: Provider resolution, lifecycle scopes, and dependency graph analysis.@fluojs/config: Portable in-memory configuration merging, validation, cloning, and typed access with no package-wide Node engine.ConfigServiceand explicit in-memoryConfigModule.load({ envFilePaths: [], ... })inputs never resolveprocess.cwd(), default.env, or Node builtins. OneConfigModule.forRoot(...)registration exports bothConfigServiceandCONFIG_RELOADER; useConfigReloadManager.create(...)for standalone reloads. OrderedenvFilePathsapply from lowest to highest precedence; omission loads.envonly withcwdor watch, or without explicitdefaults/processEnv/runtimeOverrides;[]disables file loading. Env-file, default.env, and watch paths are Node-only features guarded at execution byCONFIG_RUNTIME_UNAVAILABLE; they lazily requireprocess.getBuiltinModule(...)and provide remediation guidance when unavailable.@fluojs/i18n: Framework-agnostic internationalization package boundary whose root import depends only on@fluojs/coreand does not declare a Node.js engine floor, withI18nModule.forRoot(...)module registration that exposesI18nServiceglobally by default and supportsglobal: falsefor module-local visibility, a standalone service factory, reserved core option/error types, ICU MessageFormat support through@fluojs/i18n/icu, HTTP locale helpers and opt-inAccept-Languagepolicy helpers through@fluojs/i18n/http, opt-in non-HTTP locale adapters and header policy helpers through@fluojs/i18n/adapters, validation localization through@fluojs/i18n/validation, Node filesystem and provider-backed catalog loaders with opt-in remote cache wrappers through@fluojs/i18n/loaders/fsand@fluojs/i18n/loaders/remote, and catalog key plus typed translation helper declaration generation through@fluojs/i18n/typegen. Ecosystem parity with NestJS i18n, i18next, next-intl, and request/validation convenience glue is governed by the i18n ecosystem bridge decision record and remains documentation-first unless a future opt-in subpath satisfies the bridge acceptance criteria.@fluojs/runtime: Portable application bootstrap, module orchestration, platform shell registration, and platform snapshot production with no package-wide Node engine or eager Node builtin imports. Node listener, filesystem, logger, compression, and process-signal responsibilities moved from the removed@fluojs/runtime/nodeand@fluojs/runtime/internal-nodeentrypoints to@fluojs/platform-nodejsand@fluojs/platform-nodejs/internal; fetch-style hosts continue through@fluojs/runtime/web. Its HTTP request pipeline writes framework-managed handler results only while the response remains uncommitted. After a handler or response helper commitsRequestContext.response, the dispatcher skips a second success-response write instead of writing the final interceptor-chain result.HealthModule.forRoot(...)returns the publicRuntimeHealthModulereadiness-registration seam for first-party runtime-aware packages that must contribute/readychecks without importing internal runtime subpaths. Published@fluojs/runtime/internal*subpaths are runtime-neutral package-integration seams for first-party adapters and runtime-aware packages; they are not application-level helper contracts.
platform-*: Implement the repository policy seam namedPlatformAdapter; HTTP runtime packages do so throughHttpApplicationAdapterfrom@fluojs/http. They bridge abstract HTTP calls to runtime-specific listeners.@fluojs/socket.io: A dedicated transport-brand adapter that integrates Socket.IO v4 with fluo gateways while preserving package-level runtime limits: Node.js>=24.0.0 <27server-backed adapters and the official Bun engine path are supported, Deno and Workers are not supported, Bun requires static CORS shapes, every runtime rejects@WebSocketGateway({ serverBacked }), adapter-owned/shared HTTP listeners remain owned by the platform adapter during Socket.IO shutdown, accepted gateway work drains before managed state is cleared within the shutdown bound, and explicit numeric payload/buffer/shutdown options fail fast when invalid.
-
@fluojs/http: Routing, guards, interceptors, exception handling, immutable structured access-log lifecycle records, the portableFrameworkRequestConnectiontransport seam and immutable trusted connection API (resolveHttpConnection,HttpConnection,ResolveHttpConnectionOptions,TrustProxyPolicy, andTrustProxyPredicate), and the portable byte-range public API (createByteRangeResponse(...),ByteRangeResponseSource, andByteRangeResponseOptions). Access-logclientIdentityexplicitly opts into the direct transport peer; forwarded identity requires an explicittrustProxypolicy. It owns single-byte-range request policy, including theGET/HEADgate and identity partial-response metadata, but applications retain byte sources, exact representation sizes, filesystem open/stat/seek/close ownership, and multi-range construction. -
@fluojs/graphql: GraphQL schema exposure, root and code-first object field resolver execution, and subscriptions on top of the HTTP abstraction, with a package-ownedengines.node >=24.0.0 <27support contract; portable@fluojs/runtimehas no package-wide Node engine. -
@fluojs/openapi: Decorator-based OpenAPI 3.1.0 document generation for HTTP controllers, registered throughOpenApiModule.forRoot(...)orforRootAsync(...)with explicitsources, prebuiltdescriptors, or both. It owns configurabledocumentPath/uiPathroutes with preserved/openapi.jsonand/docsdefaults, deterministic HTTP route-collision failures for multi-document registrations, deterministic Swagger UI serving, descriptor/source collision precedence for duplicate operations, request DTO schema extraction, explicitApiParam/ApiQuery/ApiHeader/ApiCookie/ApiBodyoverride behavior, rejection of legacynullableand boolean exclusive bounds in favor of OpenAPI 3.1 null unions and finite numeric bounds, default error response policy injection or omission, anddocumentTransformhooks before served documents are snapshotted and normalized. The package declares its ownengines.node >=24.0.0 <27support contract, excluding Node versions below 24 and Node 27+; portable@fluojs/runtimehas no package-wide Node engine. -
@fluojs/react: Runtime-neutral React integration whose stable root exposes HTTP-owned React routing facades,ReactServerEntry,createReactServerEntry(...), andrenderReactResponse(...). Entries stream through lazyreact-dom/serverrenderToReadableStream(...)and accept explicitbootstrapScripts,bootstrapModules, trustedbootstrapScriptContent, andassetMaphydration metadata.@fluojs/react/viteparses already-loaded Vite manifests, and@fluojs/react/clientprovides real-anchor, full-document navigation plus hydration-safe route state without taking over matching or DTO validation. The explicitly unstable@fluojs/react/experimental/rscsubpath pins React, React DOM, and the application-selected Flight renderer to19.2.6; validates Web Streams and build-adapter capabilities; snapshots client-reference and server-to-client module maps withcreateReactRscManifest(...); returns application-encoded Flight payloads withcreateReactFlightResponse(...); and prototypes signed Server Function references plus bounded JSON transport withcreateReactServerFunctionRegistry(...)andcreateReactServerFunctionClient(...). Flight payloads and action calls both use ordinary fluo HTTP dispatch. The root and stable client subpath do not re-export RSC or Server Function code. No React subpath provides automatic Vite manifest discovery, arbitrary inline serialization, a built-in RSC renderer or build plugin, automatic"use server"transforms/export discovery, client bundle generation, file routes, SPA document swapping, client data caches, prefetch, Node pipeable root APIs, or a separate React matcher/router table.Stable phase boundaries keep root
@fluojs/reactfocused on runtime-neutral SSR contracts.@fluojs/react/viteowns Vite asset manifest parsing,@fluojs/react/clientowns HTTP-first browser navigation and hydration-safe route-state hooks, and@fluojs/react/experimental/rscowns the unstable exact-React-version RSC compatibility, client-reference/server-module manifest, HTTP-dispatched Flight response, and signed Server Function transport seams. Server Functions require an application-owned explicit POST route, Web Crypto provider, 32-byte-or-longer secret, exact origin allowlist, non-simple request marker, JSON/body/depth/result limits, and action-level or guard authorization; they do not create a renderer, build plugin, loader/cache system, or separate router. The stable root and client subpath should not be presented as a Next.js App Router clone, React Server Components framework, TanStack route tree, AngularRoutes[], file-route scanner, or primary React-ownedroutes: []table.The stable root also exports
createReactPageCatalog(...)andReactPageCatalogEntry. This read-only catalog filters authoritative compiled HTTP descriptors by React router/path markers and projects effective method, path, version, parameter names, module, router, and handler identity. It is observational only: matching, conflict detection, dispatch, and non-React route behavior remain HTTP-owned. Runtime/CLI inspection serializes the same route-kind marker asreact-pagewithout retaining request values or creating a React route table.The stable
@fluojs/react/typegentooling subpath generates deterministic, path-only TypeScript declarations, absolute href builders, route-bound real-anchor props, and typedpush/replacemethods from that catalog without widening the runtime-neutral package root. Generated navigation resolves ordinary absolute href strings into the existing HTTP-first client APIs instead of adding a runtime route table or matcher. It rejects versioned routes because the catalog cannot distinguish URI versioning from header, media-type, or custom version strategies.Stable root render policies are limited to
@PageLayout(...)and@SuspenseFallback(...)component references on@Router(...)classes and@Path(...)methods. The applicationReactPageRendereralone receives resolved base-to-derived class/method policies after HTTP matching, with the active request-scope container available throughReactRenderContext. Same-site duplicates, invalid targets/references, and policies withoutrenderPagefail during bootstrap. Suspense fallback metadata covers only descendants that suspend during SSR; it does not add handler-await, client-navigation pending UI, error/not-found ownership, or URL-prefix ancestry. The render policy decision is canonical.The React RSC graduation policy keeps
@fluojs/react/rscblocked until maintainer-approved evidence covers React/renderer versions, manifest and Server Function transport compatibility, browser/server separation, SSR/CSR/prerendering, hydration mismatch recovery, safe transfer rules, HTTP route and #2506 navigation ownership, dual-import tests, bilingual docs, and Changesets intent. Graduation never adds a stable root RSC export. When approved, the experimental path remains a tested re-export for the policy's deprecation window. -
@fluojs/jwt: HTTP-agnostic JWT signing, verification, principal normalization, refresh-token rotation contracts with optional family-scoped reuse revocation and a compatible subject-revocation fallback, and platform status/diagnostic helpers with exported status snapshot and adapter input types. -
@fluojs/passport: Strategy-agnostic authentication guards, optional auth and scope decorators,PassportModulestrategy registry wiring, Passport.js manual bridge provider bundles, bearer JWT, cookie-auth and refresh-token presets, account-linking policy helpers, public auth metadata helpers, and platform status/diagnostic helpers for auth readiness. -
@fluojs/microservices: Pattern-matching transport abstraction for TCP, Redis Pub/Sub, Redis Streams, NATS, Kafka, RabbitMQ, MQTT, and gRPC. Application registration stays onMicroservicesModule.forRoot(...), andMICROSERVICEresolves the programmaticMicroservicelifecycle facade rather than a raw transport.send()settles on a correlated response,emit()settles at outbound transport publication rather than remote-handler completion, andclose()tears down transport-owned listeners/subscriptions without closing caller-owned NATS, Kafka, or RabbitMQ collaborators. Status snapshots preserve mixed ownership: supplied gRPC servers remain externally managed while cached outbound clients remain framework-owned and are reported separately throughdetails.transportResourceOwnership. Transport-specific subpaths expose TCP, Redis Pub/Sub, Redis Streams, NATS, Kafka, RabbitMQ, MQTT, and gRPC adapters; import each class and its options only from its subpath and use the classcreate(...)factory as the canonical construction path. The root barrel exports registration, lifecycle, decorators, status, and shared types only. Safety defaults keep incomplete newline-delimited TCP frames byte-based until a complete frame can be decoded once as UTF-8, bound each frame to 1 MiB, routeport: 0outboundsend()/emit()through the OS-assigned listener, and establish a terminal facade ingress gate whenclose()starts so newsend(),emit(),serverStream(),clientStream(), andbidiStream()calls reject before transport handoff even whilelisten()is pending; the runtime shell applies the same terminal gate tosend()andemit(). Transport adapters retain their own shutdown guards. NATS close attempts every owned subscription cleanup, aggregates multiple failures, and retains only failed subscriptions for a later close retry before listen can resume. The NATS request callback boundary contains malformed frames plus response encoding orrespond()failures, reports them through the configured transport logger without closing the caller-owned NATS client, and adds no raw console fallback when a logger is absent. Concurrent or repeated TCPclose()calls share the first shutdown promise so listener and socket teardown runs once. gRPC removes eachAbortSignalabort listener after a unary call settles, when a streaming call ends or errors even before reader iteration starts, or when its reader returns early; overlapping terminal paths clean up only once. -
@fluojs/cqrs: CQRS command/query buses with bootstrap-time singleton handler discovery, explicit command/query/event handler and saga decorators, in-process saga orchestration with opaque runtime-agnosticCqrsDispatchContexttopology guardrails and one active execution owner per singleton saga provider token, and delegated domain event publishing through@fluojs/event-busafter CQRS handlers and sagas settle. Nested publication to a different route owned by the active saga provider token becomes a deadlock-safe serialized continuation; an active provider-token/event-route cycle still fails withSagaTopologyError. The package declares Node.js>=24.0.0 <27as its package-owned support contract, excluding Node.js versions below 24 and Node.js 27+. Application registration goes throughCqrsModule.forRoot(...); low-level provider assembly is not a documented public facade. Its public status snapshot helpers report command/query/event-handler/saga discovery and lifecycle details, current saga execution and shutdown-drain diagnostics, and the fixed delegated dependency; readiness and health continue to be defined by the event/saga runtime. See the CQRS architecture contract for the complete field and lifecycle meanings. -
@fluojs/event-bus: In-process domain event fan-out registered throughEventBusModule.forRoot({ global?, publish?, shutdown?, transport? }), with global provider visibility enabled by default, normalized effective singleton handler discovery, inherited event channel fan-out, bounded publish cancellation/timeouts, and shutdown drain semantics that recheck local publishes and inbound transport callbacks to live-set quiescence under one absolute deadline before transport close. It requires Node.js>=24.0.0 <27under its package-owned support contract; handler and transport failures are logged and isolated from the caller-facingpublish()promise. The only public publication path isEventBusService.publish(event, options?): Promise<EventPublishResult>. It returns delivery outcomes without exposing a second result-aware facade or legacy bus token. The root provides type-only exports ofEventDeliveryTarget,EventDeliveryStatus,EventDeliveryOutcome,EventPublishSettlement, andEventPublishResult. The narrow@fluojs/event-bus/integrationsubpath exposes only the shutdown coordinator seam for first-party integration; it is not an application-level publication API. The event-bus README owns the full contract.settleddoes not mean every reaction succeeded. Callers check all outcomes and a nonempty result; with neither matching local handlers nor a configured transport, the result isno-recipients. Lifecycle refusal returnsrejectedwith astopping/stopped/failedreason, while discovery/preparation errors still reject. Results list effective local handlers in discovery order, then outbound transport in channel order, observingsucceeded,failed,timed-out, orcancelled. They report neither remote handlers/subscribers nor durability; an adapter success with zero subscribers is still transport success.Results and outbound-publication bus logs contain no raw handler/transport errors or handler return values, retaining only existing safe target/status messages. Inbound handler processing and transport subscription/close diagnostics retain their raw errors; app-owned logs remain the application's responsibility. Awaited timeout/cancellation does not terminate started, shutdown-tracked work.
background.completion: Promise<EventPublishSettlement>ignores timeout and post-start cancellation to await actual work. -
@fluojs/event-bus/redis: Optional Redis Pub/Sub transport subpath for cross-process event-bus fan-out. It exportsRedisEventBusTransportandRedisEventBusTransportOptions, requires the application to install the optionalioredispeer, and accepts dedicated, separate caller-ownedpublishClientandsubscribeClientinstances. Transport close removes its subscriptions and listener without disconnecting either client, and durable queue/retry semantics remain with@fluojs/queue. -
@fluojs/cron: Decorator and registry scheduling for cron expressions, fixed intervals, and one-shot timeouts; immutable registry descriptor snapshots; rollback-safe dynamic cron expression and interval cadence updates whose provisional and retired handles stay tick-gated across replacement; stop-failure handle retention for retryable disable/remove operations and subsequent shutdown-hook cleanup; optional Redis distributed locking with named-client selection, lock TTL/owner controls validated before Redis I/O when enabled, per-acquisition lease tokens, release/renewal status accounting, and Redis peer loading only whendistributed.enabledistrue; bootstrap-aware dynamic task startup; bounded scheduler shutdown that rejects late queued ticks and reuses a shutdown-startshutdown.timeoutMsdeadline for post-task Redis release and immediate retry; and health/readiness status snapshots for lifecycle, task, and unresolved lock ownership visibility. Version 3 requires Node.js>=24.0.0 <27as its package-owned support contract. Consumers upgrading from version 2 must move Node.js versions below 24 and Node.js 27+ hosts to that supported range. -
@fluojs/notifications: Shared channel contract and orchestration layer for provider-specific notification packages. Application registration stays onNotificationsModule.forRoot(...)orNotificationsModule.forRootAsync({ inject, useFactory, global? }); exported notifications providers are global by default unlessglobal: falseopts into module-local visibility. It exposesNotificationsService.dispatch(...)anddispatchMany(...), optional queue-backed delivery seams for single opt-in, threshold-driven batch dispatch, and explicitdispatchMany(..., { queue: true })queue forcing belowbulkThreshold; lifecycle event publication through caller-supplied immutable observation snapshots that cannot alter the separately snapshotted channel resolution, queue jobs, generated identity, or provider delivery; deterministic generated fallback delivery/job keys for current envelope shapes while recommending caller-suppliednotification.idfor durable cross-release identity; and platform status snapshots/diagnostics throughNotificationsService.createPlatformStatusSnapshot()andcreateNotificationsPlatformStatusSnapshot(...), whereoperationMode,dependencies,bulkQueueThreshold,queueConfigured,eventPublisherConfigured, andeventPublicationEnabledlive under typeddetails. Publisher configuration remains separately visible from lifecycle enablement, sopublishLifecycleEvents: falsedoes not report an active event dependency or external ownership. Concrete queue and event-bus implementations remain outside the foundation package so applications can wire@fluojs/queue,@fluojs/event-bus, or another runtime explicitly. Queue adapter handoffs receive an optionalNotificationsQueueContextwith the caller's liveAbortSignal; the service prevents pre-aborted queue I/O, while adapters own listener cleanup and queue-specific mid-flight cancellation policy. -
@fluojs/email: Transport-agnostic email delivery core. Application registration stays onEmailModule.forRoot(...)orEmailModule.forRootAsync({ inject, useFactory, global? }); async registration does not support NestJSimports,useClass, oruseExisting, and exported email providers are global by default unlessglobal: falseopts into module-local visibility. It provides directEmailServicedelivery, a first-party notifications channel, unconditionalEmailLifecycleErrorrejection instopping,stopped, orfailedstates, and opt-inverifyOnModuleInitstartup gating that waits for successful bootstrap verification before transport handoff. Without that option, delivery may proceed while the lifecycle iscreatedorstarting. The package also provides transport lifecycle/readiness/ownership status snapshots that surface queue metadata only when callers provide queue details explicitly and optional queue worker integration through@fluojs/email/queue. -
@fluojs/email/node: Node.js specific subpath for@fluojs/emailthat provides first-party Nodemailer/SMTP transport. -
@fluojs/slack: Webhook-first Slack delivery core that can run standalone or register a first-party notifications channel. It documentsSlackModule.forRoot(...)/forRootAsync(...)with default global provider visibility andglobal: falselocal-visibility opt-out, directSlackServicedelivery,SLACK_CHANNELnotifications integration, app-owned composition for multiple Slack clients,verifyOnModuleInitbootstrap verification when a transport exposes optionalverify(), shared bootstrap/shutdown ordering that keeps factory-owned transports open until verification settles, serialized factory-owned transport cleanup across bootstrap failure and shutdown,SlackTemplateRenderernotification template rendering, payload-over-rendered merge precedence for Slack content, lifecycle/readiness status snapshots, and a transport-agnostic boundary without directprocess.envreads. -
@fluojs/discord: Webhook-first Discord delivery core that can run standalone or register a first-party notifications channel. It documentsDiscordModule.forRoot(...)/forRootAsync({ inject, useFactory, global? }), default global provider visibility withglobal: falselocal-visibility opt-out, intentionally private internal provider helpers/tokens, directDiscordServicedelivery,DISCORD_CHANNELnotifications integration, lifecycle-gated sends, transport kind and resource ownership diagnostics, optionalverifyOnModuleInitbootstrap verification,DiscordTemplateRenderernotification template rendering,DiscordService.createPlatformStatusSnapshot()andcreateDiscordPlatformStatusSnapshot(...)status snapshots, and a transport-agnostic boundary without directprocess.envreads. -
@fluojs/websockets: Runtime-neutral WebSocket gateway authoring from the root and runtime-specific registration subpaths@fluojs/websockets/node,@fluojs/websockets/bun,@fluojs/websockets/deno, and@fluojs/websockets/cloudflare-workersthat expose registration and runtime projections, while the root alone owns shared decorator and metadata authoring primitives. It ownsWebSocketRoomServiceroom membership/broadcast semantics as a type-only contract implemented by the runtime lifecycle service and injected via@Inject(...)withNodeWebSocketGatewayLifecycleServicefrom@fluojs/websockets/node, or the matching*WebSocketGatewayLifecycleServicetoken on another runtime subpath, room broadcast backpressure applied only by the Node.js-backed adapter while fetch-style runtimes do not apply a backpressure policy to room broadcasts, normalized text and binary@OnMessage()payload dispatch with positional(payload, socket, request, socketId)inputs, ignored raw handler return values after awaited completion by default with opt-in{ event, data? }replies throughreplies: { mode: 'event-envelope' }, NodeIncomingMessageguard typing for the Node subpath, fetch-styleRequestguard typing for Bun/Deno/Workers subpaths, pre-upgrade rejection through booleans, structuredWebSocketUpgradeRejectionobjects, or thrown HTTP exceptions, token-onlyNodeWebSocketGatewayLifecycleServiceresolution from@fluojs/websockets/nodefor the Node implementation, typed runtime seams such as upgrade context/guard/rejection and gateway descriptors, native host/socket/binding types owned by platform packages, a terminal Node shutdown admission gate rechecked immediately before upgrade acceptance, and retained per-connection lifecycle state that keeps disconnect cleanup queued before or during shutdown inside the bounded drain. -
@fluojs/validation: Standard-decorator input validation, DTO materialization, and request-boundary safety.PickType,OmitType,PartialType, andIntersectionTypeare available only from@fluojs/validation/mapped-types; the root has no mapped-helper aliases. -
@fluojs/serialization: Decorator-aware response serialization and output DTO shaping withExpose,ExposeClassOptions,Exclude,Transform,TransformFunction,serialize(value), andSerializerInterceptorfor HTTP response-boundary integration.SerializerInterceptorshapes framework-managed handler values whileRequestContext.responseis uncommitted. After the response is committed, it bypasses serialization and returns the value it received fromnext.handle()unchanged; other interceptors may still transform the chain result.
@fluojs/prisma: Node.js>=24.0.0 <27Prisma ORM lifecycle and ALS-backed transaction context using hostAsyncLocalStorage; the package manifest declaresengines.node >=24.0.0 <27. It exportsPrismaModule.forRoot(...)/forRootAsync(...),PrismaServiceandPrismaServiceFacade<TClient>for current-client access, manualtransaction(...), abort-awarerequestTransaction(...), platform status snapshots, named client/service/options token helpers, and a@Transaction()decorator for Service-layer transaction boundaries. A default registration aliases thePrismaServiceclass token andgetPrismaServiceToken()to the same module-owned facade; named registrations are isolated, resolve throughgetPrismaServiceToken(name), and do not expose the class token.PrismaTransactionInterceptoris removed; application-owned request boundaries callrequestTransaction(...). Shutdown drains active request and service/manual transaction boundaries before disconnecting the registered client.@fluojs/drizzle: Node.js>=24.0.0 <27Drizzle ORM lifecycle and ALS-backed transaction context using Node'snode:async_hooks, under its package-owned support contract; Node versions below 24 and Node 27+ are unsupported. It exports@Transaction(),DrizzleDatabase<TDatabase>,DrizzleDatabaseFacade<TDatabase>, and status snapshot helpers. Application registration stays onDrizzleModule.forRoot(...)/forRootAsync(...); request-wide work uses explicitDrizzleDatabase.requestTransaction(...). Drizzle's Bun SQL, Cloudflare D1, and other non-Node drivers remain outside this wrapper until a non-Node transaction-context adapter is documented; those runtimes should expose raw Drizzle handles through application-owned fluo providers instead of importing the root wrapper.@fluojs/redis: App-scoped Redis client registration, raw-client injection, JSON-awareRedisServicefacade, named-client tokens, lifecycle-owned connect/quit timeout guardrails, bootstrap rejection of duplicate default or trimmed named registration ownership identities before a client is created, platform health/readiness status snapshot helpers, and documentation guidance that Pub/Sub subscribers use dedicated Redis connections rather than sharing the ordinary command client.@fluojs/cache-manager: Application cache module registration through synchronousCacheModule.forRoot(options)or injected-factoryCacheModule.forRootAsync({ inject, useFactory, global? }), memory/Redis/custom store selection, decorator-driven GET response caching, post-write cache eviction, injectedCacheServiceoperations, low-level cache metadata helper exports, and platform status/diagnostic helpers for cache readiness. Normalized configuration shapes are private provider-assembly details. The package declaresengines.node >=24.0.0 <27as its package-owned support contract, excluding Node versions below 24 and Node 27+.@fluojs/throttler: Node.js>=24.0.0 <27decorator-driven request rate limiting withThrottlerModule.forRoot(options), explicitThrottlerGuardactivation, route/class override decorators, in-memory and Redis/custom store contracts, proxy-aware client identity controls, shared route/client bucket semantics, custom-storeretryAfterMssupport for authoritative backing-store clocks, and platform status/diagnostic helpers for backing-store readiness, ownership, and local or distributed operation visibility.@fluojs/queue: Redis-backed BullMQ job processing whose package manifest declaresengines.node >=24.0.0 <27as its package-owned support contract. Consumers upgrading from Node.js versions below 24 and Node.js 27+ must move to a supported release. Queue provides decorator-discovered singleton workers, application-suppliedownershipNamespaceidentities independent of DIclientName, pre-resource(ownershipNamespace, jobName)collision validation, 2.x compatibility diagnostics by default, opt-inownershipEnforcement: 'reject'bootstrap rejection, queue-owned duplicate Redis connections, JSON-object payload serialization, dead-letter retention, bounded read-onlyinspectDeadLetters(...)access with newest-first typed results and malformed-record counts, bootstrap-ready worker startup, bounded worker shutdown throughworkerShutdownTimeoutMs, and lifecycle/readiness status snapshots.@fluojs/mongoose: Node.js>=24.0.0 <27Mongoose lifecycle integration with application-owned concrete connections and ALS/session-aware transaction boundaries via Node'snode:async_hooks, under its package-owned support contract; Node versions below 24 and Node 27+ are unsupported. It exports@Transaction(), explicitrequestTransaction(...)request boundaries, aMongooseConnection.model(...)facade that auto-binds sessions forcreate,find,findOne,aggregate, andbulkWrite, explicitcurrentSession()access for unsupported model operations, ambient-session delegation throughconnection.transaction(...)when available, fail-open direct execution when transaction APIs are unavailable unlessstrictTransactionsis enabled, andMongooseConnection.createPlatformStatusSnapshot()shutdown snapshots that report active request/session drain state. It does not exportMongooseTransactionInterceptororcreateMongooseProviders(...).@fluojs/metrics: Node.js>=24.0.0 <27Prometheus scrape endpoint registration throughMetricsModule.forRoot(...), optional HTTP request collectors, endpoint-scopedendpointMiddleware, distinct module-levelmiddleware, runtime platform telemetry gauges, isolated-by-default or explicitly sharedprom-clientregistry ownership,MetricsServicefor custom application counters/gauges/histograms plus advancedgetRegistry()access, theRegistryre-export for shared-registry setups, and the low-levelMETER_PROVIDER/PrometheusMeterProviderbridge plus meter abstraction types for package integrations; the package manifest declaresengines.node >=24.0.0 <27.@fluojs/terminus: Aggregated health/readiness diagnostics withTerminusModule.forRoot(...), indicator/provider registration, exported indicator/provider DI tokens, execution timeouts for slow indicators, service-scoped in-flight indicator serialization, runtime platform health/readiness contributors, Prisma/Drizzle lifecycle-aware provider diagnostics, Node memory/disk indicators through@fluojs/terminus/node, and Redis lifecycle-awarePINGdiagnostics through@fluojs/terminus/rediswithout making the root package depend on optional Redis or Prisma peers, or the optional Drizzle peer.
@fluojs/cli: Node.js>=24.0.0 <27project scaffolding, generation, codemods, and inspection export/delegation for runtime-produced snapshots. This is its package-owned support contract: upgrade Node 20 and Node 22 hosts to Node.js>=24.0.0 <27; Node versions below 24 and Node 27+ are unsupported.fluo inspectowns CLI argument validation, application bootstrap/close, default JSON snapshot serialization, snapshot-plus-timing envelopes for--timing, support report artifact writing for--report,--output <path>file emission, and the handoff to Studio for Mermaid rendering. Forfluo dev --studio, the CLI-owned sidecar shares repeated or concurrentStudioSidecar.close()calls, ends its tracked SSE responses, and closes only active authenticated ingestion sockets so a client-held incomplete body cannot keep CLI teardown pending; completed ordinary requests remain outside that ingestion ownership set.@fluojs/studio: Node.js>=24.0.0 <27CLI sidecar/viewer package for the Node dev-runnerfluo dev --studiolive MVP plus static snapshot/report/timing compatibility for CI, support, architecture review, and non-Node runtime fallback workflows. Studio owns the responsibility boundary for consuming sidecar live events (snapshot,request,timing,diagnostic,restart,disconnect, andheartbeat), validating live event envelopes throughparseStudioLiveEvent(...),validateStudioLiveEvent(...), andisStudioLiveEvent(...), rejecting body-like fields (body,headers,payload,rawBody,requestBody, andresponseBody) on live request events, readingfluo inspect --jsonsnapshots, legacy standalone timing diagnostics,--timingand--json --timingsnapshot-plus-timing envelopes,--reportartifacts throughparseStudioPayload(...), filtering withapplyFilters(...), Mermaid graph rendering throughrenderMermaid(snapshot), resolving@fluojs/studio/vieweras a Node package-resolution HTML asset subpath, and exporting root Studio contract types such asStudioLiveEvent,StudioLiveSnapshot, andStudioRequestTracefor tooling.@fluojs/testing: Node.js>=24.0.0 <27conformance and integration helpers for verifying application and platform contracts, includingTest.createTestingModule({ rootModule }), request-levelTest.createApp(...), the@fluojs/testing/httprequest helper subpath, Vitest decorator tooling, request-scoped DI isolation regression helpers, body-bearing RFCQUERYand single-byte-range listener portability assertions, and portability harness cleanup guarantees.@fluojs/vite: Node.js>=24.0.0 <27Vite-facing build utilities for fluo projects; the package manifest declaresengines.node >=24.0.0 <27. It includes the maintainedfluoDecoratorsPlugin()used by generated startervite.config.tsfiles, requires Vite>=6.2.0, and lazily resolves Babel peers from eligible application.tstransforms rather than package import or plugin creation. The workspace suite runs Vite 8.2.2/Rolldown and executes field-decorator metadata while locking the plugin's pre-transform ordering.
Studio's Node.js >=24.0.0 <27 engine floor remains independently installable because its consumer-side snapshot, diagnostic, and timing declarations are runtime-neutral; @fluojs/runtime is a development-time drift check rather than a published Studio dependency. The runtime-neutral PlatformCheckResult, PlatformReadinessReport, and PlatformHealthReport declarations preserve check outcomes across inspect artifacts, and readiness and health reports may each include optional checks.
Runtime packages remain the source of inspection snapshots, timing diagnostics, request traces, route descriptors, live diagnostics, and sidecar events. The CLI either streams those values to Studio through the Node dev-runner fluo dev --studio sidecar or turns them into transportable artifacts: raw JSON, standalone timing diagnostics, a snapshot-plus-timing envelope, a report artifact, or Mermaid text when Studio is installed. @fluojs/runtime/devtools is the documented transport-neutral package-integration subpath for a host-owned StudioDevtoolsRuntime; applications pass it through the studioDevtools bootstrap option instead of mutating a process-global. Bun, Deno, and Cloudflare Workers projects use the inspect/static artifact path unless their owner supplies both a bridge and executable host integration evidence. Studio is responsible for reading, validating, filtering, viewing, and rendering both live sidecar state and inspect artifacts for humans and automation callers.
This boundary keeps graph semantics out of @fluojs/cli: the CLI may locate @fluojs/studio and call renderMermaid(snapshot), but Studio defines how internal dependency edges and external dependency nodes become Mermaid output. Consumers should use the versioned report recipe fluo inspect --report --output <path> for newly stored artifacts. Raw snapshots via fluo inspect --json --output <path>, snapshot-plus-timing envelopes via fluo inspect --timing --output <path> or fluo inspect --json --timing --output <path>, and legacy timing readers remain supported for compatibility.
platform-*: Reserved for runtime/protocol adapters that implement the documented adapter seam (HttpApplicationAdapterfor HTTP transports).*service: Concrete implementation of business logic.*module: Entry point for a package's runtime initialization.
Module and provider registration APIs use namespace facades rather than public create* factories. Application-facing module entrypoints should be exposed as XModule.forRoot(...), XModule.forRootAsync(...), XModule.register(...), or XModule.forFeature(...), with provider assembly kept internal to the package. For example, application code should import HealthModule.forRoot(...), QueueModule.forRoot(...), or TerminusModule.forRoot(...) instead of calling low-level provider/module factory helpers directly.
Raw Node adapter creation uses one path: NodeHttpApplicationAdapter.create(options) from @fluojs/platform-nodejs. Compression and multipart belong in the same options object. The existing class token and constructor remain; follow the creation migration for removed duplicate factories and type aliases.
create* remains valid for intentionally documented helper and builder APIs that do not register package modules or provider sets by themselves. Testing construction is not a free-factory exception: Test is the only public entrypoint, with Test.createApp(...) and Test.createTestingModule(...); conformance and portability harnesses use XHarness.create(...). Standalone Terminus values use XHealthIndicator.create(...). @fluojs/terminus documents only createPrismaHealthIndicatorProvider(...), createDrizzleHealthIndicatorProvider(...), and createRedisHealthIndicatorProvider(...) as indicator-level DI composition entries for TerminusModule.forRoot({ indicatorProviders }); they are not module registration facades. When a create* symbol is retained for compatibility with a module registration surface, docs and generated code should prefer the namespace facade and describe the helper as compatibility-only; for example, @fluojs/drizzle consumers should use DrizzleModule.forRoot(...) / forRootAsync(...) for application registration and receive the module-owned facade through injection, @fluojs/mongoose consumers should use MongooseModule.forRoot(...) / forRootAsync(...) for application registration because it does not expose createMongooseProviders(...), and @fluojs/microservices consumers should use MicroservicesModule.forRoot(...) with transport classes imported from their dedicated subpaths and created with create(...). @fluojs/passport documents createPassportJsStrategyBridge(...) as an official manual-composition exception because third-party Passport.js strategy instances must be bound through a provider bundle before PassportModule.forRoot(...) can register the matching strategy; cookie authentication uses the complete CookieAuthModule.forRoot(...) recipe, while separately owned cookie writers use CookieManager.create(...).
Refer to glossary-and-mental-model.md for architectural definitions.
@fluojs/mongoose exports neither createMongooseProviders(...) nor
MongooseTransactionInterceptor. Register application-owned connections only through
MongooseModule.forRoot(...) or MongooseModule.forRootAsync(...), inject
MongooseConnection, and keep an explicit request boundary application-owned
by forwarding the request signal to requestTransaction(...).
Microservices transport learning paths link back to the package contract source: TCP, RabbitMQ, and gRPC complement packages/microservices/README.md without replacing its facade, shutdown, and transport ownership contracts.
@fluojs/notifications reports configured publisher infrastructure independently from enabled lifecycle publication.
| Interface | Immutable fields |
|---|---|
NotificationSnapshotArrayBuffer |
kind: 'ArrayBuffer', byteLength, bytes |
NotificationSnapshotArrayBufferView |
kind: 'ArrayBufferView', byteOffset, byteLength, bytes, view |
NotificationSnapshotDate |
kind: 'Date', epochMilliseconds: number | null |
NotificationSnapshotMap<TKey, TValue> |
kind: 'Map', entries |
NotificationSnapshotRegExp |
kind: 'RegExp', source, flags, lastIndex |
NotificationSnapshotSet<TValue> |
kind: 'Set', values |
NotificationSnapshotUrl |
kind: 'URL', href |
NotificationSnapshotUrlSearchParams |
kind: 'URLSearchParams', query |
@fluojs/drizzle supports one default registration plus non-global named registrations. Consumers import
a module that exports the matching package-owned raw database, normalized options, disposal-hook, and lifecycle-handle
tokens. Each named registration owns an independent ALS transaction context, shutdown drain, disposal, and status
snapshot. Names do not create isolated runtime containers.
The default DrizzleDatabase class token remains default-only. Multi-client services inject a named handle token
and select it explicitly with @Transaction(...).