stream-chat-react-native-core
Version:
The official React Native and Expo components for Stream Chat, a service for building chat applications
275 lines • 11.1 kB
JavaScript
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.SqliteClientError = exports.SqliteClient = void 0;
var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime/helpers/asyncToGenerator"));
var _constants = require("./constants");
var _schema = require("./schema");
var _createCreateTableQuery = require("./sqlite-utils/createCreateTableQuery");
var sqlite;
try {
sqlite = require('@op-engineering/op-sqlite');
} catch (e) {
var isRemoteDebuggerError = e instanceof Error && e.message.includes('Failed to install');
if (isRemoteDebuggerError) {
throw e;
}
}
class SqliteClientError extends Error {
constructor(code, message, options) {
super(message);
this.name = 'SqliteClientError';
this.code = code;
this.cause = options == null ? void 0 : options.cause;
}
}
exports.SqliteClientError = SqliteClientError;
class SqliteClient {
static dbVersion = 16;
static dbName = _constants.DB_NAME;
static dbLocation = _constants.DB_LOCATION;
static TRANSIENT_ERROR = /database is locked|SQLITE_BUSY|SQLITE_LOCKED|disk i\/o|SQLITE_IOERR|unable to open|SQLITE_CANTOPEN|out of memory|readonly/i;
static UNREADABLE_ERROR = /not a database|file is encrypted|malformed|disk image is malformed|SQLite (?:error )?code:?\s*(?:26|11)\b|NOTADB|SQLITE_CORRUPT/i;
static getDbVersion = () => SqliteClient.dbVersion;
static setDbVersion = version => SqliteClient.dbVersion = version;
static recordError = e => {
SqliteClient.logger == null || SqliteClient.logger('error', e.message, {
tag: e.code
});
throw e;
};
static preflightEncryption = (0, _asyncToGenerator2.default)(function* () {
try {
SqliteClient.preflightedKey = yield SqliteClient.resolveEncryptionKey();
} catch (e) {
if (e instanceof SqliteClientError) {
SqliteClient.recordError(e);
}
throw e;
}
});
static resolveEncryptionKey = (0, _asyncToGenerator2.default)(function* () {
var getEncryptionKey = SqliteClient.getEncryptionKey;
if (!getEncryptionKey) {
return undefined;
}
if (sqlite === undefined) {
throw new SqliteClientError('SQLCIPHER_BUILD_MISSING', 'An offline database encryption key was provided but "@op-engineering/op-sqlite" ' + 'is not installed.');
}
if (typeof sqlite.isSQLCipher !== 'function' || !sqlite.isSQLCipher()) {
throw new SqliteClientError('SQLCIPHER_BUILD_MISSING', 'An offline database encryption key was provided but @op-engineering/op-sqlite was ' + 'not built with SQLCipher, so the key would be silently ignored and the offline ' + 'database written in plaintext. Add { "op-sqlite": { "sqlcipher": true } } to your ' + "application's package.json and rebuild, or stop providing a key.");
}
var encryptionKey;
try {
encryptionKey = yield getEncryptionKey();
} catch (error) {
throw new SqliteClientError('ENCRYPTION_KEY_UNAVAILABLE', 'The offline database encryption key getter threw, so the database cannot be opened.', {
cause: error
});
}
if (!encryptionKey) {
throw new SqliteClientError('ENCRYPTION_KEY_UNAVAILABLE', 'The offline database encryption key getter resolved without a key, so the database ' + 'cannot be opened.');
}
return encryptionKey;
});
static openDB = (0, _asyncToGenerator2.default)(function* () {
try {
var _SqliteClient$preflig, _SqliteClient$db;
if (sqlite === undefined) {
throw new Error('Please install "@op-engineering/op-sqlite" package to enable offline support');
}
var encryptionKey = (_SqliteClient$preflig = SqliteClient.preflightedKey) != null ? _SqliteClient$preflig : yield SqliteClient.resolveEncryptionKey();
SqliteClient.preflightedKey = undefined;
SqliteClient.db = sqlite.open({
location: SqliteClient.dbLocation,
name: SqliteClient.dbName,
...(encryptionKey ? {
encryptionKey
} : {})
});
yield (_SqliteClient$db = SqliteClient.db) == null ? void 0 : _SqliteClient$db.execute('PRAGMA foreign_keys = ON', []);
} catch (e) {
if (e instanceof SqliteClientError) {
throw e;
}
SqliteClient.logger == null || SqliteClient.logger('error', `Error opening database ${SqliteClient.dbName}`, {
error: e
});
console.error(`Error opening database ${SqliteClient.dbName}: ${e}`);
}
});
static closeDB = () => {
try {
if (!SqliteClient.db) {
throw new Error('DB is not open or initialized.');
}
SqliteClient.db.close();
SqliteClient.db = undefined;
} catch (e) {
SqliteClient.logger == null || SqliteClient.logger('error', `Error closing database ${SqliteClient.dbName}`, {
error: e
});
console.error(`Error closing database ${SqliteClient.dbName}: ${e}`);
}
};
static executeSqlBatch = function () {
var _ref4 = (0, _asyncToGenerator2.default)(function* (queries) {
if (!queries || !queries.length) {
return;
}
try {
if (!SqliteClient.db) {
throw new Error('DB is not open or initialized.');
}
var finalQueries = queries.map(query => {
if (query.length === 1) {
query.push([]);
}
return query;
});
yield SqliteClient.db.executeBatch(finalQueries);
} catch (e) {
SqliteClient.logger == null || SqliteClient.logger('error', 'SqlBatch queries failed', {
error: e,
queries
});
throw new Error(`Queries failed: ${e}`);
}
});
return function (_x) {
return _ref4.apply(this, arguments);
};
}();
static executeSql = function () {
var _ref5 = (0, _asyncToGenerator2.default)(function* (query, params) {
try {
if (!SqliteClient.db) {
throw new Error('DB is not open or initialized.');
}
var _yield$SqliteClient$d = yield SqliteClient.db.execute(query, params),
rows = _yield$SqliteClient$d.rows;
return rows ? rows : [];
} catch (e) {
SqliteClient.logger == null || SqliteClient.logger('error', 'Sql single query failed', {
error: e,
query
});
throw new Error(`Query failed: ${e}: `);
}
});
return function (_x2, _x3) {
return _ref5.apply(this, arguments);
};
}();
static dropTables = (0, _asyncToGenerator2.default)(function* () {
var queries = Object.keys(_schema.tables).map(table => [`DROP TABLE IF EXISTS ${table}`, []]);
SqliteClient.logger == null || SqliteClient.logger('info', 'Dropping tables', {
tables: Object.keys(_schema.tables)
});
yield SqliteClient.executeSqlBatch(queries);
});
static deleteDatabase = () => {
SqliteClient.logger == null || SqliteClient.logger('info', 'deleteDatabase', {
dbLocation: SqliteClient.dbLocation,
dbname: SqliteClient.dbName
});
try {
if (!SqliteClient.db) {
throw new Error('DB is not open or initialized.');
}
SqliteClient.db.delete();
} catch (e) {
SqliteClient.logger == null || SqliteClient.logger('error', 'Error deleting DB', {
dbLocation: SqliteClient.dbLocation,
dbname: SqliteClient.dbName,
error: e
});
throw new Error(`Error deleting DB: ${e}`);
}
return true;
};
static isUnreadableDbError = e => {
var _message;
var message = String((_message = e == null ? void 0 : e.message) != null ? _message : e);
if (SqliteClient.TRANSIENT_ERROR.test(message)) {
return false;
}
return SqliteClient.UNREADABLE_ERROR.test(message);
};
static initializeDatabase = (0, _asyncToGenerator2.default)(function* () {
try {
yield SqliteClient.openDB();
var version = yield SqliteClient.getUserPragmaVersion();
if (version !== SqliteClient.dbVersion) {
SqliteClient.logger == null || SqliteClient.logger('info', 'DB version mismatch');
yield SqliteClient.dropTables();
yield SqliteClient.updateUserPragmaVersion(SqliteClient.dbVersion);
}
SqliteClient.logger == null || SqliteClient.logger('info', 'create tables if not exists', {
tables: Object.keys(_schema.tables)
});
var q = Object.keys(_schema.tables).reduce((queriesSoFar, tableName) => {
queriesSoFar.push(...(0, _createCreateTableQuery.createCreateTableQuery)(tableName));
return queriesSoFar;
}, []);
yield SqliteClient.executeSqlBatch(q);
return true;
} catch (e) {
if (e instanceof SqliteClientError) {
SqliteClient.recordError(e);
}
if (SqliteClient.isUnreadableDbError(e)) {
SqliteClient.recordError(new SqliteClientError('OFFLINE_DB_UNREADABLE', 'The offline database exists but could not be read. Usually the encryption ' + 'key changed, or encryption was turned on or off while a database from ' + 'the other mode was still on disk. Delete it with ' + 'SqliteClient.deleteDatabase() and re-mount to rebuild from the server - ' + 'everything in it is a cache, except queued offline actions, which are lost.', {
cause: e
}));
}
console.log('Error initializing DB', e);
SqliteClient.logger == null || SqliteClient.logger('error', 'Error initializing DB', {
dbLocation: SqliteClient.dbLocation,
dbname: SqliteClient.dbName,
error: e
});
return false;
}
});
static updateUserPragmaVersion = function () {
var _ref8 = (0, _asyncToGenerator2.default)(function* (version) {
SqliteClient.logger == null || SqliteClient.logger('info', `updateUserPragmaVersion to ${version}`);
if (!SqliteClient.db) {
throw new Error('DB is not open or initialized.');
}
yield SqliteClient.db.execute(`PRAGMA user_version = ${version}`, []);
});
return function (_x4) {
return _ref8.apply(this, arguments);
};
}();
static getUserPragmaVersion = (0, _asyncToGenerator2.default)(function* () {
try {
if (!SqliteClient.db) {
throw new Error('DB is not open or initialized.');
}
var _yield$SqliteClient$d2 = yield SqliteClient.db.execute('PRAGMA user_version', []),
rows = _yield$SqliteClient$d2.rows;
var result = rows ? rows : [];
SqliteClient.logger == null || SqliteClient.logger('info', 'getUserPragmaVersion', {
result
});
return result[0].user_version;
} catch (e) {
console.log('Error getting user_version', e);
throw new Error(`Querying for user_version failed: ${e}`);
}
});
static resetDB = (0, _asyncToGenerator2.default)(function* () {
SqliteClient.logger == null || SqliteClient.logger('info', 'resetDB');
if (SqliteClient.db) {
yield SqliteClient.dropTables();
SqliteClient.closeDB();
}
yield SqliteClient.initializeDatabase();
});
}
exports.SqliteClient = SqliteClient;
//# sourceMappingURL=SqliteClient.js.map