UNPKG

@deepstream/client

Version:
229 lines (228 loc) 10.5 kB
"use strict"; var __values = (this && this.__values) || function(o) { var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0; if (m) return m.call(o); if (o && typeof o.length === "number") return { next: function () { if (o && i >= o.length) o = void 0; return { value: o && o[i++], done: !o }; } }; throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined."); }; var __read = (this && this.__read) || function (o, n) { var m = typeof Symbol === "function" && o[Symbol.iterator]; if (!m) return o; var i = m.call(o), r, ar = [], e; try { while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value); } catch (error) { e = { error: error }; } finally { try { if (r && !r.done && (m = i["return"])) m.call(i); } finally { if (e) throw e.error; } } return ar; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.IndexdbStorage = void 0; var Operation; (function (Operation) { Operation[Operation["GET"] = 0] = "GET"; Operation[Operation["SET"] = 1] = "SET"; Operation[Operation["DELETE"] = 2] = "DELETE"; })(Operation || (Operation = {})); var IndexdbStorage = /** @class */ (function () { function IndexdbStorage(options) { var _this = this; this.options = options; this.isReady = false; this.queuedRequests = new Map(); this.flushTimeout = null; if (typeof indexedDB === 'undefined' || indexedDB === null) { throw new Error('IndexDB currently not supported when deepstream in node'); } this.flush = this.flush.bind(this); var _a = options.indexdb, objectStoreNames = _a.objectStoreNames, storageDatabaseName = _a.storageDatabaseName, defaultObjectStoreName = _a.defaultObjectStoreName, primaryKey = _a.primaryKey; if (!objectStoreNames.includes(defaultObjectStoreName)) { objectStoreNames.push(defaultObjectStoreName); } var dbVersion = options.indexdb.dbVersion; if (options.indexdb.autoVersion) { var previousDBStructureSerialized = localStorage.getItem("deepstream-db/".concat(storageDatabaseName)); if (previousDBStructureSerialized) { var previousDBStructure = JSON.parse(previousDBStructureSerialized); var objectStoreChanged = (previousDBStructure.objectStoreNames.length !== objectStoreNames.length || previousDBStructure.objectStoreNames.some(function (name) { return !objectStoreNames.includes(name); })); if (objectStoreChanged) { dbVersion = previousDBStructure.dbVersion + 1; } else { dbVersion = previousDBStructure.dbVersion; } } else { dbVersion = 1; } } var request = indexedDB.open(storageDatabaseName, dbVersion); request.onerror = function (event) { console.error("Error opening index ".concat(storageDatabaseName), event); // TODO: Workflow for lack of permissions to use indexDB }; request.onsuccess = function (event) { _this.db = event.target.result; _this.onReady(); }; request.onupgradeneeded = function () { var db = request.result; objectStoreNames.forEach(function (objectStoreName) { if (!db.objectStoreNames.contains(objectStoreName)) { db.createObjectStore(objectStoreName, { keyPath: primaryKey }); } }); for (var i = 0; i < db.objectStoreNames.length; i++) { if (objectStoreNames.includes(db.objectStoreNames[i]) === false) { db.deleteObjectStore(db.objectStoreNames[i]); } } if (options.indexdb.autoVersion) { localStorage.setItem("deepstream-db/".concat(storageDatabaseName), JSON.stringify({ dbVersion: dbVersion, objectStoreNames: objectStoreNames })); } }; } IndexdbStorage.prototype.get = function (recordName, callback) { var ignore = this.options.ignorePrefixes.some(function (prefix) { return recordName.startsWith(prefix); }); if (ignore) { callback(recordName, -1, null); return; } this.insertRequest({ recordName: recordName, callback: callback, operation: Operation.GET }); }; IndexdbStorage.prototype.set = function (recordName, version, data, callback) { var ignore = this.options.ignorePrefixes.some(function (prefix) { return recordName.startsWith(prefix); }); if (ignore) { callback(null, recordName); return; } this.insertRequest({ recordName: recordName, version: version, callback: callback, data: data, operation: Operation.SET }); }; IndexdbStorage.prototype.delete = function (recordName, callback) { var ignore = this.options.ignorePrefixes.some(function (prefix) { return recordName.startsWith(prefix); }); if (ignore) { callback(null, recordName); return; } this.insertRequest({ recordName: recordName, callback: callback, operation: Operation.DELETE }); }; IndexdbStorage.prototype.reset = function (callback) { var _this = this; if (this.db) { this.db.close(); this.db = null; } var deleteDBReqeust = indexedDB.deleteDatabase(this.options.indexdb.storageDatabaseName); deleteDBReqeust.onblocked = function () { return setTimeout(function () { return _this.reset(callback); }, 1000); }; deleteDBReqeust.onsuccess = function () { return callback(null); }; deleteDBReqeust.onerror = function (event) { var errorMessage = "Error deleting database ".concat(_this.options.indexdb.storageDatabaseName); console.error(errorMessage, event); callback(errorMessage); }; }; IndexdbStorage.prototype.registerFlush = function () { if (this.isReady && !this.flushTimeout) { this.flushTimeout = setTimeout(this.flush, this.options.indexdb.flushTimeout); } }; IndexdbStorage.prototype.flush = function () { var e_1, _a; var _this = this; var transaction = this.db.transaction(this.queuedRequests.keys(), 'readwrite'); var _loop_1 = function (key, queuedRequests) { var objectStore = transaction.objectStore(key); queuedRequests.forEach(function (_a) { var _b; var operation = _a.operation, recordName = _a.recordName, version = _a.version, data = _a.data, callback = _a.callback; switch (operation) { case Operation.GET: { var request_1 = objectStore.get(recordName); // The api doesn't support get errors yet! request_1.onerror = function (event) { throw new Error("Requesting record ".concat(recordName, " failed")); }; request_1.onsuccess = function () { if (request_1.result) { callback(recordName, request_1.result.version, request_1.result.data); } else { callback(recordName, -1, null); } }; break; } case Operation.DELETE: { var request = objectStore.delete(recordName); request.onsuccess = function () { return callback(null); }; request.onerror = function (event) { return callback(event.errorCode); }; break; } case Operation.SET: { var request = objectStore.put((_b = {}, _b[_this.options.indexdb.primaryKey] = recordName, _b.version = version, _b.data = data, _b)); request.onsuccess = function () { return callback(null); }; request.onerror = function (event) { return callback(event.errorCode); }; break; } } }); }; try { for (var _b = __values(this.queuedRequests), _c = _b.next(); !_c.done; _c = _b.next()) { var _d = __read(_c.value, 2), key = _d[0], queuedRequests = _d[1]; _loop_1(key, queuedRequests); } } catch (e_1_1) { e_1 = { error: e_1_1 }; } finally { try { if (_c && !_c.done && (_a = _b.return)) _a.call(_b); } finally { if (e_1) throw e_1.error; } } this.queuedRequests.clear(); this.flushTimeout = null; }; IndexdbStorage.prototype.onReady = function () { this.isReady = true; this.flush(); }; IndexdbStorage.prototype.insertRequest = function (request) { var firstSlashIndex = request.recordName.indexOf('/'); var objectStoreName; if (firstSlashIndex > -1) { objectStoreName = request.recordName.substring(0, firstSlashIndex); if (this.options.indexdb.objectStoreNames.indexOf(objectStoreName) === -1) { console.error("Object store names need to be predefined, missing ".concat(objectStoreName, ". Using default objectStore instead.")); objectStoreName = this.options.indexdb.defaultObjectStoreName; } else { request.recordName = request.recordName.substring(firstSlashIndex + 1, request.recordName.length); } } else { objectStoreName = this.options.indexdb.defaultObjectStoreName; } var requests = this.queuedRequests.get(objectStoreName); if (requests === undefined) { this.queuedRequests.set(objectStoreName, [request]); } else { requests.push(request); } this.registerFlush(); }; return IndexdbStorage; }()); exports.IndexdbStorage = IndexdbStorage;