@finos/legend-lego 1.1.70 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Copyright (c) 2020-present, Goldman Sachs
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+ export declare function handleDownloadMessage(event: ExtendableMessageEvent): void;
17
+ //# sourceMappingURL=DownloadHelper.service-worker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DownloadHelper.service-worker.d.ts","sourceRoot":"","sources":["../../src/download-helper/DownloadHelper.service-worker.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAsCH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,sBAAsB,GAAG,IAAI,CAezE"}
@@ -0,0 +1,96 @@
1
+ /**
2
+ * Copyright (c) 2020-present, Goldman Sachs
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+ const TAG_REQUEST = 'download-request';
17
+ const TAG_RESPONSE = 'download-response';
18
+ const STREAM_CLOSED = '#stream-closed';
19
+ const STREAM_ABORTED = '#stream-aborted';
20
+ // will interact from `createWritableStreamFromMessageChannel`
21
+ function createReadableStreamFromMessagePort(port) {
22
+ return new ReadableStream({
23
+ start(controller) {
24
+ port.onmessage = ({ data }) => {
25
+ if (data === STREAM_CLOSED) {
26
+ return controller.close();
27
+ }
28
+ if (data === STREAM_ABORTED) {
29
+ controller.error('aborted');
30
+ return undefined;
31
+ }
32
+ controller.enqueue(data);
33
+ return undefined;
34
+ };
35
+ },
36
+ });
37
+ }
38
+ const entries = new Map();
39
+ export function handleDownloadMessage(event) {
40
+ const data = event.data;
41
+ if (event.data && event.data.tag === TAG_REQUEST) {
42
+ const port = event.ports[0];
43
+ if (port === undefined) {
44
+ throw new Error('Port 1 expected to handle download request');
45
+ }
46
+ const entry = [
47
+ createReadableStreamFromMessagePort(port),
48
+ data,
49
+ port,
50
+ ];
51
+ entries.set(data.url, entry);
52
+ port.postMessage({ tag: TAG_RESPONSE, downloadUrl: data.url });
53
+ }
54
+ }
55
+ function handleDownloadFetch(event) {
56
+ const url = event.request.url;
57
+ const entry = entries.get(url);
58
+ if (entry) {
59
+ entries.delete(url);
60
+ const [stream, data] = entry;
61
+ const { filename } = data;
62
+ const headers = new Headers({
63
+ 'Content-Type': 'application/octet-stream; charset=utf-8',
64
+ 'Content-Disposition': `attachment; filename*=UTF-8''${filename}`,
65
+ 'Content-Security-Policy': "default-src 'none'",
66
+ });
67
+ // TODO: add trace
68
+ // console.log('responding to ffetch', stream);
69
+ event.respondWith(new Response(stream, { headers }));
70
+ }
71
+ }
72
+ function handleInstall(event) {
73
+ // TODO: add trace
74
+ // console.log('service worker install', event);
75
+ event.waitUntil(self.skipWaiting());
76
+ }
77
+ function handleActivate(event) {
78
+ // TODO: add trace
79
+ // console.log('service worker activate', event);
80
+ event.waitUntil(self.clients.claim());
81
+ }
82
+ function handleMessage(event) {
83
+ // TODO: add trace
84
+ // console.log('service worker message', event);
85
+ handleDownloadMessage(event);
86
+ }
87
+ function handleFetch(event) {
88
+ // TODO: add trace
89
+ // console.log('service worker fetch', event);
90
+ handleDownloadFetch(event);
91
+ }
92
+ self.addEventListener('install', handleInstall);
93
+ self.addEventListener('activate', handleActivate);
94
+ self.addEventListener('message', handleMessage);
95
+ self.addEventListener('fetch', handleFetch);
96
+ //# sourceMappingURL=DownloadHelper.service-worker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DownloadHelper.service-worker.js","sourceRoot":"","sources":["../../src/download-helper/DownloadHelper.service-worker.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Copyright (c) 2020-present, Goldman Sachs
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+ export declare function downloadStream(): Promise<void>;
17
+ export declare function registerDownloadHelperServiceWorker(): void;
18
+ //# sourceMappingURL=MockedDownloadHelper.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MockedDownloadHelper.d.ts","sourceRoot":"","sources":["../../../src/download-helper/__test-utils__/MockedDownloadHelper.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,wBAAsB,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC,CAAG;AACxD,wBAAgB,mCAAmC,IAAI,IAAI,CAAG"}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Copyright (c) 2020-present, Goldman Sachs
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+ export async function downloadStream() { }
17
+ export function registerDownloadHelperServiceWorker() { }
18
+ //# sourceMappingURL=MockedDownloadHelper.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MockedDownloadHelper.js","sourceRoot":"","sources":["../../../src/download-helper/__test-utils__/MockedDownloadHelper.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,MAAM,CAAC,KAAK,UAAU,cAAc,KAAmB,CAAC;AACxD,MAAM,UAAU,mCAAmC,KAAU,CAAC"}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Copyright (c) 2020-present, Goldman Sachs
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+ export declare function downloadStream(responseBody: ReadableStream, filename: string): Promise<void>;
17
+ export declare function registerDownloadHelperServiceWorker(): void;
18
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/download-helper/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAqGH,wBAAsB,cAAc,CAClC,YAAY,EAAE,cAAc,EAC5B,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,IAAI,CAAC,CAsBf;AAED,wBAAgB,mCAAmC,IAAI,IAAI,CAa1D"}
@@ -0,0 +1,120 @@
1
+ /**
2
+ * Copyright (c) 2020-present, Goldman Sachs
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+ var DOWNLOAD_EVENTS;
17
+ (function (DOWNLOAD_EVENTS) {
18
+ DOWNLOAD_EVENTS["TAG_REQUEST"] = "download-request";
19
+ DOWNLOAD_EVENTS["TAG_RESPONSE"] = "download-response";
20
+ DOWNLOAD_EVENTS["STREAM_CLOSED"] = "#stream-closed";
21
+ DOWNLOAD_EVENTS["STREAM_ABORTED"] = "#stream-aborted";
22
+ })(DOWNLOAD_EVENTS || (DOWNLOAD_EVENTS = {}));
23
+ function createWritableStreamFromMessageChannel(channel) {
24
+ return new WritableStream({
25
+ write(chunk) {
26
+ channel.port1.postMessage(chunk);
27
+ },
28
+ close() {
29
+ channel.port1.postMessage(DOWNLOAD_EVENTS.STREAM_CLOSED);
30
+ },
31
+ abort() {
32
+ channel.port1.postMessage(DOWNLOAD_EVENTS.STREAM_ABORTED);
33
+ closeMessagePort(channel.port1);
34
+ closeMessagePort(channel.port2);
35
+ },
36
+ });
37
+ }
38
+ function closeMessagePort(port) {
39
+ port.onmessage = null;
40
+ port.close();
41
+ }
42
+ async function getServiceWorker() {
43
+ if (!('serviceWorker' in navigator)) {
44
+ return Promise.reject(new Error('Service worker is not available. Service Worker requires HTTPS protocol'));
45
+ }
46
+ return navigator.serviceWorker
47
+ .getRegistration()
48
+ .then((workerRegistration) => {
49
+ if (workerRegistration === undefined) {
50
+ return undefined;
51
+ }
52
+ const pending = workerRegistration.installing ?? workerRegistration.waiting;
53
+ return (workerRegistration.active ??
54
+ new Promise((resolve) => {
55
+ // if not activated, add listener to waiting or installing registration
56
+ const listener = () => {
57
+ if (pending?.state === 'activated') {
58
+ pending.removeEventListener('statechange', listener);
59
+ resolve(workerRegistration.active ?? undefined);
60
+ }
61
+ };
62
+ pending?.addEventListener('statechange', listener);
63
+ }));
64
+ });
65
+ }
66
+ function createDownloadRequest(filename) {
67
+ const PREFIX = 6;
68
+ const prefix = String(Math.random()).slice(-PREFIX);
69
+ const url = new URL(`${prefix}/${filename}`, window.location.href).toString();
70
+ return { tag: DOWNLOAD_EVENTS.TAG_REQUEST, filename, url };
71
+ }
72
+ function handleServiceWorkerDownloadResponse(event) {
73
+ const data = event.data;
74
+ if (data?.tag === DOWNLOAD_EVENTS.TAG_RESPONSE && data.downloadUrl.length) {
75
+ openInIframe(data.downloadUrl);
76
+ }
77
+ }
78
+ function openInIframe(src) {
79
+ const iframe = document.createElement('iframe');
80
+ iframe.hidden = true;
81
+ iframe.src = src;
82
+ document.body.appendChild(iframe);
83
+ return iframe;
84
+ }
85
+ export async function downloadStream(responseBody, filename) {
86
+ // creates communication channel with service worker with response handler
87
+ const channel = new MessageChannel();
88
+ channel.port1.onmessage = handleServiceWorkerDownloadResponse;
89
+ // grabs service worker and handles it download along with response channel port
90
+ const serviceWorker = await getServiceWorker();
91
+ if (!serviceWorker) {
92
+ return;
93
+ }
94
+ const downloadRequest = createDownloadRequest(filename);
95
+ serviceWorker.postMessage(downloadRequest, [channel.port2]);
96
+ // creates new data stream over communication channel and pipes given stream in it
97
+ responseBody
98
+ .pipeTo(createWritableStreamFromMessageChannel(channel))
99
+ .then(() => {
100
+ // TODO: trace success
101
+ })
102
+ .catch(() => {
103
+ // TODO: fail
104
+ });
105
+ }
106
+ export function registerDownloadHelperServiceWorker() {
107
+ if ('serviceWorker' in navigator) {
108
+ navigator.serviceWorker
109
+ .register(new URL('./DownloadHelper.service-worker.js', import.meta.url))
110
+ .then((reg) => {
111
+ // TODO: add trace
112
+ // console.debug('register service worker success', reg);
113
+ })
114
+ .catch((error) => {
115
+ // TODO: add trace
116
+ // console.debug('register service worker error', error);
117
+ });
118
+ }
119
+ }
120
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/download-helper/index.ts"],"names":[],"mappings":"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"}
package/lib/index.css CHANGED
@@ -1,4 +1,4 @@
1
- /** @license @finos/legend-lego v1.1.70
1
+ /** @license @finos/legend-lego v1.2.0
2
2
  * Copyright (c) 2020-present, Goldman Sachs
3
3
  *
4
4
  * Licensed under the Apache License, Version 2.0 (the "License");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@finos/legend-lego",
3
- "version": "1.1.70",
3
+ "version": "1.2.0",
4
4
  "description": "Legend shared advanced application components and building blocks",
5
5
  "keywords": [
6
6
  "legend",
@@ -26,6 +26,8 @@
26
26
  "./code-editor/test/MockedMonacoEditor.js": "./lib/code-editor/__test-utils__/MockedMonacoEditor.js",
27
27
  "./data-grid": "./lib/data-grid/index.js",
28
28
  "./graph-editor": "./lib/graph-editor/index.js",
29
+ "./download-helper": "./lib/download-helper/index.js",
30
+ "./download-helper/test/MockedDownloadHelper.js": "./lib/download-helper/__test-utils__/MockedDownloadHelper.js",
29
31
  "./lib/index.css": "./lib/index.css"
30
32
  },
31
33
  "module": "lib/index.js",
@@ -63,10 +65,10 @@
63
65
  "@ag-grid-enterprise/server-side-row-model": "30.2.0",
64
66
  "@ag-grid-enterprise/side-bar": "30.2.0",
65
67
  "@ag-grid-enterprise/status-bar": "30.2.0",
66
- "@finos/legend-application": "15.0.63",
67
- "@finos/legend-art": "7.1.16",
68
- "@finos/legend-graph": "31.6.7",
69
- "@finos/legend-shared": "10.0.30",
68
+ "@finos/legend-application": "15.0.64",
69
+ "@finos/legend-art": "7.1.17",
70
+ "@finos/legend-graph": "31.7.0",
71
+ "@finos/legend-shared": "10.0.31",
70
72
  "@types/css-font-loading-module": "0.0.10",
71
73
  "@types/react": "18.2.31",
72
74
  "@types/react-dom": "18.2.14",
@@ -78,7 +80,7 @@
78
80
  "react-dom": "18.2.0"
79
81
  },
80
82
  "devDependencies": {
81
- "@finos/legend-dev-utils": "2.0.82",
83
+ "@finos/legend-dev-utils": "2.1.0",
82
84
  "@jest/globals": "29.7.0",
83
85
  "cross-env": "7.0.3",
84
86
  "eslint": "8.52.0",
@@ -0,0 +1,120 @@
1
+ /**
2
+ * Copyright (c) 2020-present, Goldman Sachs
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+ const TAG_REQUEST = 'download-request';
18
+ const TAG_RESPONSE = 'download-response';
19
+
20
+ const STREAM_CLOSED = '#stream-closed';
21
+ const STREAM_ABORTED = '#stream-aborted';
22
+
23
+ // will interact from `createWritableStreamFromMessageChannel`
24
+ function createReadableStreamFromMessagePort(
25
+ port: MessagePort,
26
+ ): ReadableStream {
27
+ return new ReadableStream({
28
+ start(controller) {
29
+ port.onmessage = ({ data }) => {
30
+ if (data === STREAM_CLOSED) {
31
+ return controller.close();
32
+ }
33
+ if (data === STREAM_ABORTED) {
34
+ controller.error('aborted');
35
+ return undefined;
36
+ }
37
+ controller.enqueue(data);
38
+ return undefined;
39
+ };
40
+ },
41
+ });
42
+ }
43
+
44
+ interface DownloadRequest {
45
+ tag: string;
46
+ filename: string;
47
+ url: string;
48
+ }
49
+
50
+ const entries: Map<string, [ReadableStream, DownloadRequest, MessagePort]> =
51
+ new Map();
52
+
53
+ export function handleDownloadMessage(event: ExtendableMessageEvent): void {
54
+ const data = event.data as DownloadRequest;
55
+ if (event.data && event.data.tag === TAG_REQUEST) {
56
+ const port = event.ports[0];
57
+ if (port === undefined) {
58
+ throw new Error('Port 1 expected to handle download request');
59
+ }
60
+ const entry: [ReadableStream, DownloadRequest, MessagePort] = [
61
+ createReadableStreamFromMessagePort(port),
62
+ data,
63
+ port,
64
+ ];
65
+ entries.set(data.url, entry);
66
+ port.postMessage({ tag: TAG_RESPONSE, downloadUrl: data.url });
67
+ }
68
+ }
69
+
70
+ function handleDownloadFetch(event: FetchEvent): void {
71
+ const url = event.request.url;
72
+ const entry = entries.get(url);
73
+
74
+ if (entry) {
75
+ entries.delete(url);
76
+ const [stream, data] = entry;
77
+ const { filename } = data;
78
+ const headers = new Headers({
79
+ 'Content-Type': 'application/octet-stream; charset=utf-8',
80
+ 'Content-Disposition': `attachment; filename*=UTF-8''${filename}`,
81
+ 'Content-Security-Policy': "default-src 'none'",
82
+ });
83
+ // TODO: add trace
84
+ // console.log('responding to ffetch', stream);
85
+ event.respondWith(new Response(stream, { headers }));
86
+ }
87
+ }
88
+
89
+ // ------------------ Service Worker Lifecycle ------------------
90
+
91
+ declare const self: ServiceWorkerGlobalScope;
92
+
93
+ function handleInstall(event: ExtendableEvent): void {
94
+ // TODO: add trace
95
+ // console.log('service worker install', event);
96
+ event.waitUntil(self.skipWaiting());
97
+ }
98
+
99
+ function handleActivate(event: ExtendableEvent): void {
100
+ // TODO: add trace
101
+ // console.log('service worker activate', event);
102
+ event.waitUntil(self.clients.claim());
103
+ }
104
+
105
+ function handleMessage(event: ExtendableMessageEvent): void {
106
+ // TODO: add trace
107
+ // console.log('service worker message', event);
108
+ handleDownloadMessage(event);
109
+ }
110
+
111
+ function handleFetch(event: FetchEvent): void {
112
+ // TODO: add trace
113
+ // console.log('service worker fetch', event);
114
+ handleDownloadFetch(event);
115
+ }
116
+
117
+ self.addEventListener('install', handleInstall);
118
+ self.addEventListener('activate', handleActivate);
119
+ self.addEventListener('message', handleMessage);
120
+ self.addEventListener('fetch', handleFetch);
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Copyright (c) 2020-present, Goldman Sachs
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+ export async function downloadStream(): Promise<void> {}
18
+ export function registerDownloadHelperServiceWorker(): void {}
@@ -0,0 +1,156 @@
1
+ /**
2
+ * Copyright (c) 2020-present, Goldman Sachs
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+ enum DOWNLOAD_EVENTS {
18
+ TAG_REQUEST = 'download-request',
19
+ TAG_RESPONSE = 'download-response',
20
+ STREAM_CLOSED = '#stream-closed',
21
+ STREAM_ABORTED = '#stream-aborted',
22
+ }
23
+
24
+ function createWritableStreamFromMessageChannel(
25
+ channel: MessageChannel,
26
+ ): WritableStream {
27
+ return new WritableStream({
28
+ write(chunk) {
29
+ channel.port1.postMessage(chunk);
30
+ },
31
+ close() {
32
+ channel.port1.postMessage(DOWNLOAD_EVENTS.STREAM_CLOSED);
33
+ },
34
+ abort() {
35
+ channel.port1.postMessage(DOWNLOAD_EVENTS.STREAM_ABORTED);
36
+ closeMessagePort(channel.port1);
37
+ closeMessagePort(channel.port2);
38
+ },
39
+ });
40
+ }
41
+
42
+ function closeMessagePort(port: MessagePort): void {
43
+ port.onmessage = null;
44
+ port.close();
45
+ }
46
+
47
+ interface LegendApplicationDownloadRequest {
48
+ tag: string;
49
+ filename: string;
50
+ url: string;
51
+ }
52
+
53
+ interface LegendApplicationTagResponse {
54
+ tag: string;
55
+ downloadUrl: string;
56
+ }
57
+
58
+ async function getServiceWorker(): Promise<ServiceWorker | undefined> {
59
+ if (!('serviceWorker' in navigator)) {
60
+ return Promise.reject(
61
+ new Error(
62
+ 'Service worker is not available. Service Worker requires HTTPS protocol',
63
+ ),
64
+ );
65
+ }
66
+ return navigator.serviceWorker
67
+ .getRegistration()
68
+ .then((workerRegistration) => {
69
+ if (workerRegistration === undefined) {
70
+ return undefined;
71
+ }
72
+ const pending =
73
+ workerRegistration.installing ?? workerRegistration.waiting;
74
+ return (
75
+ workerRegistration.active ??
76
+ new Promise((resolve) => {
77
+ // if not activated, add listener to waiting or installing registration
78
+ const listener = (): void => {
79
+ if (pending?.state === 'activated') {
80
+ pending.removeEventListener('statechange', listener);
81
+ resolve(workerRegistration.active ?? undefined);
82
+ }
83
+ };
84
+ pending?.addEventListener('statechange', listener);
85
+ })
86
+ );
87
+ });
88
+ }
89
+
90
+ function createDownloadRequest(
91
+ filename: string,
92
+ ): LegendApplicationDownloadRequest {
93
+ const PREFIX = 6;
94
+ const prefix = String(Math.random()).slice(-PREFIX);
95
+ const url = new URL(`${prefix}/${filename}`, window.location.href).toString();
96
+ return { tag: DOWNLOAD_EVENTS.TAG_REQUEST, filename, url };
97
+ }
98
+
99
+ function handleServiceWorkerDownloadResponse(
100
+ event: MessageEvent<LegendApplicationTagResponse | undefined>,
101
+ ): void {
102
+ const data = event.data;
103
+ if (data?.tag === DOWNLOAD_EVENTS.TAG_RESPONSE && data.downloadUrl.length) {
104
+ openInIframe(data.downloadUrl);
105
+ }
106
+ }
107
+
108
+ function openInIframe(src: string): HTMLIFrameElement {
109
+ const iframe = document.createElement('iframe');
110
+ iframe.hidden = true;
111
+ iframe.src = src;
112
+ document.body.appendChild(iframe);
113
+ return iframe;
114
+ }
115
+
116
+ export async function downloadStream(
117
+ responseBody: ReadableStream,
118
+ filename: string,
119
+ ): Promise<void> {
120
+ // creates communication channel with service worker with response handler
121
+ const channel = new MessageChannel();
122
+ channel.port1.onmessage = handleServiceWorkerDownloadResponse;
123
+
124
+ // grabs service worker and handles it download along with response channel port
125
+ const serviceWorker = await getServiceWorker();
126
+ if (!serviceWorker) {
127
+ return;
128
+ }
129
+ const downloadRequest = createDownloadRequest(filename);
130
+ serviceWorker.postMessage(downloadRequest, [channel.port2]);
131
+
132
+ // creates new data stream over communication channel and pipes given stream in it
133
+ responseBody
134
+ .pipeTo(createWritableStreamFromMessageChannel(channel))
135
+ .then(() => {
136
+ // TODO: trace success
137
+ })
138
+ .catch(() => {
139
+ // TODO: fail
140
+ });
141
+ }
142
+
143
+ export function registerDownloadHelperServiceWorker(): void {
144
+ if ('serviceWorker' in navigator) {
145
+ navigator.serviceWorker
146
+ .register(new URL('./DownloadHelper.service-worker.js', import.meta.url))
147
+ .then((reg) => {
148
+ // TODO: add trace
149
+ // console.debug('register service worker success', reg);
150
+ })
151
+ .catch((error) => {
152
+ // TODO: add trace
153
+ // console.debug('register service worker error', error);
154
+ });
155
+ }
156
+ }
package/tsconfig.json CHANGED
@@ -39,6 +39,9 @@
39
39
  "./src/code-editor/__test-utils__/MockedMonacoEditor.ts",
40
40
  "./src/code-editor/themes/MonacoEditorThemeUtils.ts",
41
41
  "./src/data-grid/index.ts",
42
+ "./src/download-helper/DownloadHelper.service-worker.ts",
43
+ "./src/download-helper/index.ts",
44
+ "./src/download-helper/__test-utils__/MockedDownloadHelper.ts",
42
45
  "./src/graph-editor/index.ts",
43
46
  "./src/application/ActivityBar.tsx",
44
47
  "./src/application/DocumentationLink.tsx",