Skip to main content

core

The runtime engine of the webda.io framework. It manages the full lifecycle of a Webda application: loading configuration, instantiating services, routing HTTP requests, managing sessions, and providing cross-cutting concerns like logging, metrics, and caching.

Architecture​

Architecture

The framework is organized into six layers:

Application Layer​

Responsible for discovering modules, loading configuration, and bootstrapping the runtime.

  • Application -- Scans the project, parses webda.config.json, discovers installed Moddas (service types) and Models, and caches everything for fast startup.
  • UnpackedApplication -- Development-oriented variant that auto-discovers webda.module.json files and creates default services (Router, Registry, CryptoService, SessionManager) when missing.
  • Configuration -- Defines the UnpackedConfiguration schema (version 4) with service definitions, global parameters, and application settings.
  • Runner -- Orchestrates startup: creates Core from Application, initializes all services, and registers SIGINT for graceful shutdown.
  • Application Hooks -- useApplication(), useModel(), useModelId(), useParameters() for accessing application state from anywhere in the call stack.

Core Runtime​

The central orchestrator that manages the service lifecycle and dependency graph.

  • Core -- Creates and initializes services with dependency tracking, maps Models to Stores and BinaryServices, manages the operation registry. Lifecycle: initial -> loading -> initializing -> ready -> stopping -> stopped.
  • InstanceStorage -- AsyncLocalStorage-based context that holds the current Core, Application, Router, and request context. Enables the hooks pattern without passing references through every function call.
  • Core Hooks -- useCore(), useService(), useDynamicService(), useModelStore(), useModelRepository(), getMachineId().
  • Events -- Async event system with lifecycle events: Webda.Init, Webda.Request, Webda.Result, Webda.404, Webda.OperationSuccess, Webda.Configuration.Applied, etc.
  • Errors -- Typed HTTP errors: Unauthorized (401), Forbidden (403), NotFound (404), BadRequest (400), Conflict (409), TooManyRequests (429), Redirect (302), and more.

Services Layer​

All application logic lives in services. Every service extends Service which provides logging, metrics, dependency injection, and event emission.

  • Service -- Base class for all application services. Provides @Inject decorator for DI, @Route for HTTP endpoints, logger per instance, metrics support, and lifecycle hooks (init(), resolve(), stop()).
  • ServiceParameters -- Base configuration class with change watching support. Services declare their config shape by extending this class.
  • CryptoService -- Encryption, JWT signing/verification, key management with rotation support. Pluggable encrypters for configuration secrets (crypt:<encrypter>:<data> values, SecretString, webda config encrypt).
  • BinaryService -- Abstract file/binary storage with metadata, integrity challenges, and model-attribute mapping.
  • ConfigurationService -- Dynamic configuration with hot-reload from external sources (files, Kubernetes ConfigMaps, other services).

Data Layer​

Persistent storage abstraction with query support.

  • Store -- Abstract storage with CRUD, query (via WebdaQL), conditional updates, and event emission (Created, Updated, Deleted). Automatically maps to Models via scoring.
  • MemoryStore -- In-memory implementation with optional file persistence. Used as the default Registry.
  • Registry -- Key-value store for framework internals (crypto keys, service state). Backed by any Store implementation.

HTTP / Request Layer​

Handles incoming HTTP requests and manages user sessions.

  • Router -- Routes HTTP requests to service methods, manages OpenAPI spec generation, request/CORS filters, and model REST endpoints.
  • OperationContext -- Typed request/response context with generic <Input, Parameters, Output>. Provides session access, parameter parsing, header management, and streaming.
  • SessionManager -- Abstract session load/save. Default implementation uses JWT tokens in secure cookies with optional backend storage.

Cross-Cutting Concerns​

Shared infrastructure available to all services.

  • Logger -- Structured logging with per-service context. Backed by @webda/workout.
  • Metrics -- Prometheus integration via prom-client. useMetric() creates Counters, Gauges, and Histograms with automatic service labels.
  • Cache -- Decorator-based caching at four scopes: @ProcessCache() (global), @InstanceCache() (per Core), @SessionCache() (per user), @ContextCache() (per request).
  • Queue -- Message queue consumer pattern with configurable parallelism, retry backoff, and metrics. Extend for SQS, AMQP, etc.
  • Models -- Model registry with built-in types: CoreModel, User, Ident, ACLModel, OwnerModel, RegistryEntry.
  • Execution Context -- AsyncLocalStorage-based context for useContext(), useCurrentUser(), runAsSystem(), runWithContext().

Request Flow​

