Skip to content

Commit 902427e

Browse files
committed
Added the 'options' parameter to the API method 'removeItem()', in order to allow passing metadata to the cookie to delete.
- Checks if the cookie was created on 'setItem()', or delete it if the domain or path are not valid.
1 parent 42ea67e commit 902427e

File tree

9 files changed

+125
-55
lines changed

9 files changed

+125
-55
lines changed

CHANGELOG.md

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,21 @@
22

33
<!-- markdownlint-disable MD024 MD033 -->
44

5+
## 2.1.2
6+
7+
### Improvements
8+
9+
1. Added the `options` parameter to the API method `removeItem()`, in order to allow passing metadata to the cookie to delete.
10+
When using `"cookieStorage"` the new signature is: `instance.removeItem(key, options)`
11+
1. Checks if the cookie was created on `setItem()`, or delete it if the domain or path are not valid.
12+
13+
---
14+
515
## 2.1.1
616

717
### Fixes
818

9-
1. [#4](https://github.com/jherax/proxy-storage/issues/4):
10-
Removing cookies are failing when the domain or path were set in the cookie.
19+
1. [#4](https://github.com/jherax/proxy-storage/issues/4): Removing cookies are failing when the `domain` or `path` were set in the cookie.
1120
1. `setItem`: prevents converting strings values to JSON to avoid extra quotes.
1221

1322
---

README.md

Lines changed: 31 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ $ yarn add proxy-storage
5959
<script src="https://unpkg.com/proxy-storage/dist/proxy-storage.min.js"></script>
6060

6161
<!-- or from rawgit.com -->
62-
<script src="https://cdn.rawgit.com/jherax/proxy-storage/2.1.1/dist/proxy-storage.min.js"></script>
62+
<script src="https://cdn.rawgit.com/jherax/proxy-storage/2.1.2/dist/proxy-storage.min.js"></script>
6363
```
6464

6565
In the above case, [`proxyStorage`](#api) is included as a global object
@@ -153,7 +153,9 @@ It inherits the following members from the `WebStorage` prototype:
153153
<br>The `options` parameter is used only when you set `"cookieStorage"`.
154154
Read more details [here](#handling-cookies).
155155
- **`getItem`**`(key)`: retrieves a value by its `key` name.
156-
- **`removeItem`**`(key)`: deletes an item from the storage.
156+
- **`removeItem`**`(key [,options])`: deletes an item from the storage.
157+
<br>The `options` parameter is used only when you set `"cookieStorage"`.
158+
Read more details [here](#handling-cookies).
157159
- **`clear`**`()`: removes all items from the storage instance.
158160
- **`length`**: gets the number of items stored in the storage instance.
159161

@@ -234,7 +236,9 @@ Each instance handles an adapter with the following API:
234236
<br>The `options` parameter is used only when you set `"cookieStorage"`.
235237
Read more details [here](#handling-cookies).
236238
- **`getItem`**`(key)`: retrieves a value by its `key` name.
237-
- **`removeItem`**`(key)`: deletes an item from the storage.
239+
- **`removeItem`**`(key [,options])`: deletes an item from the storage.
240+
<br>The `options` parameter is used only when you set `"cookieStorage"`.
241+
Read more details [here](#handling-cookies).
238242
- **`clear`**`()`: removes all items from the storage instance.
239243
- **`length`**: gets the number of items stored in the storage instance.
240244

@@ -253,7 +257,7 @@ const sessionStore = new WebStorage('sessionStorage');
253257
sessionStore.setItem('character', { name: 'Mordecai' });
254258

255259
// store in cookies
256-
const options = { expires: {days:1} };
260+
const options = { expires: {days: 1} };
257261
const cookieStore = new WebStorage('cookieStorage');
258262
cookieStore.setItem('character', { name: 'Rigby' }, options);
259263
```
@@ -341,7 +345,8 @@ cookieStore.setItem('testing3', 3, {
341345

342346
**Important**: Take into account that if you want to modify or remove a cookie
343347
that was created with a specific `path` or `domain` / subdomain, you need to
344-
explicitate the domain attribute in `setItem(key, value, options)`.
348+
explicitate the domain attribute in the `options` when calling
349+
`setItem(key, value, options)` or `removeItem(key, options)`.
345350

346351
![cookies](https://www.dropbox.com/s/wlvgm0t8xc07me1/cookies-metadata.gif?dl=1)
347352

@@ -359,9 +364,8 @@ cookieStore.setItem('landedAnswers', 999, {
359364
});
360365

361366
// remove an external cookie in a subdomain
362-
cookieStore.setItem('optimizelyEndUserId', '', {
367+
cookieStore.removeItem('optimizelyEndUserId', {
363368
domain: '.healthcare.org',
364-
expires: {days: -1}, // trick!
365369
});
366370
```
367371

@@ -443,7 +447,7 @@ the _value_ passed and returned in each callback.
443447
import storage, { WebStorage } from 'proxy-storage';
444448

445449
// adds first interceptor for 'setItem'
446-
WebStorage.interceptors('setItem', (key, value) => {
450+
WebStorage.interceptors('setItem', (key, value/*, options*/) => {
447451
if (key === 'storage-test') {
448452
// transform the 'id' property by encoding it to base64
449453
value.id = btoa(value.id);
@@ -454,7 +458,7 @@ WebStorage.interceptors('setItem', (key, value) => {
454458
// adds second interceptor for 'setItem'
455459
WebStorage.interceptors('setItem', (key, value) => {
456460
// does not apply any transformation
457-
console.info('setItem: See the localStorage in your browser');
461+
console.info('setItem: See the application storage in your browser');
458462
console.log(`${key}: ${JSON.stringify(value)}`);
459463
});
460464

@@ -467,7 +471,7 @@ WebStorage.interceptors('getItem', (key, value) => {
467471
return value;
468472
});
469473

470-
WebStorage.interceptors('removeItem', (key) => {
474+
WebStorage.interceptors('removeItem', (key/*, options*/) => {
471475
console.log(`removeItem: ${key}`);
472476
});
473477

@@ -552,20 +556,29 @@ console.log('in memoryStorage', data);
552556

553557
## Shimming-polyfills
554558

555-
<!-- TODO: Add polyfill.io -->
556-
557559
This library is written using some of the new ES6 features, e.g.
558-
`Object.assign()`. If your target browsers does not have support,
559-
you can polyfill some of the ES2015 features with the next alternatives:
560+
`Object.assign()`. If you have to support Non-standard-compliant browsers
561+
(e.g. Internet Explorer), you can polyfill some of the ES2015 features with
562+
the following alternatives:
560563

561-
The reason is because this library use some of the new features in ES5-ES6.
562-
To overcome this problem, you may include in your project the
563-
[es6-shim](https://github.com/paulmillr/es6-shim) script before all scripts.
564+
**[es6-shim](https://github.com/paulmillr/es6-shim)**
564565

565566
```html
566-
<script src="https://cdnjs.cloudflare.com/ajax/libs/es6-shim/0.35.1/es6-shim.min.js"></script>
567+
<!-- put this script FIRST, before all other scripts -->
568+
<script src="https://cdnjs.cloudflare.com/ajax/libs/es6-shim/0.35.3/es6-shim.min.js"></script>
567569
```
568570

571+
**[polyfill.io](https://polyfill.io/v2/docs/)**
572+
573+
```html
574+
<!-- put this script FIRST, before all other scripts -->
575+
<script src="https://cdn.polyfill.io/v2/polyfill.min.js"></script>
576+
```
577+
578+
[Polyfill.io](https://polyfill.io/v2/docs/examples) reads the `User-Agent`
579+
header of each request and returns the polyfills that are suitable for the
580+
requesting browser.
581+
569582
## Running the project
570583

571584
If you want to fork or build your own, you must run this project.

dist/proxy-storage.js

Lines changed: 40 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/*! proxyStorage@v2.1.1. Jherax 2017. Visit https://github.com/jherax/proxy-storage */
1+
/*! proxyStorage@v2.1.2. Jherax 2017. Visit https://github.com/jherax/proxy-storage */
22
(function webpackUniversalModuleDefinition(root, factory) {
33
if(typeof exports === 'object' && typeof module === 'object')
44
module.exports = factory();
@@ -150,7 +150,7 @@ function setProperty(obj, name, value) {
150150

151151
/**
152152
* Validates if the key is not empty.
153-
* (null, undefined either empty string)
153+
* (null, undefined or empty string)
154154
*
155155
* @param {string} key: keyname of an element in the storage mechanism
156156
* @return {void}
@@ -231,6 +231,15 @@ var _interceptors = {
231231
clear: []
232232
};
233233

234+
/**
235+
* @private
236+
*
237+
* Keys not allowed for cookies.
238+
*
239+
* @type {RegExp}
240+
*/
241+
var bannedKeys = /^(?:expires|max-age|path|domain|secure)$/i;
242+
234243
/**
235244
* @private
236245
*
@@ -376,14 +385,20 @@ var WebStorage = function () {
376385
key: 'setItem',
377386
value: function setItem(key, value, options) {
378387
(0, _utils.checkEmpty)(key);
388+
var storageType = this.__storage__;
389+
if (storageType === 'cookieStorage' && bannedKeys.test(key)) {
390+
throw new Error('The key is a reserved word, therefore not allowed');
391+
}
379392
var v = executeInterceptors('setItem', key, value, options);
380393
if (v !== undefined) value = v;
381394
this[key] = value;
382395
// prevents converting strings to JSON to avoid extra quotes
383396
if (typeof value !== 'string') value = JSON.stringify(value);
384-
// TODO: should add setTimeout for options.expires?
385-
// TODO: prevent adding cookies when the domain or path are not valid?
386-
_proxyMechanism.proxy[this.__storage__].setItem(key, value, options);
397+
_proxyMechanism.proxy[storageType].setItem(key, value, options);
398+
// checks if the cookie was created, or delete it if the domain or path are not valid
399+
if (storageType === 'cookieStorage' && _proxyMechanism.proxy[storageType].getItem(key) === null) {
400+
delete this[key];
401+
}
387402
}
388403

389404
/**
@@ -416,18 +431,19 @@ var WebStorage = function () {
416431
* Deletes a key from the storage.
417432
*
418433
* @param {string} key: keyname of the storage
434+
* @param {object} options: additional options for cookieStorage
419435
* @return {void}
420436
*
421437
* @memberOf WebStorage
422438
*/
423439

424440
}, {
425441
key: 'removeItem',
426-
value: function removeItem(key) {
442+
value: function removeItem(key, options) {
427443
(0, _utils.checkEmpty)(key);
428-
executeInterceptors('removeItem', key);
444+
executeInterceptors('removeItem', key, options);
429445
delete this[key];
430-
_proxyMechanism.proxy[this.__storage__].removeItem(key);
446+
_proxyMechanism.proxy[this.__storage__].removeItem(key, options);
431447
}
432448

433449
/**
@@ -542,11 +558,19 @@ function buildExpirationString(date) {
542558
return expires.toUTCString();
543559
}
544560

545-
// @private
546-
var buildStringFor = function buildStringFor(key, data) {
561+
/**
562+
* @private
563+
*
564+
* Builds the string for the cookie's metadata.
565+
*
566+
* @param {string} key: name of the metadata
567+
* @param {object} data: metadata of the cookie
568+
* @return {string}
569+
*/
570+
function buildMetadataFor(key, data) {
547571
if (!data[key]) return '';
548572
return '; ' + key + '=' + data[key];
549-
};
573+
}
550574

551575
/**
552576
* @private
@@ -583,9 +607,9 @@ function cookieStorage() {
583607
if (options.domain && typeof options.domain === 'string') {
584608
metadata.domain = options.domain.trim();
585609
}
586-
var expires = buildStringFor('expires', metadata);
587-
var domain = buildStringFor('domain', metadata);
588-
var path = buildStringFor('path', metadata);
610+
var expires = buildMetadataFor('expires', metadata);
611+
var domain = buildMetadataFor('domain', metadata);
612+
var path = buildMetadataFor('path', metadata);
589613
var cookie = key + '=' + encodeURIComponent(value) + expires + domain + path;
590614
$cookie.set(cookie);
591615
},
@@ -601,8 +625,8 @@ function cookieStorage() {
601625
if (value === null) delete $cookie.data[key];
602626
return value;
603627
},
604-
removeItem: function removeItem(key) {
605-
var metadata = Object.assign({}, $cookie.data[key]);
628+
removeItem: function removeItem(key, options) {
629+
var metadata = Object.assign({}, $cookie.data[key], options);
606630
metadata.expires = { days: -1 };
607631
api.setItem(key, '', metadata);
608632
delete $cookie.data[key];

dist/proxy-storage.min.js

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/proxy-storage.min.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "proxy-storage",
3-
"version": "2.1.1",
3+
"version": "2.1.2",
44
"description": "Storage mechanism that implements the Web Storage interface",
55
"author": "David Rivera <jherax@gmail.com>",
66
"main": "dist/proxy-storage.js",

src/cookie-storage.js

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -37,11 +37,19 @@ function buildExpirationString(date) {
3737
return expires.toUTCString();
3838
}
3939

40-
// @private
41-
const buildStringFor = (key, data) => {
40+
/**
41+
* @private
42+
*
43+
* Builds the string for the cookie's metadata.
44+
*
45+
* @param {string} key: name of the metadata
46+
* @param {object} data: metadata of the cookie
47+
* @return {string}
48+
*/
49+
function buildMetadataFor(key, data) {
4250
if (!data[key]) return '';
4351
return `; ${key}=${data[key]}`;
44-
};
52+
}
4553

4654
/**
4755
* @private
@@ -78,9 +86,9 @@ export default function cookieStorage() {
7886
if (options.domain && typeof options.domain === 'string') {
7987
metadata.domain = options.domain.trim();
8088
}
81-
const expires = buildStringFor('expires', metadata);
82-
const domain = buildStringFor('domain', metadata);
83-
const path = buildStringFor('path', metadata);
89+
const expires = buildMetadataFor('expires', metadata);
90+
const domain = buildMetadataFor('domain', metadata);
91+
const path = buildMetadataFor('path', metadata);
8492
const cookie = `${key}=${encodeURIComponent(value)}${expires}${domain}${path}`;
8593
$cookie.set(cookie);
8694
},
@@ -98,8 +106,8 @@ export default function cookieStorage() {
98106
return value;
99107
},
100108

101-
removeItem(key) {
102-
const metadata = Object.assign({}, $cookie.data[key]);
109+
removeItem(key, options) {
110+
const metadata = Object.assign({}, $cookie.data[key], options);
103111
metadata.expires = {days: -1};
104112
api.setItem(key, '', metadata);
105113
delete $cookie.data[key];

src/utils.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ export function setProperty(obj, name, value) {
5555

5656
/**
5757
* Validates if the key is not empty.
58-
* (null, undefined either empty string)
58+
* (null, undefined or empty string)
5959
*
6060
* @param {string} key: keyname of an element in the storage mechanism
6161
* @return {void}

src/web-storage.js

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,15 @@ const _interceptors = {
2525
clear: [],
2626
};
2727

28+
/**
29+
* @private
30+
*
31+
* Keys not allowed for cookies.
32+
*
33+
* @type {RegExp}
34+
*/
35+
const bannedKeys = /^(?:expires|max-age|path|domain|secure)$/i;
36+
2837
/**
2938
* @private
3039
*
@@ -159,14 +168,20 @@ class WebStorage {
159168
*/
160169
setItem(key, value, options) {
161170
checkEmpty(key);
171+
const storageType = this.__storage__;
172+
if (storageType === 'cookieStorage' && bannedKeys.test(key)) {
173+
throw new Error('The key is a reserved word, therefore not allowed');
174+
}
162175
const v = executeInterceptors('setItem', key, value, options);
163176
if (v !== undefined) value = v;
164177
this[key] = value;
165178
// prevents converting strings to JSON to avoid extra quotes
166179
if (typeof value !== 'string') value = JSON.stringify(value);
167-
// TODO: should add setTimeout for options.expires?
168-
// TODO: prevent adding cookies when the domain or path are not valid?
169-
proxy[this.__storage__].setItem(key, value, options);
180+
proxy[storageType].setItem(key, value, options);
181+
// checks if the cookie was created, or delete it if the domain or path are not valid
182+
if (storageType === 'cookieStorage' && proxy[storageType].getItem(key) === null) {
183+
delete this[key];
184+
}
170185
}
171186

172187
/**
@@ -196,15 +211,16 @@ class WebStorage {
196211
* Deletes a key from the storage.
197212
*
198213
* @param {string} key: keyname of the storage
214+
* @param {object} options: additional options for cookieStorage
199215
* @return {void}
200216
*
201217
* @memberOf WebStorage
202218
*/
203-
removeItem(key) {
219+
removeItem(key, options) {
204220
checkEmpty(key);
205-
executeInterceptors('removeItem', key);
221+
executeInterceptors('removeItem', key, options);
206222
delete this[key];
207-
proxy[this.__storage__].removeItem(key);
223+
proxy[this.__storage__].removeItem(key, options);
208224
}
209225

210226
/**

0 commit comments

Comments
 (0)