From 5cd44063a21e26d07a02413344d4ff7dc9877927 Mon Sep 17 00:00:00 2001 From: sivanov Date: Mon, 4 Jul 2022 17:53:32 +0300 Subject: [PATCH 1/4] fixes for safari and firefox --- lib/package-lock.json | 15 +++++++-- lib/package.json | 1 + lib/tdf3/src/client/BrowserTdfSteam.js | 31 ++++++++++--------- .../src/client/DecoratedReadableStream.js | 8 +++++ lib/webpack.config.js | 26 +++++++--------- 5 files changed, 49 insertions(+), 32 deletions(-) diff --git a/lib/package-lock.json b/lib/package-lock.json index f7ab99eb..821af65c 100644 --- a/lib/package-lock.json +++ b/lib/package-lock.json @@ -1,16 +1,17 @@ { "name": "@opentdf/client", - "version": "0.2.2", + "version": "0.2.4", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@opentdf/client", - "version": "0.2.2", + "version": "0.2.4", "license": "BSD-3-Clause-Clear", "dependencies": { "@aws-sdk/client-s3": "^3.75.0", "axios": "^0.26.1", + "browser-fs-access": "^0.30.2", "buffer-crc32": "^0.2.13", "events": "^3.3.0", "jose": "^4.8.1", @@ -5346,6 +5347,11 @@ "dev": true, "peer": true }, + "node_modules/browser-fs-access": { + "version": "0.30.2", + "resolved": "https://registry.npmjs.org/browser-fs-access/-/browser-fs-access-0.30.2.tgz", + "integrity": "sha512-FUwj3WRO393gIQUqzvl0NyWwGwlvduBoqi1Ur5w1cnm5YyL789gGPZst3BWec2qiwlcyHjeUPNqbuC3J3YArUg==" + }, "node_modules/browser-pack": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/browser-pack/-/browser-pack-6.1.0.tgz", @@ -19047,6 +19053,11 @@ "dev": true, "peer": true }, + "browser-fs-access": { + "version": "0.30.2", + "resolved": "https://registry.npmjs.org/browser-fs-access/-/browser-fs-access-0.30.2.tgz", + "integrity": "sha512-FUwj3WRO393gIQUqzvl0NyWwGwlvduBoqi1Ur5w1cnm5YyL789gGPZst3BWec2qiwlcyHjeUPNqbuC3J3YArUg==" + }, "browser-pack": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/browser-pack/-/browser-pack-6.1.0.tgz", diff --git a/lib/package.json b/lib/package.json index 4888f794..1b33faaf 100644 --- a/lib/package.json +++ b/lib/package.json @@ -57,6 +57,7 @@ "dependencies": { "@aws-sdk/client-s3": "^3.75.0", "axios": "^0.26.1", + "browser-fs-access": "^0.30.2", "buffer-crc32": "^0.2.13", "events": "^3.3.0", "jose": "^4.8.1", diff --git a/lib/tdf3/src/client/BrowserTdfSteam.js b/lib/tdf3/src/client/BrowserTdfSteam.js index c989f29b..681c8937 100644 --- a/lib/tdf3/src/client/BrowserTdfSteam.js +++ b/lib/tdf3/src/client/BrowserTdfSteam.js @@ -1,10 +1,10 @@ -import streamSaver from 'streamsaver'; -import { WritableStream } from 'web-streams-polyfill/ponyfill'; import ReadableStream from './DecoratedReadableStream'; +import streamSaver from 'streamsaver'; +import { fileSave } from 'browser-fs-access'; class BrowserTdfStream extends ReadableStream { static convertToWebStream() { - throw new Error('Please use Web Streams in browser environment') + throw new Error('Please use Web Streams in browser environment'); } /** @@ -12,7 +12,7 @@ class BrowserTdfStream extends ReadableStream { * @return {string} - the plaintext in string form. */ async toString() { - const results = await this.toBuffer() + const results = await this.toBuffer(); return results.toString('utf8'); } @@ -47,23 +47,24 @@ class BrowserTdfStream extends ReadableStream { * Dump the stream content to a local file. This will consume the stream. * * @param {string} filepath - the path of the local file to write plaintext to. - * @param {string} encoding - the charset encoding to use. Defaults to utf-8. */ - async toFile(filepath, encoding) { - try { - new streamSaver.WritableStream(); - } catch (e) { - // Conditionally add ponyfill for Firefox - streamSaver.WritableStream = WritableStream; - } - + async toFile(filepath) { const fileName = filepath || 'download.tdf'; + const isFirefox = typeof InstallTrigger !== 'undefined'; + + if (isFirefox) { + return await fileSave(new Response(this), { + fileName: fileName, + extensions: [`.${filepath.split('.').pop()}`], + }); + } + const fileStream = streamSaver.createWriteStream(fileName, { ...(this.contentLength && { size: this.contentLength }), }); - if (WritableStream && this.pipeTo) { + if (WritableStream) { return this.pipeTo(fileStream); } @@ -78,4 +79,4 @@ class BrowserTdfStream extends ReadableStream { } } -export default BrowserTdfStream +export default BrowserTdfStream; diff --git a/lib/tdf3/src/client/DecoratedReadableStream.js b/lib/tdf3/src/client/DecoratedReadableStream.js index 87c31aec..7bf2be59 100644 --- a/lib/tdf3/src/client/DecoratedReadableStream.js +++ b/lib/tdf3/src/client/DecoratedReadableStream.js @@ -9,6 +9,14 @@ class DecoratedReadableStream extends ReadableStream { const ee = new EventEmitter(); this.on = ee.on; this.emit = ee.emit; + + const isSafari = + /constructor/i.test(window.HTMLElement) || + window?.safari?.pushNotification?.toString() === '[object SafariRemoteNotification]'; + + if (isSafari) { + Object.setPrototypeOf(this, DecoratedReadableStream.prototype); + } } /** diff --git a/lib/webpack.config.js b/lib/webpack.config.js index a8ed8259..8821e0af 100644 --- a/lib/webpack.config.js +++ b/lib/webpack.config.js @@ -6,9 +6,7 @@ const prodPattern = /^prod/i; module.exports = (env, argv) => { const isProd = prodPattern.test(argv.mode) || prodPattern.test(process.env.NODE_ENV); - const mode = (isProd) - ? 'production' - : 'development'; + const mode = isProd ? 'production' : 'development'; // CRA fails to run build with mode: 'production' const clientConfig = { @@ -27,14 +25,14 @@ module.exports = (env, argv) => { }, target: 'web', resolve: { - extensions: [ '.ts', '.tsx', '.js'], + extensions: ['.ts', '.tsx', '.js'], modules: ['src', 'node_modules'], fallback: { crypto: false, fs: false, constants: false, stream: false, - } + }, }, output: { publicPath: '', @@ -63,7 +61,7 @@ module.exports = (env, argv) => { }, target: 'node', resolve: { - extensions: [ '.ts', '.tsx', '.js'], + extensions: ['.ts', '.tsx', '.js'], modules: ['src', 'node_modules'], }, output: { @@ -89,7 +87,10 @@ module.exports = (env, argv) => { ...clientConfig.resolve, alias: { '@tdfStream': path.resolve(__dirname, '/tdf3/src/client/BrowserTdfSteam.js'), - "@runtimeConfig": path.resolve(__dirname, '/tdf3/src/utils/aws-lib-storage/runtimeConfig.browser'), + '@runtimeConfig': path.resolve( + __dirname, + '/tdf3/src/utils/aws-lib-storage/runtimeConfig.browser' + ), }, }, output: { @@ -105,11 +106,11 @@ module.exports = (env, argv) => { resolve: { ...serverConfig.resolve, fallback: { - fetch: require.resolve('node-fetch') + fetch: require.resolve('node-fetch'), }, alias: { '@tdfStream': path.resolve(__dirname, '/tdf3/src/client/NodeTdfStream.js'), - "@runtimeConfig": path.resolve(__dirname, '/tdf3/src/utils/aws-lib-storage/runtimeConfig'), + '@runtimeConfig': path.resolve(__dirname, '/tdf3/src/utils/aws-lib-storage/runtimeConfig'), }, }, output: { @@ -118,10 +119,5 @@ module.exports = (env, argv) => { }, }; - return [ - clientConfig, - serverConfig, - clientTdf3Config, - serverTdf3Config, - ]; + return [clientConfig, serverConfig, clientTdf3Config, serverTdf3Config]; }; From 60e3a3bdd0c48337e4d9206c9a4131e4b4a4d417 Mon Sep 17 00:00:00 2001 From: sivanov Date: Tue, 5 Jul 2022 12:22:26 +0300 Subject: [PATCH 2/4] subclass need workaround too --- lib/tdf3/src/client/BrowserTdfSteam.js | 6 ++++++ lib/tdf3/src/client/DecoratedReadableStream.js | 9 ++------- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/lib/tdf3/src/client/BrowserTdfSteam.js b/lib/tdf3/src/client/BrowserTdfSteam.js index 681c8937..7b841029 100644 --- a/lib/tdf3/src/client/BrowserTdfSteam.js +++ b/lib/tdf3/src/client/BrowserTdfSteam.js @@ -3,6 +3,12 @@ import streamSaver from 'streamsaver'; import { fileSave } from 'browser-fs-access'; class BrowserTdfStream extends ReadableStream { + constructor(...props) { + super(...props); + // workaround for safari https://stackoverflow.com/questions/58471434/problem-extending-native-es6-classes-in-safari + Object.setPrototypeOf(this, BrowserTdfStream.prototype); + } + static convertToWebStream() { throw new Error('Please use Web Streams in browser environment'); } diff --git a/lib/tdf3/src/client/DecoratedReadableStream.js b/lib/tdf3/src/client/DecoratedReadableStream.js index 7bf2be59..c3e5466a 100644 --- a/lib/tdf3/src/client/DecoratedReadableStream.js +++ b/lib/tdf3/src/client/DecoratedReadableStream.js @@ -10,13 +10,8 @@ class DecoratedReadableStream extends ReadableStream { this.on = ee.on; this.emit = ee.emit; - const isSafari = - /constructor/i.test(window.HTMLElement) || - window?.safari?.pushNotification?.toString() === '[object SafariRemoteNotification]'; - - if (isSafari) { - Object.setPrototypeOf(this, DecoratedReadableStream.prototype); - } + // workaround for safari https://stackoverflow.com/questions/58471434/problem-extending-native-es6-classes-in-safari + Object.setPrototypeOf(this, DecoratedReadableStream.prototype); } /** From 5b5adb7e7f1456f7ba2c24af606b19876e37f509 Mon Sep 17 00:00:00 2001 From: sivanov Date: Tue, 5 Jul 2022 12:53:37 +0300 Subject: [PATCH 3/4] check for browser added --- lib/src/utils.ts | 8 ++++++++ lib/tdf3/src/client/BrowserTdfSteam.js | 9 +++++---- lib/tdf3/src/client/DecoratedReadableStream.js | 7 +++++-- 3 files changed, 18 insertions(+), 6 deletions(-) diff --git a/lib/src/utils.ts b/lib/src/utils.ts index a15f0910..4837055c 100644 --- a/lib/src/utils.ts +++ b/lib/src/utils.ts @@ -1,3 +1,11 @@ export function isBrowser() { return typeof window !== 'undefined'; // eslint-disable-line } + +export const isSafari(): Boolean => ( + /constructor/i.test(globalThis.HTMLElement) || + globalThis?.safari?.pushNotification?.toString() === '[object SafariRemoteNotification]' +); + +export const isFirefox(): Boolean => typeof InstallTrigger !== 'undefined'; + diff --git a/lib/tdf3/src/client/BrowserTdfSteam.js b/lib/tdf3/src/client/BrowserTdfSteam.js index 7b841029..2f0c3024 100644 --- a/lib/tdf3/src/client/BrowserTdfSteam.js +++ b/lib/tdf3/src/client/BrowserTdfSteam.js @@ -1,12 +1,15 @@ import ReadableStream from './DecoratedReadableStream'; import streamSaver from 'streamsaver'; import { fileSave } from 'browser-fs-access'; +import { isSafari, isFirefox } from '../../../src/utils'; class BrowserTdfStream extends ReadableStream { constructor(...props) { super(...props); // workaround for safari https://stackoverflow.com/questions/58471434/problem-extending-native-es6-classes-in-safari - Object.setPrototypeOf(this, BrowserTdfStream.prototype); + if (isSafari()) { + Object.setPrototypeOf(this, BrowserTdfStream.prototype); + } } static convertToWebStream() { @@ -57,9 +60,7 @@ class BrowserTdfStream extends ReadableStream { async toFile(filepath) { const fileName = filepath || 'download.tdf'; - const isFirefox = typeof InstallTrigger !== 'undefined'; - - if (isFirefox) { + if (isFirefox()) { return await fileSave(new Response(this), { fileName: fileName, extensions: [`.${filepath.split('.').pop()}`], diff --git a/lib/tdf3/src/client/DecoratedReadableStream.js b/lib/tdf3/src/client/DecoratedReadableStream.js index c3e5466a..4f912f14 100644 --- a/lib/tdf3/src/client/DecoratedReadableStream.js +++ b/lib/tdf3/src/client/DecoratedReadableStream.js @@ -1,6 +1,7 @@ import { get } from 'axios'; import { S3Client } from '@aws-sdk/client-s3'; import { Upload } from '../utils/aws-lib-storage'; +import { isSafari } from '../../../src/utils'; import { EventEmitter } from 'events'; class DecoratedReadableStream extends ReadableStream { @@ -10,8 +11,10 @@ class DecoratedReadableStream extends ReadableStream { this.on = ee.on; this.emit = ee.emit; - // workaround for safari https://stackoverflow.com/questions/58471434/problem-extending-native-es6-classes-in-safari - Object.setPrototypeOf(this, DecoratedReadableStream.prototype); + if (isSafari()) { + // workaround for safari https://stackoverflow.com/questions/58471434/problem-extending-native-es6-classes-in-safari + Object.setPrototypeOf(this, DecoratedReadableStream.prototype); + } } /** From 3fbfd3b75971258b1099fe1bb429c0f62c7bea71 Mon Sep 17 00:00:00 2001 From: sivanov Date: Tue, 5 Jul 2022 12:59:35 +0300 Subject: [PATCH 4/4] utils fixed --- lib/src/utils.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/src/utils.ts b/lib/src/utils.ts index 4837055c..dfaa7f64 100644 --- a/lib/src/utils.ts +++ b/lib/src/utils.ts @@ -2,10 +2,10 @@ export function isBrowser() { return typeof window !== 'undefined'; // eslint-disable-line } -export const isSafari(): Boolean => ( - /constructor/i.test(globalThis.HTMLElement) || - globalThis?.safari?.pushNotification?.toString() === '[object SafariRemoteNotification]' -); - -export const isFirefox(): Boolean => typeof InstallTrigger !== 'undefined'; +export const isSafari = (): boolean => + /constructor/i.test(String(globalThis.HTMLElement)) || + // @ts-ignore + globalThis?.safari?.pushNotification?.toString() === '[object SafariRemoteNotification]'; +// @ts-ignore +export const isFirefox = (): boolean => typeof InstallTrigger !== 'undefined';