From 0863a4d64314dc7a6071da8ee66dd6dcf900fc39 Mon Sep 17 00:00:00 2001 From: brainfoolong Date: Tue, 31 Jan 2023 16:50:17 +0100 Subject: [PATCH] added some new features and fixes added `addAntiCacheParam` parameter to `getUrl` to add a random string to generated urls to prevent browser memory-caching added `nullIfKeyNotExist` parameter to `getUrl` added `defaultReturn` parameter to `getDataUri` fixed `convertValue` in case of `null/undefined` returns --- CHANGELOG.md | 8 +++++++- dist/browstorjs.js | 28 ++++++++++++++++++---------- docs/scripts/browstorjs.js | 28 ++++++++++++++++++---------- package-lock.json | 4 ++-- package.json | 2 +- src/browstorjs.ts | 24 +++++++++++++++--------- 6 files changed, 61 insertions(+), 33 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d6169ea..6d6baea 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +## [1.3.0] 2023-01-31 + +* added `addAntiCacheParam` parameter to `getUrl` to add a random string to generated urls to prevent browser memory-caching +* added `nullIfKeyNotExist` parameter to `getUrl` +* added `defaultReturn` parameter to `getDataUri` +* fixed `convertValue` in case of `null/undefined` returns + ## [1.2.0] 2022-08-02 * added `requestPersistentStorage` and `getStorageSpaceInfo` @@ -8,7 +15,6 @@ * added `getDataUri` function * fixed safari support for blob file storage by using ArrayBuffer instead - ## [1.0.2] 2022-07-28 * Initial release \ No newline at end of file diff --git a/dist/browstorjs.js b/dist/browstorjs.js index 3a8573d..16efe2f 100644 --- a/dist/browstorjs.js +++ b/dist/browstorjs.js @@ -1,4 +1,4 @@ -// BrowstorJS v1.2.0 @ https://github.com/NullixAT/browstorjs +// BrowstorJS v1.3.0 @ https://github.com/NullixAT/browstorjs /** * BrowstorJS * Persistent key/value data storage for your Browser and/or PWA, promisified, including file support and service worker support, all with IndexedDB. @@ -32,10 +32,11 @@ class BrowstorJS { if (!msg || !msg.browstorJsGetFileUrl) return false; // @ts-ignore + const urlData = msg.browstorJsGetFileUrl; event.source.postMessage({ 'browstorJsFileUrl': { 'key': msg.browstorJsGetFileUrl.key, - 'url': fileUrlPrefix + msg.browstorJsGetFileUrl.key + '/' + msg.browstorJsGetFileUrl.dbName + 'url': fileUrlPrefix + urlData.key + '/' + urlData.dbName + (urlData.addAntiCacheParam ? '?c=' + Math.random() : '') } }); break; @@ -47,7 +48,7 @@ class BrowstorJS { } const urlSplit = url.split('/'); const key = urlSplit[urlSplit.length - 2]; - const dbName = urlSplit[urlSplit.length - 1]; + const dbName = urlSplit[urlSplit.length - 1].split('?')[0]; // @ts-ignore event.respondWith(new Promise(async function (resolve) { const value = await (await BrowstorJS.open(dbName)).get(key); @@ -206,9 +207,13 @@ class BrowstorJS { /** * Get file url to given storage key * @param {string} key - * @return {Promise} + * @param {boolean} nullIfKeyNotExist Return null when the key not exist in db (default is return the url anyway) + * @param {boolean} addAntiCacheParam Add ?c=randomnumber to the generated to prevent browser memory-caching + * @return {Promise} Null if key does not exist and option is enabled */ - async getUrl(key) { + async getUrl(key, nullIfKeyNotExist = false, addAntiCacheParam) { + if (nullIfKeyNotExist && !(await this.get(key))) + return null; const self = this; // is undefined in private browsing mode in some browsers or in ancient browsers if (typeof navigator.serviceWorker === 'undefined') { @@ -235,21 +240,21 @@ class BrowstorJS { // send message to service worker to request the file url navigator.serviceWorker.ready.then(function (serviceWorker) { serviceWorker.active.postMessage({ - 'browstorJsGetFileUrl': { 'dbName': self.dbName, 'key': key } + 'browstorJsGetFileUrl': { 'dbName': self.dbName, 'key': key, 'addAntiCacheParam': addAntiCacheParam } }); }); }); } /** * Get a data uri that can be used as href or src for images - * If value in this key is not a file/blob than this will return a blank 1x1 pixel image data uri * @param {string} key + * @param {string|null} defaultReturn The default value that is returned in case the key does not exist * @return {Promise} */ - async getDataUri(key) { + async getDataUri(key, defaultReturn = 'data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs=') { const value = await this.convertValue(await this.get(key), 'blob'); if (!(value instanceof Blob)) - return 'data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs='; + return defaultReturn; return new Promise(function (resolve) { const reader = new FileReader(); // @ts-ignore @@ -401,7 +406,10 @@ class BrowstorJS { * @private */ async convertValue(value, to) { - if (value instanceof Blob && to === 'data') { + if (value === null || value === undefined) { + return null; + } + else if (value instanceof Blob && to === 'data') { return this.blobToBlobDataObject(value); } else if (to === 'blob' && typeof value === 'object' && typeof value.type !== 'undefined' && value.type === 'browstorJsBlobData') { diff --git a/docs/scripts/browstorjs.js b/docs/scripts/browstorjs.js index 3a8573d..16efe2f 100644 --- a/docs/scripts/browstorjs.js +++ b/docs/scripts/browstorjs.js @@ -1,4 +1,4 @@ -// BrowstorJS v1.2.0 @ https://github.com/NullixAT/browstorjs +// BrowstorJS v1.3.0 @ https://github.com/NullixAT/browstorjs /** * BrowstorJS * Persistent key/value data storage for your Browser and/or PWA, promisified, including file support and service worker support, all with IndexedDB. @@ -32,10 +32,11 @@ class BrowstorJS { if (!msg || !msg.browstorJsGetFileUrl) return false; // @ts-ignore + const urlData = msg.browstorJsGetFileUrl; event.source.postMessage({ 'browstorJsFileUrl': { 'key': msg.browstorJsGetFileUrl.key, - 'url': fileUrlPrefix + msg.browstorJsGetFileUrl.key + '/' + msg.browstorJsGetFileUrl.dbName + 'url': fileUrlPrefix + urlData.key + '/' + urlData.dbName + (urlData.addAntiCacheParam ? '?c=' + Math.random() : '') } }); break; @@ -47,7 +48,7 @@ class BrowstorJS { } const urlSplit = url.split('/'); const key = urlSplit[urlSplit.length - 2]; - const dbName = urlSplit[urlSplit.length - 1]; + const dbName = urlSplit[urlSplit.length - 1].split('?')[0]; // @ts-ignore event.respondWith(new Promise(async function (resolve) { const value = await (await BrowstorJS.open(dbName)).get(key); @@ -206,9 +207,13 @@ class BrowstorJS { /** * Get file url to given storage key * @param {string} key - * @return {Promise} + * @param {boolean} nullIfKeyNotExist Return null when the key not exist in db (default is return the url anyway) + * @param {boolean} addAntiCacheParam Add ?c=randomnumber to the generated to prevent browser memory-caching + * @return {Promise} Null if key does not exist and option is enabled */ - async getUrl(key) { + async getUrl(key, nullIfKeyNotExist = false, addAntiCacheParam) { + if (nullIfKeyNotExist && !(await this.get(key))) + return null; const self = this; // is undefined in private browsing mode in some browsers or in ancient browsers if (typeof navigator.serviceWorker === 'undefined') { @@ -235,21 +240,21 @@ class BrowstorJS { // send message to service worker to request the file url navigator.serviceWorker.ready.then(function (serviceWorker) { serviceWorker.active.postMessage({ - 'browstorJsGetFileUrl': { 'dbName': self.dbName, 'key': key } + 'browstorJsGetFileUrl': { 'dbName': self.dbName, 'key': key, 'addAntiCacheParam': addAntiCacheParam } }); }); }); } /** * Get a data uri that can be used as href or src for images - * If value in this key is not a file/blob than this will return a blank 1x1 pixel image data uri * @param {string} key + * @param {string|null} defaultReturn The default value that is returned in case the key does not exist * @return {Promise} */ - async getDataUri(key) { + async getDataUri(key, defaultReturn = 'data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs=') { const value = await this.convertValue(await this.get(key), 'blob'); if (!(value instanceof Blob)) - return 'data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs='; + return defaultReturn; return new Promise(function (resolve) { const reader = new FileReader(); // @ts-ignore @@ -401,7 +406,10 @@ class BrowstorJS { * @private */ async convertValue(value, to) { - if (value instanceof Blob && to === 'data') { + if (value === null || value === undefined) { + return null; + } + else if (value instanceof Blob && to === 'data') { return this.blobToBlobDataObject(value); } else if (to === 'blob' && typeof value === 'object' && typeof value.type !== 'undefined' && value.type === 'browstorJsBlobData') { diff --git a/package-lock.json b/package-lock.json index 791d0c3..9ef3747 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "browstorjs", - "version": "1.1.0", + "version": "1.3.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "browstorjs", - "version": "1.1.0", + "version": "1.3.0", "license": "MIT", "devDependencies": { "@playwright/test": "^1.24.1", diff --git a/package.json b/package.json index 769a100..00f02cb 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "browstorjs", - "version": "1.2.0", + "version": "1.3.0", "description": "Persistent key/value data storage for your Browser and/or PWA, promisified, including file support and service worker support, all with IndexedDB.", "scripts": { "dist": "node ./node_modules/typescript/bin/tsc --project tsconfig.json && node build/dist.js" diff --git a/src/browstorjs.ts b/src/browstorjs.ts index e4e6efe..25b0d78 100644 --- a/src/browstorjs.ts +++ b/src/browstorjs.ts @@ -47,10 +47,11 @@ export default class BrowstorJS { const msg = event.data if (!msg || !msg.browstorJsGetFileUrl) return false // @ts-ignore + const urlData = msg.browstorJsGetFileUrl event.source.postMessage({ 'browstorJsFileUrl': { 'key': msg.browstorJsGetFileUrl.key, - 'url': fileUrlPrefix + msg.browstorJsGetFileUrl.key + '/' + msg.browstorJsGetFileUrl.dbName + 'url': fileUrlPrefix + urlData.key + '/' + urlData.dbName + (urlData.addAntiCacheParam ? '?c=' + Math.random() : '') } }) break @@ -63,7 +64,7 @@ export default class BrowstorJS { const urlSplit = url.split('/') const key = urlSplit[urlSplit.length - 2] - const dbName = urlSplit[urlSplit.length - 1] + const dbName = urlSplit[urlSplit.length - 1].split('?')[0] // @ts-ignore event.respondWith(new Promise(async function (resolve) { @@ -226,9 +227,12 @@ export default class BrowstorJS { /** * Get file url to given storage key * @param {string} key - * @return {Promise} + * @param {boolean} nullIfKeyNotExist Return null when the key not exist in db (default is return the url anyway) + * @param {boolean} addAntiCacheParam Add ?c=randomnumber to the generated to prevent browser memory-caching + * @return {Promise} Null if key does not exist and option is enabled */ - async getUrl (key: string): Promise { + async getUrl (key: string, nullIfKeyNotExist = false, addAntiCacheParam: false): Promise { + if (nullIfKeyNotExist && !(await this.get(key))) return null const self = this // is undefined in private browsing mode in some browsers or in ancient browsers if (typeof navigator.serviceWorker === 'undefined') { @@ -255,7 +259,7 @@ export default class BrowstorJS { // send message to service worker to request the file url navigator.serviceWorker.ready.then(function (serviceWorker) { serviceWorker.active.postMessage({ - 'browstorJsGetFileUrl': { 'dbName': self.dbName, 'key': key } + 'browstorJsGetFileUrl': { 'dbName': self.dbName, 'key': key, 'addAntiCacheParam': addAntiCacheParam } }) }) }) @@ -263,13 +267,13 @@ export default class BrowstorJS { /** * Get a data uri that can be used as href or src for images - * If value in this key is not a file/blob than this will return a blank 1x1 pixel image data uri * @param {string} key + * @param {string|null} defaultReturn The default value that is returned in case the key does not exist * @return {Promise} */ - async getDataUri (key: string): Promise { + async getDataUri (key: string, defaultReturn: string | null = 'data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs='): Promise { const value = await this.convertValue(await this.get(key), 'blob') - if (!(value instanceof Blob)) return 'data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs=' + if (!(value instanceof Blob)) return defaultReturn return new Promise(function (resolve) { const reader = new FileReader() // @ts-ignore @@ -426,7 +430,9 @@ export default class BrowstorJS { * @private */ private async convertValue (value: any, to): Promise { - if (value instanceof Blob && to === 'data') { + if (value === null || value === undefined) { + return null + } else if (value instanceof Blob && to === 'data') { return this.blobToBlobDataObject(value) } else if (to === 'blob' && typeof value === 'object' && typeof value.type !== 'undefined' && value.type === 'browstorJsBlobData') { return this.blobDataObjectToBlob(value)