Skip to content

Soba Runtime Reference

Warning

This document is outdated. We are in the process of rewriting it

Imports

In Sobamail platform, all modules use hash values in import statements to guarantee that code is reproducible from the root module down to the last leaf in the import tree. The hash values are simply obtained by encoding Sha224 digest value of module source code using "urlsafe base64" encoding.

Here is a python script that generates the import hash for a given script file.

import sys
import hashlib

for fn in sys.argv[1:]:
    digest = hashlib.sha224(io.open(fn, "rb").read()).digest()
    digest_b64 = base64.urlsafe_b64encode(digest) \
        .replace(b"=", b"") \
        .decode("ascii")
    print(f"${fn}: ?sha224={digest_b64}")

Special JS Primitives

ArrayBuffer (Tagged)

Soba runtime adds a special type of ArrayBuffer, which is returned by soba.data.* family of functions. They are used as mutation handles instead of literal binary blobs.

API Reference

soba.app.account()

Returns the account associated with the current mailbox.

Returns:

  • String: The account name in email address format.

soba.app.instanceId()

Returns the instance id of the current application instance.

Returns:

  • String: The instance id.

soba.app.isReplicated()

Returns whether the object key at hand is replicated or not. Replicated objects are the ones that appear in the insertEvent attributes or the DeleteRow object.

Returns:

  • Boolean: true if the object at hand is replicated, false otherwise.

soba.app.mailboxUuid()

Returns the uuid of the current mailbox replica in braced hexadecimal uuid format.

Returns:

  • String: The replica uuid, in braced hexadecimal uuid format.

soba.app.objectKey()

Returns the triggering object key.

Returns:

soba.app.peers()

Returns the list of users that share this app instance.

Returns:

  • String[]: An array of email address strings.

soba.data.delete(table, hash)

Deletes data from the specified table and generates a DeleteRow mutation with a happens-before relationship with the mutation in the insertEvent attribute.

Parameters:

  • table (String): The name of the table.
  • key (Any): The hash of the row entry to be deleted, returned by the find() or insert() function.

soba.data.find(table, object)

Retrieves the mutation hash from the specified table based on the query. It's used to have dynamic happens-before relationships with other mutations. If the mutation can't be found, a fatal exception is thrown.

Parameters:

  • table (String): The name of the table.
  • object (Object): The query object used to search for the data. The object keys must be a subset of column names with LWW constaints.

Returns:

Returns an object with the following attributes:

  • hash (ArrayBuffer (Tagged)): The hash of the data that matches the query.
  • deleted (bool): If the value is not found on the target table but a deletion mutation found in the mutation log, this value is set to true, otherwise it's false.

soba.data.insert(table, data)

Inserts data into the specified table.

Parameters:

  • table (String): The name of the table.
  • data (Object): The data to be inserted. Must be a mapping from column names to values of type (String,Number,ArrayBuffer) or value null.

Return Value:

Returns an object with the following keys:

  • hash (ArrayBuffer (Tagged)): The hash value of the inserted mutation
  • inserted: Boolean: true means that the mutation was not a duplicate, so it was inserted. false means that the mutation was a duplicate and was ignored, but the hash for the actual mutation was returned.
  • applied: Boolean: Same as inserted.

soba.db.exec(query [, params ...])

Always exposes a read-only SQLite connection.

Throws in replicated context.

Parameters:

  • query: (String): The SQL query to run. Can denote parameters only using the '?' notation.
  • params: (null|true|false|Number|String|ArrayBuffer): Zero or more parameters passed to the SQL query.

Return Value:

Returns an object with the following keys:

soba.platform.releaseChannel()

Returns the release channel of the current Soba platform implementation.

Return Value:

Returns "Stable" in the real world.

soba.platform.version()

Returns the version of the current Soba platform implementation.

Throws in replicated context.

Return Value:

Returns an array of integers that represent the version of the current Soba platform implementation.

soba.log.{debug,info,warn,error}(message)

Logs a message with the specified level.

Parameters:

  • message (String): The message to be logged.

soba.mail.send(message)

Sends an email.

Throws in replicated context.

Parameters:

  • message: (Message): A Message instance.

Return Value:

Nothing.

soba.log.{debug,info,warn,error}(message)

Logs a message with the specified level.

Parameters:

  • message (String): The message to be logged.

soba.schema.table(defn)

Creates a table in the local SQLite database with the specified options:

Must be called from the Mutator constructor. Throws otherwise.

