• Beta
NodeJS SDK
  • Updated on 10 Jul 2020
  • 6 minutes to read
  • Share
  • Dark
    Light

NodeJS SDK

  • Share
  • Dark
    Light

Node-1

The Node.js support in The Ops Platform SDK allows you to write Ops in either JavaScript or Typescript. When you run ops init from the command-line, a JavaScript project will be created for you. To switch to TypeScript, you can copy the default ops.yml and Dockerfile from the JavaScript project and add them to your TypeScript project.

Node SDK Installation

You can install and use the SDK in a Node.js project like this:

$ npm install @cto.ai/sdk

Usage:

import { sdk, ux } from '@cto.ai/sdk';

sdk.exec

sdk.exec(command: string, options: ExecOptions = {}): Promise<{ stdout: string, stderr: string | child_process.ChildProcess}>

Runs a shell command inside the container. By default, it reads the full output of the command and returns it as stdout and stderr.

If this throws an ERR_CHILD_PROCESS_STDIO_MAXBUFFER error, consider using the spawn option (described below).

ExecOptions

export interface Env {
  [key: string]: string | undefined
}

export interface ExecOptions {
  spawn?: boolean
  env?: Env
}

If the spawn option is set to true, the child_process.spawn function is used to create the child process. In this case, the exec function returns a ChildProcess object rather than the stdout and stderr as strings. See the Node documentation for details on how to access the ChildProcess output streams.

The keys and values of the env option are set as environment variables for the child process. This is an alternative for providing them in the shell command that has fewer pitfalls and edge cases.

Examples:

Executing the following code in the command template:

import { sdk } from '@cto.ai/sdk'

const main = async () => {
    await sdk.exec('mkdir test-directory')
    const { stdout, stderr } = await sdk.exec('ls')

    sdk.log('stdout is:\\n', stdout)
    sdk.log('stderr is:\\n', stderr)
}

main()

will create a folder named test-directory in the container, and logs the following text.

stdout is:
demo.js
index.js
node_modules
package-lock.json
package.json
test-directory

stderr is:

The following script makes a Git commit with custom author information:

import { sdk } from '@cto.ai/sdk'

const main = async () => {
   const {name} = sdk.prompt({
       type: 'input', 
       name: 'name',
       message: 'What author name to use?',
   })
   const {email} = sdk.prompt({
       type: 'input', 
       name: 'email',
       message: 'What author email to use?',
   })
   const {message} = sdk.prompt({
       type: 'input', 
       name: 'message',
       message: 'What commit message to use?',
   })
    
    await sdk.exec(
        `git commit -a -m ${message}`,
        {env: {GIT_AUTHOR_NAME: name, GIT_AUTHOR_EMAIL: email}},
    )
}

main()

The following code reads a large compressed file and searches for lines containing a specific word:

import { sdk, ux } from '@cto.ai/sdk'

const scan = async (word) => {
  const child = await sdk.exec('zcat data.txt.gz', {spawn: true})

  const matchingLines = []
  child.stdout.setEncoding('utf8')
  for await (const chunk of child.stdout) {
    matchingLines.push(
      ...chunk.split('\n').filter((line) => line.includes(word))
    )
  }

  ux.print(`Found ${matchingLines.length} matching lines in the data file`)
  matchingLines.forEach((line) => sdk.log(line))
}

scan('DevOps')

sdk.getHostOS

sdk.getHostOS(): string

Returns the Operating System the host is running on. For remote ops, will return "unknown" as no host is accessible in the remote environment.

Example:

import { sdk } from '@cto.ai/sdk'

const main = async () => {
    const hostOs = sdk.getHostOS()
    sdk.log("Host's os is:", hostOs)
}

Output:

Host's os is: darwin

sdk.homeDir

sdk.homeDir(): string

Returns the home directory of the host machine.

Example:

import { sdk } from '@cto.ai/sdk'

const main = async () => {
  const homeDir = sdk.homeDir()
  console.log("Host's home directory is:", homeDir)
}

Output:

Host's home directory is: /root

sdk.log

sdk.log(...args: any[]): void

Logs to the console in in a standardized way. Will not be relayed to the user in a remote environment (use ux.print for that).

Example:

import { sdk } from '@cto.ai/sdk'

const main = async () => {
  sdk.log('I am a log!', '\\nI am too!')
}

Output:

I am a log!
I am too!

sdk.getStatePath

sdk.getStatePath(): string

Returns the path of the state directory. The contents of this directory are persistent through a workflow, including on remote.

