Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

ClientStorage

Package Overview
Dependencies
Maintainers
1
Versions
9
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

ClientStorage - npm Package Compare versions

Comparing version 3.0.1 to 4.0.0

browser-storage.js

437

client-storage.js
'use strict';
var DEFAULT_TTL = 3.154e+8; // 10 years
var TTL_SUFFIX = '.___exp';
var TTL_SUFFIX_LENGTH = TTL_SUFFIX.length;
var CookiesStorage = require('./cookies-storage.js');
var JSStorage = require('./js-storage.js');
var BrowserStorage = require('./browser-storage.js');
/*
* @locus Client
* @class __Cookies
* @param _cookies {String} - Current cookies as String
* @summary Internal Class
*/
function __Cookies(_cookies) {
this.cookies = {};
if (_cookies && typeof _cookies === 'string') {
this.init(_cookies);
}
}
/*
* @locus Client
* @memberOf __Cookies
* @name init
* @param _cookies {String} - Current cookies as String
* @summary parse document.cookie string
* @returns {void 0}
*/
__Cookies.prototype.init = function (_cookies) {
if (_cookies && _cookies.length) {
var self = this;
var i;
var key;
var val;
_cookies.split(/; */).forEach(function (pair) {
i = pair.indexOf('=');
if (i < 0) {
return;
}
key = unescape(pair.substr(0, i).trim());
val = pair.substr(++i, pair.length).trim();
if (val[0] === '"') {
val = val.slice(1, -1);
}
if (self.cookies[key] === void 0) {
try {
self.cookies[key] = unescape(val);
} catch (e) {
self.cookies[key] = val;
}
}
});
}
var debug = function () {
console.warn.apply(console, arguments);
};
/*
/**
* @locus Client
* @memberOf __Cookies
* @name get
* @param {String} key - The name of the cookie to read
* @summary Read a cookie. If the cookie doesn't exist a void 0 (undefined) value will be returned.
* @returns {String|void 0}
*/
__Cookies.prototype.get = function (key) {
if (!key) {
return void 0;
}
if (this.cookies.hasOwnProperty(key)) {
if (this.cookies.hasOwnProperty(key + TTL_SUFFIX)) {
var expireAt = this.cookies[key + TTL_SUFFIX];
console.log({expireAt});
if (expireAt && expireAt <= Date.now()) {
this.remove(key);
return void 0;
}
}
return this.cookies[key];
}
return void 0;
};
/*
* @locus Client
* @memberOf __Cookies
* @name set
* @param {String} key - The name of the cookie to create/overwrite
* @param {String} value - The value of the cookie
* @param {Number} ttl - Cookies TTL (e.g. max-age) in seconds
* @summary Create/overwrite a cookie.
* @returns {Boolean}
*/
__Cookies.prototype.set = function (key, value, ttl) {
if (!ttl) {
ttl = DEFAULT_TTL;
}
if (key) {
this.cookies[key] = value;
document.cookie = escape(key) + '=' + escape(value) + '; Max-Age=' + ttl + '; Path=/';
if (ttl !== DEFAULT_TTL) {
var expireAt = +(new Date(Date.now() + (ttl * 1000)));
this.cookies[key + TTL_SUFFIX] = expireAt;
document.cookie = escape(key + TTL_SUFFIX) + '=' + expireAt + '; Max-Age=' + ttl + '; Path=/';
}
return true;
}
return false;
};
/*
* @locus Client
* @memberOf __Cookies
* @name remove
* @param {String} key - The name of the cookie to remove
* @summary Remove a cookie(s).
* @returns {Boolean}
*/
__Cookies.prototype.remove = function (key) {
if (key) {
if (!this.cookies.hasOwnProperty(key)) {
return false;
}
delete this.cookies[key];
delete this.cookies[key + TTL_SUFFIX];
document.cookie = escape(key) + '=; Expires=Thu, 01 Jan 1970 00:00:00 GMT; Path=/';
document.cookie = escape(key + TTL_SUFFIX) + '=; Expires=Thu, 01 Jan 1970 00:00:00 GMT; Path=/';
return true;
} else if (key === void 0) {
var keys = Object.keys(this.cookies);
if (keys.length > 0 && keys[0] !== '') {
for (var i = 0; i < keys.length; i++) {
this.remove(keys[i]);
}
return true;
}
}
return false;
};
/*
* @locus Client
* @memberOf __Cookies
* @name has
* @param {String} key - The name of the cookie to check
* @summary Check whether a cookie key is exists
* @returns {Boolean}
*/
__Cookies.prototype.has = function (key) {
if (!key) {
return false;
}
return this.cookies.hasOwnProperty(key);
};
/*
* @locus Client
* @memberOf __Cookies
* @name keys
* @summary Returns an array of Strings with all readable cookies from this location.
* @returns {[String]}
*/
__Cookies.prototype.keys = function () {
return Object.keys(this.cookies);
};
/*
* @locus Client
* @class ClientStorage
* @param driver {Sting} - Preferable driver `localStorage` or `cookies`
* @summary Implement boilerplate Client storage functions, localStorage with fall-back to Cookies
* @param driverName {Sting} - Preferable driver `localStorage` or `cookies`
* @summary Implement boilerplate Client storage functions, localStorage with fall-back to CookiesStorage
*/
function ClientStorage(driver) {
this._data = {};
if (navigator.cookieEnabled) {
this.cookies = new __Cookies(document.cookie);
} else {
this.cookies = false;
}
function ClientStorage(driverName) {
this.data = {};
this.ttlData = {};
var StorageDriver;
this.driverName = driverName;
switch (driver) {
switch (driverName) {
case 'localStorage':
if (this.LSSupport) {
this.ls = window.localStorage || localStorage;
var i = this.ls.length;
var key;
while (i--) {
key = this.ls.key(i);
if ((key.indexOf(TTL_SUFFIX, key.length - TTL_SUFFIX_LENGTH) !== -1) && this.ls.getItem(key) <= Date.now()) {
this.ls.removeItem(key);
this.ls.removeItem(key.replace(TTL_SUFFIX, ''));
}
}
if (BrowserStorage.isSupported()) {
StorageDriver = BrowserStorage;
} else {
console.warn('ClientStorage is set to "localStorage", but it is not supported on this browser');
debug('ClientStorage is set to "localStorage", but it is not supported on this browser');
}
break;
case 'cookies':
if (this.cookies) {
this.LSSupport = false;
this.ls = null;
if (CookiesStorage.isSupported()) {
StorageDriver = CookiesStorage;
} else {
console.warn('ClientStorage is set to "cookies", but Cookies is disabled on this browser');
debug('ClientStorage is set to "cookies", but CookiesStorage is disabled on this browser');
}
break;
case 'js':
this.cookies = false;
this.LSSupport = false;
this.ls = null;
StorageDriver = JSStorage;
this.driverName = 'js';
break;
default:
if (this.LSSupport) {
this.ls = window.localStorage || localStorage;
break;
}
if (!StorageDriver) {
if (BrowserStorage.isSupported()) {
this.driverName = 'localStorage';
StorageDriver = BrowserStorage;
} else if (CookiesStorage.isSupported()) {
this.driverName = 'cookies';
StorageDriver = CookiesStorage;
} else {
this.ls = null;
this.driverName = 'js';
StorageDriver = JSStorage;
}
break;
}
this.driver = new StorageDriver(this, document.cookie);
Object.assign(this, StorageDriver.prototype);
}
/*
* @function
/**
* @locus Client
* @memberOf ClientStorage
* @name get
* @param {String} key - The name of the stored record to read
* @summary Read a record. If the record doesn't exist a null value will be returned.
* @returns {mixed}
* @param {String} key - The key of the value to read
* @summary Read a stored value by key. If the key doesn't exist a void 0 (undefined) value will be returned.
* @returns {String|Mix|void 0}
*/
ClientStorage.prototype.get = function (key) {
if (!this.has(key)) {
if (typeof key !== 'string') {
return void 0;
}
var expireAt = 0;
if (this.LSSupport) {
expireAt = this.__unescape(this.ls.getItem(key + TTL_SUFFIX));
if (expireAt && expireAt <= Date.now()) {
this.ls.removeItem(key);
this.ls.removeItem(key + TTL_SUFFIX);
if (this.data.hasOwnProperty(key)) {
if (this.ttlData[key] <= Date.now()) {
this.remove(key);
return void 0;
}
return this.__unescape(this.ls.getItem(key));
} else if (this.cookies) {
return this.__unescape(this.cookies.get(key));
return this.data[key];
}
expireAt = this._data[key + TTL_SUFFIX];
if (expireAt && expireAt <= Date.now()) {
delete this._data[key];
delete this._data[key + TTL_SUFFIX];
return void 0;
}
return this._data[key];
return void 0;
};
/*
* @function
/**
* @locus Client
* @memberOf ClientStorage
* @name set
* @param {String} key - The name of the key to create/overwrite
* @param {mixed} value - The value
* @param {Number} ttl - [OPTIONAL] Record TTL in seconds
* @summary Create/overwrite a value in storage.
* @name has
* @param {String} key - The name of the record to check
* @summary Check whether a record key is exists
* @returns {Boolean}
*/
ClientStorage.prototype.set = function (key, value, ttl) {
if (this.LSSupport) {
this.ls.setItem(key, this.__escape(value));
if (ttl) {
this.ls.setItem(key + TTL_SUFFIX, +(new Date(Date.now() + (ttl * 1000))));
}
} else if (this.cookies) {
this.cookies.set(key, this.__escape(value), ttl);
} else {
this._data[key] = value;
if (ttl) {
this._data[key + TTL_SUFFIX] = +(new Date(Date.now() + (ttl * 1000)));
}
ClientStorage.prototype.has = function (key) {
if (typeof key !== 'string') {
return false;
}
return true;
};
/*
* @function
* @memberOf ClientStorage
* @name remove
* @param {String} key - The name of the record to create/overwrite
* @summary Remove a record.
* @returns {Boolean}
*/
ClientStorage.prototype.remove = function (key) {
if (key && this.has(key)) {
if (this.LSSupport) {
this.ls.removeItem(key);
this.ls.removeItem(key + TTL_SUFFIX);
return true;
} else if (this.cookies) {
return this.cookies.remove(key);
if (this.data.hasOwnProperty(key)) {
if (this.ttlData[key] <= Date.now()) {
this.remove(key);
return false;
}
delete this._data[key];
delete this._data[key + TTL_SUFFIX];
return true;

@@ -313,47 +110,14 @@ }

/*
* @function
/**
* @locus Client
* @memberOf ClientStorage
* @name has
* @param {String} key - The name of the record to check
* @summary Check if record exists
* @returns {Boolean}
*/
ClientStorage.prototype.has = function (key) {
if (this.LSSupport) {
return !!this.ls.getItem(key);
} else if (this.cookies) {
return this.cookies.has(key);
}
return this._data.hasOwnProperty(key);
};
/*
* @function
* @memberOf ClientStorage
* @name keys
* @summary Returns all storage keys
* @returns {[String]]}
* @summary Returns an array of Strings with all readable keys.
* @returns {[String]}
*/
ClientStorage.prototype.keys = function () {
if (this.LSSupport) {
var i = this.ls.length;
var results = [];
var key;
while (i--) {
key = this.ls.key(i);
if (key.indexOf(TTL_SUFFIX, key.length - TTL_SUFFIX_LENGTH) === -1) {
results.push(this.ls.key(i));
}
}
return results;
} else if (this.cookies) {
return this.cookies.keys();
}
return Object.keys(this._data).filter(function (_key) {
return _key.indexOf(TTL_SUFFIX, _key.length - TTL_SUFFIX_LENGTH) === -1;
});
return Object.keys(this.data);
};
/*
/**
* @function

@@ -366,68 +130,9 @@ * @memberOf ClientStorage

ClientStorage.prototype.empty = function () {
if (this.LSSupport && this.ls.length > 0) {
var self = this;
this.keys().forEach(function (key) {
return self.remove(key);
});
return true;
} else if (this.cookies) {
return this.cookies.remove();
} else if (Object.keys(this._data).length){
this._data = {};
return true;
}
return false;
return this.remove();
};
/*
* @function
* @memberOf ClientStorage
* @name __escape
*/
ClientStorage.prototype.__escape = function (value) {
try {
return JSON.stringify(value);
} catch (e) {
try {
return value.toString();
} catch (err) {
return value;
}
}
};
module.exports.JSStorage = JSStorage;
module.exports.BrowserStorage = BrowserStorage;
module.exports.CookiesStorage = CookiesStorage;
/*
* @function
* @memberOf ClientStorage
* @name __unescape
*/
ClientStorage.prototype.__unescape = function (value) {
try {
return JSON.parse(value);
} catch (e) {
return value;
}
};
/*
* @memberOf ClientStorage
* @name LSSupport
* @summary Test browser for localStorage support
*/
ClientStorage.prototype.LSSupport = (function () {
try {
var support = 'localStorage' in window && window.localStorage !== null;
if (support) {
// Safari will throw an exception in Private mode
window.localStorage.setItem('___test___', 'test');
window.localStorage.removeItem('___test___');
return true;
}
return false;
} catch (e) {
return false;
}
})();
module.exports.clientStorage = ClientStorage;
module.exports.ClientStorage = new ClientStorage();
module.exports.ClientStorage = ClientStorage;
{
"name": "ClientStorage",
"version": "3.0.1",
"version": "4.0.0",
"description": "Bulletproof persistent browser storage, works with disabled Cookies and/or localStorage",

@@ -17,2 +17,3 @@ "main": "./client-storage.js",

"local storage",
"cookie",
"cookies",

@@ -32,2 +33,3 @@ "disabled cookies",

"local storage",
"cookie",
"cookies",

@@ -34,0 +36,0 @@ "disabled cookies",

@@ -1,7 +0,9 @@

# Persistent Client (Browser) Storage
<a href="https://www.patreon.com/bePatron?u=20396046">
<img src="https://c5.patreon.com/external/logo/become_a_patron_button@2x.png" width="160">
[![support](https://img.shields.io/badge/support-GitHub-white)](https://github.com/sponsors/dr-dimitru)
[![support](https://img.shields.io/badge/support-PayPal-white)](https://paypal.me/veliovgroup)
<a href="https://ostr.io/info/built-by-developers-for-developers">
<img src="https://ostr.io/apple-touch-icon-60x60.png" height="20">
</a>
# Persistent Browser (Client) Storage
- 👷 __100% Tests coverage__;

@@ -38,4 +40,12 @@ - 📦 No external dependencies;

var ClientStorage = require('ClientStorage').ClientStorage;
var clientStorage = new ClientStorage();
```
### ES6 Import:
```js
import { ClientStorage } from 'ClientStorage';
const clientStorage = new ClientStorage();
```
### ES6 Import (Meteor):

@@ -45,2 +55,3 @@

import { ClientStorage } from 'meteor/ostrio:cstorage';
const clientStorage = new ClientStorage();
```

@@ -50,35 +61,34 @@

- `ClientStorage.get('key')` - Read a record. If the key doesn't exist a *undefined* value will be returned;
- `clientStorage.get('key')` - Read a record. If the key doesn't exist a *undefined* value will be returned;
- `key` - {*String*} - Record's key;
- `ClientStorage.set('key', value[, ttl])` - Create/overwrite a value in storage;
- `clientStorage.set('key', value[, ttl])` - Create/overwrite a value in storage;
- `key` - {*String*} - Record's key;
- `value` - {*String*|[*mix*]|*Boolean*|*Object*} - Record's value (content);
- `ttl` - {*Number*} — [Optional] Record's TTL in seconds;
- `ClientStorage.remove('key')` - Remove a record;
- `clientStorage.remove('key')` - Remove a record;
- `key` - {*String*} - Record's key;
- `ClientStorage.has('key')` - Check whether a record exists, returns a boolean value;
- `clientStorage.has('key')` - Check whether a record exists, returns a boolean value;
- `key` - {*String*} - Record's key;
- `ClientStorage.keys()` - Returns an array of all storage keys;
- `ClientStorage.empty()` - Empty storage (remove all key/value pairs). __Use with caution! (*May remove cookies which weren't set by you*)__.
- `clientStorage.keys()` - Returns an array of all storage keys;
- `clientStorage.empty()` - Empty storage (remove all key/value pairs). __Use with caution! (*May remove cookies which weren't set by you*)__.
## Alternate usage:
### Use `cookies` only:
By default ClientStorage package handle selecting storage driver in the next order (descending priority):
To use `cookies` as a driver for `ClientStorage` create new instance of `clientStorage` (*camel-case, first letter __lower-case__*):
1. `localStorage`
2. `cookies`
3. `js` (*JS Object driven storage*)
```js
var clientStorage = require('ClientStorage').clientStorage;
var csCookies = new clientStorage('cookies');
csCookies.has('locale'); // false
csCookies.set('locale', 'en_US'); // true
```
To alter priority pass "preferred driver" to `new ClientStorage(driverName)` constructor.
or in ES6 (Meteor):
### Use `cookies` only:
Pass `cookies` as an argument to new instance of `ClientStorage`:
```js
import { clientStorage } from 'meteor/ostrio:cstorage';
const csLocalStorage = new clientStorage('cookies');
csLocalStorage.has('locale'); // false
csLocalStorage.set('locale', 'en_US'); // true
const { clientStorage } = require('ClientStorage');
var cookiesStorage = new ClientStorage('cookies');
cookiesStorage.has('locale'); // false
cookiesStorage.set('locale', 'en_US'); // true
```

@@ -88,18 +98,20 @@

To use `localStorage` as a driver for `ClientStorage` create new instance of `clientStorage` (*camel-case, first letter __lower-case__*):
Pass `localStorage` as an argument to new instance of `ClientStorage`:
```js
var clientStorage = require('ClientStorage').clientStorage;
var csLocalStorage = new clientStorage('localStorage');
csLocalStorage.has('locale'); // false
csLocalStorage.set('locale', 'en_US'); // true
const { clientStorage } = require('ClientStorage');
var locStorage = new ClientStorage('localStorage');
locStorage.has('locale'); // false
locStorage.set('locale', 'en_US'); // true
```
or in ES6 (Meteor):
### Use `js` only:
Pass `js` (*in-memory js object*) as an argument to new instance of `ClientStorage`:
```js
import { clientStorage } from 'meteor/ostrio:cstorage';
const csLocalStorage = new clientStorage('localStorage');
csLocalStorage.has('locale'); // false
csLocalStorage.set('locale', 'en_US'); // true
const { clientStorage } = require('ClientStorage');
var jsStorage = new ClientStorage('js');
jsStorage.has('locale'); // false
jsStorage.set('locale', 'en_US'); // true
```

@@ -111,12 +123,15 @@

Persistent `ReactiveVar` implementation:
```js
import { ReactiveVar } from 'meteor/reactive-var';
import { ReactiveVar } from 'meteor/reactive-var';
import { ClientStorage } from 'meteor/ostrio:cstorage';
const clientStorage = new ClientStorage();
const persistentReactive = (name, initial = false) => {
const persistentReactive = (name, initial = undefined) => {
let reactive;
if (ClientStorage.has(name)) {
reactive = new ReactiveVar(ClientStorage.get(name));
if (clientStorage.has(name)) {
reactive = new ReactiveVar(clientStorage.get(name));
} else {
ClientStorage.set(name, initial);
clientStorage.set(name, initial);
reactive = new ReactiveVar(initial);

@@ -131,3 +146,3 @@ }

reactive.curValue = newValue;
ClientStorage.set(name, newValue);
clientStorage.set(name, newValue);
reactive.dep.changed();

@@ -139,5 +154,5 @@ };

const UILayout = persistentReactive('UILayout', 'two-columns');
UILayout.get(); // two-columns
UILayout.set('single-column');
const layout = persistentReactive('ui-layout', 'two-columns');
layout.get(); // two-columns
layout.set('single-column');
```

@@ -148,24 +163,24 @@

```js
var ClientStorage = require('ClientStorage').ClientStorage;
const clientStorage = new (require('ClientStorage').ClientStorage);
ClientStorage.set('locale', 'en'); // true
ClientStorage.set('country', 'usa'); // true
ClientStorage.set('gender', 'male'); // true
clientStorage.set('locale', 'en'); // true
clientStorage.set('country', 'usa'); // true
clientStorage.set('gender', 'male'); // true
ClientStorage.get('gender'); // male
clientStorage.get('gender'); // male
ClientStorage.has('locale'); // true
ClientStorage.has('city'); // false
clientStorage.has('locale'); // true
clientStorage.has('city'); // false
ClientStorage.keys(); // ['locale', 'country', 'gender']
clientStorage.keys(); // ['locale', 'country', 'gender']
ClientStorage.remove('locale'); // true
ClientStorage.get('locale'); // undefined
clientStorage.remove('locale'); // true
clientStorage.get('locale'); // undefined
ClientStorage.keys(); // ['country', 'gender']
clientStorage.keys(); // ['country', 'gender']
ClientStorage.empty(); // true
ClientStorage.keys(); // []
clientStorage.empty(); // true
clientStorage.keys(); // []
ClientStorage.empty(); // false
clientStorage.empty(); // false
```

@@ -194,3 +209,4 @@

- [Become a patron](https://www.patreon.com/bePatron?u=20396046) — support my open source contributions with monthly donation
- [Sponsor via GitHub](https://github.com/sponsors/dr-dimitru)
- [Support via PayPal](https://paypal.me/veliovgroup)
- Use [ostr.io](https://ostr.io) — [Monitoring](https://snmp-monitoring.com), [Analytics](https://ostr.io/info/web-analytics), [WebSec](https://domain-protection.info), [Web-CRON](https://web-cron.info) and [Pre-rendering](https://prerendering.com) for a website

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc