@mochabug/adapt-plugin-toolkit

0.8.0-alpha.8 • Public • Published

@mochabug/adapt-plugin-toolkit

Welcome to the Mochabug's Adapt Plugins Toolkit, your treasure trove for plugin development! This toolkit is packed with type definitions, classes, functions, and more, all tailored to simplify your plugin crafting journey.

Table of Contents

Features

Simplified Runtime API Wrapping

Instead of manually invoking the runtime grpc/rest API from the environment, this package wraps them into streamlined functions. The API consists of several segments:

  • ApiBase: Accessible from any location.
  • ExecutorApi: Available during execution, from any location.
  • StopExecutorApi: Usable during the stopping of a vertex.
  • SessionExecutorApi: An API with full functionality, including the vertex session.
  • ConfiguratorApi: Accessible during configuration from any location.

The division of the APIs into various parts facilitates the management of underlying OAuth2 scopes specific to different endpoints. Thus, users don't have to delve deep into understanding the underlying scopes.

Communication Types

The package includes types to facilitate communication with the runtime APIs, ensuring seamless integration and interaction.

Mime-Type Helper Functions

Ease your work with mime-types using the provided helper functions, which are tailored for efficient handling and manipulation.

Router Classes with Automatic Endpoint Generation

Router classes are provided to simplify the handling of incoming requests, whether for internal or external endpoints. With the help of the Adaptkit package, all the endpoints are generated automatically. By using the adaptkit --init or --add commands, the correct routing gets generated without the need for memorization.

Automated API Exposure with Routers

The recommended approach is to employ a router for managing incoming traffic to your plugin. These routers automatically reveal the available API for respective endpoints. By adopting routers, users can bypass the intricacies of understanding different APIs (except for recognizing the available features), as all these details are efficiently managed by the router itself.

Installation

Installing our toolkit is a piece of cake:

npm install @mochabug/adapt-plugin-toolkit

Usage

ExternalExecutorRouter

This router is employed when the vertex is executed on external endpoints.

import { VertexConfig } from '@mochabug/adapt-plugin-toolkit/api';
import { ExternalExecutorRouter } from '@mochabug/adapt-plugin-toolkit/router';

/**
 * Constructs an instance of ExternalExecutorRouter and sets up routes.
 *
 * @name router
 * @type {ExternalExecutorRouter}
 */
export const router = new ExternalExecutorRouter()

  /**
   * Sets up a GET route for the '/api/config' endpoint.
   * Handles authorization and retrieves vertex configuration.
   *
   * @method add
   * @async
   */
  .add('GET', '/api/config', async (req, api) => {
    const authHeader = req.headers.get('Authorization')!;
    const auth = await api.authorize(authHeader.substring('Bearer '.length));

    if (!auth.ok) {
      return new Response('Unauthorized', { status: 401 });
    }

    const res = await api.getVertexConfig<VertexConfig>();
    return res.ok 
      ? new Response(JSON.stringify(res.data!.item), {
          headers: { 'Content-Type': 'application/json' },
        })
      : new Response(res.errorMessage, { status: res.errorStatus });
  })

  /**
   * Sets up a GET route for displaying a simplified "Hello World" page.
   *
   * @method add
   * @async
   */
  .add('GET', '(/?)', async () => {
    return new Response(getHelloWorldPage(), {
      headers: { 'Content-Type': 'text/html' },
    });
  });

function getHelloWorldPage(): string {
  return `
    <html>
      <head>
        <!-- Basic styles omitted for brevity -->
      </head>
      <body>
        <h1>Hello, World!</h1>
      </body>
    </html>
  `;
}

InternalExecutorRouter

The 'InternalExecutorRouter' manages internal execution events, allowing developers to handle events such as start, stop, stream, and procedure.

import { InternalExecutorRouter } from '@mochabug/adapt-plugin-toolkit/router';

/**
 * Constructs an instance of InternalExecutorRouter and sets up event handlers.
 *
 * @name router
 * @type {InternalExecutorRouter}
 */
