@digital-alchemy/core 26.1.9 → 26.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CLAUDE.md +302 -0
- package/README.md +19 -3
- package/dist/helpers/async.d.mts +37 -0
- package/dist/helpers/async.mjs +50 -15
- package/dist/helpers/async.mjs.map +1 -1
- package/dist/helpers/config-environment-loader.d.mts +39 -0
- package/dist/helpers/config-environment-loader.mjs +51 -11
- package/dist/helpers/config-environment-loader.mjs.map +1 -1
- package/dist/helpers/config-file-loader.d.mts +66 -1
- package/dist/helpers/config-file-loader.mjs +82 -6
- package/dist/helpers/config-file-loader.mjs.map +1 -1
- package/dist/helpers/config.d.mts +202 -5
- package/dist/helpers/config.mjs +60 -0
- package/dist/helpers/config.mjs.map +1 -1
- package/dist/helpers/context.d.mts +12 -1
- package/dist/helpers/cron.d.mts +154 -7
- package/dist/helpers/cron.mjs +47 -4
- package/dist/helpers/cron.mjs.map +1 -1
- package/dist/helpers/errors.d.mts +45 -0
- package/dist/helpers/errors.mjs +45 -0
- package/dist/helpers/errors.mjs.map +1 -1
- package/dist/helpers/events.d.mts +23 -0
- package/dist/helpers/events.mjs +23 -0
- package/dist/helpers/events.mjs.map +1 -1
- package/dist/helpers/extend.d.mts +50 -0
- package/dist/helpers/extend.mjs +63 -0
- package/dist/helpers/extend.mjs.map +1 -1
- package/dist/helpers/index.d.mts +9 -0
- package/dist/helpers/index.mjs +9 -0
- package/dist/helpers/index.mjs.map +1 -1
- package/dist/helpers/lifecycle.d.mts +102 -16
- package/dist/helpers/lifecycle.mjs +19 -1
- package/dist/helpers/lifecycle.mjs.map +1 -1
- package/dist/helpers/logger.d.mts +178 -17
- package/dist/helpers/logger.mjs +41 -1
- package/dist/helpers/logger.mjs.map +1 -1
- package/dist/helpers/module.d.mts +110 -0
- package/dist/helpers/module.mjs +55 -6
- package/dist/helpers/module.mjs.map +1 -1
- package/dist/helpers/service-runner.d.mts +27 -1
- package/dist/helpers/service-runner.mjs +27 -1
- package/dist/helpers/service-runner.mjs.map +1 -1
- package/dist/helpers/utilities.d.mts +123 -3
- package/dist/helpers/utilities.mjs +110 -3
- package/dist/helpers/utilities.mjs.map +1 -1
- package/dist/helpers/wiring.d.mts +385 -0
- package/dist/helpers/wiring.mjs +120 -0
- package/dist/helpers/wiring.mjs.map +1 -1
- package/dist/services/als.service.d.mts +10 -0
- package/dist/services/als.service.mjs +49 -0
- package/dist/services/als.service.mjs.map +1 -1
- package/dist/services/configuration.service.d.mts +22 -0
- package/dist/services/configuration.service.mjs +140 -12
- package/dist/services/configuration.service.mjs.map +1 -1
- package/dist/services/index.d.mts +8 -0
- package/dist/services/index.mjs +8 -0
- package/dist/services/index.mjs.map +1 -1
- package/dist/services/internal.service.d.mts +98 -19
- package/dist/services/internal.service.mjs +91 -9
- package/dist/services/internal.service.mjs.map +1 -1
- package/dist/services/is.service.d.mts +64 -4
- package/dist/services/is.service.mjs +67 -4
- package/dist/services/is.service.mjs.map +1 -1
- package/dist/services/lifecycle.service.d.mts +26 -0
- package/dist/services/lifecycle.service.mjs +67 -9
- package/dist/services/lifecycle.service.mjs.map +1 -1
- package/dist/services/logger.service.d.mts +27 -0
- package/dist/services/logger.service.mjs +133 -9
- package/dist/services/logger.service.mjs.map +1 -1
- package/dist/services/scheduler.service.d.mts +19 -0
- package/dist/services/scheduler.service.mjs +87 -4
- package/dist/services/scheduler.service.mjs.map +1 -1
- package/dist/services/wiring.service.d.mts +29 -1
- package/dist/services/wiring.service.mjs +153 -20
- package/dist/services/wiring.service.mjs.map +1 -1
- package/dist/testing/index.d.mts +4 -0
- package/dist/testing/index.mjs +4 -0
- package/dist/testing/index.mjs.map +1 -1
- package/dist/testing/mock-logger.d.mts +8 -0
- package/dist/testing/mock-logger.mjs +9 -0
- package/dist/testing/mock-logger.mjs.map +1 -1
- package/dist/testing/test-module.d.mts +107 -27
- package/dist/testing/test-module.mjs +58 -1
- package/dist/testing/test-module.mjs.map +1 -1
- package/package.json +33 -31
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config-environment-loader.mjs","sourceRoot":"","sources":["../../src/helpers/config-environment-loader.mts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,cAAc,CAAC;AAEnC,OAAO,QAAQ,MAAM,UAAU,CAAC;AAEhC,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;AAQxC,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAG5E,MAAM,CAAC,KAAK,UAAU,uBAAuB,CAG3C,EACA,OAAO,EACP,QAAQ,EACR,MAAM,EACN,OAAO,GACyD;IAChE,MAAM,QAAQ,GAAG,CAAC,CAAC;IACnB,MAAM,YAAY,GAAG,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5C,MAAM,UAAU,GAAG,MAAM,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;IAC7C,MAAM,GAAG,GAA4B,EAAE,CAAC;IACxC,MAAM,cAAc,GAAG,QAAQ,CAAC,IAAI,CAAC,OAAO,EAAE,aAAa,EAAE,GAAG,IAAI,IAAI,CAAC;IACzE,MAAM,OAAO,GAAG,QAAQ,CAAC,IAAI,CAAC,OAAO,EAAE,aAAa,EAAE,IAAI,IAAI,IAAI,CAAC;IAEnE,MAAM,UAAU,GAAG,CAAC,MAAmB,EAAE,EAAE,CACzC,OAAO,IAAI,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC;IAC5D,MAAM,SAAS,GAAG,CAAC,MAAmB,EAAE,EAAE,CACxC,cAAc,IAAI,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC;IAElE,
|
|
1
|
+
{"version":3,"file":"config-environment-loader.mjs","sourceRoot":"","sources":["../../src/helpers/config-environment-loader.mts"],"names":[],"mappings":"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"}
|
|
@@ -1,7 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* File-based configuration loader — reads JSON, YAML, and INI config files.
|
|
3
|
+
*
|
|
4
|
+
* @remarks
|
|
5
|
+
* Supports four formats (JSON, YAML, INI, and auto-detect) and searches standard
|
|
6
|
+
* config paths: `/etc/{app}`, `./{app}` (walking up the directory tree),
|
|
7
|
+
* `~/.config/{app}`, and explicit `--config` flag overrides. Files are detected
|
|
8
|
+
* by extension and parsed accordingly; if extension is ambiguous, format detection
|
|
9
|
+
* occurs in order: JSON-like start, YAML parse, INI fallback. Multiple files are
|
|
10
|
+
* merged using `deepExtend`, with earlier files providing defaults.
|
|
11
|
+
*/
|
|
1
12
|
import type { ConfigLoaderParams, ConfigLoaderReturn, ModuleConfiguration } from "./config.mts";
|
|
2
13
|
import type { PartialConfiguration, ServiceMap } from "./wiring.mts";
|
|
14
|
+
/**
|
|
15
|
+
* Supported config file extensions.
|
|
16
|
+
*/
|
|
3
17
|
export declare const SUPPORTED_CONFIG_EXTENSIONS: string[];
|
|
18
|
+
/**
|
|
19
|
+
* Generate potential file paths for a given base path.
|
|
20
|
+
*
|
|
21
|
+
* @remarks
|
|
22
|
+
* Returns an array of paths including the base, a "config" subdirectory variant,
|
|
23
|
+
* and all supported extensions of each. This is used to generate candidates
|
|
24
|
+
* without checking filesystem; callers filter to existing files.
|
|
25
|
+
*
|
|
26
|
+
* @example
|
|
27
|
+
* ```
|
|
28
|
+
* withExtensions("myapp") returns:
|
|
29
|
+
* ["myapp", "myapp.json", "myapp.ini", "myapp.yaml", "myapp.yml",
|
|
30
|
+
* "myapp/config", "myapp/config.json", ...]
|
|
31
|
+
* ```
|
|
32
|
+
*/
|
|
4
33
|
export declare function withExtensions(path: string): string[];
|
|
34
|
+
/**
|
|
35
|
+
* Resolve all existing config files for an application.
|
|
36
|
+
*
|
|
37
|
+
* @remarks
|
|
38
|
+
* Searches in order: `/etc/{name}` (Unix only), `./.{name}` (walking up the
|
|
39
|
+
* directory tree), and `~/.config/{name}` (home directory). Returns only paths
|
|
40
|
+
* that exist and are regular files. Used as the default search order when no
|
|
41
|
+
* explicit `--config` flag is provided.
|
|
42
|
+
*/
|
|
5
43
|
export declare function configFilePaths(name: string): string[];
|
|
6
|
-
|
|
44
|
+
/**
|
|
45
|
+
* Load configuration from file(s).
|
|
46
|
+
*
|
|
47
|
+
* @remarks
|
|
48
|
+
* Checks for an explicit `--config` CLI flag or `CONFIG` config value; if
|
|
49
|
+
* provided and the file does not exist, exits fatally. Otherwise, searches
|
|
50
|
+
* standard paths using `configFilePaths`. Merges all found files using
|
|
51
|
+
* `deepExtend`, with earlier files as defaults.
|
|
52
|
+
*
|
|
53
|
+
* @throws {Error} (via process.exit) when `--config` points to a non-existent file
|
|
54
|
+
* or when argv parsing fails.
|
|
55
|
+
*/
|
|
56
|
+
export declare function configLoaderFile<S extends ServiceMap = ServiceMap, C extends ModuleConfiguration = ModuleConfiguration>({ application, logger, internal }: ConfigLoaderParams<S, C>): ConfigLoaderReturn;
|
|
57
|
+
/**
|
|
58
|
+
* Parse and merge a single config file into the output object.
|
|
59
|
+
*
|
|
60
|
+
* @remarks
|
|
61
|
+
* Detects format by extension first; if ambiguous or no extension matches,
|
|
62
|
+
* uses heuristics: if content starts with `{`, tries JSON; then YAML; finally
|
|
63
|
+
* falls back to INI. File is merged into `out` using `deepExtend`.
|
|
64
|
+
*
|
|
65
|
+
* @example
|
|
66
|
+
* ```
|
|
67
|
+
* const config: PartialConfiguration = {};
|
|
68
|
+
* loadConfigFromFile(config, "/etc/myapp.yaml");
|
|
69
|
+
* // config is now merged with the file contents
|
|
70
|
+
* ```
|
|
71
|
+
*/
|
|
7
72
|
export declare function loadConfigFromFile(out: PartialConfiguration, filePath: string): void;
|
|
@@ -1,3 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* File-based configuration loader — reads JSON, YAML, and INI config files.
|
|
3
|
+
*
|
|
4
|
+
* @remarks
|
|
5
|
+
* Supports four formats (JSON, YAML, INI, and auto-detect) and searches standard
|
|
6
|
+
* config paths: `/etc/{app}`, `./{app}` (walking up the directory tree),
|
|
7
|
+
* `~/.config/{app}`, and explicit `--config` flag overrides. Files are detected
|
|
8
|
+
* by extension and parsed accordingly; if extension is ambiguous, format detection
|
|
9
|
+
* occurs in order: JSON-like start, YAML parse, INI fallback. Multiple files are
|
|
10
|
+
* merged using `deepExtend`, with earlier files providing defaults.
|
|
11
|
+
*/
|
|
1
12
|
import fs from "node:fs";
|
|
2
13
|
import { homedir } from "node:os";
|
|
3
14
|
import { join } from "node:path";
|
|
@@ -9,44 +20,91 @@ import { is } from "../index.mjs";
|
|
|
9
20
|
import { deepExtend } from "./extend.mjs";
|
|
10
21
|
import { INVERT_VALUE, START } from "./utilities.mjs";
|
|
11
22
|
const isWindows = platform === "win32";
|
|
23
|
+
/**
|
|
24
|
+
* Supported config file extensions.
|
|
25
|
+
*/
|
|
12
26
|
export const SUPPORTED_CONFIG_EXTENSIONS = ["json", "ini", "yaml", "yml"];
|
|
27
|
+
/**
|
|
28
|
+
* Generate potential file paths for a given base path.
|
|
29
|
+
*
|
|
30
|
+
* @remarks
|
|
31
|
+
* Returns an array of paths including the base, a "config" subdirectory variant,
|
|
32
|
+
* and all supported extensions of each. This is used to generate candidates
|
|
33
|
+
* without checking filesystem; callers filter to existing files.
|
|
34
|
+
*
|
|
35
|
+
* @example
|
|
36
|
+
* ```
|
|
37
|
+
* withExtensions("myapp") returns:
|
|
38
|
+
* ["myapp", "myapp.json", "myapp.ini", "myapp.yaml", "myapp.yml",
|
|
39
|
+
* "myapp/config", "myapp/config.json", ...]
|
|
40
|
+
* ```
|
|
41
|
+
*/
|
|
13
42
|
export function withExtensions(path) {
|
|
14
43
|
return [path, join(path, "config")].flatMap(path => [
|
|
15
44
|
path,
|
|
16
45
|
...SUPPORTED_CONFIG_EXTENSIONS.map(i => `${path}.${i}`),
|
|
17
46
|
]);
|
|
18
47
|
}
|
|
48
|
+
/**
|
|
49
|
+
* Resolve all existing config files for an application.
|
|
50
|
+
*
|
|
51
|
+
* @remarks
|
|
52
|
+
* Searches in order: `/etc/{name}` (Unix only), `./.{name}` (walking up the
|
|
53
|
+
* directory tree), and `~/.config/{name}` (home directory). Returns only paths
|
|
54
|
+
* that exist and are regular files. Used as the default search order when no
|
|
55
|
+
* explicit `--config` flag is provided.
|
|
56
|
+
*/
|
|
19
57
|
export function configFilePaths(name) {
|
|
20
58
|
const out = [];
|
|
59
|
+
// system-wide config (Unix only)
|
|
21
60
|
if (!isWindows) {
|
|
22
61
|
out.push(...withExtensions(join(`/etc`, `${name}`)));
|
|
23
62
|
}
|
|
63
|
+
// search up the directory tree from cwd
|
|
24
64
|
let current = cwd();
|
|
25
65
|
let next;
|
|
26
66
|
while (!is.empty(current)) {
|
|
27
67
|
out.push(...withExtensions(join(current, `.${name}`)));
|
|
28
68
|
next = join(current, "..");
|
|
69
|
+
// stop at filesystem root
|
|
29
70
|
if (next === current) {
|
|
30
71
|
break;
|
|
31
72
|
}
|
|
32
73
|
current = next;
|
|
33
74
|
}
|
|
75
|
+
// user-local config
|
|
34
76
|
out.push(...withExtensions(join(homedir(), ".config", name)));
|
|
77
|
+
// filter to existing regular files
|
|
35
78
|
return out.filter(filePath => fs.existsSync(filePath) && fs.statSync(filePath).isFile());
|
|
36
79
|
}
|
|
37
|
-
|
|
80
|
+
/**
|
|
81
|
+
* Load configuration from file(s).
|
|
82
|
+
*
|
|
83
|
+
* @remarks
|
|
84
|
+
* Checks for an explicit `--config` CLI flag or `CONFIG` config value; if
|
|
85
|
+
* provided and the file does not exist, exits fatally. Otherwise, searches
|
|
86
|
+
* standard paths using `configFilePaths`. Merges all found files using
|
|
87
|
+
* `deepExtend`, with earlier files as defaults.
|
|
88
|
+
*
|
|
89
|
+
* @throws {Error} (via process.exit) when `--config` points to a non-existent file
|
|
90
|
+
* or when argv parsing fails.
|
|
91
|
+
*/
|
|
92
|
+
export async function configLoaderFile({ application, logger, internal }) {
|
|
38
93
|
const CLI_SWITCHES = minimist(process.argv);
|
|
39
|
-
const configFile = CLI_SWITCHES.config;
|
|
94
|
+
const configFile = CLI_SWITCHES.config ?? internal?.boot?.options?.configuration?.boilerplate?.CONFIG;
|
|
40
95
|
let files;
|
|
96
|
+
// argv parsing errors result in a boolean instead of a string
|
|
41
97
|
if (is.boolean(configFile)) {
|
|
42
98
|
logger.fatal({ argv: process.argv }, "system failed to parse argv");
|
|
43
99
|
process.exit();
|
|
44
100
|
}
|
|
45
101
|
else if (is.empty(configFile)) {
|
|
102
|
+
// no explicit config; search standard paths
|
|
46
103
|
files = configFilePaths(application.name);
|
|
47
104
|
logger.trace({ files, name: configLoaderFile }, `identified config files`);
|
|
48
105
|
}
|
|
49
106
|
else {
|
|
107
|
+
// explicit config file provided; must exist
|
|
50
108
|
if (!fs.existsSync(configFile)) {
|
|
51
109
|
logger.fatal({ configFile, name: configLoaderFile }, `used {--config} to specify path that does not exist`);
|
|
52
110
|
process.exit();
|
|
@@ -62,8 +120,24 @@ export async function configLoaderFile({ application, logger }) {
|
|
|
62
120
|
files.forEach(file => loadConfigFromFile(out, file));
|
|
63
121
|
return out;
|
|
64
122
|
}
|
|
123
|
+
/**
|
|
124
|
+
* Parse and merge a single config file into the output object.
|
|
125
|
+
*
|
|
126
|
+
* @remarks
|
|
127
|
+
* Detects format by extension first; if ambiguous or no extension matches,
|
|
128
|
+
* uses heuristics: if content starts with `{`, tries JSON; then YAML; finally
|
|
129
|
+
* falls back to INI. File is merged into `out` using `deepExtend`.
|
|
130
|
+
*
|
|
131
|
+
* @example
|
|
132
|
+
* ```
|
|
133
|
+
* const config: PartialConfiguration = {};
|
|
134
|
+
* loadConfigFromFile(config, "/etc/myapp.yaml");
|
|
135
|
+
* // config is now merged with the file contents
|
|
136
|
+
* ```
|
|
137
|
+
*/
|
|
65
138
|
export function loadConfigFromFile(out, filePath) {
|
|
66
139
|
const fileContent = fs.readFileSync(filePath, "utf8").trim();
|
|
140
|
+
// check if filename has a recognized extension and parse accordingly
|
|
67
141
|
const hasExtension = SUPPORTED_CONFIG_EXTENSIONS.some(extension => {
|
|
68
142
|
if (filePath.slice(extension.length * INVERT_VALUE).toLowerCase() === extension) {
|
|
69
143
|
switch (extension) {
|
|
@@ -81,15 +155,17 @@ export function loadConfigFromFile(out, filePath) {
|
|
|
81
155
|
}
|
|
82
156
|
return false;
|
|
83
157
|
});
|
|
158
|
+
// extension was recognized and parsed
|
|
84
159
|
if (hasExtension) {
|
|
85
160
|
return;
|
|
86
161
|
}
|
|
87
|
-
//
|
|
162
|
+
// no extension; try to detect format heuristically
|
|
163
|
+
// JSON objects start with `{`
|
|
88
164
|
if (fileContent[START] === "{") {
|
|
89
165
|
deepExtend(out, JSON.parse(fileContent));
|
|
90
166
|
return;
|
|
91
167
|
}
|
|
92
|
-
//
|
|
168
|
+
// try YAML (will throw if malformed)
|
|
93
169
|
try {
|
|
94
170
|
const content = yaml.load(fileContent);
|
|
95
171
|
if (is.object(content)) {
|
|
@@ -98,9 +174,9 @@ export function loadConfigFromFile(out, filePath) {
|
|
|
98
174
|
}
|
|
99
175
|
}
|
|
100
176
|
catch {
|
|
101
|
-
//
|
|
177
|
+
// not valid YAML; continue to INI fallback
|
|
102
178
|
}
|
|
103
|
-
//
|
|
179
|
+
// final fallback: treat as INI
|
|
104
180
|
deepExtend(out, ini.decode(fileContent));
|
|
105
181
|
}
|
|
106
182
|
//# sourceMappingURL=config-file-loader.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config-file-loader.mjs","sourceRoot":"","sources":["../../src/helpers/config-file-loader.mts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAE7C,OAAO,GAAG,MAAM,KAAK,CAAC;AACtB,OAAO,IAAI,MAAM,SAAS,CAAC;AAC3B,OAAO,QAAQ,MAAM,UAAU,CAAC;AAEhC,OAAO,EAAE,EAAE,EAAE,MAAM,cAAc,CAAC;AAElC,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,YAAY,EAAE,KAAK,EAAE,MAAM,iBAAiB,CAAC;AAGtD,MAAM,SAAS,GAAG,QAAQ,KAAK,OAAO,CAAC;AAEvC,MAAM,CAAC,MAAM,2BAA2B,GAAG,CAAC,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"config-file-loader.mjs","sourceRoot":"","sources":["../../src/helpers/config-file-loader.mts"],"names":[],"mappings":"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"}
|
|
@@ -3,6 +3,14 @@ import type { INITIALIZE, INJECTED_DEFINITIONS, InternalDefinition, LOAD_PROJECT
|
|
|
3
3
|
import type { ILogger } from "./logger.mts";
|
|
4
4
|
import type { TBlackHole } from "./utilities.mts";
|
|
5
5
|
import type { ApplicationDefinition, PartialConfiguration, ServiceMap, TInjectedConfig } from "./wiring.mts";
|
|
6
|
+
/**
|
|
7
|
+
* Describes the three built-in configuration source channels.
|
|
8
|
+
*
|
|
9
|
+
* @remarks
|
|
10
|
+
* Used as the key set for {@link DataTypes} and for the `source` field on
|
|
11
|
+
* individual config definitions. Each channel can be opted in/out independently
|
|
12
|
+
* via `BootstrapOptions.configSources`.
|
|
13
|
+
*/
|
|
6
14
|
export interface ConfigLoaderSource {
|
|
7
15
|
/**
|
|
8
16
|
* will be checked for values unless `sources` is defined without argv
|
|
@@ -17,9 +25,33 @@ export interface ConfigLoaderSource {
|
|
|
17
25
|
*/
|
|
18
26
|
file: true;
|
|
19
27
|
}
|
|
28
|
+
/** A record of config-key → config-definition for a single module. */
|
|
20
29
|
export type CodeConfigDefinition = Record<string, AnyConfig>;
|
|
30
|
+
/**
|
|
31
|
+
* All supported primitive config types.
|
|
32
|
+
*
|
|
33
|
+
* @remarks
|
|
34
|
+
* Each value maps to a concrete config interface (`StringConfig`,
|
|
35
|
+
* `BooleanConfig`, etc.) and determines how the raw string from env/argv/file
|
|
36
|
+
* is coerced before injection.
|
|
37
|
+
*/
|
|
21
38
|
export type ProjectConfigTypes = "string" | "boolean" | "internal" | "number" | "record" | "string[]";
|
|
39
|
+
/**
|
|
40
|
+
* Union of all supported config definition shapes.
|
|
41
|
+
*
|
|
42
|
+
* @remarks
|
|
43
|
+
* Narrowing on the `type` discriminant gives access to the specific fields
|
|
44
|
+
* (e.g., `enum` for `StringConfig`, `default` for every typed config).
|
|
45
|
+
*/
|
|
22
46
|
export type AnyConfig = StringConfig<string> | BooleanConfig | InternalConfig<object> | NumberConfig | RecordConfig | StringArrayConfig;
|
|
47
|
+
/**
|
|
48
|
+
* Fields shared by every config definition.
|
|
49
|
+
*
|
|
50
|
+
* @remarks
|
|
51
|
+
* The `type` discriminant drives coercion in {@link parseConfig}.
|
|
52
|
+
* `source` narrows which loaders are allowed to supply this key — omit it to
|
|
53
|
+
* allow all loaders.
|
|
54
|
+
*/
|
|
23
55
|
export interface BaseConfig {
|
|
24
56
|
/**
|
|
25
57
|
* If no other values are provided, what value should be injected?
|
|
@@ -40,7 +72,32 @@ export interface BaseConfig {
|
|
|
40
72
|
*/
|
|
41
73
|
source?: (keyof ConfigLoaderSource)[];
|
|
42
74
|
}
|
|
75
|
+
/**
|
|
76
|
+
* Map of module-name → config-definition record for all known modules.
|
|
77
|
+
*
|
|
78
|
+
* @remarks
|
|
79
|
+
* Populated incrementally during bootstrap as each library calls
|
|
80
|
+
* `configuration.[LOAD_PROJECT]`. Used by all config loaders to know which
|
|
81
|
+
* keys to look up.
|
|
82
|
+
*/
|
|
43
83
|
export type KnownConfigs = Map<string, CodeConfigDefinition>;
|
|
84
|
+
/**
|
|
85
|
+
* Config definition for a typed string value.
|
|
86
|
+
*
|
|
87
|
+
* @remarks
|
|
88
|
+
* The generic parameter `STRING` lets callers constrain the injected value to a
|
|
89
|
+
* specific string literal union. When `enum` is provided the framework refuses
|
|
90
|
+
* to boot if the resolved value is not in the list.
|
|
91
|
+
*
|
|
92
|
+
* @example Enum-constrained string
|
|
93
|
+
* ```typescript
|
|
94
|
+
* const LOG_LEVEL: StringConfig<"debug" | "info" | "warn"> = {
|
|
95
|
+
* default: "info",
|
|
96
|
+
* enum: ["debug", "info", "warn"],
|
|
97
|
+
* type: "string",
|
|
98
|
+
* };
|
|
99
|
+
* ```
|
|
100
|
+
*/
|
|
44
101
|
export interface StringConfig<STRING extends string> extends BaseConfig {
|
|
45
102
|
default?: STRING;
|
|
46
103
|
/**
|
|
@@ -49,38 +106,58 @@ export interface StringConfig<STRING extends string> extends BaseConfig {
|
|
|
49
106
|
enum?: STRING[];
|
|
50
107
|
type: "string";
|
|
51
108
|
}
|
|
109
|
+
/** Config definition for a boolean value. */
|
|
52
110
|
export interface BooleanConfig extends BaseConfig {
|
|
53
111
|
default?: boolean;
|
|
54
112
|
type: "boolean";
|
|
55
113
|
}
|
|
56
114
|
/**
|
|
57
|
-
*
|
|
58
|
-
*
|
|
59
|
-
*
|
|
115
|
+
* Escape hatch for configurations that can't be expressed as a primitive.
|
|
116
|
+
*
|
|
117
|
+
* @remarks
|
|
118
|
+
* Accepts a JSON-serialisable object as its default; at runtime the raw string
|
|
119
|
+
* value from env/file is passed through `JSON.parse`. Use the `description`
|
|
120
|
+
* field to explain the expected structure, because `config-builder` cannot
|
|
121
|
+
* introspect complex shapes.
|
|
60
122
|
*
|
|
61
123
|
* This can be used to take in a complex json object, and forward the information to another library.
|
|
62
124
|
*
|
|
63
125
|
* TODO: JSON schema magic for validation / maybe config builder help
|
|
126
|
+
*
|
|
127
|
+
* For configurations that just can't be expressed any other way.
|
|
128
|
+
* Make sure to add a helpful description on how to format the value,
|
|
129
|
+
* because `config-builder` won't be able to help.
|
|
64
130
|
*/
|
|
65
131
|
export type InternalConfig<VALUE extends object> = BaseConfig & {
|
|
66
132
|
default: VALUE;
|
|
67
133
|
type: "internal";
|
|
68
134
|
};
|
|
135
|
+
/** Config definition for a numeric value. */
|
|
69
136
|
export interface NumberConfig extends BaseConfig {
|
|
70
137
|
default?: number;
|
|
71
138
|
type: "number";
|
|
72
139
|
}
|
|
73
140
|
/**
|
|
141
|
+
* Config definition for an arbitrary key/value record.
|
|
142
|
+
*
|
|
143
|
+
* @remarks
|
|
144
|
+
* Injected as a plain object; the raw value is parsed via `JSON.parse` when it
|
|
145
|
+
* arrives as a string.
|
|
146
|
+
*
|
|
74
147
|
* key/value pairs
|
|
75
148
|
*/
|
|
76
149
|
export interface RecordConfig extends BaseConfig {
|
|
77
150
|
type: "record";
|
|
78
151
|
}
|
|
152
|
+
/** Config definition for a string-array value. */
|
|
79
153
|
export interface StringArrayConfig extends BaseConfig {
|
|
80
154
|
default?: string[];
|
|
81
155
|
type: "string[]";
|
|
82
156
|
}
|
|
83
157
|
/**
|
|
158
|
+
* Serialisable representation of a module's full config for use by external
|
|
159
|
+
* tooling (e.g. the `config-builder` CLI scanner).
|
|
160
|
+
*
|
|
84
161
|
* Used with config scanner
|
|
85
162
|
*/
|
|
86
163
|
export interface ConfigDefinitionDTO {
|
|
@@ -88,6 +165,7 @@ export interface ConfigDefinitionDTO {
|
|
|
88
165
|
bootstrapOverrides?: AbstractConfig;
|
|
89
166
|
config: ConfigTypeDTO[];
|
|
90
167
|
}
|
|
168
|
+
/** Single config-item descriptor emitted by the scanner. */
|
|
91
169
|
export interface ConfigTypeDTO<METADATA extends AnyConfig = AnyConfig> {
|
|
92
170
|
/**
|
|
93
171
|
* Name of project
|
|
@@ -103,36 +181,133 @@ export interface ConfigTypeDTO<METADATA extends AnyConfig = AnyConfig> {
|
|
|
103
181
|
property: string;
|
|
104
182
|
}
|
|
105
183
|
/**
|
|
106
|
-
* Top level configuration object
|
|
184
|
+
* Top level configuration object.
|
|
185
|
+
*
|
|
186
|
+
* @remarks
|
|
187
|
+
* Downstream libraries extend this interface via declaration merging to add
|
|
188
|
+
* their own config sections. See the architecture docs for the merging pattern.
|
|
107
189
|
*
|
|
108
190
|
* Extends the global common config, adding a section for the top level application to chuck in data without affecting things
|
|
109
191
|
* Also provides dedicated sections for libraries to store their own configuration options
|
|
110
192
|
*/
|
|
111
193
|
export interface AbstractConfig {
|
|
112
194
|
}
|
|
195
|
+
/**
|
|
196
|
+
* Return type of a config loader — a partial snapshot of the global config
|
|
197
|
+
* hierarchy.
|
|
198
|
+
*/
|
|
113
199
|
export type ConfigLoaderReturn = Promise<Partial<AbstractConfig>>;
|
|
200
|
+
/**
|
|
201
|
+
* Parameters passed to every config loader at bootstrap time.
|
|
202
|
+
*
|
|
203
|
+
* @remarks
|
|
204
|
+
* Loaders receive the full application definition, the accumulated
|
|
205
|
+
* `KnownConfigs` map, the internal definition for accessing boot state, and a
|
|
206
|
+
* logger for diagnostics. Loaders must not throw; they should return an empty
|
|
207
|
+
* object when they find nothing.
|
|
208
|
+
*/
|
|
114
209
|
export type ConfigLoaderParams<S extends ServiceMap = ServiceMap, C extends OptionalModuleConfiguration = OptionalModuleConfiguration> = {
|
|
115
210
|
application: ApplicationDefinition<S, C>;
|
|
116
211
|
configs: KnownConfigs;
|
|
117
212
|
internal: InternalDefinition;
|
|
118
213
|
logger: ILogger;
|
|
119
214
|
};
|
|
215
|
+
/**
|
|
216
|
+
* Contract that all config loaders must satisfy.
|
|
217
|
+
*
|
|
218
|
+
* @remarks
|
|
219
|
+
* Each loader is registered for a specific {@link DataTypes} channel via
|
|
220
|
+
* `DigitalAlchemyConfiguration.registerLoader`. The framework calls all
|
|
221
|
+
* registered loaders during `onPostConfig` and deep-merges their results.
|
|
222
|
+
*/
|
|
120
223
|
export type ConfigLoader = <S extends ServiceMap, C extends OptionalModuleConfiguration>(params: ConfigLoaderParams<S, C>) => ConfigLoaderReturn;
|
|
224
|
+
/**
|
|
225
|
+
* Coerce a raw string (or boolean/array from argv parsing) to the target type.
|
|
226
|
+
*
|
|
227
|
+
* @remarks
|
|
228
|
+
* Called by env/argv loaders after key lookup to normalise the raw value before
|
|
229
|
+
* it is stored in the config map. `boolean` coercion is intentionally lenient:
|
|
230
|
+
* `"true"`, `"y"`, and `"1"` all produce `true`. `string[]` handles the
|
|
231
|
+
* minimist edge case where a single flag value arrives as a plain string rather
|
|
232
|
+
* than a one-element array.
|
|
233
|
+
*/
|
|
121
234
|
export declare function cast<T = unknown>(data: boolean | number[] | string | string[], type: string): T;
|
|
235
|
+
/** A record that maps config-key names to their config definitions. */
|
|
122
236
|
export type ModuleConfiguration = {
|
|
123
237
|
[key: string]: AnyConfig;
|
|
124
238
|
};
|
|
239
|
+
/** A module's config block, or `undefined` when the module declares none. */
|
|
125
240
|
export type OptionalModuleConfiguration = ModuleConfiguration | undefined;
|
|
241
|
+
/**
|
|
242
|
+
* Find the first key in `source` that also appears in `find`, using a
|
|
243
|
+
* case-insensitive fuzzy match that treats `-` and `_` as interchangeable.
|
|
244
|
+
*
|
|
245
|
+
* @remarks
|
|
246
|
+
* The search runs in two passes:
|
|
247
|
+
* 1. Exact match — fast path for the common case where cases and separators align.
|
|
248
|
+
* 2. Regex match — builds a pattern from `source[i]` that allows `-` or `_`
|
|
249
|
+
* between each word boundary, then tests every element of `find`.
|
|
250
|
+
*
|
|
251
|
+
* This is the canonical key-resolution routine called by the env and argv
|
|
252
|
+
* loaders before falling back to unqualified key search.
|
|
253
|
+
*/
|
|
126
254
|
export declare function findKey<T extends string>(source: T[], find: T[]): T;
|
|
255
|
+
/**
|
|
256
|
+
* Search `source` for the first key that case-insensitively matches `target`,
|
|
257
|
+
* treating `-` and `_` as interchangeable separators.
|
|
258
|
+
*
|
|
259
|
+
* @remarks
|
|
260
|
+
* Builds a single regex from `target` and tests it against every element of
|
|
261
|
+
* `source`. Unlike {@link findKey}, this function operates in one direction
|
|
262
|
+
* only (target → source) and is used for direct key lookups rather than
|
|
263
|
+
* cross-set intersection.
|
|
264
|
+
*/
|
|
127
265
|
export declare function iSearchKey(target: string, source: string[]): string;
|
|
128
266
|
/**
|
|
267
|
+
* Load a `.env` file into `process.env`, respecting the configured priority
|
|
268
|
+
* order.
|
|
269
|
+
*
|
|
270
|
+
* @remarks
|
|
271
|
+
* Priority (highest to lowest):
|
|
272
|
+
* 1. `--env-file` CLI switch
|
|
273
|
+
* 2. `BootstrapOptions.envFile`
|
|
274
|
+
* 3. `.env` in the current working directory (silent fallback)
|
|
275
|
+
*
|
|
276
|
+
* If the resolved path does not exist, a warning is emitted and loading is
|
|
277
|
+
* skipped rather than throwing. This keeps the application bootable in
|
|
278
|
+
* environments that intentionally have no `.env` file.
|
|
279
|
+
*
|
|
129
280
|
* priorities:
|
|
130
281
|
* - --env-file
|
|
131
282
|
* - bootstrap envFile
|
|
132
283
|
* - cwd/.env (default file)
|
|
133
284
|
*/
|
|
134
285
|
export declare function loadDotenv(internal: InternalDefinition, CLI_SWITCHES: ParsedArgs, logger: ILogger): void;
|
|
286
|
+
/**
|
|
287
|
+
* Coerce `value` to the concrete type described by `config`.
|
|
288
|
+
*
|
|
289
|
+
* @remarks
|
|
290
|
+
* Called after a raw value has been retrieved from a loader to normalise it
|
|
291
|
+
* before storage. Each branch matches a `ProjectConfigTypes` discriminant:
|
|
292
|
+
* - `"string"` — `String(value)`
|
|
293
|
+
* - `"number"` — `Number(value)`
|
|
294
|
+
* - `"string[]"` — splits on commas, or parses JSON arrays starting with `[`
|
|
295
|
+
* - `"record"` / `"internal"` — passes objects through; parses strings as JSON
|
|
296
|
+
* - `"boolean"` — accepts boolean literals and the strings `"y"` / `"true"`
|
|
297
|
+
*/
|
|
135
298
|
export declare function parseConfig(config: AnyConfig, value: unknown): any;
|
|
299
|
+
/**
|
|
300
|
+
* Internal shape of the configuration service — the object attached to
|
|
301
|
+
* `internal.boilerplate.configuration`.
|
|
302
|
+
*
|
|
303
|
+
* @remarks
|
|
304
|
+
* Symbol-keyed methods (`[INITIALIZE]`, `[INJECTED_DEFINITIONS]`,
|
|
305
|
+
* `[LOAD_PROJECT]`) are bootstrap-internal surface and should not be called by
|
|
306
|
+
* application code. Use the named methods (`getDefinitions`, `registerLoader`,
|
|
307
|
+
* `merge`, `onUpdate`, `set`) for runtime configuration interaction.
|
|
308
|
+
*
|
|
309
|
+
* @internal
|
|
310
|
+
*/
|
|
136
311
|
export type DigitalAlchemyConfiguration = {
|
|
137
312
|
[INITIALIZE]: <S extends ServiceMap, C extends OptionalModuleConfiguration>(application: ApplicationDefinition<S, C>) => Promise<string>;
|
|
138
313
|
[INJECTED_DEFINITIONS]: TInjectedConfig;
|
|
@@ -141,9 +316,13 @@ export type DigitalAlchemyConfiguration = {
|
|
|
141
316
|
registerLoader: (loader: ConfigLoader, type: DataTypes) => void;
|
|
142
317
|
merge: (incoming: Partial<PartialConfiguration>) => PartialConfiguration;
|
|
143
318
|
/**
|
|
319
|
+
* Subscribe to runtime config changes made via `config.set`.
|
|
320
|
+
*
|
|
321
|
+
* @remarks
|
|
144
322
|
* Not a replacement for `onPostConfig`
|
|
145
323
|
*
|
|
146
|
-
* Only receives updates from `config.set` calls
|
|
324
|
+
* Only receives updates from `config.set` calls — initial load values do not
|
|
325
|
+
* trigger this callback.
|
|
147
326
|
*/
|
|
148
327
|
onUpdate: <Project extends keyof TInjectedConfig, Property extends Extract<keyof TInjectedConfig[Project], string>>(callback: OnConfigUpdateCallback<Project, Property>, project?: Project, property?: Property) => void;
|
|
149
328
|
/**
|
|
@@ -153,6 +332,24 @@ export type DigitalAlchemyConfiguration = {
|
|
|
153
332
|
*/
|
|
154
333
|
set: TSetConfig;
|
|
155
334
|
};
|
|
335
|
+
/**
|
|
336
|
+
* Type-safe setter for a single config value.
|
|
337
|
+
*
|
|
338
|
+
* @remarks
|
|
339
|
+
* The generic parameters are inferred from the call site — TypeScript enforces
|
|
340
|
+
* that `property` is a valid key of the chosen `project` section and that
|
|
341
|
+
* `value` matches the declared type.
|
|
342
|
+
*/
|
|
156
343
|
export type TSetConfig = <Project extends keyof TInjectedConfig, Property extends keyof TInjectedConfig[Project]>(project: Project, property: Property, value: TInjectedConfig[Project][Property]) => void;
|
|
344
|
+
/**
|
|
345
|
+
* Callback signature for config-update subscriptions.
|
|
346
|
+
*
|
|
347
|
+
* @remarks
|
|
348
|
+
* Receives the `project` and `property` names that changed; callers read the
|
|
349
|
+
* new value directly from `config[project][property]` rather than receiving it
|
|
350
|
+
* as a parameter, which keeps the callback signature stable regardless of the
|
|
351
|
+
* value type.
|
|
352
|
+
*/
|
|
157
353
|
export type OnConfigUpdateCallback<Project extends keyof TInjectedConfig, Property extends keyof TInjectedConfig[Project]> = (project: Project, property: Property) => TBlackHole;
|
|
354
|
+
/** Union of the three supported config source channel names. */
|
|
158
355
|
export type DataTypes = keyof ConfigLoaderSource;
|