npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@psnext/block-sdk

v0.0.16

Published

**Block SDK** is a utility designed to simplify Block development on the CoreAI platform. With Block SDK, developers can securely register blocks with the CoreAI platform and facilitate two-way communication between other blocks and front-end/back-end (FE

Downloads

1,420

Readme

Block SDK

Block SDK is a utility designed to simplify Block development on the CoreAI platform. With Block SDK, developers can securely register blocks with the CoreAI platform and facilitate two-way communication between other blocks and front-end/back-end (FE/BE) components within the ecosystem. Since blocks are rendered as iframes within the CoreAI canvas, managing communication with other components often leads to duplicate code. Block SDK abstracts this complexity, providing reusable utilities and streamlining block development.

Once registered with Block SDK, developers no longer need to worry about the nuances of communication across the CoreAI platform. In addition to communication utilities, Block SDK offers features such as Event Manager, Fetcher, State Manager, Assistant Agent, ResizeObserver, and more, simplifying development efforts.

Note: This SDK is a client-side SDK intended exclusively for use with the CoreAI platform.

Migration Note: If you are migrating from a previous version (0.0.10 or earlier) of the Block SDK to the latest version, please be aware of the following changes:

  • The register method has been updated to return a Promise that resolves to an instance of the Block SDK.
  • The register method may now throw errors if block authentication fails.
  • Ensure you update your code to handle the asynchronous nature of the new register method and implement proper error handling.

Table of Contents

Installation

Block SDK is integrated into blocks via a CDN URL. Below is an example implementation using Next.js:

import Script from 'next/script';
import Block from "./components/Block";

export default function Home() {
  return (
    <main>
      <Script
        src="https://unpkg.com/@psnext/[email protected]/dist/block-sdk.js"
        strategy="beforeInteractive"
      />
      <Block />
    </main>
  );
}

Features

  1. Two-way Communication: Blocks can send and receive data from other blocks and FE/BE components (e.g., ALX, Host) on the CoreAI platform.
  2. Fetcher Utility: A wrapper around the browser fetch API, with integrated CoreAI authentication, token validation, and auto-refresh functionality.
  3. ResizeObserver Utility: A wrapper for the browser's ResizeObserver API to track block dimension changes and communicate new sizes to the CoreAI platform, ensuring dynamic resizing of block containers.
  4. Logger Utility: A logging utility that prefixes messages with CoreAI-specific details, offering multiple log levels and runtime configuration to control log output.
  5. State Manager: A utility for managing and persisting block state across sessions in build and play mode.
  6. Alx Chat Assistant Agent: BlockSDK provides seamless integration with Enterprise Assistant Agent, enabling AI-powered interactions within blocks. When a block has an assistantId configured in its apps.json, the SDK automatically handles bidirectional communication between ALX chat and the Assistant Agent. Messages from ALX chat are processed and routed to the appropriate Assistant Agent, and responses are displayed back in the ALX chat window. To enable this integration, obtain an assistantId from the Enterprise Support team and add it to your block's apps.json configuration.
  7. Additional Utilities:
    • getAppHostname: Retrieves the app's hostname, returning the parent hostname if running inside an iframe.
    • getHostFromUrl: Extracts the hostname from a given URL.
    • getAppUrl: Retrieves the app's URL.
    • getParentUrl: Retrieves the parent app's URL.
  8. Future Features: The SDK is designed to expand, with planned utilities like NotificationManager, Analytics, and Block Runner.

Usage

Register the Block SDK

Block SDK is available through the window object. To register a block with Block SDK, use the register method and provide a callback. The method returns an instance with all necessary tools for communication with other blocks and CoreAI components.

Note: During block registration, BlockSdk verifies user authentication. If the user is not authenticated, they will be automatically redirected to the login screen.

Example:

useEffect(() => {
    if (window.BlockSdk) {
      (async () => {
        const instance = await window.BlockSdk.register({
          onIncomingData: onIncomingData,
          onHostDataUpdate: onHostDataUpdate,
          onAlxData: onAlxData,
        });
        if (instance) {
          instance.resizeObserver(parentRef.current);
          blockSdkInstance.current = instance;
        }
      })();
    }
  }, []);

Send and Receive Data Between Blocks

Blocks can send and receive data to/from other blocks. Use the sendOutput method to send data:

@outputHandleId: string, // The handle id of the output to send. This is defined in the apps.json. @outputData: any // The data to send to the output

function sendOutput(outputHandleId: string) {
  blockSdkInstance.current?.sendOutput(outputHandleId, outputData[outputHandleId]);
}

Handle incoming data using the onIncomingData callback:

function onIncomingData(event: any, data: any) {
  console.log('On Incoming Data', data);
}

JSON structure of incoming data:

{
  "receivingBlockId": "0e86c994-d91f-4fe2-b8c7-7122d94c97af",
  "type": "input-event",
  "eventData": {
    "version": 2,
    "eventId": "625b593b-b871-4700-8bc0-81f915f23625",
    "timestamp": 1727734592244,
    "playId": "",
    "source": {
      "blockId": "7444e179-4171-4d0b-a7b5-abe247d6cb21",
      "blockName": "X1 Local",
      "handleId": "x1-output-1"
    },
    "payload": {
      "data": "111",
      "lastUpdatedTimestamp": 1727734592244,
      "type": "string"
    },
    "targetHandleId": "x1-input-1"
  }
}

Send and Receive Data with ALX Chat

Use sendAlxMessage to send messages to ALX Chat:

@alxMessage: any, // A message to send to ALX Chat. It could be any data type. @alxEventType: string, // Optional. The type of event to send to ALX Chat.

function sendDataToAlx() {
  blockSdkInstance.current?.sendAlxMessage(alxMessage);
}

To update an existing message:

export const ALX_EVENT_TYPE = {
  UPDATE_MESSAGE: 'UPDATE_MESSAGE',
  DISPLAY_MESSAGE: 'DISPLAY_MESSAGE',
};
function sendDataToAlx() {
  blockSdkInstance.current?.sendAlxMessage(alxMessage, ALX_EVENT_TYPE.UPDATE_MESSAGE);
}

Handle incoming ALX Chat data with onAlxData:

function onAlxData(event: any, eventData: any) {
  console.log('ALX Chat data', eventData);
}

JSON structure of ALX Chat data:

{
  "receivingBlockId": "0e86c994-d91f-4fe2-b8c7-7122d94c97af",
  "type": "alx-event",
  "eventData": {
    "version": 2,
    "eventId": "826d5b1f-e28b-4121-8be0-2664df2cc712",
    "timestamp": 1727734713896,
    "playId": "",
    "payload": { "prompt": "hello" }
  }
}

Receive App Data from Host App

The onHostDataUpdate callback is triggered when the block is loaded or when connecting edges are updated:

function onHostDataUpdate(event: any, eventData: any) {
  console.log('Host data updated', eventData);
}

Note: The onHostDataUpdate callback is triggered multiple times when the block is loaded. The first time it is triggered with the initial host data and then each time the edges are updated also it is called when the block is switched to different mode and version updates.

JSON structure of host data:

{
  "receivingBlockId": "7444e179-4171-4d0b-a7b5-abe247d6cb21",
  "type": "host-data-event",
  "eventData": {
    "version": 2,
    "eventId": "be3680a6-71c0-4acc-9c05-5a6544d483ce",
    "timestamp": 1727734340261,
    "playId": "",
    "payload": {
      "incomingEdges": [
        {
          "edgeId": "reactflow__edge-7444e179-4171-4d0b-a7b5-abe247d6cb21x1-output-1-0e86c994-d91f-4fe2-b8c7-7122d94c97afx1-input-1",
          "sourceHandleId": "x1-output-1",
          "targetHandleId": "x1-input-1",
          "sourceBlockId": "7444e179-4171-4d0b-a7b5-abe247d6cb21",
          "targetBlockId": "0e86c994-d91f-4fe2-b8c7-7122d94c97af"
        }
      ],
      "workspace": {
        "id": "05ff6020-3412-4827-a079-77a50824765d",
        "state": {
            "publishedVersionId": "6a5e3c68-3750-468f-8b6b-0d741e6a6169",
            "runId": "b6020ad4-ef3c-45d6-ba94-1a6b9e4eef7d",
            "createBuildState": false,
            "fetchBuildState": false,
            "createPlayState": false,
            "fetchPlayState": true
        },
        "mode": "play"
      },
      "project": {
        "id": "fe5c5203-97d2-43e8-a656-5ac7103ef13a"
      },
      "client": {
        "id": "4a18468e-f01b-4729-9a5b-4fb707755b41"
      },
      "appConfig": {
        "id": "7444e179-4171-4d0b-a7b5-abe247d6cb21",
        "agentUrl": "",
        "name": "X1 Local",
        "description": "X1 App",
        "appSlug": "x11",
        "width": 500,
        "height": 400,
        "defaultWidth": 1000,
        "defaultHeight": 900,
        "display_name": "X1",
        "preview_url": "/icons/Audience Builder.svg",
        "version": 2,
        "widget_url": "http://localhost:3003/web/x1",
        "miniapp_url": "http://localhost:3003/web/x1",
        "inputHandlers": [
          {
            "id": "x1-input-1",
            "name": "X1 Input 1",
            "description": "X1 Input 1",
            "type": "string"
          },
          {
            "id": "x1-input-2",
            "name": "X1 Input 2",
            "description": "X1 Input 2",
            "type": "string"
          }
        ],
        "outputHandlers": [
          {
            "id": "x1-output-1",
            "name": "X1 Output 1",
            "description": "X1 Output 1",
            "type": "string"
          },
          {
            "id": "x1-output-2",
            "name": "X1 Output 2",
            "description": "X1 Output 2",
            "type": "string"
          }
        ]
      }
    }
  }
}

Resize Observer

Use Block SDK's ResizeObserver utility to monitor block dimensions:

@blockContainer: HTMLElement, // The block container element

blockSdkInstance.current.resizeObserver(document.getElementById('block-container'));

Fetcher

Block SDK's Fetcher utility handles network requests with authentication and token refresh. Its signature matches the browser fetch API:

@url: string, // The URL to fetch @options: RequestInit, // Optional. The request options

BlockSdk.Utils.fetch(url, options);

State Manager

The State Manager utility in BlockSDK allows blocks to persist and retrieve state across sessions. This ensures continuity of data between build and run modes, facilitating smoother experiences for users.

Usage

To integrate the State Manager, pass callback handlers during the BlockSdk.register call:

useEffect(() => {
  if (window.BlockSdk) {
    (async () => {
      const instance = await window.BlockSdk.register({
        onBuildVersionUpdate: handleBuildVersionUpdate,
        onPlayInstanceUpdate: handlePlayInstanceUpdate,
      });
    })();
  }
}, []);

These callbacks are invoked whenever a new version is published in either play or build mode. Each callback is provided with a configuration object containing the following properties:

interface IStateConfig {
  publishedVersionId: string
  runId: string
  createBuildState: boolean
  fetchBuildState: boolean
  createPlayState: boolean
  fetchPlayState: boolean
}

Each flag indicates whether the corresponding action (create or fetch state) should be performed. If set to true, the relevant state method is triggered.

Handling Build Version Updates
const handleBuildVersionUpdate = async (config: IStateConfig) => {
  if (config.fetchBuildState) {
    const buildState = await blockSdkInstance.current.stateManager.fetchBuildState();
    if (buildState) {
      // Restore the UI with the fetched build state
    }
  }

  if (config.createBuildState) {
    await blockSdkInstance.current.stateManager.createBuildState({
      state: localBlockState,
    });
  }
};
Handling Play Instance Updates
const handlePlayInstanceUpdate = async (config: IStateConfig) => {
  window.BlockSdk.Utils.logger.log("Play Instance Updated", config);
  let buildState;
  if(config.fetchBuildState) {
    buildState = await blockSdkInstance.current.stateManager.fetchBuildState();
    if(buildState) {
      // Restore the UI with the fetched build state
    }
  }
  if(config.createPlayState && buildState) {
    await blockSdkInstance.current.stateManager.createPlayState({...buildState});
  }
  if(config.fetchPlayState) {
    const playState = await blockSdkInstance.current.stateManager.fetchPlayState();
    if(playState) {
      // Restore the UI with the fetched play state
    }
  }
};
Available Methods

The State Manager provides the following methods:

  • fetchBuildState : Retrieves the build state.
  • createBuildState : Create the build state.
  • fetchPlayState : Retrieves the play state.
  • createPlayState : Create the play state.
  • updatePlayState : Update the play state.
Local Development

For local development, you can use the local proxy server to proxy API requests to the CoreAI dev server. For example, if your local block runs on http://localhost:3003/web/x1, set apiBase to http://localhost:3003/web/x1/dev-proxy-api.

  await blockSdkInstance.current.stateManager.createPlayState({
    state: buildState,
    apiBase: 'http://localhost:3003/web/x1/dev-proxy-api',
  });

Here’s an example of configuring Next.js to proxy API requests to the CoreAI dev server:

const nextConfig = {
  async rewrites() {
    return [
      {
        source: '/dev-proxy-api/:path*',
        destination: 'https://dev.lionis.ai/:path*',
      },
    ];
  },
}

Troubleshotting

Property 'BlockSdk' does not exist on type 'Window & typeof globalThis'.ts(2339)

To fix this add BlockSdk in global

declare global {
  interface Window {
    BlockSdk: any;
  }
}

Contributing

To contribute and run the package locally, follow these steps:

  1. Clone the repository.
  2. Run yarn install.
  3. Run yarn dev
  4. Load SDK as module http://localhost:3008/src/index.ts

Available Scripts:

  • dev: Build for production & start the development server.
  • build: Build for production.
  • release: Generate changelog and publish to npm.
  • lint: Check for linting errors.
  • test: Run tests.
  • test:watch: Run tests in watch mode.
  • test:coverage: Run tests and generate a coverage report.
  • prepare: Set up Husky hooks.