# Configuration options Zoom Rivet configuration options let you configure a server port or enable a logging interface to enhance monitoring capabilities. ## Custom port You can use the optional port parameter in the any of the Rivet module's constructors to set a specific port for the server to run on. By default, Rivet uses port `8080`. See the following example of how you can initialize the `ChatbotClient` with a custom port: ```javascript const chatbotClient = new ChatbotClient({ clientId: process.env.CLIENT_ID, clientSecret: process.env.CLIENT_SECRET, webhooksSecretToken: process.env.WEBHOOK_SECRET_TOKEN, port: 4000, }); ``` ## Multiple Rivet clients You might need to use multiple Rivet modules within a single application. To do this, you must instantiate each Rivet module independently and provide each with a unique port. Depending on the [authorization type](/docs/rivet/javascript/authorization/#authorize-zoom-rivet-modules), you might have to use multiple [Marketplace Apps](https://marketplace.zoom.us/). See the following example of how to use two Rivet modules in tandem: ```javascript import { UsersS2SAuthClient } from "@zoom/rivet/users"; import { AccountsS2SAuthClient } from "@zoom/rivet/accounts"; (async () => { const usersClient = new UsersS2SAuthClient({ clientId: process.env.CLIENT_ID, clientSecret: process.env.CLIENT_SECRET, webhooksSecretToken: process.env.WEBHOOK_SECRET_TOKEN, accountId: process.env.ACCOUNT_ID, port: 4000, }); const accountsClient = new AccountsS2SAuthClient({ clientId: process.env.CLIENT_ID, clientSecret: process.env.CLIENT_SECRET, webhooksSecretToken: process.env.WEBHOOK_SECRET_TOKEN, accountId: process.env.ACCOUNT_ID, port: 4001, }); await usersClient.start(); await accountsClient.start(); })(); ``` ## Configure API-only clients You can set `disableReceiver` to `true` to make a Rivet client API-only. This action turns off the internal HTTP receiver. You can use this setup when you only need direct API access. If you set `disableReceiver` to `true`, OAuth does not work. This configuration is only compatible with non-OAuth flows, such as client credentials, JWT, and server-to-server (S2S). If you need an API-only client and still want to use OAuth, you must not set `disableReceiver` to `true`. Instead, configure the client to use the built-in `HttpReceiver` by setting `webhooksSecretToken` to `null` or leaving it `undefined`. This setup allows OAuth flows and prevents webhook verification that supports API-only behavior with OAuth. ## Logging By default, Zoom Rivet for JavaScript logs information from your app to the console. You can control how much logging occurs by passing in a logLevel into a Rivet module's constructor. The available log levels are `DEBUG`, `INFO`, `WARN`, and `ERROR`. By default, `logLevel` is set to `ERROR`. The following example shows how you can set the `logLevel` in the Chatbot module: ```javascript // Import LogLevel from the package import { ChatbotClient, LogLevel } from "@zoom/rivet/chatbot"; // ... // You can set logLevel in the constructor of any module const chatbotClient = new ChatbotClient({ clientId: process.env.CLIENT_ID, clientSecret: process.env.CLIENT_SECRET, webhooksSecretToken: process.env.WEBHOOK_SECRET_TOKEN, logLevel: LogLevel.INFO, }); // ... ``` ### Redirecting outputs Rivet allows you to add your own custom logger if you want to send your logs elsewhere or want more control. Here we show how you can initialize the Zoom Rivet module's client to add a logging interface. The interface requires the methods in the table below. | Name | Input | Output | | ------------ | ----------------------------------------------- | ----------------------------------------------- | | `info()` | `...msg: any[]` | void | | `debug()` | `...msg: any[]` | void | | `warn()` | `...msg: any[]` | void | | `error()` | `...msg: any[]` | void | | `setName()` | `name: string` | void | | `getLevel()` | `void` | level: string as: 'info' 'debug' 'error' 'warn' | | `setLevel()` | level: string as: 'info' 'debug' 'error' 'warn' | void | This code snippet example defines a custom logger class, `MyLogger`. It creates a custom logging system that handles different log types (e.g., debug, warn, error, info) with specific behavior. It then uses this custom logger with a chatbot client for logging purposes. ```javascript import { LogLevel } from "@zoom/rivet/logger"; class MyLogger { name = ""; level = LogLevel.INFO; debug(...msg) { // Custom debug logic here console.log("[debug]", ...msg); } warn(...msg) { // Custom warn logic here console.log("[warn]", ...msg); } error(...msg) { // Custom error logic here console.log("[error]", ...msg); } info(...msg) { // Custom info logic here console.log("[info]", ...msg); } setLevel(level) { this.level = level; } getLevel() { return this.level; } setName(name) { this.name = name; } } const chatbotClient = new ChatbotClient({ clientId: process.env.CLIENT_ID, clientSecret: process.env.CLIENT_SECRET, webhooksSecretToken: process.env.WEBHOOK_SECRET_TOKEN, logger: new MyLogger(), }); ``` ## Authorization Token Storage By default, Rivet stores authorization tokens in memory. This method works well for short-lived, non-refreshable tokens, like client credentials or JWT; however, it may be desirable to have token storage attached to a persistent database for tokens, like User OAuth, where user interaction is required. Otherwise, if the default in-memory token store is used, your app may need to re-authorize each time Rivet restarts. To provide a custom token store, define and implement the `tokenStore` property in the options of the module constructor you wish to use. See the following code snippet for an example using Video SDK. ```javascript import { VideoSdkClient } from "@zoom/rivet/videosdk"; const videoSdkClient = new VideoSdkClient({ clientId: process.env.CLIENT_ID, clientSecret: process.env.CLIENT_SECRET, tokenStore: { getLatestToken: () => { // Fetch the most recent token that was stored. For example, fetch the // first row from a date-descending relational database. }, storeToken: (token) => { // Store the most recent token in the database. // // If using TypeScript, the token argument can be used to further inspect // what data is available for storage, such as its value and expiration. }, }, webhooksSecretToken: "", }); ```