TypeScript Code for Workers

The minimal expected code is a function exported as default that should return the result of the worker’s script execution.

📘

Note

The supported TypeScript version in the JFrog Platform is ES2022, with the default configuration.

For example:

export default async function MyFunction() {

   // Do what you want

   return {
       status: 'DOWNLOAD_PROCEED',
       message: 'proceed',
   }
}

To enhance the developer experience we have chosen to use TypeScript. The worker function takes two inputs, which are injected.

export default async function (context: PlatformContext, data: T) Promise<U> {

   // Do what you want

   return {
       status: 'DOWNLOAD_PROCEED',
       message: 'proceed',
   }
}

Where T and U types stand for the data type (for example, BeforeDownloadRequest) and the expected returned response (like BeforeDownloadResponse for BeforeDownloadRequest).

Event payloads include a userContext object for the user or token that triggered the event. The object contains id (user ID or token ID), isToken, and realm. For more information, see Configure Workers for Custom Flows.

You can give a name to your function for convenience. You can also use anonymous functions instead.

The code editor also supports arrow functions. The samples provided in the documentation use arrow functions.

TypeScript APIs

You can use the following common interface types in your Worker code.

❗️

Important

Import statements are not allowed in the code, but you can use JavaScript natives.

Timing functions such as setTimeout, setInterval, or setImmediate are part of the Node.js API, which is disabled in the Worker sandbox.

PlatformContext

interface PlatformContext {
   baseUrl: string; // platform base URL
   clients: PlatformClients; // clients to communicate with the platform or external resources
   platformToken: string; // platform access token
   wait: (delayMs: number) => Promise<void> // creates a promise that resolves after "duration" expressed in millisecondes
   state: StateManager; // State manager to store and retrieve state for this Worker between executions
   getRemainingExecutionTime: () => number // remaining milliseconds before the Worker execution times out
   crypto: PlatformCrypto; // hash, HMAC, and cryptographically secure random bytes
}

PlatformCrypto

Use context.crypto to hash data, compute HMAC values, and generate cryptographically secure random bytes in a Worker script. The Node.js crypto module is not available in the Worker sandbox. These methods are available from Workers 1.306.0.

Supported hash and HMAC algorithms are sha256 and sha512. The encoding argument is optional and defaults to hex. You can also set it to base64. randomBytes generates at most 4096 bytes.

For example:

export default async (context: PlatformContext): Promise<any> => {
  const digest = context.crypto.hash('sha256', 'hello');
  const hmac = context.crypto.hmac('sha256', 'secret', 'hello');
  const nonce = context.crypto.randomBytes(32);
  const digestBase64 = context.crypto.hash('sha512', 'hello', 'base64');

  return { digest, hmac, nonce, digestBase64 };
};
📘

PlatformCrypto Errors

  • An unsupported hash algorithm raises Unsupported hash algorithm '<algorithm>'. Supported: sha256, sha512.
  • An unsupported HMAC algorithm raises Unsupported hmac algorithm '<algorithm>'. Supported: sha256, sha512.
  • An unsupported encoding raises Unsupported encoding '<encoding>'. Supported: hex, base64.
  • A randomBytes size that is not a positive integer raises crypto.randomBytes size must be a positive integer.
  • A randomBytes size greater than 4096 raises crypto.randomBytes size cannot exceed 4096 bytes.
interface PlatformCrypto {
  /**
   * Computes a cryptographic hash of the given data
   * @param {string} algorithm - The hash algorithm to use. Supported: 'sha256', 'sha512'
   * @param {string} data - The data to hash
   * @param {string} encoding - The output encoding. Defaults to 'hex'
   */
  hash(algorithm: 'sha256' | 'sha512', data: string, encoding?: 'hex' | 'base64'): string;

  /**
   * Computes an HMAC of the given data using the given key
   * @param {string} algorithm - The hash algorithm to use. Supported: 'sha256', 'sha512'
   * @param {string} key - The HMAC key
   * @param {string} data - The data to authenticate
   * @param {string} encoding - The output encoding. Defaults to 'hex'
   */
  hmac(algorithm: 'sha256' | 'sha512', key: string, data: string, encoding?: 'hex' | 'base64'): string;

  /**
   * Generates cryptographically secure random bytes
   * @param {number} size - The number of random bytes to generate
   * @param {string} encoding - The output encoding. Defaults to 'hex'
   */
  randomBytes(size: number, encoding?: 'hex' | 'base64'): string;
}

