diff --git a/index.js b/index.js index 02704c4..9620d69 100644 --- a/index.js +++ b/index.js @@ -83,53 +83,55 @@ async function saveFile(structureId, req, uploadedFile, asset=false) { return file } -function bootstrapContext(structureId, routeId, initContext) { - const allDbInstances = {}; - function getDb(alias) { - return allDbInstances[alias]; +// A console whose log() mirrors to stdout and to the structure's logs table. +function makeConsole(structureId, routeId) { + return { + log: function (...content) { + content.forEach((c) => console.log(c)); + 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) }, + }; +} - // 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; +function bootstrapContext(structureId, routeId, initContext) { + const structure = model.getStructure(structureId); + const console = makeConsole(structureId, routeId); + const libs = makeLibs(structureId, console); - const libs = { eta, db: getDb, push: webPush, files: { saveFile: (...args) => saveFile(structureId, ...args) } }; - - let dbs = model.getDbsForStructure(structureId); - let context = vm.createContext({ + return vm.createContext({ ...initContext, - require: function (str) { - return libs[str]; - }, + require: (name) => libs[name], module: { exports: null }, - console: { - log: function (...content) { - content.forEach((c) => console.log(c)); - model.createLog(structureId, routeId, inspectArgs(content)); - }, - }, + console, vapidPublicKey: vapidPublicKey, fetch: fetch, clearTimeout: clearTimeout, setTimeout: setTimeout, - route: function (url) { - return withPrefix(__urlPrefix, url); - }, + route: makeRoute(structure), }); - 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) {