diff --git a/extensions/hellodriver/config.json b/extensions/hellodriver/config.json new file mode 100644 index 000000000..fd463ad11 --- /dev/null +++ b/extensions/hellodriver/config.json @@ -0,0 +1,3 @@ +{ + "test": "yes I am a test" +} \ No newline at end of file diff --git a/extensions/hellodriver.js b/extensions/hellodriver/hellodriver.js similarity index 85% rename from extensions/hellodriver.js rename to extensions/hellodriver/hellodriver.js index ade7622f0..9e26d89cc 100644 --- a/extensions/hellodriver.js +++ b/extensions/hellodriver/hellodriver.js @@ -48,6 +48,11 @@ extension.on('create.interfaces', event => { * permission to access this driver: * * service:no-frills:ii:hello-world + * + * The value of `` 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'}!`; }, }); diff --git a/extensions/hellodriver/package.json b/extensions/hellodriver/package.json new file mode 100644 index 000000000..7bfb73777 --- /dev/null +++ b/extensions/hellodriver/package.json @@ -0,0 +1,5 @@ +{ + "name": "hellodriver", + "main": "hellodriver.js", + "type": "module" +} \ No newline at end of file diff --git a/src/backend/src/Kernel.js b/src/backend/src/Kernel.js index 001c36fd7..0e2079d1b 100644 --- a/src/backend/src/Kernel.js +++ b/src/backend/src/Kernel.js @@ -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); }