Script execution and execution result

To refresh your memory, this is what an automation script looks like:
export default {
  trigger (t) {...}

  // Here, we will focus on this part
  exec (args, ctx) {...}
}

Execution arguments

Execution arguments (the args parameter of the exec function) contain the core data that your logic is able to work with. The data differs based on the event that triggered the automation script. To examplify; user related events define what user is involved, while record related events define the involved record and the module.

Refer to Resources and events for a complete reference of what data each event exposes.

Arguments to a client-script are provided via references to the original objects, meaning that any change to the argument parameter reflects back to the original object.

Arguments to a server-script are provided as a copy of the original object, meaning that the changes are not reflected on the original object.

Execution context

Execution context (the ctx parameter of the exec function) contains contextual information and utilities that can be used within script execution. The context between all of the events is static.

Table 1. Execution of context parameters:

ctx.console

The console parameter defines a logger.

When executing client scripts, this is the built-in window.console; when executing server secripts, this is a Pino logger.

ctx.log

ctx.log is an alias for ctx.console

ctx.$authUser

$authUser is a reference to the invoking user.

ctx.SystemAPI

SystemAPI is the Corteza API client.

ctx.ComposeAPI

ComposeAPI is the Corteza Low Code API client.

ctx.System

System defines a set of helper methods to work with the core system

ctx.Compose

Compose defines a set of helper methods to work with Corteza Low Code resources.

ctx.ComposeUI

ComposeUI defines a set of helper methods to work with Corteza Low Code user interface.

ctx.frontendBaseURL

frontendBaseURL defines the base URL address that the front-end web applications are running. This is useful when generating URL addresses that point to the Corteza applications (such as a link to the newly created lead).

Execution result

DevNote expand this section.

The execution result (the final output of the exec function) implicitly determines what is to follow.

Table 2. There are three possibilities:

The execution is terminated

When an automation script execution is terminated (when any error other then Aborted occurs or the value of false is returned), the operation that triggered the script execution is also terminated. No further actions are performed.

An example:
export default {
  trigger (t) {...}

  exec (args, ctx) {
    throw new Error('Oh no, something went wrong')
  }
}

The execution is aborted

When an automation script execution is aborted (an error with the value of Aborted occurs, or the value of false is returned), the current automation script is canceled, while any further automation scripts (in addition to the initial operation) are allowed to continue.

An example:
export default {
  trigger (t) {...}

  exec (args, ctx) {
    throw new Error('Aborted')
    // OR
    return false
  }
}

The execution is successful

Any other execution result is considered as successful. The value implicitly affects the result of the invoking operation; what this means correlates the event as discussed in the following sub-sections.

export default {
  trigger (t) {...}

  exec ({ $record }, ctx) {
    return $record
  }
}

Implicit script execution result

The following only applies for before events.

When a non-zero value is returned, that value is used instead of the original value, for example; when we change the name of a contact, the changed name will be used instead of the original one. If we do not return anything (e.g. null or undefined), the change is reverted.

An example:
export default {
  triggers ({ before }) {
    return before('create', 'update')
      .where('module','contact')
  },

  exec({ $record }, ctx) {
    $record.values.FullName = `${$record.values.FirstName} ${$record.values.LastName}`
    return $record
  },
}

The return values for after events are discarded (the value was already saved).

Sink script execution result

The returned value of a sink script is used to construct the HTTP response. This can be as simple as returning static HTML pages (the below example does this) or as complex as implementing OAuth authentication flows or fetching data from external sources.

Make sure that your responses define appropriate headers, such as the content type, status code, and body.

A simple example:
export default {
  security: 'super-secret-user',

  triggers ({ on }) {
    return on('request')
      .where('request.path', '/some/extension')
      .where('request.method', 'GET')
      .for('system:sink')
  },

  exec ({ $request, $response }, { Compose }) {
    $response.status = 200
    $response.header = { 'Content-Type': ['text/html; charset=UTF-8'] }
    $response.body = `<h1>Hello World!</h1>`

    return $response
  },
}
A complex example:
export default {
  security: 'super-secret-user',

  triggers ({ on }) {
    return on('request')
      .where('request.path', '/model/roi')
      .where('request.method', 'GET')
      .for('system:sink')
  },

  async exec ({ $request, $response }, { Compose }) {
    $response.status = 200
    $response.header = { 'Content-Type': ['application/json'] }

    let pl = {}
    try {
      pl.product = await fetchProduct($request.query.productCode[0])
      pl.roi = await calculateRoi(pl.product)
    } catch ({ message }) {
      $response.status = 500
      $response.body = JSON.stringify({
        error: message,
      })
      return $response
    }

    $response.body = JSON.stringify(pl)
    return $response
  },
}