+
+Sigma Computing Plugins provides an API for third-party applications add
+additional functionality into an existing Sigma workbook.
+
+Plugins are built using Sigma’s Plugin API. This API communicates data and
+interaction events between a Sigma workbook and the plugin. Plugins are hosted
+by their developer and rendered in an iframe in Sigma.
+
+#### Warning: Breaking Changes
+
+`@sigmacomputing/plugin` has moved to https://github.com/sigmacomputing/plugin and
+is now open source. Please read our
+[CHANGELOG.md](https://github.com/sigmacomputing/plugin/blob/main/CHANGELOG.md)
+to review any breaking changes that have been made.
+
+## Requirements
+
+To test your plugin in Sigma Plugin Dev Playground, you must:
+
+- Have an Admin, Creator or Explorer account type
+- Have Can Edit permission on the work
+- Be in the workbook’s Edit mode
+
+To test a development version of a registered plugin, you must:
+
+- Have either:
+ - An Admin account type
+ - A custom account type that supports plugin developer feature permissions
+
+- Have "can edit" permission on the workbook
+- Be in the workbook’s Edit mode
+
+Your plugin must be a Javascript-based project and run in the browser.
+
+## Getting Started
+
+### Installation
+
+Provided you have already followed the steps to create a plugin and a plugin
+development environment, you can install `@sigmacomputing/plugin` using one of
+the following commands
+
+```sh
+yarn add @sigmacomputing/plugin
+# or
+npm install @sigmacomputing/plugin
+```
+
+If you have yet to set up your development environment, follow one of the setup
+guides below
+
+### Create a Development Project
+
+At Sigma, we use React for all of our frontend development. This was taken into
+consideration when building Sigma’s Plugin feature.
+
+While you are not required to use React for your plugin, it must be written in
+Javascript and React is recommended. We support both a standard Javascript API
+and a React Hooks API.
+
+#### Create a Project with Vite
+
+1. Open your terminal and navigate to the directory you want to create your
+ project in.
+2. Create your new project. We recommend using
+ [`create-vite`](https://www.npmjs.com/package/create-vite).
+
+ ```sh
+ yarn create vite
+ # or
+ npm create vite@latest
+ ```
+
+3. Then follow the prompts! You can also directly specify the project name and the template you want to use via additional command line options. For example, to scaffold a Vite + Vue project, run:
+
+ ```sh
+ yarn create vite my-vue-app --template vue
+ ```
+
+4. Navigate to the project's main directory.
+
+ ```sh
+ cd
+ ```
+
+5. Use your package manager to install Sigma’s plugin library. We recommend
+ using `yarn`.
+
+ ```sh
+ yarn add @sigmacomputing/plugin
+ ```
+
+6. Spin up your local development server.
+
+ ```sh
+ yarn && yarn dev
+ ```
+
+7. Start developing:
+ - Get started with Sigma’s Plugin APIs.
+ - Test your plugin directly in a Sigma workbook using the Sigma Plugin Dev
+ Playground.
+ - By default, vite dev servers run on http://localhost:5173.
+
+NOTE: Facebook's [create-react-app](https://github.com/facebook/create-react-app) is deprecated. You should use [vite](https://github.com/vitejs/vite) to setup your project.
+
+## Testing your Plugin
+
+Plugin developers should have access to a special plugin called Sigma Plugin Dev
+Playground. This plugin is available from any workbook and points to
+http://localhost:3000, by default.
+
+If you cannot find this plugin, or would like a development playground with an
+alternative default host, please contact your Organization Admin with a request
+to Register a Plugin with its production URL set to your preferred development
+URL.
+
+### Using the Development Playground
+
+Before you start:
+
+- Set your plugin’s development URL to http://localhost:3000.
+- Start your plugin locally
+
+ > Note: If you followed our recommendations under
+ > [#create-a-development-project](#create-a-development-project), enter the
+ > following command in your terminal:
+ >
+ > ```sh
+ > yarn && yarn dev
+ > ```
+
+1. Create/open a workbook.
+2. In the workbook header, click Edit.
+3. Click the + button in the sidebar, to open the workbook’s ADD NEW panel.
+4. Select the PLUGINS element type, located under UI ELEMENTS.
+5. The editor panel will show you a list of available plugins. Select Sigma
+ Plugin Dev Playground.
+6. Your new plugin element will appear on the page.
+
+> **Note:**
+> The editor panel will only display content if you have configured your plugin
+> using Sigma’s plugin [Configuration API](#documentation).
+> Likewise, the element will only display content if your plugin is configured to display content.
+> If you change a plugin's configuration options, input values will need to be
+> re-added in the editor panel.
+
+**Now what?**
+
+- You can refresh your plugin as you make changes to its code. This option is
+ available from the element’s menu.
+- You are responsible for hosting your plugin. [Learn more](#host-your-plugin).
+- When you’re ready to register your plugin, [Add your custom your
+ Plugin](https://help.sigmacomputing.com/hc/en-us/articles/4410105794963) with
+ Sigma.
+
+## Documentation
+
+#### CustomPluginConfigOptions
+
+A plugin can be configured with any number of configuration fields. Each field
+type has its own configuration options. Each field type is also guaranteed to
+have the following options:
+
+- `name : string` - the name of the field
+- `type : string` - the field type
+- `label : string (optional)` - a display name for the field
+
+
+Full CustomPluginConfigOptions Type
+
+```ts
+type CustomPluginConfigOptions =
+ | {
+ type: 'group';
+ name: string;
+ label?: string;
+ }
+ | {
+ type: 'element';
+ name: string;
+ label?: string;
+ }
+ | {
+ type: 'column';
+ name: string;
+ label?: string;
+ allowedTypes?: ValueType[];
+ source: string;
+ allowMultiple: boolean;
+ }
+ | {
+ type: 'text';
+ name: string;
+ label?: string;
+ source?: string; // can point to a group or element config
+ secure?: boolean; // if true will omit from prehydrated configs
+ multiline?: boolean;
+ placeholder?: string;
+ defaultValue?: string;
+ }
+ | {
+ type: 'toggle';
+ name: string;
+ label?: string;
+ source?: string;
+ defaultValue?: boolean;
+ }
+ | {
+ type: 'checkbox';
+ name: string;
+ label?: string;
+ source?: string;
+ defaultValue?: boolean;
+ }
+ | {
+ type: 'radio';
+ name: string;
+ label?: string;
+ source?: string;
+ values: string[];
+ singleLine?: boolean;
+ defaultValue?: string;
+ }
+ | {
+ type: 'dropdown';
+ name: string;
+ label?: string;
+ source?: string;
+ width?: string;
+ values: string[];
+ defaultValue?: string;
+ }
+ | {
+ type: 'color';
+ name: string;
+ label?: string;
+ source?: string;
+ }
+ | {
+ type: 'variable';
+ name: string;
+ label?: string;
+ allowedTypes?: ControlType[];
+ }
+ | {
+ type: 'interaction';
+ name: string;
+ label?: string;
+ }
+ | {
+ type: 'action-trigger';
+ name: string;
+ label?: string;
+ }
+ | {
+ type: 'action-effect';
+ name: string;
+ label?: string;
+ }
+ | {
+ type: 'url-parameter';
+ name: string;
+ };
+```
+
+
+
+**Group**
+
+Can be used to identify a group of related fields
+
+**Element**
+
+A custom element that is added by your plugin
+
+**Column**
+
+A custom column configuration that your plugin uses
+
+Additional Fields
+
+- `allowedTypes : ValueType[] (optional)` - the allowed data types that this
+ column can contain where `ValueType` has the following type:
+
+ ```ts
+ type ValueType =
+ | 'boolean'
+ | 'datetime'
+ | 'number'
+ | 'integer'
+ | 'text'
+ | 'variant'
+ | 'link'
+ | 'error';
+ ```
+
+- `source : string` - the data source that should be used to supply this field
+- `allowMultiple : boolean` - whether multiple columns should be allowed as
+ input for this field
+
+**Text**
+
+A configurable text input for your plugin
+
+Additional Fields
+
+- `source : string (optional)` - the data source that should be used to supply this field
+- `secure : boolean (optional)` - whether to omit input from pre-hydrated configs
+- `multiline : boolean (optional)` - whether this text input should allow
+ multiple lines
+- `placeholder : string (optional)` - the placeholder for this input field
+- `defaultValue : string (optional)` - the default value for this input field
+
+**Toggle**
+
+A configurable toggle for your plugin
+
+Additional Fields
+
+- `source : string (optional)` - the data source that should be used to supply this field
+- `defaultValue : boolean (optional)` - the default value for this input field
+
+**Checkbox**
+
+A configurable checkbox for your plugin
+
+Additional Fields
+
+- `source : string (optional)` - the data source that should be used to supply this field
+- `defaultValue : boolean (optional)` - the default value for this input field
+
+**Radio**
+
+A configurable radio button for your plugin
+
+Additional Fields
+
+- `source : string (optional)` - the data source that should be used to supply
+ this field
+- `values : string[]` - the options to show for this input field
+- `singleLine : boolean (optional)` - whether to display options on a single
+ line. Good for (2-3) options
+- `defaultValue : boolean (optional)` - the default value for this input field
+
+**Dropdown**
+
+A configurable dropdown for your plugin
+
+Additional Fields
+
+- `source : string (optional)` - the data source that should be used to supply
+ this field
+- `values : string[]` - the options to show for this input field
+- `width : string (optional)` - how wide the dropdown should be in pixels
+- `defaultValue : boolean (optional)` - the default value for this input field
+
+**Color**
+
+A configurable color picker for your plugin
+
+Additional Fields
+
+- `source : string (optional)` - the data source that should be used to supply
+ this field
+
+**Variable**
+
+A configurable workbook variable to control other elements within your workbook
+
+Additional Fields
+
+- `allowedTypes : ControlType[] (optional)` - the allowed control types that this
+ variable can use where `ControlType` has the following type:
+
+ ```ts
+ type ControlType =
+ | 'boolean'
+ | 'date'
+ | 'number'
+ | 'text'
+ | 'text-list'
+ | 'number-list'
+ | 'date-list'
+ | 'number-range'
+ | 'date-range';
+ ```
+
+**Interaction**
+
+A configurable workbook interaction to interact with other charts within your workbook
+
+**Action Trigger**
+
+A configurable action trigger to trigger actions in other elements within your workbook
+
+**Action Effect**
+
+A configurable action effect that can be triggered by other elements within your workbook
+
+**URL Parameter**
+
+A configurable URL parameter that can be read from and written to the browser's URL. This allows plugins to sync state with the URL for bookmarking and sharing.
+
+Additional Fields
+
+- `name : string` - The config ID used to access this URL parameter via the API
+
+#### PluginInstance
+
+```ts
+interface PluginInstance {
+ sigmaEnv: 'author' | 'viewer' | 'explorer';
+
+ config: {
+ /**
+ * Getter for entire Plugin Config
+ */
+ get(): Partial | undefined;
+
+ /**
+ * Performs a shallow merge between current config and passed in config
+ */
+ set(config: Partial): void;
+
+ /**
+ * Getter for key within plugin config
+ */
+ getKey(key: K): Pick;
+
+ /**
+ * Assigns key value pair within plugin
+ */
+ setKey(key: K, value: Pick): void;
+
+ /**
+ * Subscriber for Plugin Config
+ */
+ subscribe(listener: (arg0: T) => void): Unsubscriber;
+
+ /**
+ * Set possible options for plugin config
+ */
+ configureEditorPanel(options: CustomPluginConfigOptions[]): void;
+
+ /**
+ * Gets a static image of a workbook variable
+ */
+ getVariable(configId: string): WorkbookVariable;
+
+ /**
+ * Setter for workbook variable passed in
+ */
+ setVariable(configId: string, ...values: unknown[]): void;
+
+ /**
+ * Getter for interaction selection state
+ */
+ getInteraction(configId: string): WorkbookSelection[];
+
+ /**
+ * Setter for interaction selection state
+ */
+ setInteraction(
+ configId: string,
+ elementId: string,
+ selection: WorkbookSelection[],
+ ): void;
+
+ /**
+ * Triggers an action based on the provided action trigger ID
+ */
+ triggerAction(configId: string): void;
+
+ /**
+ * Registers an effect with the provided action effect ID
+ */
+ registerEffect(configId: string, effect: Function): void;
+
+ /**
+ * Overrider function for Config loading state
+ */
+ setLoadingState(isLoading: boolean): void;
+
+ /**
+ * Allows users to subscribe to changes in the passed in variable
+ */
+ subscribeToWorkbookVariable(
+ configId: string,
+ callback: (input: WorkbookVariable) => void,
+ ): Unsubscriber;
+
+ /**
+ * Allows users to subscribe to changes in the url parameter
+ */
+ subscribeToUrlParameter(
+ configId: string,
+ callback: (input: UrlParameter) => void,
+ ): Unsubscriber;
+
+ /**
+ * Gets the current value of a url parameter
+ */
+ getUrlParameter(configId: string): UrlParameter;
+
+ /**
+ * Setter for url parameter
+ */
+ setUrlParameter(configId: string, value: string): void;
+
+ /**
+ * @deprecated Use Action API instead
+ * Allows users to subscribe to changes in the passed in interaction ID
+ */
+ subscribeToWorkbookInteraction(
+ configId: string,
+ callback: (input: WorkbookSelection[]) => void,
+ ): Unsubscriber;
+ };
+
+ elements: {
+ /**
+ * Getter for Column Data by parent sheet ID
+ */
+ getElementColumns(configId: string): Promise;
+
+ /**
+ * Subscriber to changes in column data by ID
+ */
+ subscribeToElementColumns(
+ configId: string,
+ callback: (cols: WbElementColumns) => void,
+ ): Unsubscriber;
+
+ /**
+ * Subscriber for the data within a given sheet
+ */
+ subscribeToElementData(
+ configId: string,
+ callback: (data: WbElementData) => void,
+ ): Unsubscriber;
+ };
+
+ style: {
+ /**
+ * Subscribe to workbook style updates
+ */
+ subscribe(callback: (style: PluginStyle) => void): () => void;
+
+ /**
+ * Request current style from workbook
+ */
+ get(): Promise;
+ };
+
+ /**
+ * Destroys plugin instance and removes all subscribers
+ */
+ destroy(): void;
+}
+```
+
+### Framework Agnostic API
+
+#### client
+
+The client is a pre-initialized plugin instance. You can use this instance
+directly or create your own instance using `initialize`
+
+```ts
+const client: PluginInstance = initialize();
+```
+
+Usage
+
+```ts
+import { client } from '@sigmacomputing/plugin';
+
+client.config.configureEditorPanel([
+ { name: 'source', type: 'element' },
+ { name: 'dimension', type: 'column', source: 'source', allowMultiple: true },
+]);
+```
+
+#### initialize()
+
+Instead of using the pre-initialized plugin instance, you can create your own
+plugin instance.
+
+```ts
+function initialize(): PluginInstance;
+```
+
+Usage
+
+```ts
+import { initialize } from '@sigmacomputing/plugin';
+
+const myClient: PluginInstance = initialize();
+
+myClient.config.configureEditorPanel([
+ { name: 'source', type: 'element' },
+ { name: 'dimension', type: 'column', source: 'source', allowMultiple: true },
+]);
+```
+
+### React API
+
+####
+
+A context provider your plugin that enables all of the other React API hooks.
+You should wrap your plugin with this provider if your want to use the plugin
+hook API.
+
+```ts
+interface SigmaClientProviderProps {
+ client: PluginInstance;
+ children?: ReactNode;
+}
+
+function SigmaClientProvider(props: SigmaClientProviderProps): ReactNode;
+```
+
+#### usePlugin()
+
+Gets the entire plugin instance
+
+```ts
+function usePlugin(): PluginInstance;
+```
+
+#### useEditorPanelConfig()
+
+Provides a setter for the plugin's configuration options
+
+```ts
+function useEditorPanelConfig(nextOptions: CustomPluginConfigOptions[]): void;
+```
+
+Provides a setter for the Plugin's Config Options
+
+Arguments
+
+- `nextOptions : CustomPluginConfigOptions[]` - Updated possible Config Options
+
+#### useLoadingState()
+
+Gets the current plugin's loading state and a setter. Call the setter with
+`false` when your plugin has finished loading
+
+```ts
+function useLoadingState(
+ initialState: boolean,
+): [boolean, (nextState: boolean) => void];
+```
+
+Arguments
+
+- `initialState : boolean` - Initial loading state (typically `true`; then set to `false` when ready)
+
+#### useElementColumns()
+
+Provides the latest column values from corresponding sheet
+
+```ts
+function useElementColumns(elementId: string): WorkbookElementColumns;
+```
+
+Arguments
+
+- `elementId : string` - A workbook element’s unique identifier.
+
+Returns the column information from the specified element.
+
+```ts
+interface WorkbookElementColumn {
+ id: string;
+ name: string;
+ columnType: ValueType;
+}
+
+interface WorkbookElementColumns {
+ [colId: string]: WbElementColumn;
+}
+```
+
+#### useElementData()
+
+Provides the latest data values from corresponding sheet, up to 25000 values.
+
+```ts
+function useElementData(configId: string): WorkbookElementData;
+```
+
+Arguments
+
+- `configId : string` - A workbook element’s unique identifier from the plugin config.
+
+Returns the row data from the specified element.
+
+```ts
+interface WorkbookElementData {
+ [colId: string]: any[];
+}
+```
+
+#### usePaginatedElementData()
+
+Provides the latest data values from the corresponding sheet (initially 25000), and provides a
+callback for fetching more data in chunks of 25000 values.
+
+```ts
+function useElementData(configId: string): [WorkbookElementData, () => void];
+```
+
+Arguments
+
+- `configId : string` - A workbook element’s unique identifier from the plugin config.
+
+Returns the row data from the specified element, and a callback for fetching
+more data.
+
+```ts
+interface WorkbookElementData {
+ [colId: string]: any[];
+}
+```
+
+#### useVariable()
+
+Returns a given variable's value and a setter to update that variable
+
+```ts
+function useVariable(
+ configId: string,
+): [WorkbookVariable | undefined, (...values: unknown[]) => void];
+```
+
+Arguments
+
+- `configId : string` - The config ID corresponding to the workbook control variable
+
+The returned setter function accepts 1 or more variable values expressed as an
+array or multiple parameters
+
+```ts
+function setVariableCallback(...values: unknown[]): void;
+```
+
+#### useUrlParameter()
+
+Returns a given URL parameter's value and a setter to update that URL parameter
+
+```ts
+function useUrlParameter(
+ configId: string,
+): [UrlParameter | undefined, (value: string) => void];
+```
+
+Arguments
+
+- `configId : string` - The config ID corresponding to the URL parameter
+
+The returned setter function accepts a string value that will be set as the URL parameter value
+
+```ts
+function setUrlParameterCallback(value: string): void;
+```
+
+The URL parameter value has the following structure:
+
+```ts
+interface UrlParameter {
+ value: string;
+}
+```
+
+Example
+
+```ts
+const [urlParam, setUrlParam] = useUrlParameter('myParamId');
+
+// Read the current value
+console.log(urlParam?.value); // e.g., "current-value"
+
+// Update the URL parameter
+setUrlParam('new-value');
+```
+
+Framework Agnostic Usage
+
+You can also use the URL parameter API without React hooks:
+
+```ts
+import { initialize } from '@sigmacomputing/plugin';
+
+const client = initialize();
+
+// Get current value
+const urlParam = client.config.getUrlParameter('myParamId');
+console.log(urlParam?.value);
+
+// Set a new value
+client.config.setUrlParameter('myParamId', 'new-value');
+
+// Subscribe to changes
+const unsubscribe = client.config.subscribeToUrlParameter(
+ 'myParamId',
+ urlParam => {
+ console.log('URL parameter updated:', urlParam.value);
+ },
+);
+```
+
+#### useInteraction()
+
+Returns a given interaction's selection state and a setter to update that interaction
+
+```ts
+function useInteraction(
+ configId: string,
+ elementId: string,
+): [WorkbookSelection | undefined, (value: WorkbookSelection[]) => void];
+```
+
+Arguments
+
+- `configId : string` - The config ID corresponding to the workbook interaction
+- `elementId : string` - The ID of the element that this interaction is
+ associated with
+
+The returned setter function accepts an array of workbook selection elements
+
+```ts
+function setVariableCallback(value: WorkbookSelection[]): void;
+```
+
+#### useActionTrigger()
+
+- `configId : string` - The config ID corresponding to the action trigger
+
+Returns a callback function to trigger one or more action effects for a given action trigger
+
+```ts
+function useActionTrigger(configId: string): () => void;
+```
+
+#### useActionEffect()
+
+Registers and unregisters an action effect within the plugin
+
+```ts
+function useActionEffect(configId: string, effect: () => void);
+```
+
+Arguments
+
+- `configId : string` - The config ID corresponding to the action effect
+- `effect : Function` - The function to be called when the effect is triggered
+
+#### usePluginStyle()
+
+Returns style properties from the workbook.
+
+```ts
+function usePluginStyle(): PluginStyle | undefined;
+```
+
+> **Note:** Currently, the `PluginStyle` interface only supports the `backgroundColor` property, which reflects the background color set in the workbook for the plugin element.
+
+#### useConfig()
+
+Returns the workbook element’s current configuration. If a key is provided, only
+the associated configuration is returned.
+
+```ts
+function useConfig(key?: string): any;
+```
+
+Arguments
+
+- `key : string (optional)` - The name of a key within the associated
+ `PluginConfigOptions` object
+
+## Examples
+
+Sigma’s development team has created a set of example plugins, listed below.
+
+All of our example plugins are hosted and can be added to your organization. To
+view / add an example plugin to your organization, follow the steps to register
+a plugin using its Production URL, listed below.
+
+You can also visit Sigma’s [Sample Plugin
+repository](https://github.com/sigmacomputing/sigma-sample-plugins) directly on
+Github.
+
+### Available Plugins
+
+- **Recharts Bar Chart** - A basic bar chart built with the Recharts library.
+ - [Source Code](https://github.com/sigmacomputing/sigma-sample-plugins/tree/main/sample-plugin-bar-chart)
+ - Production URL: https://sigma-sample-bar-chart-54049.netlify.app/
+
+- **D3 Candlestick** - A candlestick visualization built with D3.
+ - [Source Code](https://github.com/sigmacomputing/sigma-sample-plugins/tree/main/sample-plugin-bar-chart)
+ - Production URL: https://sigma-sample-candlestick-chart-1664e5.netlify.app/
+
+- **Narrative Science Quill** - Demonstrates secure text entry.
+ - [Source Code]()
+ - Production URL: https://narrativescience-quill-3ee312.netlify.app/
+
+- **D3 Graph** - Demonstrates usage of multiple data sources and in-memory
+ joins.
+ - [Source Code](https://github.com/sigmacomputing/sigma-sample-plugins/tree/main/d3-graph)
+ - Production URL: https://d3-graph-3a0d0f.netlify.app/
+
+- **D3 Sunburst** - A sunburst visualization built with D3.
+ - [Source Code](https://github.com/sigmacomputing/sigma-sample-plugins/tree/main/d3-sunburst)
+ - Production URL: https://d3-sunburst-b97c7c.netlify.app/
+
+- **Frappe Heatmap** - A basic Frappe visualization example.
+ - [Source Code](https://github.com/sigmacomputing/sigma-sample-plugins/tree/main/frappe-heatmap)
+ - Production URL: https://frappe-heatmap-9a4163.netlify.app/
+
+### Use an Example in Your Organization
+
+To add an example plugin to your organization, follow the steps to [register a
+plugin](https://help.sigmacomputing.com/hc/en-us/articles/4410105794963) using
+its Production URL, listed in the [examples](#available-plugins) above.
+
+### Run an Example Locally
+
+1. Open your terminal, and navigate to the directory you want to save the example’s in.
+2. Clone Sigma’s [Sample Plugin
+ repository](https://github.com/sigmacomputing/sigma-sample-plugins).
+
+ ```sh
+ git clone https://github.com/sigmacomputing/sigma-sample-plugins.git
+ ```
+
+3. Navigate to the plugin you would like to try.
+
+ ```sh
+ cd sigma-sample-plugins/
+ ```
+
+4. Run the plugin.
+
+ ```sh
+ yarn && yarn start
+ ```
+
+> **Note**: For additional instructions, visit the README file located in the main directory of any given example plugin.
+
+## Host Your Plugin
+
+As a plugin developer, you are responsible for hosting your plugin(s). If you’re
+new to hosting your own projects, here are a few popular hosting platforms you
+can get started with:
+
+- [Heroku](https://devcenter.heroku.com/)
+- [Netlify](https://www.netlify.com/)
+
+## Contributing
+
+We welcome contributions to `@sigmacomputing/plugin`!
+
+🐛 Issues, 📥 Pull requests and 🌟 Stars are always welcome.
+Read our [contributing
+guide](https://github.com/sigmacomputing/plugin/blob/main/CONTRIBUTING.md) to
+get started.
+
+**yarn format**
+
+Format your code to match the sigmacomputing style guide
+
+**yarn test**
+
+Check if the unit tests all pass
+
+> You can also run the tests in `--watch` mode with **yarn test:watch**
diff --git a/packages/plugin-sdk/package.json b/packages/plugin-sdk/package.json
new file mode 100644
index 0000000..a65e23f
--- /dev/null
+++ b/packages/plugin-sdk/package.json
@@ -0,0 +1,56 @@
+{
+ "name": "@sigmacomputing/plugin",
+ "version": "1.1.1",
+ "description": "Sigma Computing Plugin Client SDK",
+ "license": "MIT",
+ "type": "module",
+ "scripts": {
+ "build": "tsdown",
+ "build:watch": "tsdown --watch",
+ "format": "yarn g:format",
+ "lint": "yarn g:lint",
+ "prepublish": "yarn types && yarn build",
+ "publish": "yarn npm publish",
+ "test": "vitest run",
+ "test:watch": "vitest",
+ "types": "tsc -b --noEmit"
+ },
+ "peerDependencies": {
+ "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
+ },
+ "peerDependenciesMeta": {
+ "react": {
+ "optional": true
+ }
+ },
+ "devDependencies": {
+ "tsdown": "^0.21.10",
+ "vitest": "^4.1.5"
+ },
+ "main": "./dist/cjs/index.cjs",
+ "module": "./dist/esm/index.js",
+ "types": "./dist/cjs/index.d.cts",
+ "unpkg": "./dist/umd/sigmacomputing-plugin.umd.js",
+ "jsdelivr": "./dist/umd/sigmacomputing-plugin.umd.js",
+ "exports": {
+ ".": {
+ "import": {
+ "types": "./dist/esm/index.d.ts",
+ "default": "./dist/esm/index.js"
+ },
+ "require": {
+ "types": "./dist/cjs/index.d.cts",
+ "default": "./dist/cjs/index.cjs"
+ }
+ },
+ "./package.json": "./package.json"
+ },
+ "files": [
+ "dist/**/*",
+ "src/**/*",
+ "!src/**/__tests__/**/*"
+ ],
+ "publishConfig": {
+ "access": "public"
+ }
+}
diff --git a/src/client.ts b/packages/plugin-sdk/src/client.ts
similarity index 100%
rename from src/client.ts
rename to packages/plugin-sdk/src/client.ts
diff --git a/src/client/__tests__/initialize.test.ts b/packages/plugin-sdk/src/client/__tests__/initialize.test.ts
similarity index 100%
rename from src/client/__tests__/initialize.test.ts
rename to packages/plugin-sdk/src/client/__tests__/initialize.test.ts
diff --git a/src/client/initialize.ts b/packages/plugin-sdk/src/client/initialize.ts
similarity index 99%
rename from src/client/initialize.ts
rename to packages/plugin-sdk/src/client/initialize.ts
index b84e478..8a93187 100644
--- a/src/client/initialize.ts
+++ b/packages/plugin-sdk/src/client/initialize.ts
@@ -28,7 +28,7 @@ export function initialize(): PluginInstance {
try {
pluginConfig[key] = JSON.parse(value);
} catch (_err: unknown) {
- if (__VITEST_BROWSER__ && (key === 'frameId' || key === 'sessionId')) {
+ if (__VITEST_BROWSER__ && (key === 'iframeId' || key === 'sessionId')) {
// noop: vitest browser injects these into the test iframe URL
} else {
console.error(
diff --git a/src/error.ts b/packages/plugin-sdk/src/error.ts
similarity index 67%
rename from src/error.ts
rename to packages/plugin-sdk/src/error.ts
index e737dc6..801a871 100644
--- a/src/error.ts
+++ b/packages/plugin-sdk/src/error.ts
@@ -1,10 +1,10 @@
import { CustomPluginConfigOptions } from './types';
export function validateConfigId(
- configId: string,
+ configId: string | undefined,
expectedConfigType: CustomPluginConfigOptions['type'],
) {
if (configId === undefined) {
- console.warn(`Invalid config ${expectedConfigType}: ${configId}`);
+ console.warn(`Invalid config ${expectedConfigType}`);
}
}
diff --git a/src/globals.d.ts b/packages/plugin-sdk/src/globals.d.ts
similarity index 100%
rename from src/globals.d.ts
rename to packages/plugin-sdk/src/globals.d.ts
diff --git a/src/index.ts b/packages/plugin-sdk/src/index.ts
similarity index 100%
rename from src/index.ts
rename to packages/plugin-sdk/src/index.ts
diff --git a/src/react.ts b/packages/plugin-sdk/src/react.ts
similarity index 100%
rename from src/react.ts
rename to packages/plugin-sdk/src/react.ts
diff --git a/src/react/Context.ts b/packages/plugin-sdk/src/react/Context.ts
similarity index 100%
rename from src/react/Context.ts
rename to packages/plugin-sdk/src/react/Context.ts
diff --git a/src/react/Provider.tsx b/packages/plugin-sdk/src/react/Provider.tsx
similarity index 100%
rename from src/react/Provider.tsx
rename to packages/plugin-sdk/src/react/Provider.tsx
diff --git a/src/react/hooks.ts b/packages/plugin-sdk/src/react/hooks.ts
similarity index 100%
rename from src/react/hooks.ts
rename to packages/plugin-sdk/src/react/hooks.ts
diff --git a/src/types.ts b/packages/plugin-sdk/src/types.ts
similarity index 100%
rename from src/types.ts
rename to packages/plugin-sdk/src/types.ts
diff --git a/src/utils/deepEqual.ts b/packages/plugin-sdk/src/utils/deepEqual.ts
similarity index 100%
rename from src/utils/deepEqual.ts
rename to packages/plugin-sdk/src/utils/deepEqual.ts
diff --git a/src/utils/polyfillRequestAnimationFrame.ts b/packages/plugin-sdk/src/utils/polyfillRequestAnimationFrame.ts
similarity index 100%
rename from src/utils/polyfillRequestAnimationFrame.ts
rename to packages/plugin-sdk/src/utils/polyfillRequestAnimationFrame.ts
diff --git a/packages/plugin-sdk/tsconfig.app.json b/packages/plugin-sdk/tsconfig.app.json
new file mode 100644
index 0000000..2ed40b8
--- /dev/null
+++ b/packages/plugin-sdk/tsconfig.app.json
@@ -0,0 +1,7 @@
+{
+ "extends": "../../tsconfig.app.json",
+ "compilerOptions": {
+ "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo"
+ },
+ "include": ["src"]
+}
diff --git a/packages/plugin-sdk/tsconfig.json b/packages/plugin-sdk/tsconfig.json
new file mode 100644
index 0000000..da3c747
--- /dev/null
+++ b/packages/plugin-sdk/tsconfig.json
@@ -0,0 +1,10 @@
+{
+ "compilerOptions": {
+ "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.tsbuildinfo"
+ },
+ "files": [],
+ "references": [
+ { "path": "./tsconfig.app.json" },
+ { "path": "./tsconfig.node.json" }
+ ]
+}
diff --git a/packages/plugin-sdk/tsconfig.node.json b/packages/plugin-sdk/tsconfig.node.json
new file mode 100644
index 0000000..42f7286
--- /dev/null
+++ b/packages/plugin-sdk/tsconfig.node.json
@@ -0,0 +1,7 @@
+{
+ "extends": "../../tsconfig.node.json",
+ "compilerOptions": {
+ "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo"
+ },
+ "include": ["tsdown.config.ts", "vitest.config.ts"]
+}
diff --git a/packages/plugin-sdk/tsdown.config.ts b/packages/plugin-sdk/tsdown.config.ts
new file mode 100644
index 0000000..fdb5930
--- /dev/null
+++ b/packages/plugin-sdk/tsdown.config.ts
@@ -0,0 +1,15 @@
+import { defineConfig, mergeConfig } from 'tsdown';
+
+// @ts-ignore - base config is defined outside of this package
+import baseConfig from '../../tsdown.base.ts';
+
+import packageJson from './package.json' with { type: 'json' };
+
+export default mergeConfig(
+ baseConfig,
+ defineConfig({
+ define: {
+ __VERSION__: JSON.stringify(packageJson.version),
+ },
+ }),
+);
diff --git a/packages/plugin-sdk/vitest.config.ts b/packages/plugin-sdk/vitest.config.ts
new file mode 100644
index 0000000..c3e1107
--- /dev/null
+++ b/packages/plugin-sdk/vitest.config.ts
@@ -0,0 +1,15 @@
+import { defineConfig, mergeConfig } from 'vitest/config';
+
+// @ts-ignore - base config is defined outside of this package
+import baseConfig from '../../vitest.base.ts';
+
+import packageJson from './package.json' with { type: 'json' };
+
+export default mergeConfig(
+ baseConfig,
+ defineConfig({
+ define: {
+ __VERSION__: JSON.stringify(packageJson.version),
+ },
+ }),
+);
diff --git a/tsconfig.app.json b/tsconfig.app.json
new file mode 100644
index 0000000..15eb924
--- /dev/null
+++ b/tsconfig.app.json
@@ -0,0 +1,11 @@
+{
+ "extends": "./tsconfig.base.json",
+ "compilerOptions": {
+ "composite": true,
+ "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
+
+ "lib": ["DOM", "ESNext"],
+ "jsx": "react",
+ "types": ["vitest/globals"]
+ }
+}
diff --git a/tsconfig.base.json b/tsconfig.base.json
new file mode 100644
index 0000000..0e42b90
--- /dev/null
+++ b/tsconfig.base.json
@@ -0,0 +1,18 @@
+{
+ "compilerOptions": {
+ "lib": ["ESNext"],
+
+ "module": "ESNext",
+ "moduleResolution": "bundler",
+ "target": "ESNext",
+
+ "noImplicitAny": true,
+ "strict": true,
+
+ "allowSyntheticDefaultImports": true,
+ "esModuleInterop": true,
+ "skipLibCheck": true,
+
+ "forceConsistentCasingInFileNames": true
+ }
+}
diff --git a/tsconfig.json b/tsconfig.json
index 250fae3..e485c7a 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -1,20 +1,13 @@
{
+ "extends": "./tsconfig.node.json",
"compilerOptions": {
- "lib": ["DOM", "ESNext"],
-
- "module": "ESNext",
- "moduleResolution": "bundler",
- "target": "ESNext",
-
- "jsx": "react",
- "noImplicitAny": true,
- "strict": true,
-
- "allowSyntheticDefaultImports": true,
- "esModuleInterop": true,
- "forceConsistentCasingInFileNames": true,
- "skipLibCheck": true,
- "types": ["vitest/globals"]
+ "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.tsbuildinfo"
},
- "include": ["src", "vitest.config.ts", "tsdown.config.ts"]
+ "include": [
+ ".github/**/*.ts",
+ ".lintstagedrc.ts",
+ "scripts/**/*.ts",
+ "tsdown.base.ts",
+ "vitest.base.ts"
+ ]
}
diff --git a/tsconfig.node.json b/tsconfig.node.json
new file mode 100644
index 0000000..6ee1402
--- /dev/null
+++ b/tsconfig.node.json
@@ -0,0 +1,9 @@
+{
+ "extends": "./tsconfig.base.json",
+ "compilerOptions": {
+ "composite": true,
+ "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
+
+ "types": ["node"]
+ }
+}
diff --git a/tsdown.config.ts b/tsdown.base.ts
similarity index 89%
rename from tsdown.config.ts
rename to tsdown.base.ts
index 6eea879..d0d941e 100644
--- a/tsdown.config.ts
+++ b/tsdown.base.ts
@@ -7,7 +7,9 @@ export default defineConfig({
failOnWarn: true,
logLevel: 'warn',
- dts: true,
+ dts: {
+ build: true,
+ },
entry: ['src/index.ts'],
format: {
esm: {
@@ -32,6 +34,11 @@ export default defineConfig({
},
},
},
+ inputOptions: {
+ transform: {
+ jsx: 'react',
+ },
+ },
platform: 'browser',
sourcemap: true,
diff --git a/turbo.json b/turbo.json
new file mode 100644
index 0000000..26cf168
--- /dev/null
+++ b/turbo.json
@@ -0,0 +1,43 @@
+{
+ "$schema": "https://v2-9-7.turborepo.dev/schema.json",
+ "noUpdateNotifier": true,
+ "tasks": {
+ "build": {
+ "dependsOn": ["^build"],
+ "outputLogs": "new-only",
+ "inputs": [
+ "src/**",
+ "tsconfig.json",
+ "tsdown.config.ts",
+ "$TURBO_ROOT$/tsdown.base.ts",
+ "$TURBO_ROOT$/yarn.lock"
+ ],
+ "outputs": ["dist/**"]
+ },
+ "test": {
+ "dependsOn": ["^build", "^test"],
+ "outputLogs": "new-only",
+ "inputs": [
+ "src/**",
+ "vitest.config.ts",
+ "$TURBO_ROOT$/vitest.base.ts",
+ "$TURBO_ROOT$/yarn.lock"
+ ]
+ },
+ "types": {
+ "dependsOn": ["^build", "^types"],
+ "outputLogs": "new-only",
+ "inputs": [
+ "src/**",
+ "tsconfig.json",
+ "tsconfig.app.json",
+ "$TURBO_ROOT$/tsconfig.base.json",
+ "$TURBO_ROOT$/tsconfig.app.json",
+ "$TURBO_ROOT$/yarn.lock"
+ ]
+ }
+ },
+ "futureFlags": {
+ "watchUsingTaskInputs": true
+ }
+}
diff --git a/vitest.config.ts b/vitest.base.ts
similarity index 77%
rename from vitest.config.ts
rename to vitest.base.ts
index d090783..b211dbc 100644
--- a/vitest.config.ts
+++ b/vitest.base.ts
@@ -1,11 +1,8 @@
import { playwright } from '@vitest/browser-playwright';
import { defineConfig } from 'vitest/config';
-import packageJson from './package.json' with { type: 'json' };
-
export default defineConfig({
define: {
- __VERSION__: JSON.stringify(packageJson.version),
__VITEST_BROWSER__: true.toString(),
},
test: {
diff --git a/yarn.lock b/yarn.lock
index 4b38e28..62a6350 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -709,9 +709,9 @@ __metadata:
languageName: node
linkType: hard
-"@sigmacomputing/plugin@workspace:.":
+"@sigmacomputing/plugin-sdk-root@workspace:.":
version: 0.0.0-use.local
- resolution: "@sigmacomputing/plugin@workspace:."
+ resolution: "@sigmacomputing/plugin-sdk-root@workspace:."
dependencies:
"@arethetypeswrong/core": "npm:^0.18.2"
"@types/node": "npm:^24.0.0"
@@ -723,10 +723,21 @@ __metadata:
oxlint-tsgolint: "npm:^0.16.0"
playwright: "npm:^1.49.0"
publint: "npm:^0.3.18"
+ syncpack: "npm:^14.3.1"
tsdown: "npm:^0.21.10"
+ turbo: "npm:^2.9.7"
typescript: "npm:^6.0.2"
unplugin-unused: "npm:^0.5.7"
vitest: "npm:^4.1.5"
+ languageName: unknown
+ linkType: soft
+
+"@sigmacomputing/plugin@workspace:packages/plugin-sdk":
+ version: 0.0.0-use.local
+ resolution: "@sigmacomputing/plugin@workspace:packages/plugin-sdk"
+ dependencies:
+ tsdown: "npm:^0.21.10"
+ vitest: "npm:^4.1.5"
peerDependencies:
react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
peerDependenciesMeta:
@@ -742,6 +753,48 @@ __metadata:
languageName: node
linkType: hard
+"@turbo/darwin-64@npm:2.9.7":
+ version: 2.9.7
+ resolution: "@turbo/darwin-64@npm:2.9.7"
+ conditions: os=darwin & cpu=x64
+ languageName: node
+ linkType: hard
+
+"@turbo/darwin-arm64@npm:2.9.7":
+ version: 2.9.7
+ resolution: "@turbo/darwin-arm64@npm:2.9.7"
+ conditions: os=darwin & cpu=arm64
+ languageName: node
+ linkType: hard
+
+"@turbo/linux-64@npm:2.9.7":
+ version: 2.9.7
+ resolution: "@turbo/linux-64@npm:2.9.7"
+ conditions: os=linux & cpu=x64
+ languageName: node
+ linkType: hard
+
+"@turbo/linux-arm64@npm:2.9.7":
+ version: 2.9.7
+ resolution: "@turbo/linux-arm64@npm:2.9.7"
+ conditions: os=linux & cpu=arm64
+ languageName: node
+ linkType: hard
+
+"@turbo/windows-64@npm:2.9.7":
+ version: 2.9.7
+ resolution: "@turbo/windows-64@npm:2.9.7"
+ conditions: os=win32 & cpu=x64
+ languageName: node
+ linkType: hard
+
+"@turbo/windows-arm64@npm:2.9.7":
+ version: 2.9.7
+ resolution: "@turbo/windows-arm64@npm:2.9.7"
+ conditions: os=win32 & cpu=arm64
+ languageName: node
+ linkType: hard
+
"@tybys/wasm-util@npm:^0.10.1":
version: 0.10.1
resolution: "@tybys/wasm-util@npm:0.10.1"
@@ -2661,6 +2714,97 @@ __metadata:
languageName: node
linkType: hard
+"syncpack-darwin-arm64@npm:14.3.1":
+ version: 14.3.1
+ resolution: "syncpack-darwin-arm64@npm:14.3.1"
+ conditions: os=darwin & cpu=arm64
+ languageName: node
+ linkType: hard
+
+"syncpack-darwin-x64@npm:14.3.1":
+ version: 14.3.1
+ resolution: "syncpack-darwin-x64@npm:14.3.1"
+ conditions: os=darwin & cpu=x64
+ languageName: node
+ linkType: hard
+
+"syncpack-linux-arm64-musl@npm:14.3.1":
+ version: 14.3.1
+ resolution: "syncpack-linux-arm64-musl@npm:14.3.1"
+ conditions: os=linux & cpu=arm64
+ languageName: node
+ linkType: hard
+
+"syncpack-linux-arm64@npm:14.3.1":
+ version: 14.3.1
+ resolution: "syncpack-linux-arm64@npm:14.3.1"
+ conditions: os=linux & cpu=arm64
+ languageName: node
+ linkType: hard
+
+"syncpack-linux-x64-musl@npm:14.3.1":
+ version: 14.3.1
+ resolution: "syncpack-linux-x64-musl@npm:14.3.1"
+ conditions: os=linux & cpu=x64
+ languageName: node
+ linkType: hard
+
+"syncpack-linux-x64@npm:14.3.1":
+ version: 14.3.1
+ resolution: "syncpack-linux-x64@npm:14.3.1"
+ conditions: os=linux & cpu=x64
+ languageName: node
+ linkType: hard
+
+"syncpack-windows-arm64@npm:14.3.1":
+ version: 14.3.1
+ resolution: "syncpack-windows-arm64@npm:14.3.1"
+ conditions: os=win32 & cpu=arm64
+ languageName: node
+ linkType: hard
+
+"syncpack-windows-x64@npm:14.3.1":
+ version: 14.3.1
+ resolution: "syncpack-windows-x64@npm:14.3.1"
+ conditions: os=win32 & cpu=x64
+ languageName: node
+ linkType: hard
+
+"syncpack@npm:^14.3.1":
+ version: 14.3.1
+ resolution: "syncpack@npm:14.3.1"
+ dependencies:
+ syncpack-darwin-arm64: "npm:14.3.1"
+ syncpack-darwin-x64: "npm:14.3.1"
+ syncpack-linux-arm64: "npm:14.3.1"
+ syncpack-linux-arm64-musl: "npm:14.3.1"
+ syncpack-linux-x64: "npm:14.3.1"
+ syncpack-linux-x64-musl: "npm:14.3.1"
+ syncpack-windows-arm64: "npm:14.3.1"
+ syncpack-windows-x64: "npm:14.3.1"
+ dependenciesMeta:
+ syncpack-darwin-arm64:
+ optional: true
+ syncpack-darwin-x64:
+ optional: true
+ syncpack-linux-arm64:
+ optional: true
+ syncpack-linux-arm64-musl:
+ optional: true
+ syncpack-linux-x64:
+ optional: true
+ syncpack-linux-x64-musl:
+ optional: true
+ syncpack-windows-arm64:
+ optional: true
+ syncpack-windows-x64:
+ optional: true
+ bin:
+ syncpack: index.cjs
+ checksum: 10c0/c3b0d87cc6df19053069b049805e704abc2ac2c344eff27f810a8c36d79eee2603f0aa88c5fc2c2651f2c30d5c879475c73c630a463460e0b75e941d241b482d
+ languageName: node
+ linkType: hard
+
"tar@npm:^6.1.11, tar@npm:^6.2.1":
version: 6.2.1
resolution: "tar@npm:6.2.1"
@@ -2785,6 +2929,35 @@ __metadata:
languageName: node
linkType: hard
+"turbo@npm:^2.9.7":
+ version: 2.9.7
+ resolution: "turbo@npm:2.9.7"
+ dependencies:
+ "@turbo/darwin-64": "npm:2.9.7"
+ "@turbo/darwin-arm64": "npm:2.9.7"
+ "@turbo/linux-64": "npm:2.9.7"
+ "@turbo/linux-arm64": "npm:2.9.7"
+ "@turbo/windows-64": "npm:2.9.7"
+ "@turbo/windows-arm64": "npm:2.9.7"
+ dependenciesMeta:
+ "@turbo/darwin-64":
+ optional: true
+ "@turbo/darwin-arm64":
+ optional: true
+ "@turbo/linux-64":
+ optional: true
+ "@turbo/linux-arm64":
+ optional: true
+ "@turbo/windows-64":
+ optional: true
+ "@turbo/windows-arm64":
+ optional: true
+ bin:
+ turbo: bin/turbo
+ checksum: 10c0/5fa010810ce251279dac83db02e60ebd8014cf8e74e69a6c09751ae28aef0fdb95aa09b059ce8c987a1746dd5b04bb3002bd7fdcb6d0016d8690f079fec43921
+ languageName: node
+ linkType: hard
+
"typescript@npm:5.6.1-rc":
version: 5.6.1-rc
resolution: "typescript@npm:5.6.1-rc"