export const router = new InternalExecutorRouter()

  /**
   * Handles the 'start' event, called when vertex execution begins.
   *
   * @method onStart
   * @async
   */
  .onStart(async (req, api) => {
    const start = await req.json<StartExecutionRequest>();
    console.log('Start event triggered', start);
  })

  /**
   * Handles the 'stop' event, called when the vertex stops, either from a trigger or forcibly.
   *
   * @method onStop
   * @async
   */
  .onStop(async (req, api) => {
    console.log('Stop event triggered');
  })

  /**
   * Handles the 'stream' event, called when stream content becomes available.
   *
   * @method onStream
   * @async
   */
  .onStream(async (req, api, name) => {
    console.log(`Stream event triggered: ${name}`);
    const res = await req.json<StreamResult>();
    console.log(res);
  })

  /**
   * Handles the 'procedure' event, called when a procedure result is available.
   *
   * @method onProcedure
   * @async
   */
  .onProcedure(async (req, api, name) => {
    console.log(`Procedure event triggered: ${name}`);
    const res = await req.json<ProcedureResult>();
    console.log(res);
  });

ExternalConfiguratorRouter

This router is employed when the vertex is in the configuration phase. It's always used for a configuring vertex.

import { 
  ConfiguratorApi, 
  Exchange, 
  SignalDescriptor 
} from '@mochabug/adapt-plugin-toolkit/api';
import { 
  ExternalConfiguratorRouter, 
  joinPaths 
} from '@mochabug/adapt-plugin-toolkit/router';
import { getMimeType } from '@mochabug/adapt-plugin-toolkit/mime';
import { Component, Config } from './types';

/**
 * Reads files to be served to the client.
 * This function retrieves MIME types and optionally encodes in gzip.
 *
 * @param api Configurator API
 * @param filepath Path to the file
 * @param encoding Encoding type
 * @returns {Response} The file content as a response
 */
async function readFile(
  api: ConfiguratorApi,
  filepath: string,
  encoding: string | null,
): Promise<Response> {
  const path = joinPaths('/config-gui', filepath);
  const res = await api.readFile(path);
  if (!res.ok) {
    console.error(res);
    return new Response(res.errorMessage, { status: res.errorStatus });
  }

  const data = res.data!;
  const mime = getMimeType(path);
  const headers = new Headers();
  if (mime) {
    headers.set('Content-Type', mime.mime);
    if (encoding?.includes('gzip') && mime.gzip) {
      headers.set('Content-Encoding', 'gzip');
    }
  } else {
    headers.set('Content-Type', data.mime);
  }
  return new Response(data.content, { headers });
}

/**
 * Constructs an instance of ExternalConfiguratorRouter.
 *
 * @name router
 * @type {ExternalConfiguratorRouter}
 */
export const router = new ExternalConfiguratorRouter()
  /**
   * GET handler for configuration retrieval.
   *
   * @method add
   * @async
   */
  .add('GET', '/api/config', async (req, api) => {
    const authHeader = req.headers.get('Authorization')!;
    const auth = await api.authorize(authHeader.substring('Bearer '.length));
    if (!auth.ok) {
      console.error(auth);
      return new Response(auth.errorMessage, { status: auth.errorStatus });
    }

    const res = await api.getVertexConfig<any>(['config']);
    if (!res.ok) {
      console.error(res);
      return new Response(res.errorMessage, { status: res.errorStatus });
    }

    const config = res.data!.item;
    return new Response(JSON.stringify(config.config), {
      headers: { 'Content-Type': 'application/json' },
    });
  })

  /**
   * Serves the index.html file.
   *
   * @method add
   * @async
   */
  .add('GET', '(/?)', async (req, api) => {
    return await readFile(api, 'index.html', req.headers.get('Accept-Encoding'));
  })

  /**
   * Serves other required files.
   *
   * @method add
   * @async
   */
  .add('GET', '(.*)', async (req, api, route) => {
    return await readFile(api, route.path, req.headers.get('Accept-Encoding'));
  });

InternalConfiguratorRouter

While currently, this router is only used to export as an empty router, more features will be incorporated into it over time.

import { InternalConfiguratorRouter } from '@mochabug/adapt-plugin-toolkit/router';

export const router = new InternalConfiguratorRouter();
// As more features are added over time, corresponding handlers will be set up here.

ApiBase Class Documentation

Represents the base class for the API. The executor and configurator APIs extend this class. It is not intended to be used on its own.

Methods

getVariable(name: string): Promise<Result<string>>

