Allow fetch in db library vm contexts

Db library scripts are basically a JS module scoped to the db, and
handlers already get fetch — but runLibrary's own vm context only
bound sql/console, so any library calling fetch (e.g. the chat db's
OpenAI call) threw ReferenceError. Since library calls are often
fire-and-forget inside setTimeout (no rejection handler), that
crashed the whole process. Bind fetch in all three places a library
script runs: request-time (runLibrary), the library-editor save eval,
and repl.

Also add `bliss link` to bliss-cli for jumping straight to a
structure/route/template/db's workshop editor URL, including
resolving a db by its require('db')(alias) name.
This commit is contained in:
Your Name 2026-08-02 23:19:24 -04:00
parent 44f345fff0
commit 03a9d2143d
4 changed files with 62 additions and 4 deletions

View file

@ -74,6 +74,23 @@ bliss preview-route <sid> <rid> # rendered HTML of a GET route
bliss preview-template <sid> <tid> # rendered HTML using the template's test_object
```
## Links
Jump straight into the workshop editor for something instead of constructing
the URL by hand:
```bash
bliss link structure <sid>
bliss link route <sid> <rid>
bliss link template <sid> <tid>
bliss link db <sid> <dbId> # by numeric db id
bliss link db <sid> <alias> # or by the alias used in require('db')(alias)
```
`bliss link db` resolves an alias (e.g. `chat`, as in `require('db')('chat')`)
by looking at the structure's attached dbs — handy since the same alias name
often points to a different db per structure (aliased/cloned dbs).
## Editing code (handlers, templates, library)
Handlers/templates/library are multiline code. Write the code to a temp file and

View file

@ -212,6 +212,44 @@ const commands = {
);
out(await c.getText(`/workshop/${sid}/template/${tid}/preview`));
},
async link({ pos }) {
const [type, sid, ref] = pos;
need(
type && sid,
"usage: bliss link structure <sid> | route <sid> <rid> | template <sid> <tid> | db <sid> <dbId|alias>",
);
switch (type) {
case "structure":
out(`${c.BASE}/workshop/${sid}`);
break;
case "route":
need(ref, "usage: bliss link route <sid> <rid>");
out(`${c.BASE}/workshop/${sid}/route/${ref}`);
break;
case "template":
need(ref, "usage: bliss link template <sid> <tid>");
out(`${c.BASE}/workshop/${sid}/template/${ref}`);
break;
case "db": {
need(ref, "usage: bliss link db <sid> <dbId|alias>");
let dbId = ref;
if (!/^\d+$/.test(ref)) {
// ref is an alias (the string passed to require('db')(alias) in
// handler code) rather than a numeric db id — resolve it.
const { dbs } = await c.getJSON(`/plumbing/structures/${sid}`);
const match = dbs.find((d) => d.alias === ref);
need(match, `no db aliased "${ref}" on structure ${sid}`);
dbId = match.id;
}
out(`${c.BASE}/workshop/${sid}/db/${dbId}`);
break;
}
default:
throw new Error(
`unknown link type "${type}" (want structure|route|template|db)`,
);
}
},
async upload({ pos }) {
const [sid, filepath] = pos;
need(sid && filepath, "usage: bliss upload <structureId> <filepath>");