# Runtime Client

The Twilio **Runtime Client** provides a direct way of orchestrating the various parts of the Twilio Runtime without requiring an imported module. Using the Runtime Client, developers can reference other [Functions](/docs/serverless/functions-assets/functions) to better organize their code, access configuration and files stored in [Assets](/docs/serverless/functions-assets/assets), and manage real-time data via [Twilio Sync](/docs/sync).

Access the Runtime Client in a Function by referencing `Runtime`, which exposes the following API:

* [Methods](#methods)
  * [getAssets()](#getassets)
  * [getFunction()](#getfunctions)
  * [getSync()](#getsyncoptions)

## Methods

### `getAssets()`

The `getAssets` method returns an object that contains the names each **private** Asset in a Service. Each Asset name serves as the key to an Asset object that contains the `path` to that Asset, as well as an `open` method that can be conveniently used to access its contents. These paths can be used to retrieve files served on [Twilio Assets](/docs/serverless/functions-assets/assets).

For example, executing `Runtime.getAssets()` could return an object with the following private Assets:

```javascript
{
  '/names.json': {
    path: '/var/task/files/ZNdad14da2e70d2533f640cf362fec0609',
    open: [Function: open]
  },
  '/rickroll.mp3': {
    path: '/var/task/files/ZNdfbfaf15a02e244fa11337548dabd9d0',
    open: [Function: open]
  },
  '/helper-method.js': {
    path: '/var/task/files/ZN5d6d933785a76da25056328a5764d49b',
    open: [Function: open]
  }
}
```

> \[!WARNING]
>
> `getAssets()` only returns **private** Assets. Public and protected assets can be accessed via their publicly facing urls without the need for calling `getAssets()`. Refer to the [visibility guide](/docs/serverless/functions-assets/visibility) for more context!

> \[!WARNING]
>
> Note that an Asset such as `names.json` will be returned with a key of `'/names.json'`. To correctly retrieve the Asset and its path, the leading `/` and extension must be part of the key used to access the object returned by `Runtime.getAssets()`.
>
> For example: `Runtime.getAssets()['/names.json'].path`

#### Asset Properties

| **Property** | **Type**   | **Description**                                                                       |
| ------------ | ---------- | ------------------------------------------------------------------------------------- |
| `path`       | `string`   | String specifying the location of the private Asset                                   |
| `open`       | `function` | Convenience method that returns the contents of the file from `path` in utf8 encoding |

#### Examples

> \[!NOTE]
>
> If you would like to include a JavaScript module that isn't available on npm, the best way to do so is to upload the module as a **private** Asset, then use `getAssets` in order to require the module as shown in the [Load a module from an asset](#load-a-module-from-an-asset) code example.

```js title="Retrieve the path of an Asset" description="Example of how to get the file path for an Asset"
exports.handler = function (context, event, callback) {
  // Note: the leading slash and file extension are necessary to access the Asset
  const path = Runtime.getAssets()['/my-asset.json'].path;

  console.log('The path is: ' + path);

  return callback();
};
```

```js title="Load a module from an Asset" description="Example of how to load a third party library stored in an Asset"
exports.handler = function (context, event, callback) {
  // First, get the path for the Asset
  const path = Runtime.getAssets()['/answer-generator.js'].path;

  // Next, you can use require() to import the library
  const module = require(path);

  // Finally, use the module as you would any other!
  console.log('The answer to your riddle is: ' + module.getAnswer());

  return callback();
};
```

```js title="Read the contents of an Asset" description="Leverage the built-in open method for convenience"
exports.handler = function (context, event, callback) {
  const openFile = Runtime.getAssets()['/my_file.txt'].open;
  // Calling open is equivalent to using fs.readFileSync(asset.filePath, 'utf8')
  const text = openFile();

  console.log('Your file contents: ' + text);

  return callback();
};
```

```js title="Read the contents of an Asset" description="Directly read the contents of an Asset using filesystem methods"
// We're reading a file from the file system, so we'll need to import fs
const fs = require('fs');

exports.handler = async function (context, event, callback) {
  // Retrieve the path of your file
  const file = Runtime.getAssets()['/my_file.txt'].path;
  // Asynchronously read the file using a different encoding from utf8
  const text = await fs.readFile(file, 'base64');

  console.log('Your file contents: ' + text);

  return callback();
};
```

### `getFunctions()`

The `getFunctions` method returns an object that contains the names of every Function in the Service. Each Function name serves as the key to a Function object that contains the `path` to that Function. These paths can be used to import code from other Functions and to compose code hosted on Twilio Functions.

For example, executing `Runtime.getFunctions()` could return an object with the following Functions:

```javascript
{
  'sms/reply': {
    path: '/var/task/handlers/ZNdad14da2e70d2533f640cf362fec0609.js',
  },
  'helper': {
    path: '/var/task/handlers/ZNdfbfaf15a02e244fa11337548dabd9d0.js',
  },
  'example-function': {
    path: '/var/task/handlers/ZN5d6d933785a76da25056328a5764d49b.js',
  },
}
```

> \[!WARNING]
>
> Note that, unlike an Asset, a Function such as `sms/reply.js` will be returned with a key of `"sms/reply"`. To correctly retrieve the Function and its path, do *not* include characters such as a leading slash or the `.js` extension in the key used to access the object returned by `Runtime.getFunctions()`.
>
> For example: `Runtime.getFunctions()["sms/reply"].path`

#### Function Properties

| **Property** | **Type** | **Description**                                |
| ------------ | -------- | ---------------------------------------------- |
| `path`       | `string` | String specifying the location of the Function |

#### Examples \[#examples-2]

```js title="Retrieve the path for a Function" description="Example of how to retrieve the file path for a Function"
exports.handler = function (context, event, callback) {
  // Get the path for the Function. Note that the key of the function
  // is not preceded by a "/" as is the case with Assets
  const path = Runtime.getFunctions()['example-function'].path;

  console.log('The path to your Function is: ' + path);

  return callback();
};
```

#### Include a private Function in another Function

Private Functions are a great way to store methods that may be reused between your other Functions. For example, lets say we have a private Function called `Zoltar` that exports a fortune-generating method, `ask`:

```js title="Define a private helper Function" description="Implement Zoltar and define an ask method"
exports.ask = () => {
  // We're not totally sure if Zoltar's advice is all that helpful
  const fortunes = [
    'A long-forgotten loved one will appear soon.',
    'Are you sure the back door is locked?',
    "Communicate!  It can't make things any worse.",
    'Do not sleep in a eucalyptus tree tonight.',
    'Fine day for friends.',
    'Good news.  Ten weeks from Friday will be a pretty good day.',
    'Living your life is a task so difficult, it has never been attempted before.',
    'Stay away from flying saucers today.',
    'The time is right to make new friends.',
    'Try to relax and enjoy the crisis.',
    'You need more time; and you probably always will.',
    'Your business will assume vast proportions.',
  ];

  // Generate a random index and return the given fortune
  return fortunes[Math.floor(Math.random() * fortunes.length)];
};
```

You could then access this private method by using `Runtime.getFunctions()` to get the path for the Zoltar Function, import Zoltar as a JavaScript module using `require`, and then access the `ask` method as in the following code sample:

```js title="Include code from a Function" description="Example of how to include code from other Functions"
exports.handler = function (context, event, callback) {
  // First, get the path for the Function. Note that the key of the function
  // is not preceded by a "/" as is the case with Assets
  const zoltarPath = Runtime.getFunctions()['zoltar'].path;
 
  // Next, use require() to import the library
  const zoltar = require(zoltarPath);
 
  // Finally, use the module as you would any other!
  console.log('The answer to your riddle is: ' + zoltar.ask());
 
  return callback();
}
```

### `getSync(options?)`

We've made it convenient for you to access the Sync REST API from Functions. Use the Runtime Client to access any of [Sync's real-time data primitives](/docs/sync/objects-overview) and store information between Function invocations. The same data can be accessed using the [Sync API library](/docs/sync/api), making Sync from Functions the perfect way to update your real-time apps and dashboards.

The Runtime Client provides a wrapper around the Twilio REST API Helper for [Twilio Sync](/docs/sync). By default, calling `Runtime.getSync()` will return a Sync Service object that has been configured to work with your default Sync Instance.

For added convenience and less typing, the following methods returned from `getSync` are renamed from their usual name in the Node.js SDK, as you will see in the examples.

| **Default method name** | **Method name in Functions** |
| ----------------------- | ---------------------------- |
| `syncMaps`              | `maps`                       |
| `syncLists`             | `lists`                      |

#### Arguments

`getSync` optionally accepts a configuration object with the following properties.

| **Parameter** | **Type** | **Description**                                                                                                     |
| ------------- | -------- | ------------------------------------------------------------------------------------------------------------------- |
| `serviceName` | `string` | String specifying either the `serviceSid` or `uniqueName` of the Sync Service to connect to. Defaults to `default`. |

#### Examples \[#examples-3]

```js title="Get the default Sync Service Instance" description="Example of how to get the default Sync Service Instance"
exports.handler = (context, event, callback) => {
  // Use the getSync method with no arguments to get a reference to the default
  // Sync document for your account. Fetch returns a Promise, which will
  // eventually resolve to metadata about the Sync Service, such as its SID
  Runtime.getSync()
    .fetch()
    .then((defaultSyncService) => {
      console.log('Sync Service SID: ', defaultSyncService.sid);
      return callback(null, defaultSyncService.sid);
    })
    .catch((error) => {
      console.log('Sync Error: ', error);
      return callback(error);
    });
};
```

```js title="Get an existing Sync Service Instance" description="Example of how to use Runtime Client to get an Sync Service Instance by providing the SID"
exports.handler = (context, event, callback) => {
  // Pass a serviceName to getSync to get a reference to that specific
  // Sync document on your account. Fetch returns a Promise, which will
  // eventually resolve to metadata about the Sync Service, such as friendlyName
  Runtime.getSync({ serviceName: 'ISXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX' })
    .fetch()
    .then((syncService) => {
      console.log('Sync Service Name: ' + syncService.friendlyName);
      return callback(null, syncService.friendlyName);
    })
    .catch((error) => {
      console.log('Sync Error: ', error);
      return callback(error);
    });
};
```

```js title="Create a Sync Map using Runtime Client" description="Example of how to create a Map in Sync with the Runtime Client"
exports.handler = (context, event, callback) => {
  // maps, which is a shortcut to syncMaps, allows you to create a new Sync Map
  // instance. Be sure to provide a uniqueName identifier!
  Runtime.getSync()
    .maps.create({
      uniqueName: 'spaceShips',
    })
    .then((newMap) => {
      console.log(newMap);
      return callback(null, newMap);
    })
    .catch((error) => {
      console.log('Sync Error: ', error);
      return callback(error);
    });
};
```

```js title="Add entry to a Sync Map with Runtime Client" description="Example of how to add an entry to a Sync Map with the Runtime Client"
exports.handler = (context, event, callback) => {
  // Given an existing Sync Map with the uniqueName of spaceShips, you can use
  // syncMapItems.create to add a new key:data pair which will be accessible
  // to any other Function or product with access to the Sync Map!
  Runtime.getSync()
    .maps('spaceShips')
    .syncMapItems.create({
      key: 'fastestShip',
      data: {
        name: 'Millenium Falcon',
      },
    })
    .then((response) => {
      console.log(response);
      return callback(null, response);
    })
    .catch((error) => {
      console.log('Sync Error: ', error);
      return callback(error);
    });
};
```

```js title="Create a Sync List with Runtime Client" description="Example of how to create Sync List with Runtime Client"
exports.handler = (context, event, callback) => {
  // If your use case warrants a list data structure instead of a map, you
  // can instantiate a Sync List. As with Maps, be sure to provide a uniqueName!
  Runtime.getSync()
    .lists.create({
      uniqueName: 'spaceShips',
    })
    .then((newList) => {
      console.log(newList);
      return callback(null, newList);
    })
    .catch((error) => {
      console.log('Sync Error: ', error);
      return callback(error);
    });
};
```

```js title="Append to Sync List with Runtime Client" description="Example of how to append to a Sync List using the Runtime Client"
exports.handler = (context, event, callback) => {
  // Given an existing Sync List with the uniqueName of spaceShips, you can use
  // syncListItems.create to append a new data entry which will be accessible
  // to any other Function or product with access to the Sync List!
  Runtime.getSync()
    .lists('spaceShips')
    .syncListItems.create({
      data: {
        text: 'Millennium Falcon',
      },
    })
    .then((response) => {
      console.log(response);
      return callback(null, response);
    })
    .catch((error) => {
      console.log('Sync Error: ', error);
      return callback(error);
    });
};
```

```js title="Create a Sync Document with Runtime Client" description="Example of how to create a Sync Document using the Runtime Client"
exports.handler = (context, event, callback) => {
  // Last but not least, it's also possible to create Sync Documents.
  // As always, remember to provide a uniqueName to identify your Document.
  Runtime.getSync()
    .documents.create({
      uniqueName: 'userPreferences',
      data: {
        greeting: 'Ahoyhoy!',
      },
    })
    .then((newDoc) => {
      console.log(newDoc);
      return callback(null, newDoc);
    })
    .catch((error) => {
      console.log('Sync Error: ', error);
      return callback(error);
    });
};
```

```js title="Perform multiple Sync actions in a Function" description="Example of creating a Sync Map and adding data to it in the same Function execution"
exports.handler = async (context, event, callback) => {
  // Grab a reference to the Sync object since we'll be using it a few times
  const sync = Runtime.getSync();

  try {
    // First, lets create a brand new Sync Map
    const newMap = await sync.maps.create({ uniqueName: 'quicklyUpdatedMap' });
    console.log('newMap: ', newMap);

    // Now, let's access that map and add a new item to it.
    // Be sure to specify a unique key and data for the item!
    // Creation is an async operation, so we need to await it.
    const newMapItem = await sync.maps(newMap.sid).syncMapItems.create({
      key: 'fastestShip',
      data: {
        name: 'Millenium Falcon',
      },
    });

    // Now that we have a new item, let's log and return it.
    console.log('newMapItem: ', newMapItem);
    return callback(null, newMapItem);
  } catch (error) {
    // Be sure to log and return any errors that occur!
    console.error('Sync Error: ', error);
    return callback(error);
  }
};
```
