2022-12-09 10:08:21 -08:00
..
2022-12-09 10:08:21 -08:00
2022-12-09 10:08:21 -08:00
2022-12-09 10:08:21 -08:00
2022-12-09 10:08:21 -08:00
2022-12-09 10:08:21 -08:00
2022-12-09 10:08:21 -08:00

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