@qikdev/sdk
Version:
Promise based Javascript SDK
376 lines (298 loc) • 19.3 kB
HTML
<html lang="en">
<head>
<meta charset="utf-8">
<title>qik.storage.js - Documentation</title>
<script src="scripts/prettify/prettify.js"></script>
<script src="scripts/prettify/lang-css.js"></script>
<!--[if lt IE 9]>
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
<link type="text/css" rel="stylesheet" href="styles/prettify.css">
<link type="text/css" rel="stylesheet" href="styles/jsdoc.css">
<script src="scripts/nav.js" defer></script>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
<input type="checkbox" id="nav-trigger" class="nav-trigger" />
<label for="nav-trigger" class="navicon-button x">
<div class="navicon"></div>
</label>
<label for="nav-trigger" class="overlay"></label>
<nav >
<h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="access.html">access</a><ul class='methods'><li data-type='method'><a href="access.html#.actionableScopes">actionableScopes</a></li><li data-type='method'><a href="access.html#.allPermissions">allPermissions</a></li><li data-type='method'><a href="access.html#.allPermissionTypes">allPermissionTypes</a></li><li data-type='method'><a href="access.html#.allUserScopes">allUserScopes</a></li><li data-type='method'><a href="access.html#.canCreate">canCreate</a></li><li data-type='method'><a href="access.html#.canDeleteItem">canDeleteItem</a></li><li data-type='method'><a href="access.html#.canEditItem">canEditItem</a></li><li data-type='method'><a href="access.html#.canEraseItem">canEraseItem</a></li><li data-type='method'><a href="access.html#.canKnowOf">canKnowOf</a></li><li data-type='method'><a href="access.html#.canListItem">canListItem</a></li><li data-type='method'><a href="access.html#.canRestoreItem">canRestoreItem</a></li><li data-type='method'><a href="access.html#.canViewItem">canViewItem</a></li><li data-type='method'><a href="access.html#.checkActionAccess">checkActionAccess</a></li><li data-type='method'><a href="access.html#.getAllDescendants">getAllDescendants</a></li><li data-type='method'><a href="access.html#.has">has</a></li><li data-type='method'><a href="access.html#.hasFeature">hasFeature</a></li><li data-type='method'><a href="access.html#.hashPermissions">hashPermissions</a></li><li data-type='method'><a href="access.html#.isAdministrator">isAdministrator</a></li><li data-type='method'><a href="access.html#.isAssignee">isAssignee</a></li><li data-type='method'><a href="access.html#.isOwner">isOwner</a></li></ul></li><li><a href="api.html">api</a><ul class='methods'><li data-type='method'><a href="api.html#.generateEndpointURL">generateEndpointURL</a></li></ul></li><li><a href="auth.html">auth</a><ul class='methods'><li data-type='method'><a href="auth.html#.changeOrganisation">changeOrganisation</a></li><li data-type='method'><a href="auth.html#.ensureValidToken">ensureValidToken</a></li><li data-type='method'><a href="auth.html#.getCurrentToken">getCurrentToken</a></li><li data-type='method'><a href="auth.html#.getCurrentUser">getCurrentUser</a></li><li data-type='method'><a href="auth.html#.impersonate">impersonate</a></li><li data-type='method'><a href="auth.html#.login">login</a></li><li data-type='method'><a href="auth.html#.logout">logout</a></li><li data-type='method'><a href="auth.html#.retrieveUserFromResetToken">retrieveUserFromResetToken</a></li><li data-type='method'><a href="auth.html#.sendResetPasswordRequest">sendResetPasswordRequest</a></li><li data-type='method'><a href="auth.html#.set">set</a></li><li data-type='method'><a href="auth.html#.sync">sync</a></li><li data-type='method'><a href="auth.html#.updateUserWithToken">updateUserWithToken</a></li></ul></li><li><a href="cache.html">cache</a><ul class='methods'><li data-type='method'><a href="cache.html#.get">get</a></li><li data-type='method'><a href="cache.html#.reset">reset</a></li></ul></li><li><a href="content.html">content</a><ul class='methods'><li data-type='method'><a href="content.html#.create">create</a></li><li data-type='method'><a href="content.html#.delete">delete</a></li><li data-type='method'><a href="content.html#.get">get</a></li><li data-type='method'><a href="content.html#.getFromSlug">getFromSlug</a></li><li data-type='method'><a href="content.html#.glossary">glossary</a></li><li data-type='method'><a href="content.html#.list">list</a></li><li data-type='method'><a href="content.html#.patch">patch</a></li><li data-type='method'><a href="content.html#.restore">restore</a></li><li data-type='method'><a href="content.html#.scopeGlossary">scopeGlossary</a></li><li data-type='method'><a href="content.html#.update">update</a></li><li data-type='method'><a href="content.html#.validateField">validateField</a></li><li data-type='method'><a href="content.html#.variables">variables</a></li></ul></li><li><a href="files.html">files</a><ul class='methods'><li data-type='method'><a href="files.html#.downloadUrl">downloadUrl</a></li><li data-type='method'><a href="files.html#.duration">duration</a></li><li data-type='method'><a href="files.html#.filesize">filesize</a></li><li data-type='method'><a href="files.html#.getBinaryTypeFromMime">getBinaryTypeFromMime</a></li><li data-type='method'><a href="files.html#.mediaUrl">mediaUrl</a></li></ul></li><li><a href="filter.html">filter</a><ul class='methods'><li data-type='method'><a href="filter.html#.activeFilterComparators">activeFilterComparators</a></li><li data-type='method'><a href="filter.html#.activeFilterKeys">activeFilterKeys</a></li><li data-type='method'><a href="filter.html#.activeFilterOperators">activeFilterOperators</a></li><li data-type='method'><a href="filter.html#.activeFilters">activeFilters</a></li><li data-type='method'><a href="filter.html#.activeFilterValues">activeFilterValues</a></li><li data-type='method'><a href="filter.html#.filterChangeString">filterChangeString</a></li><li data-type='method'><a href="filter.html#.isValidFilter">isValidFilter</a></li></ul></li><li><a href="geo.html">geo</a><ul class='methods'><li data-type='method'><a href="geo.html#.distance">distance</a></li><li data-type='method'><a href="geo.html#.getDefaultCountry">getDefaultCountry</a></li><li data-type='method'><a href="geo.html#.getDefaultTimezone">getDefaultTimezone</a></li><li data-type='method'><a href="geo.html#.getPosition">getPosition</a></li><li data-type='method'><a href="geo.html#.stopWatchPosition">stopWatchPosition</a></li><li data-type='method'><a href="geo.html#.watchPosition">watchPosition</a></li></ul></li><li><a href="module-QikStorage-CookieStorageAdapter.html">CookieStorageAdapter</a><ul class='methods'><li data-type='method'><a href="module-QikStorage-CookieStorageAdapter.html#getCookieOptions">getCookieOptions</a></li><li data-type='method'><a href="module-QikStorage-CookieStorageAdapter.html#isCookieMode">isCookieMode</a></li></ul></li><li><a href="module-QikStorage-LocalStorageAdapter.html">LocalStorageAdapter</a></li><li><a href="module-QikStorage-StorageAdapter.html">StorageAdapter</a><ul class='methods'><li data-type='method'><a href="module-QikStorage-StorageAdapter.html#clearUser">clearUser</a></li><li data-type='method'><a href="module-QikStorage-StorageAdapter.html#getAccessToken">getAccessToken</a></li><li data-type='method'><a href="module-QikStorage-StorageAdapter.html#getRefreshToken">getRefreshToken</a></li><li data-type='method'><a href="module-QikStorage-StorageAdapter.html#getTokenExpiry">getTokenExpiry</a></li><li data-type='method'><a href="module-QikStorage-StorageAdapter.html#getUser">getUser</a></li><li data-type='method'><a href="module-QikStorage-StorageAdapter.html#isAvailable">isAvailable</a></li><li data-type='method'><a href="module-QikStorage-StorageAdapter.html#setUser">setUser</a></li></ul></li><li><a href="socket.html">socket</a><ul class='methods'><li data-type='method'><a href="socket.html#.channel">channel</a></li><li data-type='method'><a href="socket.html#.close">close</a></li><li data-type='method'><a href="socket.html#.connect">connect</a></li><li data-type='method'><a href="socket.html#.reconnect">reconnect</a></li><li data-type='method'><a href="socket.html#.subscribe">subscribe</a></li><li data-type='method'><a href="socket.html#.unsubscribe">unsubscribe</a></li></ul></li><li><a href="system.html">system</a><ul class='methods'><li data-type='method'><a href="system.html#.countries">countries</a></li></ul></li><li><a href="utils.html">utils</a><ul class='methods'><li data-type='method'><a href="utils.html#.cleanValue">cleanValue</a></li><li data-type='method'><a href="utils.html#.comma">comma</a></li><li data-type='method'><a href="utils.html#.errorMessage">errorMessage</a></li><li data-type='method'><a href="utils.html#.exists">exists</a></li><li data-type='method'><a href="utils.html#.extractFromArray">extractFromArray</a></li><li data-type='method'><a href="utils.html#.formatCurrency">formatCurrency</a></li><li data-type='method'><a href="utils.html#.getTypeFromID">getTypeFromID</a></li><li data-type='method'><a href="utils.html#.guid">guid</a></li><li data-type='method'><a href="utils.html#.hash">hash</a></li><li data-type='method'><a href="utils.html#.id">id</a></li><li data-type='method'><a href="utils.html#.ids">ids</a></li><li data-type='method'><a href="utils.html#.isValidEmailAddress">isValidEmailAddress</a></li><li data-type='method'><a href="utils.html#.loadExternalScript">loadExternalScript</a></li><li data-type='method'><a href="utils.html#.loadExternalStyle">loadExternalStyle</a></li><li data-type='method'><a href="utils.html#.machineName">machineName</a></li><li data-type='method'><a href="utils.html#.mapParameters">mapParameters</a></li><li data-type='method'><a href="utils.html#.matchInArray">matchInArray</a></li><li data-type='method'><a href="utils.html#.parseBoolean">parseBoolean</a></li><li data-type='method'><a href="utils.html#.parseDate">parseDate</a></li><li data-type='method'><a href="utils.html#.parseEmail">parseEmail</a></li><li data-type='method'><a href="utils.html#.parseInt">parseInt</a></li><li data-type='method'><a href="utils.html#.parseNumber">parseNumber</a></li><li data-type='method'><a href="utils.html#.parseURL">parseURL</a></li></ul></li></ul><h3>Modules</h3><ul><li><a href="module-QikStorage.html">QikStorage</a><ul class='methods'><li data-type='method'><a href="module-QikStorage.html#.createStorageAdapter">createStorageAdapter</a></li></ul></li></ul><h3>Global</h3><ul><li><a href="global.html#EventDispatcher">EventDispatcher</a></li></ul>
</nav>
<div id="main">
<h1 class="page-title">qik.storage.js</h1>
<section>
<article>
<pre class="prettyprint source linenums"><code>/**
* Storage abstraction layer for handling both localStorage and httpOnly cookie storage
* @module QikStorage
*/
/**
* Base storage interface
*/
class StorageAdapter {
constructor() {
if (this.constructor === StorageAdapter) {
throw new Error("StorageAdapter is an abstract class and cannot be instantiated directly");
}
}
/**
* Get user session data
* @returns {Object|null} User session object
*/
getUser() {
throw new Error("getUser method must be implemented");
}
/**
* Set user session data
* @param {Object} user User session object
*/
setUser(user) {
throw new Error("setUser method must be implemented");
}
/**
* Clear user session data
*/
clearUser() {
throw new Error("clearUser method must be implemented");
}
/**
* Get current access token
* @returns {String|null} Access token
*/
getAccessToken() {
throw new Error("getAccessToken method must be implemented");
}
/**
* Get current refresh token
* @returns {String|null} Refresh token
*/
getRefreshToken() {
throw new Error("getRefreshToken method must be implemented");
}
/**
* Get token expiry date
* @returns {String|null} Token expiry date
*/
getTokenExpiry() {
throw new Error("getTokenExpiry method must be implemented");
}
/**
* Check if storage is available
* @returns {Boolean} Whether storage is available
*/
isAvailable() {
throw new Error("isAvailable method must be implemented");
}
}
/**
* localStorage-based storage adapter (current behavior)
*/
class LocalStorageAdapter extends StorageAdapter {
constructor() {
super();
this.storage = {};
}
getUser() {
return this.storage.user || null;
}
setUser(user) {
this.storage.user = user;
}
clearUser() {
delete this.storage.user;
}
getAccessToken() {
const user = this.getUser();
return user?.token?.accessToken || null;
}
getRefreshToken() {
const user = this.getUser();
return user?.token?.refreshToken || null;
}
getTokenExpiry() {
const user = this.getUser();
return user?.token?.expires || null;
}
isAvailable() {
return true; // Always available as it uses in-memory storage
}
}
/**
* Cookie-based storage adapter for httpOnly cookies
*/
class CookieStorageAdapter extends StorageAdapter {
constructor(options = {}) {
super();
this.options = {
domain: options.domain || this._detectDomain(),
secure: options.secure !== false, // Default to true
sameSite: options.sameSite || 'lax',
...options
};
this.sessionStorage = {}; // In-memory storage for session data
}
/**
* Auto-detect appropriate cookie domain
* @private
*/
_detectDomain() {
if (typeof window === 'undefined') return null;
const hostname = window.location.hostname;
// For localhost, don't set domain
if (hostname === 'localhost' || hostname === '127.0.0.1') {
return null;
}
// For IP addresses, don't set domain
if (/^\d+\.\d+\.\d+\.\d+$/.test(hostname)) {
return null;
}
// For subdomains, use parent domain (e.g., .example.com)
const parts = hostname.split('.');
if (parts.length > 2) {
return '.' + parts.slice(-2).join('.');
}
return null; // Let browser handle single domain
}
/**
* Read a cookie value
* @private
*/
_getCookie(name) {
if (typeof document === 'undefined') return null;
const value = `; ${document.cookie}`;
const parts = value.split(`; ${name}=`);
if (parts.length === 2) {
return parts.pop().split(';').shift();
}
return null;
}
/**
* Set a cookie value (for non-httpOnly cookies only)
* @private
*/
_setCookie(name, value, options = {}) {
if (typeof document === 'undefined') return;
const opts = { ...this.options, ...options };
let cookieString = `${name}=${value}`;
if (opts.domain) {
cookieString += `; Domain=${opts.domain}`;
}
if (opts.secure) {
cookieString += '; Secure';
}
if (opts.sameSite) {
cookieString += `; SameSite=${opts.sameSite}`;
}
if (opts.maxAge) {
cookieString += `; Max-Age=${opts.maxAge}`;
}
document.cookie = cookieString;
}
/**
* Delete a cookie
* @private
*/
_deleteCookie(name) {
this._setCookie(name, '', { maxAge: 0 });
}
getUser() {
return this.sessionStorage.user || null;
}
setUser(user) {
if (user) {
// Store session data in memory (accessible to JavaScript)
const { token, ...sessionData } = user;
this.sessionStorage.user = sessionData;
// Tokens are handled by httpOnly cookies set by the server
// We don't store them in JavaScript for security
} else {
this.sessionStorage.user = null;
}
}
clearUser() {
delete this.sessionStorage.user;
// Note: httpOnly cookies will be cleared by server response
// But we can clear any non-httpOnly cookies we might have set
this._deleteCookie('qik_session_id');
}
getAccessToken() {
// In cookie mode, we can't access httpOnly cookies from JavaScript
// The browser will automatically include them in requests
// Return null to indicate tokens are handled by cookies
return null;
}
getRefreshToken() {
// Same as access token - handled by httpOnly cookies
return null;
}
getTokenExpiry() {
// We can't read httpOnly cookie expiry from JavaScript
// The server will handle token expiry validation
return null;
}
isAvailable() {
// Check if we're in a browser environment and cookies are enabled
if (typeof document === 'undefined') return false;
try {
// Test if we can set/read cookies
const testCookie = 'qik_test_cookie';
this._setCookie(testCookie, 'test');
const canRead = this._getCookie(testCookie) === 'test';
this._deleteCookie(testCookie);
return canRead;
} catch (e) {
return false;
}
}
/**
* Check if we're in cookie mode
* @returns {Boolean}
*/
isCookieMode() {
return true;
}
/**
* Get cookie configuration options
* @returns {Object}
*/
getCookieOptions() {
return { ...this.options };
}
}
/**
* Factory function to create appropriate storage adapter
* @param {Object} options Configuration options
* @param {Boolean} options.useHttpOnlyCookies Whether to use cookie storage
* @param {Object} options.cookieConfig Cookie configuration options
* @returns {StorageAdapter} Storage adapter instance
*/
export function createStorageAdapter(options = {}) {
if (options.useHttpOnlyCookies) {
const cookieAdapter = new CookieStorageAdapter(options.cookieConfig);
// Fallback to localStorage if cookies aren't available
if (!cookieAdapter.isAvailable()) {
console.warn('Qik SDK: Cookies not available, falling back to localStorage mode');
return new LocalStorageAdapter();
}
return cookieAdapter;
}
return new LocalStorageAdapter();
}
export { StorageAdapter, LocalStorageAdapter, CookieStorageAdapter };
</code></pre>
</article>
</section>
</div>
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.6.11</a> on Mon Jul 13 2026 18:49:48 GMT+1000 (Australian Eastern Standard Time) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
</footer>
<script>prettyPrint();</script>
<script src="scripts/polyfill.js"></script>
<script src="scripts/linenumber.js"></script>
</body>
</html>