altair-graphql-core 7.2.1 → 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) {
@@ -9,7 +9,7 @@ class ScriptEvaluatorClientEngine {
9
9
  this.timeout = timeout;
10
10
  }
11
11
  async getClient() {
12
- const client = this.client ?? this.engineFactory.create();
12
+ const client = this.client ?? (await this.engineFactory.create());
13
13
  this.client = client;
14
14
  return client;
15
15
  }
@@ -119,7 +119,7 @@ export interface ScriptWorkerMessageData {
119
119
  payload: any;
120
120
  }
121
121
  export interface ScriptEvaluatorClientFactory {
122
- create: () => ScriptEvaluatorClient;
122
+ create: () => Promise<ScriptEvaluatorClient>;
123
123
  }
124
124
  export declare abstract class ScriptEvaluatorClient {
125
125
  abstract subscribe<T extends ScriptEvent>(type: T, handler: (type: T, e: ScriptEventData<T>) => void): void;
@@ -128,6 +128,26 @@ export interface SettingsState {
128
128
  * Enable the scrollbar in the tab list
129
129
  */
130
130
  enableTablistScrollbar?: boolean;
131
+ /**
132
+ * Whether to include descriptions in the introspection result
133
+ */
134
+ 'introspection.options.description'?: boolean;
135
+ /**
136
+ * Whether to include `specifiedByUrl` in the introspection result
137
+ */
138
+ 'introspection.options.specifiedByUrl'?: boolean;
139
+ /**
140
+ * Whether to include `isRepeatable` flag on directives
141
+ */
142
+ 'introspection.options.directiveIsRepeatable'?: boolean;
143
+ /**
144
+ * Whether to include `description` field on schema
145
+ */
146
+ 'introspection.options.schemaDescription'?: boolean;
147
+ /**
148
+ * Whether target GraphQL server supports deprecation of input values
149
+ */
150
+ 'introspection.options.inputValueDeprecation'?: boolean;
131
151
  }
132
152
  export {};
133
153
  //# sourceMappingURL=settings.interfaces.d.ts.map
@@ -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
@@ -296,6 +296,26 @@
296
296
  "description": "Number of items allowed in history pane",
297
297
  "type": "number"
298
298
  },
299
+ "introspection.options.description": {
300
+ "description": "Whether to include descriptions in the introspection result",
301
+ "type": "boolean"
302
+ },
303
+ "introspection.options.directiveIsRepeatable": {
304
+ "description": "Whether to include `isRepeatable` flag on directives",
305
+ "type": "boolean"
306
+ },
307
+ "introspection.options.inputValueDeprecation": {
308
+ "description": "Whether target GraphQL server supports deprecation of input values",
309
+ "type": "boolean"
310
+ },
311
+ "introspection.options.schemaDescription": {
312
+ "description": "Whether to include `description` field on schema",
313
+ "type": "boolean"
314
+ },
315
+ "introspection.options.specifiedByUrl": {
316
+ "description": "Whether to include `specifiedByUrl` in the introspection result",
317
+ "type": "boolean"
318
+ },
299
319
  "language": {
300
320
  "$ref": "#/definitions/SettingsLanguage",
301
321
  "description": "Specifies the language"
@@ -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) {
@@ -6,7 +6,7 @@ export class ScriptEvaluatorClientEngine {
6
6
  this.timeout = timeout;
7
7
  }
8
8
  async getClient() {
9
- const client = this.client ?? this.engineFactory.create();
9
+ const client = this.client ?? (await this.engineFactory.create());
10
10
  this.client = client;
11
11
  return client;
12
12
  }
@@ -119,7 +119,7 @@ export interface ScriptWorkerMessageData {
119
119
  payload: any;
120
120
  }
121
121
  export interface ScriptEvaluatorClientFactory {
122
- create: () => ScriptEvaluatorClient;
122
+ create: () => Promise<ScriptEvaluatorClient>;
123
123
  }
124
124
  export declare abstract class ScriptEvaluatorClient {
125
125
  abstract subscribe<T extends ScriptEvent>(type: T, handler: (type: T, e: ScriptEventData<T>) => void): void;
@@ -296,6 +296,26 @@
296
296
  "description": "Number of items allowed in history pane",
297
297
  "type": "number"
298
298
  },
299
+ "introspection.options.description": {
300
+ "description": "Whether to include descriptions in the introspection result",
301
+ "type": "boolean"
302
+ },
303
+ "introspection.options.directiveIsRepeatable": {
304
+ "description": "Whether to include `isRepeatable` flag on directives",
305
+ "type": "boolean"
306
+ },
307
+ "introspection.options.inputValueDeprecation": {
308
+ "description": "Whether target GraphQL server supports deprecation of input values",
309
+ "type": "boolean"
310
+ },
311
+ "introspection.options.schemaDescription": {
312
+ "description": "Whether to include `description` field on schema",
313
+ "type": "boolean"
314
+ },
315
+ "introspection.options.specifiedByUrl": {
316
+ "description": "Whether to include `specifiedByUrl` in the introspection result",
317
+ "type": "boolean"
318
+ },
299
319
  "language": {
300
320
  "$ref": "#/definitions/SettingsLanguage",
301
321
  "description": "Specifies the language"
@@ -128,6 +128,26 @@ export interface SettingsState {
128
128
  * Enable the scrollbar in the tab list
129
129
  */
130
130
  enableTablistScrollbar?: boolean;
131
+ /**
132
+ * Whether to include descriptions in the introspection result
133
+ */
134
+ 'introspection.options.description'?: boolean;
135
+ /**
136
+ * Whether to include `specifiedByUrl` in the introspection result
137
+ */
138
+ 'introspection.options.specifiedByUrl'?: boolean;
139
+ /**
140
+ * Whether to include `isRepeatable` flag on directives
141
+ */
142
+ 'introspection.options.directiveIsRepeatable'?: boolean;
143
+ /**
144
+ * Whether to include `description` field on schema
145
+ */
146
+ 'introspection.options.schemaDescription'?: boolean;
147
+ /**
148
+ * Whether target GraphQL server supports deprecation of input values
149
+ */
150
+ 'introspection.options.inputValueDeprecation'?: boolean;
131
151
  }
132
152
  export {};
133
153
  //# sourceMappingURL=settings.interfaces.d.ts.map
@@ -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