refactor: untangle bootstrapContext into makeConsole/makeLibs/runLibrary

Remove the shared-mutable-state dance where each db library was run in
the handler context via `context.sql = x; run; module.exports = null`.
Split into three single-purpose functions:

- makeConsole(structureId, routeId) — the logs-table-backed console
- runLibrary(sql, source, console) — eval one library in its own context
- makeLibs(structureId, console) — the require() targets map

Libraries are still evaluated eagerly per request (no laziness), and
still see `sql` and `console`, so behavior is preserved. Verified the
prime db library's top-level console.log still fires on a live request.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Your Name 2026-08-02 22:30:34 -04:00
parent d01f1411c5
commit d34c917ef9

View file

@ -83,53 +83,55 @@ async function saveFile(structureId, req, uploadedFile, asset=false) {
return file return file
} }
function bootstrapContext(structureId, routeId, initContext) { // A console whose log() mirrors to stdout and to the structure's logs table.
const allDbInstances = {}; function makeConsole(structureId, routeId) {
function getDb(alias) { return {
return allDbInstances[alias];
}
// todo wrap template in data-bliss-edit-template thing since ws can't take us to the editor on a component basis?? maybe...
// for now just designing with component approach
const eta = model.getTemplater(structureId);
const structure = model.getStructure(structureId)
const __urlPrefix = structure.route_prefix;
const libs = { eta, db: getDb, push: webPush, files: { saveFile: (...args) => saveFile(structureId, ...args) } };
let dbs = model.getDbsForStructure(structureId);
let context = vm.createContext({
...initContext,
require: function (str) {
return libs[str];
},
module: { exports: null },
console: {
log: function (...content) { log: function (...content) {
content.forEach((c) => console.log(c)); content.forEach((c) => console.log(c));
model.createLog(structureId, routeId, inspectArgs(content)); model.createLog(structureId, routeId, inspectArgs(content));
}, },
}, };
}
// Evaluate a db's "library" script with `sql` and `console` bound, returning
// its exports. Each library runs in its own context so nothing leaks between dbs.
function runLibrary(sql, librarySource, console) {
const libContext = vm.createContext({ sql, console, module: { exports: null } });
vm.runInContext(librarySource, libContext);
return libContext.module.exports;
}
// The `require(name)` targets available to a user handler.
function makeLibs(structureId, console) {
const dbs = {};
for (let appDb of model.getDbsForStructure(structureId)) {
const sql = model.getDbInstance(appDb.id);
dbs[appDb.alias] = { library: runLibrary(sql, appDb.library, console), sql };
}
return {
eta: model.getTemplater(structureId),
db: (alias) => dbs[alias],
push: webPush,
files: { saveFile: (...args) => saveFile(structureId, ...args) },
};
}
function bootstrapContext(structureId, routeId, initContext) {
const structure = model.getStructure(structureId);
const console = makeConsole(structureId, routeId);
const libs = makeLibs(structureId, console);
return vm.createContext({
...initContext,
require: (name) => libs[name],
module: { exports: null },
console,
vapidPublicKey: vapidPublicKey, vapidPublicKey: vapidPublicKey,
fetch: fetch, fetch: fetch,
clearTimeout: clearTimeout, clearTimeout: clearTimeout,
setTimeout: setTimeout, setTimeout: setTimeout,
route: function (url) { route: makeRoute(structure),
return withPrefix(__urlPrefix, url);
},
}); });
for (let appDb of dbs) {
let dbInstance = model.getDbInstance(appDb.id);
context.sql = dbInstance;
vm.runInContext(appDb.library, context);
allDbInstances[appDb.alias] = {
library: context.module.exports,
sql: dbInstance,
};
context.module.exports = null;
}
return context;
} }
function withPrefix(prefix, url) { function withPrefix(prefix, url) {