PlatformClients

Axios

The object axios is available inside the script. You can use this object to perform external calls. For more information, refer to the Axios Documentation.

interface PlatformClients {
   platformHttp: PlatformHttpClient // generic HTTP client to communicate with the platform. Hostname and token are set automatically.
   axios: AxiosInstance // generic HTTP client to communicate with external web resources.
}

Fire-and-Forget Methods

Fire-and-forget HTTP calls let Workers trigger notifications or downstream jobs without waiting for a response. The JFrog Platform schedules the request and moves on, so a long external call does not hold the Worker open or cause an execution timeout. Use a standard awaited HTTP call when the Worker needs the response to determine what happens next.

These methods are on context.clients.axios. They schedule the HTTP request and return immediately. For examples, see fire-and-forget HTTP calls.

📘

Note

A successful Worker run means only that the request was scheduled. It doesn't mean the other system received the request, returned a 200 status, or finished the work.

export interface ExtendedAxios {
    /**
     * Triggers an HTTP GET request and does not wait for the response (fire-and-forget).
     * Note: completion is not guaranteed. If the target server ties request processing to the client connection, it may abort the work when the client disconnects.
     */
    getAndForget: <D = any, P = any>(
        url: string,
        config?: AxiosRequestConfig<D, P>
    ) => void;

    /**
     * Triggers an HTTP PUT request and does not wait for the response (fire-and-forget).
     * Note: completion is not guaranteed. If the target server ties request processing to the client connection, it may abort the work when the client disconnects.
     */
    putAndForget: <D = any, P = any>(
        url: string,
        data?: D,
        config?: AxiosRequestConfig<D, P>
    ) => void;

    /**
     * Triggers an HTTP POST request and does not wait for the response (fire-and-forget).
     * Note: completion is not guaranteed. If the target server ties request processing to the client connection, it may abort the work when the client disconnects.
     */
    postAndForget: <D = any, P = any>(
        url: string,
        data?: D,
        config?: AxiosRequestConfig<D, P>
    ) => void;

    /**
     * Triggers an HTTP DELETE request and does not wait for the response (fire-and-forget).
     * Note: completion is not guaranteed. If the target server ties request processing to the client connection, it may abort the work when the client disconnects.
     */
    deleteAndForget: <D = any, P = any>(
        url: string,
        config?: AxiosRequestConfig<D, P>
    ) => void;

    /**
     * Triggers an HTTP HEAD request and does not wait for the response (fire-and-forget).
     * Note: completion is not guaranteed. If the target server ties request processing to the client connection, it may abort the work when the client disconnects.
     */
    headAndForget: <D = any, P = any>(
        url: string,
        config?: AxiosRequestConfig<D, P>
    ) => void;

    /**
     * Triggers an HTTP PATCH request and does not wait for the response (fire-and-forget).
     * Note: completion is not guaranteed. If the target server ties request processing to the client connection, it may abort the work when the client disconnects.
     */
    patchAndForget: <D = any, P = any>(
        url: string,
        data?: D,
        config?: AxiosRequestConfig<D, P>
    ) => void;

    /**
     * Triggers an HTTP REQUEST and does not wait for the response (fire-and-forget).
     * Note: completion is not guaranteed. If the target server ties request processing to the client connection, it may abort the work when the client disconnects.
     */
    requestAndForget: <D = any, P = any>(
        config: AxiosRequestConfig<D, P>
    ) => void;
}

PlatformHttpClient

PlatformHttpClient relies on Axios to perform HTTP requests. It is a ready to use client to call any JFrog Platform REST API. The endpoint input must be a relative URL with the pattern <serviceName>/api/<endpoint>. For example, the methods of the PlatformHttpClient, /artifactory/api/system/ping, return an object of type IPlatformHttpResponse or throw an object of type PlatformHttpClientError as error.

Use request(method, body, headers) when you need to send a request body with DELETE, or to specify a custom method, body, and headers. The get, post, put, patch, and delete methods are unchanged. The delete method does not accept a request body.

interface PlatformHttpClient {
   /**
    * Perform HTTP GET request to the JFrog Platform
    * @param {string} endpoint - API endpoint. For example, /artifactory/api/repositories
    * @param {Record<string, string>} headers - additional headers used in the request
    */
   get(endpoint: string, headers?: Record<string, string>): Promise<IPlatformHttpResponse>