Parameters:

  • defn (Object): The definition object for the table.
  • name (String): The name of the table.
  • insertEvent (Class): Mutation object generated on row insertion
  • deleteEvent (Class): Mutation object generated on row deletion. Must be DeleteRow object from the Base.mjs module.
  • columns (Array): An array of column definitions.

    • name (String): The name of the column.
    • checks (Array): An array of single column check objects.
    • op (String): The check operation to be performed. One of: ["==", "!=", "typeof", "in", "fk", "lww", "regexp"]

      These values mean the following:

      • ==: The equals constraint: The incoming value must be a constant equal to the value stored in the value key. This is enforced by a SQLite CHECK constraint, so consult the SQLite docs for exact semantics.

      • !=: The not equals constraint: The incoming value must be a constant not equal to the value stored in the value key. This is enforced by a SQLite CHECK constraint, so consult the SQLite docs for exact semantics.

      • typeof: The type-of constraint: The type of the incoming value must equal to the value stored in the value key. Accepted values for this constraint are: ["blob", "integer", "null", "real", "text"] This is enforced by a SQLite CHECK constraint, using SQLite's typeof operator, so consult the SQLite docs for exact semantics.

      • in: The in constraint: The incoming value must be equal to one of the values stored in the Array inside the value key. This is enforced by a SQLite CHECK constraint, using SQLite's IN operator, so consult the SQLite docs for exact semantics.

      • fk: The foreign key constraint: The incoming value must be equal to one of the values stored in the given column of the given table. This is enforced by a SQLite FOREIGN KEY ... ON DELETE CASCADE constraint. This constraint establishes a happens-before relation between the insert mutation of the target table and the insert mutation at hand. This prevents execution of the mutation at hand by other replicas if its parent mutation is missing.

      • lww: The last-write-wins constraint: The incoming value must be different from one of the values stored in the given column of the current table. This is enforced by a SQLite UNIQUE constraint. This constraint establishes a happens-before relation between the DeleteRow mutation of the insert mutation at hand, if it exists, according to the following rules:

      • If the value is missing from the table:

        • If a DeleteRow mutation can't be found in the mutation log for the same value, no causal relationship stems from the LWW constraint.

        • If a DeleteRow mutation is found in the mutation log for the same value, a happens-before relationship is established.

      • If the value already exists and the digest value of the new insert mutation matches with the previous insert mutation, the current insert operation is ignored.

      • If the value already exists and the digest value of the new insert mutation does not match with the previous insert mutation, a DeleteRow mutation is generated for the column value in previous insert mutation and the new insert mutation is generated to have a happens-before relationship with this new DeleteRow mutation.

      • regexp: The regular expression constraint: The incoming value must be a string and must match the given regular expression in the value key. This is enforced by a CHECK constraint using SQLite's REGEXP operator, which in turn calls into the native regular expression engine of V8, so consult the SQLite, V8 and ECMAScript docs for exact semantics.

    • value (Any): The value to be used in the check.

    • table (String): The name of the table to be used in foreign key constraint
    • column (String): The name of the column of the target table to be used in the foreign key constraint.
  • checks (Array): An array of multi-column check objects.

    • op (string): The check operation to be performed. One of: ["fk", "lww"]
    • Check-specific keys specified below:
    • op === "lww": For the Last-Write-Wins check:
      • columns (string[]): The name of the columns to be used in the LWW checks.
      • value (true): Must be true
    • op === "fk": For the Foreign Key check:
      • table (string): The name of the target table.
      • columns ({col:string}[]): A mapping from column names of the source table to the column names of the target table

    The multi-column FK and LWW checks operate the same as their single-column variants. The column names and values are serialized to JSON and treated exactly like the single-column constraints.

soba.task.emit(object)

Used to return a persistent response to the current event. Useful for triggering other apps.

Parameters:

  • object: null|true|false|String|Number|ArrayBuffer|Array|Object: A Javascript object that can be serialized as msgpack.

Returns:

Nothing.

soba.task.respond(object)

Used to return an ephemeral response to the current event. Useful for responding to application GUI requests.

Parameters:

  • object: null|true|false|String|Number|ArrayBuffer|Array|Object: A Javascript object that can be serialized as msgpack -- ie only consisting of the listed primitives.

Returns:

Nothing.

soba.type.folderName.isValid(s)

Checks whether the given string is a valid folder name.

Parameters:

  • s (String): The string to be checked

Returns:

  • Boolean: true if the string is a valid folder name, false otherwise.

soba.type.userName.isValid(s)

Checks whether the given string is a valid user name.

Parameters:

  • s (String): The string to be checked

Returns:

  • Boolean: true if the string is a valid user name, false otherwise.

soba.type.uuid.v4()

Generates a UUIDv4.

Throws in replicated context.

Returns:

  • String: A new uuid, in braced hexadecimal uuid format.