This is a highly flexible architecture. By decoupling the routine
specification from the execution harness, you are creating a language-agnostic
registry that can easily distribute logic to edge workers, local CLI tools, or
browser-based engines.
Here is a blueprint to build the 1.0 version of the routine development and
registry service, focusing on the Node.js/JS ecosystem while laying the
groundwork for polyglot support.
1. Directory Structure
A clean separation between the catalog data (the routines) and the platform
(the harness) ensures the registry can be version-controlled independently of
the runner.
2. The Standardized spec.json
The specification acts as the contract. For 1.0, we define the parameter
schema and point the implementations map to the Javascript entry point.
{ "name": "calculate_tax", "description": "Calculates regional tax based on a
provided subtotal.", "parameters": { "subtotal": { "type": "number",
"required": true }, "region": { "type": "string", "required": false,
"default": "FI" } }, "implementations": { "javascript": { "entry":
"implementations/javascript/index.js", "format": "anonymous_function" } } }
The JS implementation (index.js) should be a pure, anonymous function to allow
easy evaluation without scope pollution:
async (params) => { const rate = params.region === 'FI' ? 0.24 : 0.20; return
params.subtotal + (params.subtotal * rate); }
3. The Execution Harness (runner.js)
To safely execute these routines in Node.js while keeping them compatible with
V8/QuickJS, use Node's vm module. This provides an isolated context where the
anonymous function can be evaluated and executed with the provided parameters.
const vm = require('vm'); const fs = require('fs').promises; const path =
require('path'); async function runRoutine(routineName, params, language =
'javascript') { const specPath = path.join(__dirname, '../routines',
routineName, 'spec.json'); const spec = JSON.parse(await fs.readFile(specPath,
'utf8')); // 1. Parameter Validation & Defaults injection const
executionParams = {}; for (const [key, config] of Object.entries(spec.parameter
s)) { if (config.required && params[key] === undefined) { throw new
Error(`Missing required parameter: ${key}`); } executionParams[key] =
params[key] ?? config.default; } // 2. Load Implementation const implConfig =
spec.implementations[language]; if (!implConfig) throw new Error(`No
${language} implementation found.`); const codePath = path.join(__dirname,
'../routines', routineName, implConfig.entry); const code = await
fs.readFile(codePath, 'utf8'); // 3. Sandboxed Execution // Wrapping the
anonymous function in parentheses to evaluate it as an expression const script
= new vm.Script(`(${code})`); const context = vm.createContext({}); // Add
globals here if needed (e.g., fetch, console) const fn = script.runInContext(co
ntext); return await fn(executionParams); } module.exports = { runRoutine };
4. The Catalog API (api.js)
Using Express and swagger-ui-express, we can expose the catalog and execution
endpoints. The OpenAPI definition is built dynamically or served statically.
const express = require('express'); const swaggerUi = require('swagger-ui-expre
ss'); const { runRoutine } = require('./runner'); const fs = require('fs').prom
ises; const app = express(); app.use(express.json()); // OpenAPI definition
stub const swaggerDocument = { openapi: '3.0.0', info: { title: 'Routine
Registry API', version: '1.0.0' }, paths: { '/routines/{name}/run': { post: {
summary: 'Run a routine', parameters: [{ name: 'name', in: 'path', required:
true }], requestBody: { content: { 'application/json': {} } }, responses: {
'200': { description: 'Success' } } } } } }; app.use('/docs', swaggerUi.serve,
swaggerUi.setup(swaggerDocument)); // --- API Endpoints --- // Run routine
app.post('/routines/:name/run', async (req, res) => { try { const result =
await runRoutine(req.params.name, req.body); res.json({ success: true, result
}); } catch (err) { res.status(400).json({ success: false, error: err.message
}); } }); // List routines (simplified) app.get('/routines', async (req, res)
=> { const dirs = await fs.readdir('./routines'); res.json(dirs); // In
production, read and map the spec.json files }); app.listen(3000, () =>
console.log('Registry API running on port 3000'));
5. Single-File Packager (packager.js)
To make these routines portable to browsers or QuickJS runtimes, this script
bundles the specification and the implementation into a single evaluatable
string or CommonJS module.
const fs = require('fs').promises; const path = require('path'); async
function packageRoutine(routineName) { const routineDir = path.join(__dirname,
'../routines', routineName); const spec = JSON.parse(await fs.readFile(path.joi
n(routineDir, 'spec.json'), 'utf8')); const jsEntry = spec.implementations.java
script.entry; const code = await fs.readFile(path.join(routineDir, jsEntry),
'utf8'); // Creates an immediately invokable string that returns an object
containing the spec and the runner const bundled = ` (function() { return {
spec: ${JSON.stringify(spec)}, run: ${code} }; })() `; // Can be written to a
dist/ directory or returned via an API endpoint return bundled.trim(); }
Usage: By calling eval(bundledString), the consumer instantly gets an object
with .spec (for UI generation or validation) and .run(params) (for execution),
entirely self-contained.