   /**
    * Perform HTTP POST request to JFrog platform
    * @param {string} endpoint - API endpoint. For example, /artifactory/api/repositories
    * @param {any} requestData - data sent in request body
    * @param {Record<string, string>} headers - additional headers used in the request
    */
   post(endpoint: string, requestData?: any, headers?: Record<string, string>): Promise<IPlatformHttpResponse>


   /**
    * Perform HTTP PUT request to JFrog platform
    * @param {string} endpoint - API endpoint. For example, /artifactory/api/repositories
    * @param {any} requestData - data sent in request body
    * @param {Record<string, string>} headers - additional headers used in the request
    */
   put(endpoint: string, requestData?: any, headers?: Record<string, string>): Promise<IPlatformHttpResponse>


   /**
    * Perform HTTP PATCH request to JFrog platform
    * @param {string} endpoint - API endpoint. For example, /artifactory/api/repositories
    * @param {any} requestData - data sent in request body
    * @param {Record<string, string>} headers - additional headers used in the request
    */
   patch(endpoint: string, requestData?: any, headers?: Record<string, string>): Promise<IPlatformHttpResponse>


   /**
    * Perform HTTP DELETE request to JFrog platform
    * @param {string} endpoint - API endpoint. For example, /artifactory/api/repositories
    * @param {Record<string, string>} headers - additional headers used in the request
    */
   delete(endpoint: string, headers?: Record<string, string>): Promise<IPlatformHttpResponse>


   /**
    * Perform an HTTP request to the JFrog Platform. Use this method when you need to send a body with DELETE, or to specify the HTTP method, body, and headers without changing get, post, put, patch, or delete.
    * @param {string} method - HTTP method. For example, GET, POST, PUT, PATCH, or DELETE
    * @param {any} body - data sent in the request body, including for DELETE
    * @param {Record<string, string>} headers - additional headers used in the request
    */
   request(method: string, body?: any, headers?: Record<string, string>): Promise<IPlatformHttpResponse>
}

IPlatformHttpResponse

interface IPlatformHttpResponse {
   /**
    * HTTP status
    */
   status: number;
   /**
    * Response headers
    */
   headers: Record<string, string>;
   /**
    * Parsed response body
    */
   data: any;
}

PlatformHttpClientError

interface PlatformHttpClientError {
    /**
     * The reason of the error
     */
    message: string;

    /**
     * Http status
     */
    status: number;
}

StateManager

This interface allows you to set or modify a Worker state at runtime, which persists between Worker runs. For example:

export default async (context: PlatformContext): Promise<any> => {
  context.state.has('foo'); // false
  context.state.set('foo', 'bar');
  context.state.has('foo'); // true

  return context.state.getAll(); // { "foo": "bar" }
};

The state is stored as a string: to safely retrieve a number, use the following syntax:

const numberStr = context.state.get('number');
const number = Number.parseInt(numberStr) || 0;

This code will try to get the property ‘number’ from the state and convert it to a number. If it doesn't exist or cannot be parsed, the code returns 0.

📘

StateManager Limitations

  • The state tool does not support concurrent executions of the same Worker.
  • In case of execution failure, the state will not be saved.
  • A Worker state can hold a maximum of 10 items by default: Self-Managed users can change this value in ​Workers YAML Configuration​​.
  • A state item key-value pair cannot exceed 40 characters for the key and 250 characters for the value.
interface StateManager {
    /**
     * Retrieves a value from the state by its key
     * @param {string} key - The key of the value to retrieve
     */
    get(key: string): string;
    /**
     * Sets a value in the state by its key
     * @param {string} key - The key of the value to set
     * @param {any} value - The value to set. If the value is not a string, it will be converted to a JSON string.
     */
    set(key: string, value: any): void;
    /**
     * Checks if a value exists in the state by its key
     * @param {string} key - The key of the value to check
     * @returns {boolean} - True if the value exists, false otherwise
     */
    has(key: string): boolean;
    /**
     * Deletes a value from the state by its key.
     * If it does not exist, it does nothing.
     * @param {string} key - The key of the value to delete
     */
    delete(key: string): void;
    /**
     * Clears the entire state
     */
    clear(): void;
    /**
     * Returns a copy of the entire state
     */
    getAll(): Record<string, string>;
}

Did this page help you?