Retrieves the variable with the specified name.

  • Parameters:

    • name: string: The name of the variable to retrieve.
  • Returns:

    • Promise<Result<string>>: A promise that resolves to the variable value, or an error result if the variable does not exist.

getVariables(...names: string[]): Promise<Result<Record<string, string>>>

Retrieves multiple variables with the specified names.

  • Parameters:

    • ...names: string[]: The names of the variables to retrieve.
  • Returns:

    • Promise<Result<Record<string, string>>>: A promise that resolves to an object mapping variable names to their values.

getUserVariable(name: string): Promise<Result<string>>

Retrieves the user variable with the specified name.

  • Parameters:

    • name: string: The name of the user variable to retrieve.
  • Returns:

    • Promise<Result<string>>: A promise that resolves to the user variable value, or an error result if the user variable does not exist.

getUserVariables(...names: string[]): Promise<Result<Record<string, string>>>

Retrieves multiple user variables with the specified names.

  • Parameters:

    • ...names: string[]: The names of the user variables to retrieve.
  • Returns:

    • Promise<Result<Record<string, string>>>: A promise that resolves to an object mapping user variable names to their values.

getUserToken(name: string): Promise<Result<Token>>

Retrieves the user token with the specified name.

  • Parameters:

    • name: string: The name of the user token to retrieve.
  • Returns:

    • Promise<Result<Token>>: A promise that resolves to the user token, or an error result if the user token does not exist.

getUserTokens(...names: string[]): Promise<Result<Record<string, Token>>>

Retrieves multiple user tokens with the specified names.

  • Parameters:

    • ...names: string[]: The names of the user tokens to retrieve.
  • Returns:

    • Promise<Result<Record<string, Token>>>: A promise that resolves to an object mapping user token names to their tokens.

userMtls(req: Request, name: string): Promise<Response>

Performs a user mTLS request.

  • Parameters:

    • req: Request: The request object.
    • name: string: The name of the request.
  • Returns:

    • Promise<Response>: A promise that resolves to the response of the request.

pluginMtls(req: Request, name: string): Promise<Response>

Performs a plugin mTLS request.

  • Parameters:

    • req: Request: The request object.
    • name: string: The name of the request.
  • Returns:

    • Promise<Response>: A promise that resolves to the response of the request.

authorize(token: string): Promise<Result<never>>

Authorizes the request using the specified token. Defaults to bearer token authorization.

  • Parameters:

    • token: string: The token to use for authorization.
  • Returns:

    • Promise<Result<never>>: A promise that resolves to true if the request is authorized, false otherwise.

readFile(path: string): Promise<Result<AssetFile>>

Reads a file from the specified path.

  • Parameters:

    • path: string: The path of the file to read.
  • Returns:

    • Promise<Result<AssetFile>>: A promise that resolves to the file content and MIME type, or an error result if the file does not exist or the MIME type is not supported.

readDirectory(path: string): Promise<Result<AssetDirectory>>

Reads a directory from the specified path.

  • Parameters:

    • path: string: The path of the directory to read.
  • Returns:

    • Promise<Result<AssetDirectory>>: A promise that resolves to the directory content, or an error result if the directory does not exist or the content is not in the expected format.

ExecutorApi

ExecutorApi represents the least privileged Executor API that cannot access the session. It extends the ApiBase class.

Methods

getVertexConfig<T>(fieldMask?: string[]): Promise<Result<T>>

Retrieves the vertex configuration.

  • Parameters:
    • fieldMask (optional) - The field mask for the vertex configuration. Type: string[]
  • Returns: A promise that resolves to the vertex configuration.

getBoundGlobalSignal(name: string): Promise<Result<any>>

Retrieves the global signal with the specified name.

  • Parameters:
    • name - The name of the global signal. Type: string
  • Returns: A promise that resolves to the global signal or an error result if not found.

getBoundGlobalSignals(...names: string[]): Promise<Result<Record<string, any>>>

Retrieves multiple global signals with the specified names.

  • Parameters:
    • names - The names of the global signals. Type: string[]
  • Returns: A promise that resolves to an object mapping global signal names to their signals.

getLocalStore(namespace: 'vertex' | 'plugin'): Store<ExecutorServiceImpl, ExecutorServiceBatchStoreRequest_Namespace>