Example:

import { sdk } from '@cto.ai/sdk'

const main = async () => {
  const statePath = sdk.getStatePath()
  sdk.log('The state path is:', statePath)
}

Output:

The state path is: /root/.config/@cto.ai/ops/superman/test-op/00000000-1111-2222-3333-444444444444

sdk.setConfig

sdk.setConfig(key: string, value: string): Promise<void>

Stores a key-value pair in the persistent team configuration. If the key is already present, the value will be replaced with the one provided.

Example:

import { sdk } from '@cto.ai/sdk'

const main = async () => {
    const key = 'test-key'
    // config = {}
    const initialConfig = await sdk.getConfig(key)
    sdk.log('Initial config', initialConfig)

    // config = { test-key: 'Value one' }
    await sdk.setConfig(key, 'Value one')
    const insertedConfig = await sdk.getConfig(key)
    sdk.log('Inserted config', insertedConfig)

    // config = { test-key: 'Value two' }
    await sdk.setConfig(key, 'Value two')
    const updatedConfig = await sdk.getConfig(key)
    sdk.log('Updated config', updatedConfig)
}

Output:

Initial config null
Inserted config Value one
Updated config Value two

sdk.deleteConfig

sdk.deleteConfig(key: string): Promise<boolean>

Deletes a key-value pair in the persistent team configuration. Returns true if the key exists and the deletion is successful, or false if the key cannot be found.

Example:

import { sdk } from '@cto.ai/sdk'

const main = async () => {
    const key = 'test-key'

    // config = {}
    const initialConfig = await sdk.getConfig(key)
    sdk.log('Initial config', initialConfig)

    // config = { 'test-key': 'Value one' }
    await sdk.setConfig(key, 'Value one')
    const insertedConfig = await sdk.getConfig(key)
    sdk.log('Inserted config', insertedConfig)

    // config = {}
    const deleted = await sdk.deleteConfig(key)
    if (deleted) {
        sdk.log('Deleted config')
    }
}

Output:

Initial config null
Inserted config Value one
Deleted config

sdk.getConfig

sdk.getConfig(key: string): Promise<string | null>

Gets the value that is saved under the given key in the persistent team configuration, or null if the key is not set.

Example

See sdk.setConfig above.

sdk.getAllConfig

sdk.getAllConfig(): Promise<object>

Gets the full contents of the persistent team configuration.

Example

import { sdk } from '@cto.ai/sdk'

const main = async () => {
    await sdk.setConfig('key1', 'Value one')
    await sdk.setConfig('key2', 'Value two')
    
    const fullConfig = await sdk.getAllConfig()
    sdk.log('Full config: ', JSON.stringify(fullConfig))
}

sdk.getSecret

sdk.getSecret(key: string, hidden: boolean = false): Promise<any>

Requests a secret from the secret store with the given key.

If the secret exists, it is returned. A notification is printed to the user that the secret has been accessed, unless the hidden argument is true.

If the secret does not exist, the user is prompted to provide a replacement, either from the secret store or by direct entry through their interface.

Example

import { sdk } from '@cto.ai/sdk'

const main = async () => {
    const { SECRET } = sdk.getSecret('SECRET')
    // `ux.print` hides secret values but `sdk.log` does not.
    sdk.log(`my secret is ${SECRET}`)
}

main()

Output

my secret is SUPER_SECRET_VALUE

sdk.setSecret

sdk.setSecret(key: string, value: string): Promise<any | null>

Sets a particular value into the secret store.

If the secret already exists, the user is prompted on whether to overwrite it.

Returns the key that the secret is set to, or null if the user declines to overwrite the existing value.

Example

import { sdk, ux } from '@cto.ai/sdk'

const main = async () => {
    const { key } = await sdk.setSecret("secret1", "it's a secret to everybody")
    await ux.print(key)
}

Output

secret1

sdk.track

sdk.track(tags, metadata): Promise<any>

Send workflow events to The Ops Platform.

  • tags: (String || String[]) Tags for the event you want to track
  • metaData: (Object) Data you want to be tracked

sdk.events

This function will return the information that has been stored by sdk.track.

async function events(start: string, end?: string) -> Promise<Array<Any>>

Retrieve workflow events from The Ops Platform.

The start and end time can be given as ISO strings, for example "2020-05-12T20:47:45Z"

🚀 What's next?

  • To learn more about the UX options available for you, please go to Node.js UX page.
  • To see which prompts we offer for this SDK, you can go to Node.js Prompts page.
Was this article helpful?