supercookie
Version:
A tool for managing and creating the most versatile cookies ever seen without all the fuss.
604 lines • 25.9 kB
JavaScript
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