Retrieves a local store instance based on the provided namespace.

  • Parameters:
    • namespace - The desired namespace for the store. Can be either 'vertex' or 'plugin'.
  • Returns: An instance of the Store class with the appropriate namespace.

getSessionApi(authHeader: string): SessionExecutorApi

Retrieves the session API from the basic api by setting the correct auth header value (i.e. Bearer ).

  • Parameters:
    • authHeader - The auth header value to use for the session API (e.g., Bearer ). Type: string
  • Returns: Returns the SessionExecutorApi.

BatchBuilder

Utility class for building batch operations for the KV store.

Methods

put(key: string, value: any, options?: PutOptions): this

Adds a put operation to the batch.

  • Parameters:
    • key - The key to set. Type: string
    • value - The value to set for the key. Type: any
    • options (optional) - Optional settings for the put operation. Type: PutOptions
  • Returns: The current instance of the builder.

get(key: string): this

Adds a get operation to the batch.

  • Parameters:
    • key - The key to retrieve. Type: string
  • Returns: The current instance of the builder.

delete(key: string): this

Adds a delete operation to the batch.

  • Parameters:
    • key - The key to delete. Type: string
  • Returns: The current instance of the builder.

build(): KeyValueOperation[]

Finalizes the batch and returns the array of operations.

  • Returns: The array of operations.

Store

Represents a store on a specific namespace.

Constructor

constructor(service: T, namespace: N)

Initializes a new instance of the Store.

  • Parameters:
    • service - The service instance. Type: T
    • namespace - The namespace. Type: N

Methods

(For brevity, only the method signatures are provided here. You can use a similar format as provided for the ExecutorApi class to describe each method in detail.)

  • put(key: string, value: any, options?: PutOptions): Promise<Result<never>>
  • get(key: string): Promise<Result<Value>>
  • delete(key: string): Promise<Result<never>>
  • pop(key: string): Promise<Result<Value>>
  • batch(ops: KeyValueOperation[]): Promise<Result<BatchResult>>

Related Types and Interfaces

PutOptions

This interface provides additional settings for put operations:

  • ttl (optional) - Type: number
  • failIfExists (optional) - Type: boolean

BatchResult

Represents the result of a batch operation.

  • Properties:
    • status - The global status for the entire batch operation. Type: GlobalResponseStatus
    • result - An array containing results of each operation within the batch. Type: OperationResult[]

StopExecutorApi

StopExecutorApi represents a basic API with session storage. This provides the available endpoints when a session is stopping. It extends the ExecutorApi class.

Constructor

constructor(env: ExecutorEnvironment, pluginToken: string, sessionAuthHeader: string)

Creates an instance of PrivilegedExecutorApi.

  • Parameters:
    • env - The executor environment. Type: ExecutorEnvironment
    • pluginToken - The plugin token from: X-Mochabug-Adapt-Plugin-Token. Type: string
    • sessionAuthHeader - The privileged authorization header. Type: string

Methods

getSessionStore(namespace: 'vertex' | 'plugin'): Store<ExecutorServiceImpl, ExecutorServiceBatchStoreRequest_Namespace>

Retrieves a session store instance based on the provided namespace.

  • Parameters:
    • namespace - The desired namespace for the store. It can be either 'vertex' or 'plugin'.
      • 'vertex' maps to ExecutorServiceBatchStoreRequest_Namespace.NAMESPACE_VERTEX_INSTANCE
      • 'plugin' maps to ExecutorServiceBatchStoreRequest_Namespace.NAMESPACE_PLUGIN_INSTANCE
  • Returns: An instance of the Store class with the appropriate namespace for the session.

SessionExecutorApi

SessionExecutorApi represents the Privileged Executor API and extends the StopExecutorApi class.

Constructor

constructor(env: ExecutorEnvironment, pluginToken: string, sessionAuthHeader: string)

Creates an instance of PrivilegedExecutorApi.

  • Parameters:
    • env - The executor environment. Type: ExecutorEnvironment
    • pluginToken - The plugin token from: X-Mochabug-Adapt-Plugin-Token. Type: string
    • sessionAuthHeader - The privileged authorization header. Type: string

Methods

