Skip to content

Instantly share code, notes, and snippets.

@ovcharik
Created January 11, 2018 14:03
Show Gist options
  • Save ovcharik/a208bd5731ef1e28a5f08544905a137e to your computer and use it in GitHub Desktop.
Save ovcharik/a208bd5731ef1e28a5f08544905a137e to your computer and use it in GitHub Desktop.
Cookie storage with chunks
const cookieStorage = {
get COOKIE() { return window.document.cookie; },
set COOKIE(v: string) { window.document.cookie = v; },
get ITEMS(): { [key: string]: string } {
return this.COOKIE
.split(/;\s*/)
.filter(Boolean)
.map(s => s.match(/^([^=]+)=(.*)$/))
.reduce((mem, [str, key, value]) => {
mem[key] = decodeURIComponent(value);
return mem;
}, {});
},
get DEFAULT_OPTIONS() {
const nextYear = new Date();
nextYear.setFullYear(nextYear.getFullYear() + 1);
return {
path: '/',
domain: window.location.hostname,
expires: nextYear,
};
},
get DEFAULT_CHUNK() {
return {
size: 4000,
maxCount: 10,
};
},
_getOptionsString(options: { path?: string, domain?: string, expires?: Date|number } = {}) {
const opts = Object.assign(this.DEFAULT_OPTIONS, options) as {
path: string,
domain: string,
expires?: Date|number|string,
};
if (typeof opts.expires === 'number')
opts.expires = (opts.expires !== 0) ? new Date(opts.expires) : undefined;
if (opts.expires instanceof Date)
opts.expires = opts.expires.toUTCString();
return Object.keys(opts)
.filter(key => Boolean(opts[key]))
.map(key => `${key}=${opts[key]}`)
.join('; ');
},
getItem(key: string) {
return this.ITEMS[key];
},
setItem(
key: string,
value: string,
options: { path?: string, domain?: string, expires?: Date|number } = {}
) {
const optionsString = this._getOptionsString(options);
const encoded = encodeURIComponent(value);
if (encoded.length > this.DEFAULT_CHUNK.size) {
console.warn('Cookie limit is 4 KB.');
}
this.COOKIE = `${key}=${encodeURIComponent(value)}; ${optionsString}`;
},
removeItem(key: string) {
this.setItem(key, '', { expires: -1 });
},
setItemByChunks(
key: string,
value: string,
options: { path?: string, domain?: string, expires?: Date|number } = {},
chunkOptions: { size?: number, maxCount?: number } = {}
) {
const { size: chunkSize, maxCount: chunkMaxCount } = Object.assign(this.DEFAULT_CHUNK, chunkOptions) as {
size: number,
maxCount: number,
};
const optionsString = this._getOptionsString(options);
encodeURIComponent(value)
.match(/(%.{2}|.)/g)
.reduce((chunks, symbol) => {
let lastIndex = chunks.length - 1;
let lastChunk = chunks[lastIndex];
if ((lastChunk.length + symbol.length) > chunkSize) {
lastIndex += 1;
lastChunk = '';
}
chunks[lastIndex] = lastChunk + symbol;
return chunks;
}, [''])
.forEach((chunk, index) => {
this.COOKIE = `${key}-${index}=${chunk}; ${optionsString}`;
});
},
getItemByChunks(key: string) {
const items = this.ITEMS;
return Object
.keys(items)
.map(k => k.match(/(^.*?)\-(\d+$)/))
.filter(Boolean)
.filter(([k, name, index]) => name === key)
.map(([k, name, index]) => index)
.map(Number)
.sort()
.reduce((result, index) => result + items[`${key}-${index}`], '');
},
removeItemByChunks(key: string) {
Object
.keys(this.ITEMS)
.map(k => k.match(/(^.*?)\-(\d+$)/))
.filter(Boolean)
.filter(([k, name]) => name === key)
.forEach(([k]) => this.removeItem(k));
},
clear() {
Object
.keys(this.ITEMS)
.forEach(key => this.removeItem(key));
},
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment