Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 11 additions & 5 deletions docs/getting-started/application-startup.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,18 @@ import { applicationConsumers } from './apps/ApplicationConsumers.js';
import { recurringSchedulers } from './apps/ApplicationSchedulers.js';
import GetUserByIdRoute from './apps/api/routes/GetUserByIdRoute.js';

const environmentSchema = {
NODE_ENV: { defaultValue: 'local', type: 'string' },
PORT: { defaultValue: 3000, type: 'number' },
} as const;

const kernel = new Kernel({
environmentSchema,
sourceDirectory: 'src',
servicesYamlPath: 'config/container/services.yaml',
});

kernel.loadEnvironmentVariables(process.env.NODE_ENV || 'local');
kernel.loadEnvironmentVariables();

await kernel.dependencyInjection({
containerBuild: kernel.environment.NODE_ENV !== 'production',
Expand All @@ -27,21 +33,21 @@ kernel.registerSchedulers(...recurringSchedulers);

const server = new ExpressKernelServer({
kernel,
port: Number(kernel.environment.PORT ?? 3000),
port: kernel.environment.PORT,
});
kernel.registerShutdownHook(() => server.close());

await server.run();
await kernel.runConsumers();
await kernel.runSchedulers();

kernel.logger.info(
`Application running on port ${kernel.environment.PORT ?? 3000}`,
);
kernel.logger.info(`Application running on port ${kernel.environment.PORT}`);
```

`loadEnvironmentVariables()` loads `.env.local` by default when `NODE_ENV` is
not set. Passing `test` loads `.env.test`; passing an empty string loads `.env`.
When a schema is configured, required variables are validated and values are
parsed before they are exposed through `kernel.environment`.

`containerBuild: true` regenerates `config/container/services.yaml`. Production
runtimes should usually load the generated YAML instead of rebuilding from
Expand Down
14 changes: 7 additions & 7 deletions docs/getting-started/package-map.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,13 @@ Bootstrap code chooses adapters.

## Core

| Area | Import | Purpose |
| ---------------------- | ----------------------------------------- | ------------------------------------------------------------------------ |
| Kernel runtime | `@haskou/ddd-kernel` | Registers consumers, routes, schedulers, runtimes and shutdown hooks. |
| Environment variables | `@haskou/ddd-kernel` | Loads `.env.<environment>` files and exposes `Kernel.environment`. |
| Dependency injection | `@haskou/ddd-kernel/dependency-injection` | Wraps `node-dependency-injection` and container YAML generation/loading. |
| Lifecycle | `@haskou/ddd-kernel/lifecycle` | Runtime and initializer contracts. |
| Kernel logger contract | `@haskou/ddd-kernel/contracts/kernel` | `KernelLogger` interface. |
| Area | Import | Purpose |
| ---------------------- | ----------------------------------------- | ---------------------------------------------------------------------------------------------------- |
| Kernel runtime | `@haskou/ddd-kernel` | Registers consumers, routes, schedulers, runtimes and shutdown hooks. |
| Environment variables | `@haskou/ddd-kernel` | Loads `.env.<environment>` files and exposes typed `kernel.environment` when a schema is configured. |
| Dependency injection | `@haskou/ddd-kernel/dependency-injection` | Wraps `node-dependency-injection` and container YAML generation/loading. |
| Lifecycle | `@haskou/ddd-kernel/lifecycle` | Runtime and initializer contracts. |
| Kernel logger contract | `@haskou/ddd-kernel/contracts/kernel` | `KernelLogger` interface. |

`dotenv`, `node-dependency-injection` and `fs-extra` are package dependencies
because the core environment and DI implementations use them directly.
Expand Down
27 changes: 19 additions & 8 deletions docs/reference/kernel.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,18 +79,29 @@ kernel-owned access point:
const port = Number(Kernel.environment.HTTP_PORT ?? 3000);
```

Applications can type known variables by augmenting `NodeJS.ProcessEnv`:
For typed access and runtime validation, pass an environment schema when
creating the kernel:

```ts
declare global {
namespace NodeJS {
interface ProcessEnv {
HTTP_PORT?: string;
}
}
}
const environmentSchema = {
ENABLE_JOBS: { defaultValue: false, type: 'boolean' },
HTTP_PORT: { required: true, type: 'number' },
SERVICE_NAME: { type: 'string' },
} as const;

const kernel = new Kernel({ environmentSchema });

kernel.loadEnvironmentVariables();

kernel.environment.HTTP_PORT; // number
kernel.environment.ENABLE_JOBS; // boolean
kernel.environment.SERVICE_NAME; // string | undefined
```

Required variables throw `KernelEnvironmentValidationError` when they are
missing. `number` and `boolean` values are parsed after `.env` files are loaded.
Boolean values accept `true`, `false`, `1`, `0`, `yes`, `no`, `on` and `off`.

## Dependency Injection

Most applications call this once during startup:
Expand Down
13 changes: 8 additions & 5 deletions example/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,15 @@ import path from 'node:path';
import GetUserByIdRoute from './apps/api/routes/GetUserByIdRoute.js';

const rootDirectory = process.cwd();
const environmentSchema = {
NODE_ENV: { defaultValue: 'local', type: 'string' },
PORT: { defaultValue: 3000, type: 'number' },
} as const;

// The kernel owns application lifecycle, dependency injection and shared
// infrastructure such as logging.
const kernel = new Kernel({
environmentSchema,
servicesYamlPath: path.resolve(
rootDirectory,
'config',
Expand All @@ -33,7 +38,7 @@ const kernel = new Kernel({

// Environment variables are loaded before DI/adapters read their process.env
// fallbacks. With NODE_ENV unset this loads .env.local.
kernel.loadEnvironmentVariables(process.env.NODE_ENV || 'local');
kernel.loadEnvironmentVariables();

// In development the container is rebuilt from default exports under src/.
// In production it can reuse the generated services.yaml file.
Expand Down Expand Up @@ -64,7 +69,7 @@ const requestLoggerMiddleware: RequestHandler = (request, response, next) => {

const server = new ExpressKernelServer({
kernel,
port: Number(kernel.environment.PORT ?? 3000),
port: kernel.environment.PORT,
});

// The Express adapter stays optional. HTTP middleware, hooks and error handlers
Expand All @@ -88,9 +93,7 @@ server
kernel.registerShutdownHook(() => server.close());

await server.run();
kernel.logger.info(
`Application running on port ${kernel.environment.PORT ?? 3000}`,
);
kernel.logger.info(`Application running on port ${kernel.environment.PORT}`);

// Delegate OS signals to the kernel so consumers, schedulers, servers and logs
// are stopped consistently.
Expand Down
2 changes: 1 addition & 1 deletion example/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@
integrity sha512-Waj1cwPXJDucOib4a3bAISsKJVb15MKi9IvmTI/7ssVEm6sywXGjVJDhl6/umt1pK1ZS7PacXU3A1PmFKHEZ2w==

"@haskou/ddd-kernel@file:..":
version "1.0.3"
version "1.1.0"
dependencies:
dotenv "^16.6.1"
fs-extra "^11.3.5"
Expand Down
Loading
Loading