UNPKG

@qikdev/sdk

Version:

Promise based Javascript SDK

376 lines (298 loc) 19.3 kB
<!DOCTYPE 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>