Space Script allows you to extend SilverBullet with JavaScript from within your space using `space-script` [[Blocks]]. It’s script... in (your) [[Spaces|space]]. Get it?
> **warning** **Security**
> Space script allows for arbitrary JavaScript to be run in the client and server, there are security risks involved **if malicious users get write access to your space (folder)** or if you copy & paste random scripts from the Internet without understanding what they do.
> If this makes you very queazy, you can disable Space Script by setting the `SB_SPACE_SCRIPT` environment variable to `off`
Space scripts are defined by simply using `space-script` fenced code blocks in your space. This can happen on any [[Pages]] you like, but for organizational reasons it’s recommended you put them on [[Meta Pages]].
You will get JavaScript [[Markdown/Syntax Highlighting]] for these blocks.
Upon client and server boot, all indexed scripts will be loaded and activated. To reload scripts on-demand, use the {[System: Reload]} command (bound to `Ctrl-Alt-r` for convenience).
If you use things like `console.log` in your script, you will see this output either in your server’s logs or browser’s JavaScript console (depending on where the script will be invoked).
Depending on where code is run (client or server), a slightly different JavaScript API will be available. However, code should ideally primarily rely on the following explicitly exposed APIs:
* [fetch](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API) (making fetch calls directly from the browser on the client, and via Deno’s fetch implementation on the server)
* [Temporal](https://tc39.es/proposal-temporal/docs/) (implemented via a polyfill)
SilverBullet offers a set of [[Functions]] you can use in its [[Template Language]]. You can extend this set of functions using space script using the `silverbullet.registerFunction` API.
Even though a [[Functions#readPage(name)]] function already exist, you could implement it in space script as follows (let’s name it `myReadPage`) using the `syscall` API (detailed further in [[#Syscalls]]):
Various interesting events are triggered on SilverBullet’s central event bus. Space script can listen to these events and do something with them.
The `silverbullet.registerEventListener` API takes two arguments:
*`def`, currently just one option:
*`name`: Name of the event. This name can contain `*` as a wildcard.
*`callback`: the callback function to invoke (can be `async` or not). This callback is passed an object with two keys:
*`name`: the name of the event triggered (useful if you use a wildcard event listener)
*`data`: the event data
To discover what events exist, you can do something like the following to listen to all events and log them to the JavaScript console. Note that different events are triggered on the client and server, so watch both logs:
Let’s say you want to automatically add a completion date to a task whenever you complete it, the [[Plugs/Tasks]] plug emits a `task:stateChange` event you can listen to:
Whenever a HTTP request is sent to your SilverBullet server under this prefix, for instance `https://notes.myserver.com/_/hello` a `http:request:/hello` event is emitted. If a handler responds to it, this response will be used as the HTTP response.
> Custom HTTP endpoints are not authenticated. If you want to add authentication, you have to do this manually, e.g. by checking for an “Authorization” header in your code.
SilverBullet indexes various types of content as [[Objects]]. There are various ways to define [[Attributes]] for these objects, such as the [attribute: my value] syntax. However, using space script you can write your own code to extract attribute values not natively supported using the registerAttributeExtractor API.
*`tags`: Array of tags this extractor should be applied to, could be a built-in tag such as `item`, `page`, `paragraph`, `header`, or `task`, but also any custom tags you define.
Note that indexing happens on every page save. You have to run {[Space: Reindex]} to have the new attribute extractor apply across changes in your entire space.
Let’s say you want to use the syntax `✅ 2024-02-27` in a task to signify when that task was completed and strip it from the task name. Here’s an example:
The primary way to interact with the SilverBullet environment is using “syscalls”. Syscalls expose SilverBullet functionality largely available both on the client and server in a safe way.
In your space script, a syscall is invoked via `syscall(name, arg1, arg2)` and usually returns a [Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) with the result.