UNPKG

supercookie

Version:

A tool for managing and creating the most versatile cookies ever seen without all the fuss.

604 lines 25.9 kB
var __rest = (this && this.__rest) || function (s, e) { var t = {}; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) t[p] = s[p]; if (s != null && typeof Object.getOwnPropertySymbols === "function") for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) { if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) t[p[i]] = s[p[i]]; } return t; }; var _a; const SCOptions = ["domain", "expires", "name", "partitioned", "path", "sameSite", "secure", "value", "preserveFalsyExpirations", "onReady"]; class SuperCookie { constructor(nameOrParameters, valueOrParameters, parameters) { var _b; this.__pVals = {}; this.ready = false; this.__formatter = { superCookie: new Proxy((() => { }), { apply: (t, thisArg, [v, options]) => { const { preserveFalsyExpirations = this.preserveFalsyExpirations } = options || {}; return _a.__formatter.superCookie(v, { preserveFalsyExpirations }); }, get: (t, p, r) => { return _a.__formatter.superCookie[p]; } }), cookie: new Proxy((() => { }), { apply: (t, thisArg, [v, options]) => { const { preserveFalsyExpirations = this.preserveFalsyExpirations } = options || {}; return _a.__formatter.cookie(v, { preserveFalsyExpirations }); }, get: (t, p, r) => { return _a.__formatter.cookie[p]; } }) }; this.asObject = () => (Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({ name: this.name, value: this.value }, (this.domain !== undefined ? { domain: this.domain } : {})), (this.expires !== undefined ? { expires: this.expires } : {})), (this.path !== undefined ? { path: this.path } : {})), (this.sameSite !== undefined ? { sameSite: this.sameSite } : {})), (this.secure !== undefined ? { secure: this.secure } : {}))); this.copy = (name) => { return new _a(this.parameters); }; this.delete = () => { return _a.delete(this.name, { path: this.path, domain: this.domain }); }; this.deleteSync = () => this.setSync({ expires: null }); this.equals = (cookie) => _a.equals(this, cookie); this.get = () => this.ready ? _a.get(this.name, { preserveFalsyExpirations: this.preserveFalsyExpirations }) : new Promise((res) => { res(this.getSync()); }); this.getSync = () => _a.getSync(this.name); this.toString = () => { const params = [`${this.name}=${this.value}`, this.expires && `expires=${this.expires}`, this.path && `path=${this.path}`, this.domain && `domain=${this.domain}`]; if (this.secure) { params.unshift('__Secure-'); } if (this.sameSite !== undefined) { params.push(`SameSite=${this.sameSite}`); } return params.filter((a) => a).join('; '); }; this.__prune = (...args) => { let superCookie = this.asObject(); for (const key of args) { delete superCookie[key]; } return superCookie; }; const _c = _a.__sortFromArgs(nameOrParameters, valueOrParameters, parameters), { name, value } = _c, params = __rest(_c, ["name", "value"]); if (!name) { throw `SuperCookie always requires a name value.`; } const curr = _a.__getAllSimpleSync()[name]; if (!value && !curr) { throw `SuperCookie must have a value or be an existing cookie.`; } this.__pVals = _a.__formatter.superCookie(value ? Object.assign({ name, value }, params) : Object.assign(Object.assign(Object.assign(Object.assign({}, curr), (value ? { value } : {})), params), (this.preserveFalsyExpirations === undefined ? {} : { preserveFalsyExpirations: params.preserveFalsyExpirations }))); this.set = this.set.bind(this); this.onReady = (_b = params.onReady) === null || _b === void 0 ? void 0 : _b.bind(this); _a.get(name, { preserveFalsyExpirations: params.preserveFalsyExpirations }).then((cookie) => { if (cookie && cookie.expires === null) { delete cookie.expires; } if (!cookie || !this.equals(cookie)) { this.set(Object.assign(Object.assign({}, cookie), this.parameters())).then(() => { var _b; (_b = this.__theThenValue) === null || _b === void 0 ? void 0 : _b.call(this, this); this.__thenHolder = null; this.addEventListener((event) => { if (this.ready && !this.equals(event.change)) { this.__pVals = _a.__formatter.superCookie(Object.assign(Object.assign({}, event.change), { preserveFalsyExpirations: this.preserveFalsyExpirations })); } }); }).catch(err => { throw (err === null || err === void 0 ? void 0 : err.message) ? err.message : err; }); } }).catch(err => { console.error((err === null || err === void 0 ? void 0 : err.message) || err); }); if (!name) { } } get name() { return String(this.parameters.name); } set name(value) { throw "name is a read only attribute"; } get value() { return this.parameters.value; } set value(value) { this.parameters.value = value; } get domain() { return this.parameters.domain; } set domain(value) { this.parameters.domain = value; } get expires() { return this.parameters.expires; } set expires(value) { this.parameters.expires = value; } get partitioned() { return this.parameters.partitioned; } set partitioned(v) { this.parameters.partitioned = v; } get path() { return this.parameters.path; } set path(value) { this.parameters.path = value; } get sameSite() { return this.parameters.sameSite; } set sameSite(sameSite) { this.parameters.sameSite = sameSite; } get secure() { return this.parameters.secure; } set secure(value) { this.parameters.secure = value; } get cookie() { return this.__formatter.cookie(this.__pVals); } set cookie(v) { throw "cookie is readonly"; } get parameters() { return new Proxy(() => this.__pVals, { apply: (t, thisArg, args) => { return this.__pVals; }, get: (t, p, r) => { return this.__pVals[p]; }, set: (t, p, v, r) => { const val = _a.__formatter.superCookie[p](v, this.preserveFalsyExpirations); this.ready = false; switch (p) { case 'expires': this.__pVals.expires = this.__formatter.superCookie.expires(val); break; case 'preserveFalsyExpirations': case 'partitioned': case "secure": this.__pVals[p] = val; break; case 'name': case 'domain': case 'path': this.__pVals[p] = val; break; case 'value': this.__pVals.value = val; break; case 'onReady': this.onReady = val; break; case 'sameSite': this.sameSite = val; break; default: console.error(`Invalid parameter ${p} submitted to SuperCookie.parameters`); } this.get().then(curr => { if (!this.equals(curr)) { this.set().then(() => { var _b; this.ready = true; (_b = this.onReady) === null || _b === void 0 ? void 0 : _b.call(this); }); } }); return true; } }); } set parameters(parameters) { this.__pVals = this.__formatter.superCookie(parameters); if (this.ready) { this.ready = false; this.get().then((cookie) => { if (!this.equals(cookie)) { this.set().then(() => { var _b; this.ready = true; (_b = this.onReady) === null || _b === void 0 ? void 0 : _b.call(this); }); } }); } } get __theThenValue() { if (this.__thenHolder === null) { throw "then has already been retrieved. SuperCookie.then should never be retrieved outside of internal processes."; } return this.__thenHolder; } set then(v) { throw "then is read only"; } get __listeners() { return _a.__listeners; } set __theThenValue(func) { if (this.__thenHolder === null) { throw "Then has already been returned. Cannot set the then function now."; } this.__thenHolder = func; } addEventListener(listener) { var _b; const l = (evt) => { const changed = evt.changed.map(v => _a.__formatter.superCookie(v)); const change = changed.find(v => _a.equals({ name: this.name, path: this.path }, { name: v.name, path: v.path })); if (!change) { return; } const e = new Proxy(evt, { get: (t, path, r) => { const p = path; switch (p) { case 'change': return change; case 'changed': return changed; default: return typeof t[p] === 'function' ? t[p].bind(t) : t[p]; } } }); listener(e); }; this.__listeners.set(listener, l); (_b = _a.__cookieStore) === null || _b === void 0 ? void 0 : _b.addEventListener('change', l); } removeEventListener(listener) { var _b; const val = this.__listeners.get(listener); this.__listeners.delete(listener); (_b = _a.__cookieStore) === null || _b === void 0 ? void 0 : _b.removeEventListener('change', val); } set(valueOrParameters, parameters) { this.ready = false; if (!valueOrParameters) { valueOrParameters = this.__prune('name'); } else if (!parameters) { parameters = typeof valueOrParameters === 'object' && Object.keys(valueOrParameters).every(v => SCOptions.includes(v)) ? undefined : this.__prune('name', 'value'); } let _b = _a.__sortFromArgs(this.parameters.name, valueOrParameters, parameters), { name, value = this.value } = _b, params = __rest(_b, ["name", "value"]); return new Promise((res, rej) => { _a.set(name, value, params).then(v => { var _b; this.ready = true; (_b = this.onReady) === null || _b === void 0 ? void 0 : _b.call(this); this.get().then(v => { if (!v) { console.log('This cookie has been deleted.'); this.__pVals = { name: this.name }; } else { this.__pVals = Object.assign(Object.assign(Object.assign({}, v), (this.onReady ? { onReady: this.onReady } : {})), (this.preserveFalsyExpirations ? { preserveFalsyExpirations: this.preserveFalsyExpirations } : {})); } res(true); }); }); }); } setSync(valueOrParameters, parameters) { _a.setSync(this.name, valueOrParameters, parameters); } get then() { if (this.ready) { throw "SuperCookie.prototype.then can only be utilized before the SuperCookie is in ready state."; } else { return (func) => { this.__theThenValue = () => { func(this); }; }; } } static addEventListener(listener) { var _b; const val = (evt) => { listener(new Proxy(evt, { get: (t, key, r) => { if (key === 'changed') { return evt.changed.map(v => this.__formatter.superCookie(v)); } else { return typeof evt[key] === 'function' ? evt[key].bind(evt) : evt[key]; } } })); }; this.__listeners.set(listener, val); (_b = _a.__cookieStore) === null || _b === void 0 ? void 0 : _b.addEventListener('change', val); } static copy(name, newName, { preserveFalsyExpirations } = {}) { return _a.get(name).then(({ domain, expires, partitioned, path, sameSite, value, secure }) => new _a(newName, { domain, expires, partitioned, path, sameSite, secure, value, preserveFalsyExpirations })); } static delete(name, pathOrPathAndDomain) { const { path, domain } = pathOrPathAndDomain ? typeof pathOrPathAndDomain === 'string' ? { path: pathOrPathAndDomain } : pathOrPathAndDomain : {}; const options = Object.assign(Object.assign({ name }, (path === undefined ? {} : { path })), (domain === undefined ? {} : { domain })); this.__cookieStore.delete(options); } static get(name, options) { return new Promise(res => { this.getAll(options).then(cookies => { res(cookies.find(v => v.name === name) || null); }); }); } static getAll(options) { return new Promise((res, rej) => { _a.__cookieStore.getAll().then((cookies) => { const processed = cookies.map((cookie) => { for (const i in cookie) { if (cookie[i] === null) { delete cookie[i]; } } return this.__formatter.superCookie(cookie, options); }); res(processed); }).catch((err) => { rej({ message: (err === null || err === void 0 ? void 0 : err.message) || err }); }); }); } static removeEventListener(listener) { return _a.__cookieStore.removeEventListener('change', listener); } static set(nameOrParameters, valueOrParameters, parameters) { const _b = this.__sortFromArgs(nameOrParameters, valueOrParameters, parameters), { name, value } = _b, params = __rest(_b, ["name", "value"]); const cookieStyle = _a.__formatter.cookie(Object.assign({ name, value }, params)); const size = new Blob([`${cookieStyle.name}=${cookieStyle.value}`]).size; if (size >= 4096) { throw "Your cookie is too large! Setting it would result in serious problems!"; } if (size > 3800) { console.warn(`Your cookie is ${size} bytes, which is approaching the maximum of 4096 bytes. Consider refactoring this cookie.`); } return _a.__cookieStore.set(cookieStyle); } static setSync(nameOrParameters, valueOrParameters, parameters) { const _b = this.__formatter.cookie(this.__sortFromArgs(nameOrParameters, valueOrParameters, parameters)), { name, value } = _b, params = __rest(_b, ["name", "value"]); if (name && value) { let cookieString = name + '=' + encodeURIComponent(value) + ';'; if (params) { const theParams = _a.__formatter.cookie(params); for (const i in theParams) { if (![undefined, null].includes(theParams[i])) { switch (i) { case 'expires': cookieString += ` expires=${theParams.expires};`; break; case 'path': cookieString += ` path=${theParams.path};`; break; case 'secure': cookieString += theParams.secure ? ' secure;' : ""; break; case 'sameSite': cookieString += ` samesite=${theParams.sameSite};`; break; case 'domain': cookieString += ` domain=${theParams.domain};`; break; case 'partitioned': cookieString += theParams.partitioned ? ' partitioned;' : ""; break; } } } } document.cookie = cookieString; } else { throw 'TypeError: Requires both name and value arguments'; } } static get __cookieStore() { return typeof window === 'undefined' ? null : window.cookieStore || null; } static get __dCookie() { return typeof window === 'undefined' ? null : window.document.cookie; } } _a = SuperCookie; SuperCookie.__listeners = new Map(); SuperCookie.getSync = (cookieName, options) => { const { name, value } = _a.getAllSync(options).find(v => v.name === cookieName); return { name, value }; }; SuperCookie.getAllSync = (options) => { return _a.__dCookie.split(';').map((v) => { const [tname, tvalue] = v.trim().split('='); const { name, value } = _a.__formatter.superCookie({ name: tname, value: tvalue }, options); return { name, value }; }); }; SuperCookie.equals = (cookie1, cookie2) => { cookie1 = cookie1 instanceof _a ? cookie1.asObject() : _a.__formatter.superCookie(cookie1); cookie2 = cookie2 instanceof _a ? cookie2.asObject() : _a.__formatter.superCookie(cookie2); return _a.__compareObject(cookie1, cookie2); }; SuperCookie.__compareObject = (obj, obj2) => { for (const i of Object.keys(Object.assign(Object.assign({}, obj), obj2))) { const val1 = obj[i]; const val2 = obj2[i]; if ([null, undefined].includes(val1) && [null, undefined].includes(val2)) { continue; } else if (typeof val1 !== typeof val2 || (typeof val1 === 'object' ? !_a.__compareObject(val1, val2) : val1 !== val2)) { return false; } } return true; }; SuperCookie.__cookievalueConvert = (value, topLevel) => { if (value === undefined) { return 'undefined:undefined'; } if (value === null) { return 'null:null'; } switch (value.constructor.name) { case 'Date': return `${value.constructor.name}:${value.toJSON()}`; case 'Symbol': return `${value.constructor.name}:${value.toString().substring(7, value.toString().length - 1)}`; case 'Boolean': case 'BigInt': return `${value.constructor.name}:${value}`; default: return typeof value === 'object' ? topLevel ? `${value.constructor.name}:${JSON.stringify(_a.__cookievalueConvert(value))}` : value instanceof Array ? value.map((v) => _a.__cookievalueConvert(v)) : Object.entries(value).reduce((value, entry) => (Object.assign(Object.assign({}, value), { [entry[0]]: _a.__cookievalueConvert(entry[1]) })), {}) : value; } }; SuperCookie.__formatter = new Proxy({}, { get: (_t, p, _r) => { if (!['superCookie', 'cookie'].includes(p)) { throw new TypeError('Invalid Formatter option attempted'); } return new Proxy((() => { }), { apply: (t, thisArg, [params, options]) => { let retVal = {}; for (const i in params) { if (i === 'expires' || ![undefined, null].includes(params[i])) { retVal[i] = thisArg[p][i](params[i]); } } return retVal; }, get: (obj, key, ref) => { return (v, options) => { if (v === null || v === void 0 ? void 0 : v.preserveFalsyExpirations) { var preserveFalsyExpirations = v === null || v === void 0 ? void 0 : v.preserveFalsyExpirations; delete v.preserveFalsyExpirations; } else { var preserveFalsyExpirations = (options === null || options === void 0 ? void 0 : options.preserveFalsyExpirations) || false; } switch (key) { case 'expires': if (p === 'cookie') { if (v !== undefined) { v = (v instanceof Date ? v : new Date(v === false ? new Date().getTime() + 34560000000 : v === null ? 0 : v)); return v.getTime(); } } else { v = v instanceof Date ? v : [undefined, false, null].includes(v) ? v : new Date(v); if (v instanceof Date && v.getTime() > new Date().getTime() + 25920000000 && !preserveFalsyExpirations) { return false; } return v; } case 'value': return p === 'cookie' ? _a.__cookievalueConvert(v, true) : typeof v === 'string' ? _a.__superCookieValueConvert(v) : v; case 'name': v = v.toString(); case 'sameSite': case 'domain': case 'path': return v; case 'secure': case 'partitioned': return v; default: throw new TypeError('Invalid parameter submitted'); } }; } }); } }); SuperCookie.__getAllSimpleSync = () => { return _a.__dCookie.split(';').reduce((full, v) => { const [name, value] = v.trim().split('='); full[name] = { name, value }; return full; }, {}); }; SuperCookie.__sortFromArgs = (nameOrParameters, valueOrParameters, params) => { if (!nameOrParameters) { return null; } const name = !(typeof nameOrParameters === 'object') ? String(nameOrParameters) : String(nameOrParameters.name); const value = params ? valueOrParameters : typeof valueOrParameters === 'object' ? Object.keys(valueOrParameters).every(v => SCOptions.includes(v)) ? valueOrParameters.value : valueOrParameters : valueOrParameters; const parameters = params ? params : typeof nameOrParameters === 'object' ? nameOrParameters : (valueOrParameters === null || valueOrParameters === void 0 ? void 0 : valueOrParameters.value) && valueOrParameters; return Object.assign({ name, value }, parameters); }; SuperCookie.__superCookieValueConvert = (value, topLevel) => { if (value instanceof Array) { return value.map(value => _a.__superCookieValueConvert(value)); } if (value instanceof Object) { return Object.entries(value).reduce((val, entry) => (Object.assign(Object.assign({}, val), { [entry[0]]: _a.__superCookieValueConvert(entry[1]) })), {}); } if (typeof value === 'number' || (Number(value) == value && String(Number(value)) === value)) { return Number(value); } if (typeof value === 'string' && !value.includes(":")) { return value; } if (typeof value === 'string' && value === 'null:null') { return null; } if (typeof value === 'string' && value === 'undefined:undefined') { return undefined; } const [identifier, ...decodedVal] = value.split(':'); value = decodedVal.join(':'); switch (identifier) { case 'Array': case 'Object': return _a.__superCookieValueConvert(JSON.parse(value)); case 'Date': return new Date(value); case 'Boolean': return value === 'true'; case 'BigInt': return BigInt(value); case 'Symbol': return Symbol(value); default: return value; } }; export default SuperCookie; //# sourceMappingURL=index.js.map