listBoundReceiverSignals(pageSize?: number, orderDescending?: boolean): Promise<Result<{ signals: Record<string, any>; receiver: string; cursor?: string }>>

Lists bound receiver signals.

  • Parameters:
    • pageSize (optional) - The page size for the listing. Type: number
    • orderDescending (optional) - Indicates whether to order the signals in descending order. Type: boolean
  • Returns: A promise that resolves to the list of bound receiver signals.

continueListBoundReceiverSignals(cursor: string): Promise<Result<{ signals: Record<string, any>; receiver: string; cursor?: string }>>

Continues listing bound receiver signals.

  • Parameters:
    • cursor - The cursor to continue listing from. Type: string
  • Returns: A promise that resolves to the continued list of bound receiver signals.

getBoundReceiverSignal(name: string): Promise<Result<any>>

Retrieves the bound receiver signal with the specified name.

  • Parameters:
    • name - The name of the bound receiver signal. Type: string
  • Returns: A promise that resolves to the receiver signal or an error.

getBoundReceiverSignals(...names: string[]): Promise<Result<Record<string, any>>>

Retrieves multiple bound receiver signals with the specified names.

  • Parameters:
    • names - The names of the bound receiver signals. Type: string[]
  • Returns: A promise that resolves to a record of bound receiver signals.

complete(transmitter: string, signals: { [name: string]: any; }): Promise<Result<never>>

Completes an execution for the specified transmitter and signals.

  • Parameters:
    • transmitter - The transmitter identifier. Type: string
    • signals - The signals to be sent. Type: Record<string, any>
  • Returns: A promise that resolves when the execution is completed or encounters an error.

executeProcedure(name: string, receiver: string, signals: { [name: string]: any; }): Promise<Result<ProcedureOperation>>

Executes a procedure with the specified name, receiver, and signals.

  • Parameters:
    • name - The name of the procedure. Type: string
    • receiver - The receiver identifier. Type: string
    • signals - The signals to be sent. Type: Record<string, any>
  • Returns: A promise that resolves to the procedure operation or an error.

getProcedure(id: string): Promise<Result<ProcedureOperation>>

Retrieves the procedure operation with the specified ID.

  • Parameters:
    • id - The ID of the procedure operation. Type: string
  • Returns: A promise that resolves to the procedure operation or an error.

cancelProcedure(id: string): Promise<Result<never>>

Cancels the procedure operation with the specified ID.

  • Parameters:
    • id - The ID of the procedure operation. Type: string
  • Returns: A promise that resolves when the procedure operation is canceled or encounters an error.

startStream(name: string, receiver: string, signals: { [name: string]: any; }): Promise<Result<never>>

Starts the stream with the specified name.

  • Parameters:
    • name - The name of the stream. Type: string
    • receiver - The receiver identifier. Type: string
    • signals - The signals to be sent. Type: Record<string, any>
  • Returns: A promise that resolves when the stream is started or encounters an error.

cancelStream(name: string): Promise<Result<never>>

Cancels the stream with the specified name.

  • Parameters:
    • name - The name of the stream. Type: string
  • Returns: A promise that resolves when the stream is canceled or encounters an error.

ConfiguratorApi

ConfiguratorApi represents the API for the Configurator and extends the ApiBase class.

Constructor

constructor(env: ConfiguratorEnvironment, pluginToken: string)

Creates an instance of ConfiguratorApi.

  • Parameters:
    • env - The environment for the Configurator. Type: ConfiguratorEnvironment
    • pluginToken - The plugin token from X-Mochabug-Adapt-Plugin-Token. Type: string

Methods

getVertexConfig<T>(fieldMask?: string[]): Promise<Result<{ item: T, errors: ConfigError[], receiverErrors: BindingError[], bindingErrors: BindingError[] }>>

Retrieves the vertex configuration with an optional field mask.

  • Parameters:
    • fieldMask (optional) - The field mask. Type: string[]
  • Returns: A promise that resolves to the updated vertex configuration and errors.

patchVertexConfig<T>(value: any): Promise<Result<{ item: T, errors: ConfigError[], receiverErrors: BindingError[], bindingErrors: BindingError[] }>>

Patches the vertex configuration with the provided value using JSON Merge Patch (RFC 7396).

  • Parameters:
    • value - The patch value. Type: any
  • Returns: A promise that resolves to the updated vertex configuration and errors.

