altair-graphql-core 7.2.2 → 7.2.3

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.
@@ -4,10 +4,22 @@ export declare const instanceTypes: {
4
4
  readonly PANEL: "panel";
5
5
  };
6
6
  export type InstanceType = (typeof instanceTypes)[keyof typeof instanceTypes];
7
- export interface FrameQueryParams {
7
+ export interface FrameOptions {
8
+ /**
9
+ * Source origin of the parent window
10
+ */
8
11
  sc: string;
12
+ /**
13
+ * Plugin ID
14
+ */
9
15
  id: string;
16
+ /**
17
+ * Instance type of the plugin
18
+ */
10
19
  instanceType: InstanceType;
20
+ /**
21
+ * Additional parameters
22
+ */
11
23
  [key: string]: string;
12
24
  }
13
25
  export declare class PluginFrameWorker extends EvaluatorWorker {
@@ -17,7 +29,7 @@ export declare class PluginFrameWorker extends EvaluatorWorker {
17
29
  private params;
18
30
  constructor();
19
31
  getInstanceType(): InstanceType;
20
- getParams(): FrameQueryParams;
32
+ getParams(): FrameOptions;
21
33
  onMessage<T extends string, P = unknown>(handler: (e: EventData<T, P>) => void): void;
22
34
  send(type: string, payload: any): void;
23
35
  onError(handler: (err: any) => void): void;
@@ -10,10 +10,13 @@ class PluginFrameWorker extends worker_1.EvaluatorWorker {
10
10
  constructor() {
11
11
  super();
12
12
  this.instanceType = exports.instanceTypes.MAIN;
13
- const params = Object.fromEntries(new URLSearchParams(window.location.search));
13
+ // Check for params in special params object on the window object first. Using srcdoc, we will set the params on the window object
14
+ const paramFromWindow = window.__ALTAIR_PLUGIN_PARAMS__;
15
+ const paramsFromUrl = Object.fromEntries(new URLSearchParams(window.location.search));
16
+ const params = paramFromWindow ?? paramsFromUrl;
14
17
  this.params = params;
15
- // Get the source origin that embeds the iframe from the URL query parameter
16
18
  if (!params.sc) {
19
+ console.log('Invalid source provided!', paramFromWindow, paramsFromUrl);
17
20
  throw new Error('Invalid source provided!');
18
21
  }
19
22
  if (!params.id) {
@@ -38,7 +41,7 @@ class PluginFrameWorker extends worker_1.EvaluatorWorker {
38
41
  });
39
42
  }
40
43
  send(type, payload) {
41
- window.parent.postMessage({ type, payload }, this.origin);
44
+ window.parent.postMessage({ type, payload, frameId: this.id }, this.origin);
42
45
  }
43
46
  onError(handler) {
44
47
  window.addEventListener('error', handler);
@@ -1,8 +1,14 @@
1
1
  import { PluginCapabilities } from './capabilities';
2
- interface PluginEntry {
2
+ interface PluginHtmlEntry {
3
3
  type: 'html';
4
4
  path: string;
5
5
  }
6
+ interface PluginJsEntry {
7
+ type: 'js';
8
+ scripts: string[];
9
+ styles: string[];
10
+ }
11
+ type PluginEntry = PluginHtmlEntry | PluginJsEntry;
6
12
  export interface PluginV3Manifest {
7
13
  /**
8
14
  * Version of manifest (should be 3). It is a control measure for variations in the plugin versions
@@ -1,13 +1,23 @@
1
1
  import { EvaluatorWorker, EventData } from '../../evaluator/worker';
2
2
  import { InstanceType } from './frame-worker';
3
- export interface PluginParentWorkerOptions {
3
+ interface BasePluginParentWorkerOptions {
4
4
  id: string;
5
- pluginEntrypointUrl: string;
6
5
  disableAppend?: boolean;
7
6
  instanceType?: InstanceType;
8
7
  additionalParams?: Record<string, string>;
9
8
  additionalSandboxAttributes?: string[];
10
9
  }
10
+ interface PluginParentWorkerOptionsWithScripts extends BasePluginParentWorkerOptions {
11
+ type: 'scripts';
12
+ sandboxUrl: string;
13
+ scriptUrls: string[];
14
+ styleUrls: string[];
15
+ }
16
+ interface PluginParentWorkerOptionsWithUrl extends BasePluginParentWorkerOptions {
17
+ type: 'url';
18
+ pluginEntrypointUrl: string;
19
+ }
20
+ export type PluginParentWorkerOptions = PluginParentWorkerOptionsWithScripts | PluginParentWorkerOptionsWithUrl;
11
21
  export declare class PluginParentWorker extends EvaluatorWorker {
12
22
  private opts;
13
23
  constructor(opts: PluginParentWorkerOptions);
@@ -22,4 +32,5 @@ export declare class PluginParentWorker extends EvaluatorWorker {
22
32
  onError(handler: (err: unknown) => void): void;
23
33
  destroy(): void;
24
34
  }
35
+ export {};
25
36
  //# sourceMappingURL=parent-worker.d.ts.map
@@ -32,16 +32,26 @@ class PluginParentWorker extends worker_1.EvaluatorWorker {
32
32
  id: this.opts.id,
33
33
  instanceType: this.getInstanceType(),
34
34
  };
35
- const url = (0, url_1.urlWithParams)(this.opts.pluginEntrypointUrl, params);
36
- iframe.src = url;
35
+ // NOTE: Don't add allow-same-origin to the sandbox attribute!
37
36
  iframe.sandbox.add('allow-scripts');
38
- iframe.sandbox.add('allow-same-origin');
39
37
  if (this.opts.additionalSandboxAttributes) {
40
38
  this.opts.additionalSandboxAttributes.forEach((attr) => {
41
39
  iframe.sandbox.add(attr);
42
40
  });
43
41
  }
44
42
  iframe.referrerPolicy = 'no-referrer';
43
+ if (this.opts.type === 'scripts') {
44
+ const url = (0, url_1.urlWithParams)(this.opts.sandboxUrl, {
45
+ ...params,
46
+ sandbox_type: 'plugin',
47
+ plugin_sandbox_opts: JSON.stringify(this.opts),
48
+ });
49
+ iframe.src = url;
50
+ }
51
+ else if (this.opts.type === 'url') {
52
+ const url = (0, url_1.urlWithParams)(this.opts.pluginEntrypointUrl, params);
53
+ iframe.src = url;
54
+ }
45
55
  if (!this.opts.disableAppend) {
46
56
  document.body.appendChild(iframe);
47
57
  }
@@ -58,7 +68,11 @@ class PluginParentWorker extends worker_1.EvaluatorWorker {
58
68
  }
59
69
  onMessage(handler) {
60
70
  window.addEventListener('message', (e) => {
61
- if (e.origin !== new URL(this.opts.pluginEntrypointUrl).origin) {
71
+ if (e.origin !== 'null' || e.source !== this.iframe.contentWindow) {
72
+ return;
73
+ }
74
+ if (e.data.frameId !== this.opts.id) {
75
+ console.error('Invalid frameId in data', e.data.frameId, this.opts.id);
62
76
  return;
63
77
  }
64
78
  handler(e.data);
@@ -66,7 +80,13 @@ class PluginParentWorker extends worker_1.EvaluatorWorker {
66
80
  }
67
81
  send(type, payload) {
68
82
  this.frameReady().then(() => {
69
- this.iframe.contentWindow?.postMessage({ type, payload }, this.opts.pluginEntrypointUrl);
83
+ this.iframe.contentWindow?.postMessage({ type, payload },
84
+ // https://web.dev/articles/sandboxed-iframes#safely_sandboxing_eval
85
+ // Note that we're sending the message to "*", rather than some specific
86
+ // origin. Sandboxed iframes which lack the 'allow-same-origin' header
87
+ // don't have an origin which you can target: you'll have to send to any
88
+ // origin, which might alow some esoteric attacks. Validate your output!
89
+ '*');
70
90
  });
71
91
  }
72
92
  onError(handler) {
@@ -0,0 +1,3 @@
1
+ export declare const injectScript: (url: string) => Promise<unknown>;
2
+ export declare const injectStylesheet: (url: string) => Promise<unknown>;
3
+ //# sourceMappingURL=inject.d.ts.map
@@ -0,0 +1,35 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.injectStylesheet = exports.injectScript = void 0;
4
+ const injectScript = (url) => {
5
+ return new Promise((resolve, reject) => {
6
+ const head = document.getElementsByTagName('head')[0];
7
+ if (!head) {
8
+ return reject(new Error('No head found!'));
9
+ }
10
+ const script = document.createElement('script');
11
+ script.type = 'text/javascript';
12
+ script.src = url;
13
+ script.onload = () => resolve(null);
14
+ script.onerror = (err) => reject(err);
15
+ head.appendChild(script);
16
+ });
17
+ };
18
+ exports.injectScript = injectScript;
19
+ const injectStylesheet = (url) => {
20
+ return new Promise((resolve, reject) => {
21
+ const head = document.getElementsByTagName('head')[0];
22
+ if (!head) {
23
+ return reject(new Error('No head found!'));
24
+ }
25
+ const style = document.createElement('link');
26
+ style.type = 'text/css';
27
+ style.rel = 'stylesheet';
28
+ style.href = url;
29
+ style.onload = () => resolve(null);
30
+ style.onerror = (err) => reject(err);
31
+ head.appendChild(style);
32
+ });
33
+ };
34
+ exports.injectStylesheet = injectStylesheet;
35
+ //# sourceMappingURL=inject.js.map
@@ -4,10 +4,22 @@ export declare const instanceTypes: {
4
4
  readonly PANEL: "panel";
5
5
  };
6
6
  export type InstanceType = (typeof instanceTypes)[keyof typeof instanceTypes];
7
- export interface FrameQueryParams {
7
+ export interface FrameOptions {
8
+ /**
9
+ * Source origin of the parent window
10
+ */
8
11
  sc: string;
12
+ /**
13
+ * Plugin ID
14
+ */
9
15
  id: string;
16
+ /**
17
+ * Instance type of the plugin
18
+ */
10
19
  instanceType: InstanceType;
20
+ /**
21
+ * Additional parameters
22
+ */
11
23
  [key: string]: string;
12
24
  }
13
25
  export declare class PluginFrameWorker extends EvaluatorWorker {
@@ -17,7 +29,7 @@ export declare class PluginFrameWorker extends EvaluatorWorker {
17
29
  private params;
18
30
  constructor();
19
31
  getInstanceType(): InstanceType;
20
- getParams(): FrameQueryParams;
32
+ getParams(): FrameOptions;
21
33
  onMessage<T extends string, P = unknown>(handler: (e: EventData<T, P>) => void): void;
22
34
  send(type: string, payload: any): void;
23
35
  onError(handler: (err: any) => void): void;
@@ -7,10 +7,13 @@ export class PluginFrameWorker extends EvaluatorWorker {
7
7
  constructor() {
8
8
  super();
9
9
  this.instanceType = instanceTypes.MAIN;
10
- const params = Object.fromEntries(new URLSearchParams(window.location.search));
10
+ // Check for params in special params object on the window object first. Using srcdoc, we will set the params on the window object
11
+ const paramFromWindow = window.__ALTAIR_PLUGIN_PARAMS__;
12
+ const paramsFromUrl = Object.fromEntries(new URLSearchParams(window.location.search));
13
+ const params = paramFromWindow ?? paramsFromUrl;
11
14
  this.params = params;
12
- // Get the source origin that embeds the iframe from the URL query parameter
13
15
  if (!params.sc) {
16
+ console.log('Invalid source provided!', paramFromWindow, paramsFromUrl);
14
17
  throw new Error('Invalid source provided!');
15
18
  }
16
19
  if (!params.id) {
@@ -35,7 +38,7 @@ export class PluginFrameWorker extends EvaluatorWorker {
35
38
  });
36
39
  }
37
40
  send(type, payload) {
38
- window.parent.postMessage({ type, payload }, this.origin);
41
+ window.parent.postMessage({ type, payload, frameId: this.id }, this.origin);
39
42
  }
40
43
  onError(handler) {
41
44
  window.addEventListener('error', handler);
@@ -1,8 +1,14 @@
1
1
  import { PluginCapabilities } from './capabilities';
2
- interface PluginEntry {
2
+ interface PluginHtmlEntry {
3
3
  type: 'html';
4
4
  path: string;
5
5
  }
6
+ interface PluginJsEntry {
7
+ type: 'js';
8
+ scripts: string[];
9
+ styles: string[];
10
+ }
11
+ type PluginEntry = PluginHtmlEntry | PluginJsEntry;
6
12
  export interface PluginV3Manifest {
7
13
  /**
8
14
  * Version of manifest (should be 3). It is a control measure for variations in the plugin versions
@@ -1,13 +1,23 @@
1
1
  import { EvaluatorWorker, EventData } from '../../evaluator/worker';
2
2
  import { InstanceType } from './frame-worker';
3
- export interface PluginParentWorkerOptions {
3
+ interface BasePluginParentWorkerOptions {
4
4
  id: string;
5
- pluginEntrypointUrl: string;
6
5
  disableAppend?: boolean;
7
6
  instanceType?: InstanceType;
8
7
  additionalParams?: Record<string, string>;
9
8
  additionalSandboxAttributes?: string[];
10
9
  }
10
+ interface PluginParentWorkerOptionsWithScripts extends BasePluginParentWorkerOptions {
11
+ type: 'scripts';
12
+ sandboxUrl: string;
13
+ scriptUrls: string[];
14
+ styleUrls: string[];
15
+ }
16
+ interface PluginParentWorkerOptionsWithUrl extends BasePluginParentWorkerOptions {
17
+ type: 'url';
18
+ pluginEntrypointUrl: string;
19
+ }
20
+ export type PluginParentWorkerOptions = PluginParentWorkerOptionsWithScripts | PluginParentWorkerOptionsWithUrl;
11
21
  export declare class PluginParentWorker extends EvaluatorWorker {
12
22
  private opts;
13
23
  constructor(opts: PluginParentWorkerOptions);
@@ -22,4 +32,5 @@ export declare class PluginParentWorker extends EvaluatorWorker {
22
32
  onError(handler: (err: unknown) => void): void;
23
33
  destroy(): void;
24
34
  }
35
+ export {};
25
36
  //# sourceMappingURL=parent-worker.d.ts.map
@@ -29,16 +29,26 @@ export class PluginParentWorker extends EvaluatorWorker {
29
29
  id: this.opts.id,
30
30
  instanceType: this.getInstanceType(),
31
31
  };
32
- const url = urlWithParams(this.opts.pluginEntrypointUrl, params);
33
- iframe.src = url;
32
+ // NOTE: Don't add allow-same-origin to the sandbox attribute!
34
33
  iframe.sandbox.add('allow-scripts');
35
- iframe.sandbox.add('allow-same-origin');
36
34
  if (this.opts.additionalSandboxAttributes) {
37
35
  this.opts.additionalSandboxAttributes.forEach((attr) => {
38
36
  iframe.sandbox.add(attr);
39
37
  });
40
38
  }
41
39
  iframe.referrerPolicy = 'no-referrer';
40
+ if (this.opts.type === 'scripts') {
41
+ const url = urlWithParams(this.opts.sandboxUrl, {
42
+ ...params,
43
+ sandbox_type: 'plugin',
44
+ plugin_sandbox_opts: JSON.stringify(this.opts),
45
+ });
46
+ iframe.src = url;
47
+ }
48
+ else if (this.opts.type === 'url') {
49
+ const url = urlWithParams(this.opts.pluginEntrypointUrl, params);
50
+ iframe.src = url;
51
+ }
42
52
  if (!this.opts.disableAppend) {
43
53
  document.body.appendChild(iframe);
44
54
  }
@@ -55,7 +65,11 @@ export class PluginParentWorker extends EvaluatorWorker {
55
65
  }
56
66
  onMessage(handler) {
57
67
  window.addEventListener('message', (e) => {
58
- if (e.origin !== new URL(this.opts.pluginEntrypointUrl).origin) {
68
+ if (e.origin !== 'null' || e.source !== this.iframe.contentWindow) {
69
+ return;
70
+ }
71
+ if (e.data.frameId !== this.opts.id) {
72
+ console.error('Invalid frameId in data', e.data.frameId, this.opts.id);
59
73
  return;
60
74
  }
61
75
  handler(e.data);
@@ -63,7 +77,13 @@ export class PluginParentWorker extends EvaluatorWorker {
63
77
  }
64
78
  send(type, payload) {
65
79
  this.frameReady().then(() => {
66
- this.iframe.contentWindow?.postMessage({ type, payload }, this.opts.pluginEntrypointUrl);
80
+ this.iframe.contentWindow?.postMessage({ type, payload },
81
+ // https://web.dev/articles/sandboxed-iframes#safely_sandboxing_eval
82
+ // Note that we're sending the message to "*", rather than some specific
83
+ // origin. Sandboxed iframes which lack the 'allow-same-origin' header
84
+ // don't have an origin which you can target: you'll have to send to any
85
+ // origin, which might alow some esoteric attacks. Validate your output!
86
+ '*');
67
87
  });
68
88
  }
69
89
  onError(handler) {
@@ -0,0 +1,3 @@
1
+ export declare const injectScript: (url: string) => Promise<unknown>;
2
+ export declare const injectStylesheet: (url: string) => Promise<unknown>;
3
+ //# sourceMappingURL=inject.d.ts.map
@@ -0,0 +1,30 @@
1
+ export const injectScript = (url) => {
2
+ return new Promise((resolve, reject) => {
3
+ const head = document.getElementsByTagName('head')[0];
4
+ if (!head) {
5
+ return reject(new Error('No head found!'));
6
+ }
7
+ const script = document.createElement('script');
8
+ script.type = 'text/javascript';
9
+ script.src = url;
10
+ script.onload = () => resolve(null);
11
+ script.onerror = (err) => reject(err);
12
+ head.appendChild(script);
13
+ });
14
+ };
15
+ export const injectStylesheet = (url) => {
16
+ return new Promise((resolve, reject) => {
17
+ const head = document.getElementsByTagName('head')[0];
18
+ if (!head) {
19
+ return reject(new Error('No head found!'));
20
+ }
21
+ const style = document.createElement('link');
22
+ style.type = 'text/css';
23
+ style.rel = 'stylesheet';
24
+ style.href = url;
25
+ style.onload = () => resolve(null);
26
+ style.onerror = (err) => reject(err);
27
+ head.appendChild(style);
28
+ });
29
+ };
30
+ //# sourceMappingURL=inject.js.map
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "altair-graphql-core",
3
3
  "description": "Several of the core logic for altair graphql client",
4
- "version": "7.2.2",
4
+ "version": "7.2.3",
5
5
  "author": "Samuel Imolorhe <altair@sirmuel.design> (https://sirmuel.design)",
6
6
  "bugs": "https://github.com/altair-graphql/altair/issues",
7
7
  "dependencies": {
@@ -76,5 +76,5 @@
76
76
  "test": "jest"
77
77
  },
78
78
  "types": "./build/index.d.ts",
79
- "gitHead": "b4bb105113b498fc8a82fbc3c1e1fc42d9531155"
79
+ "gitHead": "ddd163425d45994df9b5f214f848f597a9c85f81"
80
80
  }