diff --git a/extensions/exports_something.js b/extensions/exports_something.js new file mode 100644 index 00000000..53c8424e --- /dev/null +++ b/extensions/exports_something.js @@ -0,0 +1,5 @@ +//@puter priority -1 +console.log('exporting something...'); +runtime.exports = { + testval: 5 +}; diff --git a/extensions/imports_something.js b/extensions/imports_something.js new file mode 100644 index 00000000..15eaa304 --- /dev/null +++ b/extensions/imports_something.js @@ -0,0 +1,3 @@ +console.log('importing something...'); +const { testval } = runtime.import('exports_something'); +console.log(testval); diff --git a/src/backend/src/Kernel.js b/src/backend/src/Kernel.js index c805b013..786ed87e 100644 --- a/src/backend/src/Kernel.js +++ b/src/backend/src/Kernel.js @@ -32,6 +32,8 @@ const { prependToJSFiles } = require("./kernel/modutil"); const uuid = require('uuid'); const readline = require("node:readline/promises"); +const { RuntimeModuleRegistry } = require("./extension/RuntimeModuleRegistry"); +const { RuntimeModule } = require("./extension/RuntimeModule"); const { quot } = libs.string; @@ -50,6 +52,8 @@ class Kernel extends AdvancedBase { this.entry_path = entry_path; this.extensionExports = {}; this.registry = {}; + + this.runtimeModuleRegistry = new RuntimeModuleRegistry(); } add_module (module) { @@ -380,6 +384,7 @@ class Kernel extends AdvancedBase { `const { use: puter } = globalThis.__puter_extension_globals__.useapi;`, `const extension = globalThis.__puter_extension_globals__` + `.extensionObjectRegistry[${JSON.stringify(extension_id)}];`, + `const runtime = extension.runtime;`, `const config = extension.config;`, `const registry = extension.registry;`, `const register = registry.register;`, @@ -392,6 +397,10 @@ class Kernel extends AdvancedBase { const mod = new ExtensionModule(); mod.extension = new Extension(); + + const runtimeModule = new RuntimeModule({ name: mod_name }); + this.runtimeModuleRegistry.register(runtimeModule); + mod.extension.runtime = runtimeModule; mod_entry.module = mod; diff --git a/src/backend/src/extension/RuntimeModule.js b/src/backend/src/extension/RuntimeModule.js new file mode 100644 index 00000000..ab6f11d7 --- /dev/null +++ b/src/backend/src/extension/RuntimeModule.js @@ -0,0 +1,30 @@ +const { AdvancedBase } = require("@heyputer/putility"); + +class RuntimeModule extends AdvancedBase { + constructor (options = {}) { + super(); + this.exports_ = undefined; + this.exports_is_set_ = false; + this.remappings = options.remappings ?? {}; + + this.name = options.name ?? undefined; + } + set exports (value) { + this.exports_is_set_ = true; + this.exports_ = value; + } + get exports () { + if ( this.exports_is_set_ === false && this.defer ) { + this.exports = this.defer(); + } + return this.exports_; + } + import (name) { + if ( this.remappings.hasOwnProperty(name) ) { + name = this.remappings[name]; + } + return this.runtimeModuleRegistry.exportsOf(name); + } +} + +module.exports = { RuntimeModule }; diff --git a/src/backend/src/extension/RuntimeModuleRegistry.js b/src/backend/src/extension/RuntimeModuleRegistry.js new file mode 100644 index 00000000..fe28c844 --- /dev/null +++ b/src/backend/src/extension/RuntimeModuleRegistry.js @@ -0,0 +1,34 @@ +const { AdvancedBase } = require("@heyputer/putility"); +const { RuntimeModule } = require("./RuntimeModule"); + +class RuntimeModuleRegistry extends AdvancedBase { + constructor () { + super(); + this.modules_ = {}; + } + + register (extensionModule, options = {}) { + if ( ! (extensionModule instanceof RuntimeModule) ) { + throw new Error(`expected a RuntimeModule, but got: ${ + extensionModule?.constructor?.name ?? typeof extensionModule})`); + } + const uniqueName = options.as ?? extensionModule.name ?? require('uuid').v4(); + if ( this.modules_.hasOwnProperty(uniqueName) ) { + throw new Error(`duplicate runtime module: ${uniqueName}`); + } + console.log(`registering with name... ${uniqueName}`); + this.modules_[uniqueName] = extensionModule; + extensionModule.runtimeModuleRegistry = this; + } + + exportsOf (name) { + if ( ! this.modules_[name] ) { + throw new Error(`could not find runtime module: ${name}`); + } + return this.modules_[name].exports; + } +} + +module.exports = { + RuntimeModuleRegistry +};