@sigmacomputing/plugin 1.1.0 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,10 +1,11 @@
1
1
  {
2
2
  "name": "@sigmacomputing/plugin",
3
- "version": "1.1.0",
4
- "description": "Sigma Computing Plugin Client API",
3
+ "version": "1.2.0",
4
+ "description": "Sigma Computing Plugin Client SDK",
5
5
  "license": "MIT",
6
6
  "homepage": "https://github.com/sigmacomputing/plugin",
7
- "main": "./dist/index.js",
7
+ "type": "module",
8
+ "packageManager": "yarn@4.13.0",
8
9
  "repository": {
9
10
  "type": "git",
10
11
  "url": "https://github.com/sigmacomputing/plugin.git"
@@ -13,41 +14,76 @@
13
14
  "email": "support@sigmacomputing.com",
14
15
  "url": "https://github.com/sigmacomputing/plugin/issues"
15
16
  },
16
- "packageManager": "yarn@4.4.1",
17
- "files": [
18
- "dist/*"
19
- ],
20
- "typesVersions": {
21
- "*": {
22
- "react": [
23
- "dist/react/index.d.ts"
24
- ]
25
- }
26
- },
27
17
  "scripts": {
28
- "build": "yarn tsc --build tsconfig.build.json",
29
- "build:watch": "yarn build --watch",
30
- "format": "prettier --write 'src/**/*.{ts,tsx}' 'jest.config.ts'",
18
+ "build": "tsdown",
19
+ "build:watch": "tsdown --watch",
20
+ "bump": "tsx scripts/bump-version.ts",
21
+ "format": "yarn oxfmt",
22
+ "lint": "yarn oxlint",
31
23
  "precommit": "lint-staged",
32
- "prepublish": "yarn build",
33
- "test": "jest --ci",
34
- "test:watch": "yarn test --watch"
24
+ "publish": "yarn build && yarn npm publish",
25
+ "test": "vitest run",
26
+ "test:watch": "vitest",
27
+ "types": "tsc --noEmit"
35
28
  },
36
29
  "peerDependencies": {
37
- "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0",
38
- "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
30
+ "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
31
+ },
32
+ "peerDependenciesMeta": {
33
+ "react": {
34
+ "optional": true
35
+ }
39
36
  },
40
37
  "devDependencies": {
41
- "@jest/types": "^27.5.1",
42
- "@types/jest": "^27.5.1",
43
- "@types/node": "^18.7.14",
44
- "@types/react": "^19.0.0",
45
- "@types/react-dom": "^19.0.0",
46
- "jest": "^27.5.1",
47
- "jest-watch-typeahead": "^2.1.1",
48
- "lint-staged": "^13.0.3",
49
- "prettier": "^2.7.1",
50
- "ts-jest": "^27.1.4",
51
- "typescript": "^4.8.2"
38
+ "@actions/core": "^3.0.1",
39
+ "@arethetypeswrong/core": "^0.18.2",
40
+ "@inquirer/prompts": "^8.4.2",
41
+ "@testing-library/dom": "10.4.1",
42
+ "@testing-library/react": "16.3.2",
43
+ "@types/node": "^24.0.0",
44
+ "@types/react": "19.2.14",
45
+ "@types/react-dom": "19.2.3",
46
+ "@types/semver": "^7.7.1",
47
+ "@vitest/browser-playwright": "^4.1.5",
48
+ "lint-staged": "^16.4.0",
49
+ "oxfmt": "^0.38.0",
50
+ "oxlint": "^1.53.0",
51
+ "oxlint-tsgolint": "^0.16.0",
52
+ "playwright": "^1.49.0",
53
+ "publint": "^0.3.18",
54
+ "react": "19.2.5",
55
+ "react-dom": "19.2.5",
56
+ "semver": "^7.7.4",
57
+ "tsdown": "^0.21.10",
58
+ "tsx": "^4.21.0",
59
+ "typescript": "^6.0.2",
60
+ "unplugin-unused": "^0.5.7",
61
+ "vitest": "^4.1.5"
62
+ },
63
+ "main": "./dist/cjs/index.cjs",
64
+ "module": "./dist/esm/index.js",
65
+ "types": "./dist/cjs/index.d.cts",
66
+ "unpkg": "./dist/umd/sigmacomputing-plugin.umd.js",
67
+ "jsdelivr": "./dist/umd/sigmacomputing-plugin.umd.js",
68
+ "exports": {
69
+ ".": {
70
+ "import": {
71
+ "types": "./dist/esm/index.d.ts",
72
+ "default": "./dist/esm/index.js"
73
+ },
74
+ "require": {
75
+ "types": "./dist/cjs/index.d.cts",
76
+ "default": "./dist/cjs/index.cjs"
77
+ }
78
+ },
79
+ "./package.json": "./package.json"
80
+ },
81
+ "files": [
82
+ "dist/**/*",
83
+ "src/**/*",
84
+ "!src/**/__tests__/**/*"
85
+ ],
86
+ "publishConfig": {
87
+ "access": "public"
52
88
  }
53
89
  }
