dev(extensions): improved configuration support

Extensions now read configuration objects under the "extensions" block
in the backend configuration. Additionally, a `config.json` for default
values directly in the extension's directory is now supported.
This commit is contained in:
KernelDeimos
2025-10-01 15:27:58 -04:00
parent 94c0490f34
commit ec8111cc2f
4 changed files with 36 additions and 4 deletions

View File

@@ -0,0 +1,3 @@
{
"test": "yes I am a test"
}

View File

@@ -48,6 +48,11 @@ extension.on('create.interfaces', event => {
* permission to access this driver:
*
* service:no-frills:ii:hello-world
*
* The value of `<subject>` can be one of many "special" values
* to demonstrate capabilities of drivers or extensions, including:
* - `%fail%`: simulate an error response from a driver
* - `%config%`: return the effective configuration object
*/
extension.on('create.drivers', event => {
event.createDriver('hello-world', 'no-frills', {
@@ -55,6 +60,9 @@ extension.on('create.drivers', event => {
if ( subject === '%fail%' ) {
throw new Error('failing on purpose');
}
if ( subject === '%config%' ) {
return JSON.stringify(config ?? null);
}
return `Hello, ${subject ?? 'World'}!`;
},
});

View File

@@ -0,0 +1,5 @@
{
"name": "hellodriver",
"main": "hellodriver.js",
"type": "module"
}

View File

@@ -34,6 +34,7 @@ const uuid = require('uuid');
const readline = require("node:readline/promises");
const { RuntimeModuleRegistry } = require("./extension/RuntimeModuleRegistry");
const { RuntimeModule } = require("./extension/RuntimeModule");
const deep_proto_merge = require("./config/deep_proto_merge");
const { quot } = libs.string;
@@ -381,6 +382,17 @@ class Kernel extends AdvancedBase {
mod_entry.jsons.puter = obj;
})());
}
const config_json_path = path_.join(mod_path, 'config.json');
if ( fs.existsSync(config_json_path) ) {
promises.push((async () => {
const buffer = await fs.promises.readFile(config_json_path);
const json = buffer.toString();
const obj = JSON.parse(json);
mod_entry.priority = obj.priority ?? mod_entry.priority;
mod_entry.jsons.config = obj;
})());
}
// Copy mod contents to `/mod_packages`
promises.push(fs.promises.cp(mod_path, mod_package_dir, {
@@ -445,6 +457,14 @@ class Kernel extends AdvancedBase {
const packageJSON = mod_entry.jsons.package;
Object.defineProperty(mod.extension, 'config', {
get: () => {
const builtin_config = mod_entry.jsons.config ?? {};
const user_config = require('./config').extensions?.[packageJSON.name] ?? {};
return deep_proto_merge(user_config, builtin_config);
},
});
const maybe_promise = (typ => typ.trim().toLowerCase())(packageJSON.type ?? '') === 'module'
? await import(path_.join(require_dir, packageJSON.main ?? 'index.js'))
: require(require_dir);
@@ -474,10 +494,6 @@ class Kernel extends AdvancedBase {
mod.extension.on('init', exportObject.init);
}
Object.defineProperty(mod.extension, 'config', {
get: () => require('./config').services?.[extension_name] ?? {},
});
// This is where the 'install' event gets triggered
await mod.install(context);
}