postVertexConfig<T>(value: T): Promise<Result<{ item: T, errors: ConfigError[], receiverErrors: BindingError[], bindingErrors: BindingError[] }>>

Posts the vertex configuration with the specified value.

  • Parameters:
    • value - The updated value. Type: T
  • Returns: A promise that resolves to the updated vertex configuration and errors.

listVertexTransmitters(filter?: string, pageSize?: number, orderBy?: 'vertex' | 'transmitter', orderDescending?: boolean, fieldMask?: string[]): Promise<Result<{ items: VertexTransmitter[]; receiver?: string; cursor?: string }>>

Lists the vertex transmitters with optional filters, page size, ordering, and field mask.

  • Parameters:
    • filter (optional) - The filter. Type: string
    • pageSize (optional) - The page size. Type: number
    • orderBy (optional) - The ordering. Type: 'vertex' | 'transmitter'
    • orderDescending (optional) - Indicates if the order is descending. Type: boolean
    • fieldMask (optional) - The field mask. Type: string[]
  • Returns: A promise that resolves to the list of vertex transmitters, receiver, and cursor.

continueListVertexTransmitters(cursor: string): Promise<Result<{ items: VertexTransmitter[], receiver?: string, cursor?: string }>>

Continues the listing of vertex transmitters with the specified cursor.

  • Parameters:
    • cursor - The cursor. Type: string
  • Returns: A promise that resolves to the list of vertex transmitters, receiver, and cursor.

getReceiverName(): Promise<Result<string>>

Retrieves the receiver name.

  • Returns: A promise that resolves to the receiver name.

listGlobalSignals(filter?: string, pageSize?: number, orderBy?: 'name_desc' | 'name_asc', fieldMask?: string[]): Promise<Result<{ items: GlobalSignal[]; cursor?: string }>>

Lists the global signals with optional filters, page size, ordering, and field mask.

  • Parameters:
    • filter (optional) - The filter. Type: string
    • pageSize (optional) - The page size. Type: number
    • orderBy (optional) - The ordering. Type: 'name_desc' | 'name_asc'
    • fieldMask (optional) - The field mask. Type: string[]
  • Returns: A promise that resolves to the list of global signals and cursor.

continueListGlobalSignals(cursor: string): Promise<Result<{ items: GlobalSignal[]; cursor?: string }>>

Continues the listing of global signals with the specified cursor.

  • Parameters:
    • cursor - The cursor. Type: string
  • Returns: A promise that resolves to the list of global signals and cursor.

getGlobalSignal(name: string): Promise<Result<GlobalSignal>>

Retrieves the global signal with the specified name.

  • Parameters:
    • name - The name of the global signal. Type: string
  • Returns: A promise that resolves to the global signal, or an error result if not found.

getGlobalSignals(...names: string[]): Promise<Result<Record<string, GlobalSignal>>>

Retrieves the global signals with the specified names.

  • Parameters:
    • names - The names of the global signals. Type: string[]
  • Returns: A promise that resolves to a record of the global signals.

getLocalStore(namespace: 'vertex' | 'plugin'): Store<ConfiguratorServiceImpl, ConfiguratorServiceBatchStoreRequest_Namespace>

Retrieves a local store instance for the configurator based on the provided namespace.

  • Parameters:
    • namespace - The desired namespace for the configurator store. 'vertex' maps to ConfiguratorServiceBatchStoreRequest_Namespace.NAMESPACE_VERTEX and 'plugin' maps to ConfiguratorServiceBatchStoreRequest_Namespace.NAMESPACE_PLUGIN. Type: 'vertex' | 'plugin'
  • Returns: An instance of the Store class with the appropriate namespace for the configurator.

Contributing

@mochabug/adapt-plugin-toolkit s is a community-driven, open-source project, and we warmly welcome your contributions! If you have an idea for a new type, a bug report, or would like to help with documentation, please open an issue or submit a pull request.

Package Sidebar

Install

npm i @mochabug/adapt-plugin-toolkit

Weekly Downloads

2

Version

0.8.0-alpha.8

License

Apache-2.0

Unpacked Size

776 kB

Total Files

45

Last publish

Collaborators

  • patruf
  • mikaelhedberg