@@ -0,0 +1,280 @@
1
+ import {
2
+ PluginConfig,
3
+ PluginInstance,
4
+ PluginMessageResponse,
5
+ PluginStyle,
6
+ UrlParameter,
7
+ WorkbookSelection,
8
+ WorkbookVariable,
9
+ } from '../types';
10
+ import { validateConfigId } from '../utils/error';
11
+
12
+ export function initialize<T = {}>(): PluginInstance<T> {
13
+ const pluginConfig: Partial<PluginConfig<T>> = {
14
+ config: {} as T,
15
+ };
16
+
17
+ let subscribedInteractions: Record<string, WorkbookSelection[]> = {};
18
+ let subscribedWorkbookVars: Record<string, WorkbookVariable> = {};
19
+ let subscribedUrlParameters: Record<string, UrlParameter> = {};
20
+ const registeredEffects: Record<string, () => void> = {};
21
+
22
+ const listeners: {
23
+ [event: string]: Function[];
24
+ } = {};
25
+
26
+ const location = new URL(document.location.href);
27
+ for (const [key, value] of location.searchParams.entries()) {
28
+ try {
29
+ pluginConfig[key] = JSON.parse(value);
30
+ } catch (_err: unknown) {
31
+ if (__VITEST_BROWSER__ && (key === 'iframeId' || key === 'sessionId')) {
32
+ // noop: vitest browser injects these into the test iframe URL
33
+ } else {
34
+ console.error(
35
+ `Failed to parse URL param ${key} with value ${value} as JSON.`,
36
+ );
37
+ }
38
+ }
39
+ }
40
+
41
+ const listener = (e: PluginMessageResponse) => {
42
+ emit(e.data.type, e.data.result, e.data.error);
43
+ };
44
+
45
+ window.addEventListener('message', listener, false);
46
+ window.addEventListener('click', () => execPromise('wb:plugin:focus'));
47
+
48
+ on('wb:plugin:config:update', (config: PluginConfig<T>) => {
49
+ Object.assign(pluginConfig, config);
50
+ emit('config', pluginConfig.config ?? {});
51
+ });
52
+
53
+ // send initialize event
54
+ void execPromise('wb:plugin:init', __VERSION__).then(config => {
55
+ Object.assign(pluginConfig, config);
56
+ emit('init', pluginConfig);
57
+ emit('config', pluginConfig.config);
58
+ });
59
+
60
+ on(
61
+ 'wb:plugin:variable:update',
62
+ (updatedVariables: Record<string, WorkbookVariable>) => {
63
+ subscribedWorkbookVars = {};
64
+ Object.assign(subscribedWorkbookVars, updatedVariables);
65
+ },
66
+ );
67
+
68
+ on('wb:plugin:selection:update', (updatedInteractions: unknown) => {
69
+ subscribedInteractions = {};
70
+ Object.assign(subscribedInteractions, updatedInteractions);
71
+ });
72
+
73
+ on(
74
+ 'wb:plugin:url-parameter:update',
75
+ (updatedUrlParameters: Record<string, UrlParameter>) => {
76
+ subscribedUrlParameters = {};
77
+ Object.assign(subscribedUrlParameters, updatedUrlParameters);
78
+ },
79
+ );
80
+
81
+ on('wb:plugin:action-effect:invoke', (configId: string) => {
82
+ const effect = registeredEffects[configId];
83
+ if (!effect) {
84
+ throw new Error(`Unknown action effect with name: ${configId}`);
85
+ }
86
+ effect();
87
+ });
88
+
89
+ function on(event: string, listener: Function) {
90
+ listeners[event] = listeners[event] || [];
91
+ listeners[event].push(listener);
92
+ }
93
+
94
+ function off(event: string, listener: Function) {
95
+ if (listeners[event] == null) return;
96
+ listeners[event] = listeners[event].filter(a => a !== listener);
97
+ }
98
+
99
+ function emit(event: string, ...args: any) {
100
+ Object.values(listeners[event] || []).forEach(fn => fn(...args));
101
+ }
102
+
103
+ function execPromise<R>(event: string, ...args: any): Promise<R> {
104
+ return new Promise((resolve, reject) => {
105
+ const callback = (data: R, error: any) => {
106
+ if (error) reject(error);
107
+ else resolve(data);
108
+ off(event, callback);
109
+ };
110
+ on(event, callback);
111
+ window.parent.postMessage(
112
+ { type: event, args, elementId: pluginConfig.id },
113
+ pluginConfig?.wbOrigin ?? '*',
114
+ );
115
+ });
116
+ }
117
+
118
+ return {
119
+ get sigmaEnv() {
120
+ return pluginConfig.sigmaEnv;
121
+ },
122
+
123
+ get isScreenshot() {
124
+ return pluginConfig.screenshot;
125
+ },
126
+
127
+ config: {
128
+ // @ts-ignore TODO: Fix
129
+ getKey(key) {
130
+ return pluginConfig?.config?.[key];
131
+ },
132
+ get() {
133
+ return pluginConfig.config;
134
+ },
135
+ set(partialConfig) {
136
+ void execPromise('wb:plugin:config:update', partialConfig);
137
+ },
138
+ setKey(key, value) {
139
+ void execPromise('wb:plugin:config:update', {
140
+ [key]: value,
141
+ });
142
+ },
143
+ subscribe(listener) {
144
+ on('config', listener);
145
+ return () => off('config', listener);
146
+ },
147
+ getVariable(configId: string) {
148
+ validateConfigId(configId, 'variable');
149
+ return subscribedWorkbookVars[configId];
150
+ },
151
+ setVariable(configId: string, ...values: unknown[]) {
152
+ validateConfigId(configId, 'variable');
153
+ void execPromise('wb:plugin:variable:set', configId, ...values);
154
+ },
155
+ getInteraction(configId: string) {
156
+ validateConfigId(configId, 'interaction');
157
+ return subscribedInteractions[configId];
158
+ },
159
+ setInteraction(
160
+ configId: string,
161
+ elementId: string,
162
+ selection:
163
+ | string[]
164
+ | Array<Record<string, { type: string; val?: unknown }>>,
165
+ ) {
166
+ validateConfigId(configId, 'interaction');
167
+ void execPromise(
168
+ 'wb:plugin:selection:set',
169
+ configId,
170
+ elementId,
171
+ selection,
172
+ );
173
+ },
174
+ triggerAction(configId: string) {
175
+ validateConfigId(configId, 'action-trigger');
176
+ void execPromise('wb:plugin:action-trigger:invoke', configId);
177
+ },
178
+ registerEffect(configId: string, effect: () => void) {
179
+ validateConfigId(configId, 'action-effect');
180
+ registeredEffects[configId] = effect;
181
+ return () => {
182
+ delete registeredEffects[configId];
183
+ };
184
+ },
185
+ configureEditorPanel(options) {
186
+ void execPromise('wb:plugin:config:inspector', options);
187
+ },
188
+ setLoadingState(loadingState) {
189
+ void execPromise('wb:plugin:config:loading-state', loadingState);
190
+ },
191
+ subscribeToWorkbookVariable(configId, callback) {
192
+ validateConfigId(configId, 'variable');
193
+ const setValues = (values: Record<string, WorkbookVariable>) => {
194
+ callback(values[configId]);
195
+ };
196
+ on('wb:plugin:variable:update', setValues);
197
+ return () => {
198
+ off('wb:plugin:variable:update', setValues);
199
+ };
200
+ },
201
+ subscribeToWorkbookInteraction(configId, callback) {
202
+ validateConfigId(configId, 'interaction');
203
+ const setValues = (values: Record<string, WorkbookSelection[]>) => {
204
+ callback(values[configId]);
205
+ };
206
+ on('wb:plugin:selection:update', setValues);
207
+ return () => {
208
+ off('wb:plugin:selection:update', setValues);
209
+ };
210
+ },
211
+ subscribeToUrlParameter(configId, callback) {
212
+ validateConfigId(configId, 'url-parameter');
213
+ const setValues = (values: Record<string, UrlParameter>) => {
214
+ callback(values[configId]);
215
+ };
216
+ setValues(subscribedUrlParameters);
217
+ on('wb:plugin:url-parameter:update', setValues);
218
+ return () => {
219
+ off('wb:plugin:url-parameter:update', setValues);
220
+ };
221
+ },
222
+ getUrlParameter(configId: string) {
223
+ validateConfigId(configId, 'url-parameter');
224
+ return subscribedUrlParameters[configId];
225
+ },
226
+ setUrlParameter(configId: string, value: string) {
227
+ validateConfigId(configId, 'url-parameter');
228
+ void execPromise('wb:plugin:url-parameter:set', configId, value);
229
+ },
230
+ },
231
+ elements: {
232
+ getElementColumns(configId) {
233
+ validateConfigId(configId, 'element');
234
+ return execPromise('wb:plugin:element:columns:get', configId);
235
+ },
236
+ subscribeToElementColumns(configId, callback) {
237
+ validateConfigId(configId, 'element');
238
+ const eventName = `wb:plugin:element:${configId}:columns`;
239
+ on(eventName, callback);
240
+ void execPromise('wb:plugin:element:subscribe:columns', configId);
241
+
242
+ return () => {
243
+ off(eventName, callback);
244
+ void execPromise('wb:plugin:element:unsubscribe:columns', configId);
245
+ };
246
+ },
247
+ subscribeToElementData(configId, callback) {
248
+ validateConfigId(configId, 'element');
249
+ const eventName = `wb:plugin:element:${configId}:data`;
250
+ on(eventName, callback);
251
+ void execPromise('wb:plugin:element:subscribe:data', configId);
252
+
253
+ return () => {
254
+ off(eventName, callback);
255
+ void execPromise('wb:plugin:element:unsubscribe:data', configId);
256
+ };
257
+ },
258
+ fetchMoreElementData(configId) {
259
+ validateConfigId(configId, 'element');
260
+ void execPromise('wb:plugin:element:fetch-more', configId);
261
+ },
262
+ },
263
+
264
+ style: {
265
+ subscribe(callback: (style: PluginStyle) => void) {
266
+ on('wb:plugin:style:update', callback);
267
+ return () => off('wb:plugin:style:update', callback);
268
+ },
269
+
270
+ get() {
271
+ return execPromise('wb:plugin:style:get');
272
+ },
273
+ },
274
+
275
+ destroy() {
276
+ Object.keys(listeners).forEach(event => delete listeners[event]);
277
+ window.removeEventListener('message', listener, false);
278
+ },
279
+ };
280
+ }
package/src/client.ts ADDED
@@ -0,0 +1,3 @@
1
+ import { initialize } from './client/initialize';
2
+
3
+ export const client = initialize();
@@ -0,0 +1,2 @@
1
+ declare const __VERSION__: string;
2
+ declare const __VITEST_BROWSER__: boolean;
@@ -1,5 +1,5 @@
1
1
  export * from './types';
2
2
  export * from './react';
3
3
  export * from './client';
4
+
4
5
  export { polyfillRequestAnimationFrame } from './utils/polyfillRequestAnimationFrame';
5
- //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,6 @@
1
+ import * as React from 'react';
2
+
3
+ import { client } from '../client';
4
+ import { PluginInstance } from '../types';
5
+
6
+ export const PluginContext = React.createContext<PluginInstance>(client);
@@ -0,0 +1,20 @@
1
+ import * as React from 'react';
2
+
3
+ import { PluginInstance } from '../types';
4
+
5
+ import { PluginContext } from './Context';
6
+
7
+ export interface SigmaClientProviderProps<T = any> {
8
+ client: PluginInstance<T>;
9
+ children?: React.ReactNode;
10
+ }
11
+
12
+ export function SigmaClientProvider<T = any>(
13
+ props: SigmaClientProviderProps<T>,
14
+ ) {
15
+ return (
16
+ <PluginContext.Provider value={props.client}>
17
+ {props.children}
18
+ </PluginContext.Provider>
19
+ );
20
+ }