TS/JS Cloud Functions for PocketBase
Write all your PocketBase server-side logic in TS/JS
PBScript allows you to write PocketBase server-side functions in Typescript or Javascript without recompiling.
With PBScript, you can:
- ✅ Write your server-side logic in Typescript or JS
- ✅ Access models, collections, transactions, hooks, and all server-side features of PocketBase
- ✅ Communicate with PocketBase using a streamlined JavaScript-style API
- ✅ Deploy and alter cloud functions without rebuilding or even restarting PocketBase
- ✅ Roll back to previous versions
- ✅ Use the
pbscript
CLI tool for intelligent dev mode, live deployment, and rollback
Table of Contents
Introduction
PBScript extends PocketBase with an ES-5.1 (ECMA 262) scripting engine powered by goja.
Code executes in a secure sandboxed environment without a Node.js API or Web APIs. Instead, the runtime environment is PocketBase-specific, with full access to PocketBase's native Go extension API and includes streamlined functions and helper utilities written in JavaScript (@pbscript/core).
Use pbscript
command line tool to build and publish cloud functions to any PBScript-enabled PocketBase instance.
Getting Started
1. Create a PocketBase instance
To run JS functions, you need to run a PocketBase instance which has been enhanced with PBScript.
You can do it any way you like, just as long as you end up with an admin login for the next section.
Option 1 (free): run fully managed on pockethost.io
The absolute easiest way to provision a new PocketBase instance enhanced with PBScript is to use pockethost.io. You'll be up and running with a PocketBase URL in under 30 seconds. This is as close to a Firebase/Supabase BaaS experience as you can get.
Option 2 (free): run self-managed on fly.io
If you'd rather manage your resources yourself, you can follow the instructions in this thread to get up and running on fly.io.
This option takes about 30 minutes to set up.
Option 3 (free): run a custom build locally
If you just want to run locally or have a special use case, you can create your own build.
Create pocketbase.go
:
package main
import (
"log"
pocketbase "github.com/benallfree/pbscript/modules/pbscript"
)
func main() {
app := pocketbase.New()
if err := app.Start(); err != nil {
log.Fatal(err)
}
}
On the command line, run:
go get github.com/benallfree/pbscript/modules/pbscript
go run pocketbase.go serve
> Server started at: http://127.0.0.1:8090
- REST API: http://127.0.0.1:8090/api/
- Admin UI: http://127.0.0.1:8090/_/
2. Create a new JS/TS project
You can create any type of TS/JS project you want, but here's the package.json
we recommend. We also have a sample PBScript project you can check out.
The important part is that your script gets bundled as ES5:
{
"name": "sample",
"version": "0.0.1",
"dependencies": {
"@pbscript/core": "^0.0.1"
},
"scripts": {
"build": "parcel build --no-cache",
"deploy:local": "pbscript deploy --host 'http://127.0.0.1:8090'",
"dev": "chokidar 'src/**' './node_modules/**' -c 'yarn build && yarn deploy:local' --initial"
},
"targets": {
"iife": {
"source": "./src/index.ts",
"context": "browser",
"outputFormat": "global",
"sourceMap": {
"inline": true
}
}
},
"devDependencies": {
"chokidar-cli": "^3.0.0",
"parcel": "^2.7.0"
}
}
3. Use the `pbscript` CLI tool to log in
Enter your project directory and log in to your PocketBase instance using the admin account you created in Step #1:
npx pbscript login <username> <password> --host <pocketbase URL>
This will create a file named .pbcache
. Add it to .gitignore
.
Developing your script
In your command shell, run:
npx pbscript dev
PBScript is designed for a fast development cycle. If you used our package.json
, this command will watch for changes (in ./dist
) and re-deploy your script on every change.
PBScript updates do not require a PocketBase restart. Old versions of your script are kept in an archive table for easy rollbacks.
Building and deploying your script
pbscript
knows how to deploy to any PBScript-enabled PocketBase instance.
Connect to your live site
First, connect to your live site. pbscript
will remember your credentials for future commands.
npx pbscript login <username> <password> --host https://yourproject.pockethost.io
Saved to .pbcache
Build your ./dist/index.js
bundle
You can build your script bundle however you want, just make sure you end up with ONE bundle file in ./dist/index.js
. If you use source maps, inline them. pbscript
only deploys this one file.
Deploy your latest changes
You can deploy changes at any time without restarting PocketBase. All realtime connections and users will remain connected.
pbscript deploy --host <your pocketbase URL>
Or, add it to package.json
:
"scripts": {
"deploy": "pbscript deploy --host https://yourproject.pockethost.io"
}
API
PBScript runs in a secure sandboxed environment inside PocketBase. A simplified subset of PocketBase's hooks are available. Complete Typescript definitions are included.
You might be accustomed to using the NodeJS API or the browser Web API, but those APIs are not core features of ECMAScript. They are not safe or allowed in the PocketBase execution environment.
Instead, your script runs in the PocketBaseApi
execution environment. PocketBaseApi
set of API calls to interact with PocketBase. With it, you can do CRUD, transactions, hook into PocketBase events, new API endpoints, and generally extend PocketBase.
PBScript imports a __go
variable containing low-level access to the PocketBase native API and other helpers implemented in Go. @pbscript/core uses __go
internally, but if there is something missing, you may be able to accomplish it yourself by accessing __go
directly.
__go.ping()
Test function that should return Hello from Go!
Example:
console.log(__go.ping())
__go.addRoute()
Add an API route.
Example:
__go.addRoute({
method: HttpMethods.Get,
path: `/api/hello`
handler: (context)=>{
context.send(HttpStatus.Ok, `Hello back!`)
}
})
__go.app
Low-level primitive providing direct access to the PocketBase
app instance. Normally you will not access this directly. The @pbscript/core library is built on top of this.
Advanced
Upgrading an Existing Custom PocketBase
The easiest way to get PBScript is to use our custom PocketBase module github.com/benallfree/pbscript/modules/pocketbase:
package main
import (
"log"
"github.com/benallfree/pbscript/packages/pocketbase" // Notice this is a custom version of the PocketBase module
)
func main() {
app := pocketbase.New()
if err := app.Start(); err != nil {
log.Fatal(err)
}
}
If you are already using a custom PocketBase build, just swap out github.com/pocketbase/pocketbase
with github.com/benallfree/pbscript/packages/pocketbase
and everything will work as expected.
Or, if you prefer, you can do exactly what our custom module does:
package main
import (
"github.com/pocketbase/pocketbase"
"github.com/benallfree/pbscript/packages/pbscript"
)
func main() {
app := pocketbase.New()
pbscript.StartPBScript(app) // Magic line to enable PBScript
if err := app.Start(); err != nil {
log.Fatal(err)
}
}
Changelog
0.0.2
- Transaction support
0.0.1
- Initial release