HTTP Request
|
v
HttpContext (parse headers, cookies, body)
|
v
OperationContext / WebContext (typed I/O)
|
v
SessionManager.load() (JWT from cookie)
|
v
Router.execute() (match route, run filters)
|
v
Service method (business logic)
|
v
SessionManager.save() (persist if dirty)
|
v
HTTP Response

Hooks API​

The hooks pattern provides access to framework singletons from any point in the call stack, powered by AsyncLocalStorage:

HookReturnsUse case
useCore()CoreAccess the runtime engine
useApplication()ApplicationAccess project metadata and configuration
useService(name)Typed serviceGet a named service ("Registry", "CryptoService", etc.)
useDynamicService(name)ServiceGet a service by arbitrary name
useModel(name)ModelDefinitionGet a model class with metadata
useModelId(object)stringGet the model identifier for an instance
useModelStore(name)IStoreGet the store assigned to a model
useModelRepository(name)RepositoryGet the repository for a model
useContext()ContextGet the current request context
useCurrentUser()UserGet the authenticated user
useCurrentUserId()stringGet the user ID or "system"
useLogger(class)LoggerGet a logger with class context
useMetric(type, config)Counter/Gauge/HistogramCreate a prometheus metric
useParameters()Configuration["parameters"]Get global configuration parameters
getMachineId()stringGet a stable machine identifier

Dependency Injection​

Services declare dependencies with the @Inject decorator:

import { Service, Inject } from "@webda/core";

class MyService extends Service {
// Inject by service name
@Inject("CryptoService")
crypto: CryptoService;

// Inject from a parameter value
@Inject("params:storeName", "Registry")
store: Store;

// Optional injection
@Inject("NotificationService", undefined, true)
notifications?: NotificationService;
}

Configuration​

Applications are configured via webda.config.json (version 4):

{
"version": 4,
"parameters": {
"routePrefix": "/api",
"metrics": { "prefix": "myapp_" }
},
"services": {
"MyStore": {
"type": "MemoryStore",
"model": "MyApp/MyModel"
},
"MyService": {
"type": "MyApp/MyService",
"storeName": "MyStore"
}
}
}

Template variables​

replaceVariables(value, replacements) and templateVariables(value, replacements) substitute ${path.to.property} using own properties of the replacement data. templateVariables also adds the application project information and now. Prefix a placeholder with `` to keep it literal.

Templates support the string transforms .toUpperCase(), .toLowerCase(), .trim(), .trimStart(), and .trimEnd(). Other JavaScript expressions, arbitrary function calls, and prototype traversal are rejected. Compute other values in application code and pass them as replacements. Backticks and backslashes outside placeholders are ordinary text.

Events​

Services emit typed async events. Subscribe with on():

// Core lifecycle events
useCoreEvents("Webda.Init", () => { /* framework ready */ });
useCoreEvents("Webda.Request", ({ context }) => { /* new request */ });

// Store events
myStore.on("Store.Created", ({ object }) => { /* model created */ });
myStore.on("Store.Updated", ({ object }) => { /* model updated */ });
myStore.on("Store.Deleted", ({ object }) => { /* model deleted */ });

Error Handling​

Throw typed HTTP errors from services:

import * as WebdaError from "@webda/core";

throw new WebdaError.NotFound("User not found");
throw new WebdaError.Forbidden("Insufficient permissions");
throw new WebdaError.BadRequest("Invalid input", "VALIDATION_ERROR");
throw new WebdaError.Redirect("https://example.com/new-location");

Ecosystem​

@webda/core is the foundation. The full framework includes:

PackagePurpose
@webda/modelsModel base classes, relations, repositories
@webda/compilerTypeScript compiler with schema generation
@webda/utilsUtilities (debounce, dirty tracking, state machines) and shared TypeScript utility types
@webda/workoutLogging infrastructure
@webda/testMulti-framework test decorators (vitest, jest, mocha, bun)
@webda/qlWebdaQL query language
@webda/cloudeventsCloudEvents filtering
@webda/cacheCaching decorators
@webda/serializeSerialization framework
@webda/content-mapperJSON Schema generator

Deep-dive sub-pages​

  • Architecture — 6-layer overview with diagram
  • Service Lifecycle — resolve → init → run → stop
  • Services — Service, @Bean, @Inject, ServiceParameters
  • Stores — Store contract, query interface, events
  • Context — WebContext, sessions, request lifecycle
  • Routing — @Route, @Operation, REST auto-generation
  • Events — Core.on, store events, @On decorator
  • Errors — WebdaError hierarchy and HTTP status mapping
  • Logging — useLog + @webda/workout integration
  • CLI — webda runtime commands

CoreFeatures​

CoreServices​

Other​