Nile Server
Type: Reference / Specification
Path: nile/
1. Purpose
The Nile Server module provides the top-level factory for bootstrapping a Nile application. createNileServer is the single entry point developers use to wire together the Action Engine, shared context, and interface layers (REST, and later WebSocket/RPC).
1.1 Responsibilities
- Bootstrapping: Create and connect the Action Engine,
NileContext, and REST interface from a singleServerConfig - Context ownership: Create a single
NileContextinstance shared across all interfaces - Context access: Export
getContext()to retrieve the runtime context from anywhere within a request scope - Lifecycle: Execute
onBoothooks after initialization with crash safety - Diagnostics: Route diagnostic output through
createDiagnosticsLogfromutils/diagnostics-log.ts, which checksresources.loggerfirst and falls back toconsole.log. Seedocs/internals/logging.mdsection 7.
1.2 Non-Goals
- Transport logic: The server module does not handle HTTP routing, CORS, or request parsing. That is the REST layer's responsibility.
- Engine internals: The server does not manage action execution or hook pipelines. It delegates to the engine.
2. createNileServer
Path: nile/server.ts
2.1 Initialization Sequence
- Validate: Throws immediately if
config.servicesis empty - Create
NileContext: Single instance withconfig.resourcesattached - Create Engine: Passes
services,diagnostics, and global hook handlers - Log services table: When
config.logServicesistrue, prints aconsole.tableof registered services (name, description, actions). Always prints, not gated bydiagnostics - Create REST app: Only if
config.restis provided. Passes engine, context,serverName, andruntime(defaults to"bun") - Print REST endpoint URLs: When REST is configured, prints
POST http://host:port/baseUrl/servicesand optionallyGET http://host:port/statusviaconsole.log. Usesrest.host(default"localhost") andrest.port(default8000) - Run
onBoot: Async IIFE that awaits the callback. On failure, logs via diagnostics logger and callsprocess.exit(1)to crash the process. The server must not run in a degraded state after a failed boot sequence
2.2 Return Value (NileServer)
restis only present whenconfig.restwas providedengineprovides direct access togetServices,getServiceActions,getAction,executeActioncontextis the sharedNileContextpassed to all layersaddMiddlewareregisters middleware that runs before the services POST handler. Middleware is executed in registration order via a dynamic runner. A middleware can return aResponseto short-circuit the request (skipping downstream middleware and the handler).
3. ServerConfig
runtimelives only onServerConfigand is piped tocreateRestAppas a parameter. It is not duplicated ontoRestConfig.servicesis required. An empty array throws at initialization.diagnosticsdefaults tofalse. When enabled, internal modules emit diagnostic output throughcreateDiagnosticsLog.logServicesdefaults totrue. Prints aconsole.tableof registered services (Service, Description, Actions count). Not gated bydiagnostics. SetlogServices: falseto suppress.- When REST is configured, endpoint URLs are always printed via
console.logusingrest.host(default"localhost") andrest.port(default8000). forceNewInstancedefaults tofalse. Whenfalse, a secondcreateNileServercall returns the existing server instance with a warning logged. Set totrueto explicitly create a new instance (useful in tests).
4. NileContext
Path: nile/nile.ts
Factory: createNileContext(params?)
The context is a singleton per server. It carries interface-specific data, hook execution state, session storage, and a general-purpose key-value store. It supports an optional TDB generic to provide type safety for the database resource.
4.1 Key-Value Store
_store is a Map<string, unknown> exposed as readonly. Use get/set methods for access.
4.2 Sessions
Each NileContext owns its own session store. Multiple server instances do not share session state.
Session keys are "rest" | "ws" | "rpc", matching the interface types.
4.3 Hook Context
hookContext tracks the lifecycle of a single action execution. It is reset at the start of each executeAction call via resetHookContext(actionName, input).
Mutation methods: updateHookState, addHookLog, setHookError, setHookOutput.
4.4 Request-Scoped Contexts (AsyncLocalStorage)
Interface-specific data (rest, ws, rpc, sessions) is isolated per-request via AsyncLocalStorage. Concurrent requests never see each other's state.
The REST layer wraps each incoming request in runInRequestScope(), which creates an isolated RequestStore for that request's lifetime. All async continuations within the request see the same store.
Key exports:
RequestStore: interface for per-request state (rest,ws,rpc,sessions)runInRequestScope(store, fn): runs a callback within an isolated request scopegetRequestStore(): retrieves the current request's store (undefined outside a request)
4.5 Resources
Extensible via index signature. Passed through from ServerConfig.resources. The database field is typed as TDB (defaulting to unknown).
5. Key Types
5.1 BeforeActionHandler
Global hook that runs before every action. Returns a Result. Err halts the pipeline.
5.2 AfterActionHandler
Global hook that runs after every action. Receives the action result and can transform it.
5.3 Sessions
5.4 Resources
The logger field accepts a NileLogger. The return type of createLogger from the logging module enables handleError and createDiagnosticsLog to log through the same logger instance.
6. Constraints
- One context per server:
createNileContextis called once increateNileServer. All interfaces share this instance. - Generic Database Support: To avoid generic leakage into the core engine, the database type
TDBis only present inNileContextandResources. High-level components (Engine, REST) useunknown. onBootcrashes on failure: TheonBootcallback is awaited inside an async IIFE. If it fails,process.exit(1)is called. This is intentional. A failed boot means the server cannot operate correctly.- Singleton by default: A second
createNileServercall returns the existing instance unlessforceNewInstance: trueis passed. A warning is logged when the cached instance is returned. - Runtime default: If
config.runtimeis omitted, it defaults to"bun". This affects static file serving and runtime-specific behavior. - No dynamic service injection: Services are fixed at boot time. Adding services after initialization is not supported.
7. Failure Modes
- Empty services:
createNileServerthrows immediately with a descriptive error onBootcrash: Logged via diagnostics logger, thenprocess.exit(1). The server does not start in a degraded state.- Missing resources:
resourcesis optional. Diagnostics fall back toconsole.logwhenresources.loggeris absent (handled bycreateDiagnosticsLog) - Double initialization: Returns cached instance with a warning unless
forceNewInstance: true
8. getContext
Path: nile/server.ts
Exported function that retrieves the runtime NileContext from anywhere within a request scope. It accepts an optional TDB generic for type-safe database access. The context is stored in a module-level variable set during createNileServer initialization.
8.1 Usage Pattern
getContext is designed to be called from action handlers or utility functions that need access to the context but don't receive it as a parameter:
8.2 Constraints
- Must be called after server initialization:
getContextthrows if called beforecreateNileServerhas run - Must be called within a request scope: The context singleton is set at server boot. Per-request data (interface contexts, sessions) is isolated via AsyncLocalStorage. Use
context.get("rest")orcontext.getSession("rest")within request handlers
8.3 Failure Modes
- Called before server boot: Throws
"getContext: Server not initialized. Call createNileServer first."