mirror of
https://github.com/HeyPuter/puter.git
synced 2026-01-05 12:40:26 -06:00
dev: add runtime modules for imports and exports
RuntimeModule is a new construct which represents the import/export
mechanism for Puter extensions. This can be thought of as analogous
to node's Module class. These are called "runtime modules" because
extensions have less control of what they're consuming than a typical
npm module; i.e. `runtime.import('database')` will provide a version
of 'database' that's compatible with the importing extension, but the
version used can't be locked or otherwise determined by the extension.
This commit is contained in:
committed by
KernelDeimos
parent
860388c3cb
commit
9aef281ad2
5
extensions/exports_something.js
Normal file
5
extensions/exports_something.js
Normal file
@@ -0,0 +1,5 @@
|
||||
//@puter priority -1
|
||||
console.log('exporting something...');
|
||||
runtime.exports = {
|
||||
testval: 5
|
||||
};
|
||||
3
extensions/imports_something.js
Normal file
3
extensions/imports_something.js
Normal file
@@ -0,0 +1,3 @@
|
||||
console.log('importing something...');
|
||||
const { testval } = runtime.import('exports_something');
|
||||
console.log(testval);
|
||||
@@ -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;
|
||||
|
||||
|
||||
30
src/backend/src/extension/RuntimeModule.js
Normal file
30
src/backend/src/extension/RuntimeModule.js
Normal file
@@ -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 };
|
||||
34
src/backend/src/extension/RuntimeModuleRegistry.js
Normal file
34
src/backend/src/extension/RuntimeModuleRegistry.js
Normal file
@@ -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
|
||||
};
|
||||
Reference in New Issue
Block a user