All files / kernel-browser-runtime/src background-captp.ts

100% Statements 10/10
100% Branches 5/5
100% Functions 4/4
100% Lines 10/10

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124                                                  10x 10x                   3x 2x   1x                   2x                                                                                                                     4x   4x           4x           3x  
import { makeCapTP } from '@endo/captp';
import type { JsonRpcMessage, JsonRpcCall } from '@metamask/kernel-utils';
import type { JsonRpcNotification } from '@metamask/utils';
 
import type { CapTPMessage, KernelFacade } from './types.ts';
 
export type { CapTPMessage };
 
/**
 * A CapTP JSON-RPC notification.
 */
export type CapTPNotification = JsonRpcNotification & {
  method: 'captp';
  params: [CapTPMessage];
};
 
/**
 * Check if a message is a CapTP JSON-RPC notification.
 *
 * @param message - The message to check.
 * @returns True if the message is a CapTP notification.
 */
export function isCapTPNotification(
  message: JsonRpcMessage,
): message is CapTPNotification {
  const { method, params } = message as JsonRpcCall;
  return method === 'captp' && Array.isArray(params) && params.length === 1;
}
 
/**
 * Extract the CapTP message from a notification.
 *
 * @param message - The notification message.
 * @returns The CapTP message.
 */
export function getCapTPMessage(message: JsonRpcMessage): CapTPMessage {
  if (!isCapTPNotification(message)) {
    throw new Error('Not a CapTP notification');
  }
  return message.params[0];
}
 
/**
 * Create a CapTP JSON-RPC notification.
 *
 * @param captpMessage - The CapTP message to wrap.
 * @returns The JSON-RPC notification.
 */
export function makeCapTPNotification(captpMessage: CapTPMessage): JsonRpcCall {
  return {
    jsonrpc: '2.0',
    method: 'captp',
    params: [captpMessage],
  };
}
 
/**
 * Options for creating a background CapTP endpoint.
 */
export type BackgroundCapTPOptions = {
  /**
   * Function to send CapTP messages to the kernel.
   *
   * @param message - The CapTP message to send.
   */
  send: (message: CapTPMessage) => void;
};
 
/**
 * The background's CapTP endpoint.
 */
export type BackgroundCapTP = {
  /**
   * Dispatch an incoming CapTP message from the kernel.
   *
   * @param message - The CapTP message to dispatch.
   * @returns True if the message was handled.
   */
  dispatch: (message: CapTPMessage) => boolean;
 
  /**
   * Get the remote kernel facade.
   * This is how the background calls kernel methods using E().
   *
   * @returns A promise for the kernel facade remote presence.
   */
  getKernel: () => Promise<KernelFacade>;
 
  /**
   * Abort the CapTP connection.
   *
   * @param reason - The reason for aborting.
   */
  abort: (reason?: unknown) => void;
};
 
/**
 * Create a CapTP endpoint for the background script.
 *
 * This sets up a CapTP connection to the kernel. The background can then use
 * `E(kernel).method()` to call kernel methods.
 *
 * @param options - The options for creating the CapTP endpoint.
 * @returns The background CapTP endpoint.
 */
export function makeBackgroundCapTP(
  options: BackgroundCapTPOptions,
): BackgroundCapTP {
  const { send } = options;
 
  const { dispatch, getBootstrap, abort } = makeCapTP(
    'background',
    send,
    undefined, // No bootstrap - we only want to call the kernel
  );
 
  return harden({
    dispatch,
    getKernel: getBootstrap,
    abort,
  });
}
harden(makeBackgroundCapTP);