diff --git a/public/index.html b/public/index.html
index 0a2c37e73..ed3115bc1 100644
--- a/public/index.html
+++ b/public/index.html
@@ -40,6 +40,7 @@
+
diff --git a/public/scripts/extensions/infinity-context/index.js b/public/scripts/extensions/infinity-context/index.js
index 77319b466..0a54e5961 100644
--- a/public/scripts/extensions/infinity-context/index.js
+++ b/public/scripts/extensions/infinity-context/index.js
@@ -1,11 +1,11 @@
import { saveSettingsDebounced, getCurrentChatId, system_message_types, extension_prompt_types, eventSource, event_types, getRequestHeaders, CHARACTERS_PER_TOKEN_RATIO, substituteParams, max_context, } from "../../../script.js";
import { humanizedDateTime } from "../../RossAscends-mods.js";
import { getApiUrl, extension_settings, getContext, doExtrasFetch } from "../../extensions.js";
-import { getFileText, onlyUnique, splitRecursive, IndexedDBStore } from "../../utils.js";
+import { getFileText, onlyUnique, splitRecursive } from "../../utils.js";
export { MODULE_NAME };
const MODULE_NAME = 'chromadb';
-const dbStore = new IndexedDBStore('SillyTavern', MODULE_NAME);
+const dbStore = localforage.createInstance({ name: 'SillyTavern_ChromaDB' });
const defaultSettings = {
strategy: 'original',
@@ -59,7 +59,7 @@ async function invalidateMessageSyncState(messageId) {
console.log('CHROMADB: invalidating message sync state', messageId);
const state = await getChatSyncState();
state[messageId] = 0;
- await dbStore.put(getCurrentChatId(), state);
+ await dbStore.setItem(getCurrentChatId(), state);
}
async function getChatSyncState() {
@@ -69,7 +69,7 @@ async function getChatSyncState() {
}
const context = getContext();
- const chatState = (await dbStore.get(currentChatId)) || [];
+ const chatState = (await dbStore.getItem(currentChatId)) || [];
// if the chat length has decreased, it means that some messages were deleted
if (chatState.length > context.chat.length) {
@@ -92,7 +92,7 @@ async function getChatSyncState() {
chatState[i] = 0;
}
}
- await dbStore.put(currentChatId, chatState);
+ await dbStore.setItem(currentChatId, chatState);
return chatState;
}
@@ -304,7 +304,7 @@ async function filterSyncedMessages(splitMessages) {
}
console.debug('CHROMADB: sync state', syncState.map((v, i) => ({ id: i, synced: v })));
- await dbStore.put(getCurrentChatId(), syncState);
+ await dbStore.setItem(getCurrentChatId(), syncState);
// remove messages that are already synced
return splitMessages.filter((_, i) => !removeIndices.includes(i));
@@ -325,7 +325,7 @@ async function onPurgeClick() {
});
if (purgeResult.ok) {
- await dbStore.delete(chat_id);
+ await dbStore.removeItem(chat_id);
toastr.success('ChromaDB context has been successfully cleared');
}
}
diff --git a/public/scripts/localforage.min.js b/public/scripts/localforage.min.js
new file mode 100644
index 000000000..7403f8f08
--- /dev/null
+++ b/public/scripts/localforage.min.js
@@ -0,0 +1,7 @@
+/*!
+ localForage -- Offline Storage, Improved
+ Version 1.10.0
+ https://localforage.github.io/localForage
+ (c) 2013-2017 Mozilla, Apache License 2.0
+*/
+!function(a){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=a();else if("function"==typeof define&&define.amd)define([],a);else{var b;b="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this,b.localforage=a()}}(function(){return function a(b,c,d){function e(g,h){if(!c[g]){if(!b[g]){var i="function"==typeof require&&require;if(!h&&i)return i(g,!0);if(f)return f(g,!0);var j=new Error("Cannot find module '"+g+"'");throw j.code="MODULE_NOT_FOUND",j}var k=c[g]={exports:{}};b[g][0].call(k.exports,function(a){var c=b[g][1][a];return e(c||a)},k,k.exports,a,b,c,d)}return c[g].exports}for(var f="function"==typeof require&&require,g=0;g=43)}}).catch(function(){return!1})}function n(a){return"boolean"==typeof xa?va.resolve(xa):m(a).then(function(a){return xa=a})}function o(a){var b=ya[a.name],c={};c.promise=new va(function(a,b){c.resolve=a,c.reject=b}),b.deferredOperations.push(c),b.dbReady?b.dbReady=b.dbReady.then(function(){return c.promise}):b.dbReady=c.promise}function p(a){var b=ya[a.name],c=b.deferredOperations.pop();if(c)return c.resolve(),c.promise}function q(a,b){var c=ya[a.name],d=c.deferredOperations.pop();if(d)return d.reject(b),d.promise}function r(a,b){return new va(function(c,d){if(ya[a.name]=ya[a.name]||B(),a.db){if(!b)return c(a.db);o(a),a.db.close()}var e=[a.name];b&&e.push(a.version);var f=ua.open.apply(ua,e);b&&(f.onupgradeneeded=function(b){var c=f.result;try{c.createObjectStore(a.storeName),b.oldVersion<=1&&c.createObjectStore(wa)}catch(c){if("ConstraintError"!==c.name)throw c;console.warn('The database "'+a.name+'" has been upgraded from version '+b.oldVersion+" to version "+b.newVersion+', but the storage "'+a.storeName+'" already exists.')}}),f.onerror=function(a){a.preventDefault(),d(f.error)},f.onsuccess=function(){var b=f.result;b.onversionchange=function(a){a.target.close()},c(b),p(a)}})}function s(a){return r(a,!1)}function t(a){return r(a,!0)}function u(a,b){if(!a.db)return!0;var c=!a.db.objectStoreNames.contains(a.storeName),d=a.versiona.db.version;if(d&&(a.version!==b&&console.warn('The database "'+a.name+"\" can't be downgraded from version "+a.db.version+" to version "+a.version+"."),a.version=a.db.version),e||c){if(c){var f=a.db.version+1;f>a.version&&(a.version=f)}return!0}return!1}function v(a){return new va(function(b,c){var d=new FileReader;d.onerror=c,d.onloadend=function(c){var d=btoa(c.target.result||"");b({__local_forage_encoded_blob:!0,data:d,type:a.type})},d.readAsBinaryString(a)})}function w(a){return g([l(atob(a.data))],{type:a.type})}function x(a){return a&&a.__local_forage_encoded_blob}function y(a){var b=this,c=b._initReady().then(function(){var a=ya[b._dbInfo.name];if(a&&a.dbReady)return a.dbReady});return i(c,a,a),c}function z(a){o(a);for(var b=ya[a.name],c=b.forages,d=0;d0&&(!a.db||"InvalidStateError"===e.name||"NotFoundError"===e.name))return va.resolve().then(function(){if(!a.db||"NotFoundError"===e.name&&!a.db.objectStoreNames.contains(a.storeName)&&a.version<=a.db.version)return a.db&&(a.version=a.db.version+1),t(a)}).then(function(){return z(a).then(function(){A(a,b,c,d-1)})}).catch(c);c(e)}}function B(){return{forages:[],db:null,dbReady:null,deferredOperations:[]}}function C(a){function b(){return va.resolve()}var c=this,d={db:null};if(a)for(var e in a)d[e]=a[e];var f=ya[d.name];f||(f=B(),ya[d.name]=f),f.forages.push(c),c._initReady||(c._initReady=c.ready,c.ready=y);for(var g=[],h=0;h>4,k[i++]=(15&d)<<4|e>>2,k[i++]=(3&e)<<6|63&f;return j}function O(a){var b,c=new Uint8Array(a),d="";for(b=0;b>2],d+=Da[(3&c[b])<<4|c[b+1]>>4],d+=Da[(15&c[b+1])<<2|c[b+2]>>6],d+=Da[63&c[b+2]];return c.length%3==2?d=d.substring(0,d.length-1)+"=":c.length%3==1&&(d=d.substring(0,d.length-2)+"=="),d}function P(a,b){var c="";if(a&&(c=Ua.call(a)),a&&("[object ArrayBuffer]"===c||a.buffer&&"[object ArrayBuffer]"===Ua.call(a.buffer))){var d,e=Ga;a instanceof ArrayBuffer?(d=a,e+=Ia):(d=a.buffer,"[object Int8Array]"===c?e+=Ka:"[object Uint8Array]"===c?e+=La:"[object Uint8ClampedArray]"===c?e+=Ma:"[object Int16Array]"===c?e+=Na:"[object Uint16Array]"===c?e+=Pa:"[object Int32Array]"===c?e+=Oa:"[object Uint32Array]"===c?e+=Qa:"[object Float32Array]"===c?e+=Ra:"[object Float64Array]"===c?e+=Sa:b(new Error("Failed to get type for BinaryArray"))),b(e+O(d))}else if("[object Blob]"===c){var f=new FileReader;f.onload=function(){var c=Ea+a.type+"~"+O(this.result);b(Ga+Ja+c)},f.readAsArrayBuffer(a)}else try{b(JSON.stringify(a))}catch(c){console.error("Couldn't convert value into a JSON string: ",a),b(null,c)}}function Q(a){if(a.substring(0,Ha)!==Ga)return JSON.parse(a);var b,c=a.substring(Ta),d=a.substring(Ha,Ta);if(d===Ja&&Fa.test(c)){var e=c.match(Fa);b=e[1],c=c.substring(e[0].length)}var f=N(c);switch(d){case Ia:return f;case Ja:return g([f],{type:b});case Ka:return new Int8Array(f);case La:return new Uint8Array(f);case Ma:return new Uint8ClampedArray(f);case Na:return new Int16Array(f);case Pa:return new Uint16Array(f);case Oa:return new Int32Array(f);case Qa:return new Uint32Array(f);case Ra:return new Float32Array(f);case Sa:return new Float64Array(f);default:throw new Error("Unkown type: "+d)}}function R(a,b,c,d){a.executeSql("CREATE TABLE IF NOT EXISTS "+b.storeName+" (id INTEGER PRIMARY KEY, key unique, value)",[],c,d)}function S(a){var b=this,c={db:null};if(a)for(var d in a)c[d]="string"!=typeof a[d]?a[d].toString():a[d];var e=new va(function(a,d){try{c.db=openDatabase(c.name,String(c.version),c.description,c.size)}catch(a){return d(a)}c.db.transaction(function(e){R(e,c,function(){b._dbInfo=c,a()},function(a,b){d(b)})},d)});return c.serializer=Va,e}function T(a,b,c,d,e,f){a.executeSql(c,d,e,function(a,g){g.code===g.SYNTAX_ERR?a.executeSql("SELECT name FROM sqlite_master WHERE type='table' AND name = ?",[b.storeName],function(a,h){h.rows.length?f(a,g):R(a,b,function(){a.executeSql(c,d,e,f)},f)},f):f(a,g)},f)}function U(a,b){var c=this;a=j(a);var d=new va(function(b,d){c.ready().then(function(){var e=c._dbInfo;e.db.transaction(function(c){T(c,e,"SELECT * FROM "+e.storeName+" WHERE key = ? LIMIT 1",[a],function(a,c){var d=c.rows.length?c.rows.item(0).value:null;d&&(d=e.serializer.deserialize(d)),b(d)},function(a,b){d(b)})})}).catch(d)});return h(d,b),d}function V(a,b){var c=this,d=new va(function(b,d){c.ready().then(function(){var e=c._dbInfo;e.db.transaction(function(c){T(c,e,"SELECT * FROM "+e.storeName,[],function(c,d){for(var f=d.rows,g=f.length,h=0;h0)return void f(W.apply(e,[a,h,c,d-1]));g(b)}})})}).catch(g)});return h(f,c),f}function X(a,b,c){return W.apply(this,[a,b,c,1])}function Y(a,b){var c=this;a=j(a);var d=new va(function(b,d){c.ready().then(function(){var e=c._dbInfo;e.db.transaction(function(c){T(c,e,"DELETE FROM "+e.storeName+" WHERE key = ?",[a],function(){b()},function(a,b){d(b)})})}).catch(d)});return h(d,b),d}function Z(a){var b=this,c=new va(function(a,c){b.ready().then(function(){var d=b._dbInfo;d.db.transaction(function(b){T(b,d,"DELETE FROM "+d.storeName,[],function(){a()},function(a,b){c(b)})})}).catch(c)});return h(c,a),c}function $(a){var b=this,c=new va(function(a,c){b.ready().then(function(){var d=b._dbInfo;d.db.transaction(function(b){T(b,d,"SELECT COUNT(key) as c FROM "+d.storeName,[],function(b,c){var d=c.rows.item(0).c;a(d)},function(a,b){c(b)})})}).catch(c)});return h(c,a),c}function _(a,b){var c=this,d=new va(function(b,d){c.ready().then(function(){var e=c._dbInfo;e.db.transaction(function(c){T(c,e,"SELECT key FROM "+e.storeName+" WHERE id = ? LIMIT 1",[a+1],function(a,c){var d=c.rows.length?c.rows.item(0).key:null;b(d)},function(a,b){d(b)})})}).catch(d)});return h(d,b),d}function aa(a){var b=this,c=new va(function(a,c){b.ready().then(function(){var d=b._dbInfo;d.db.transaction(function(b){T(b,d,"SELECT key FROM "+d.storeName,[],function(b,c){for(var d=[],e=0;e '__WebKitDatabaseInfoTable__'",[],function(c,d){for(var e=[],f=0;f0}function ha(a){var b=this,c={};if(a)for(var d in a)c[d]=a[d];return c.keyPrefix=ea(a,b._defaultConfig),ga()?(b._dbInfo=c,c.serializer=Va,va.resolve()):va.reject()}function ia(a){var b=this,c=b.ready().then(function(){for(var a=b._dbInfo.keyPrefix,c=localStorage.length-1;c>=0;c--){var d=localStorage.key(c);0===d.indexOf(a)&&localStorage.removeItem(d)}});return h(c,a),c}function ja(a,b){var c=this;a=j(a);var d=c.ready().then(function(){var b=c._dbInfo,d=localStorage.getItem(b.keyPrefix+a);return d&&(d=b.serializer.deserialize(d)),d});return h(d,b),d}function ka(a,b){var c=this,d=c.ready().then(function(){for(var b=c._dbInfo,d=b.keyPrefix,e=d.length,f=localStorage.length,g=1,h=0;h=0;b--){var c=localStorage.key(b);0===c.indexOf(a)&&localStorage.removeItem(c)}}):va.reject("Invalid arguments"),h(d,b),d}function ra(a,b){a[b]=function(){var c=arguments;return a.ready().then(function(){return a[b].apply(a,c)})}}function sa(){for(var a=1;a delete tokenCache[key]);
- await objectStore.delete('tokenCache');
+ await objectStore.removeItem('tokenCache');
} catch (e) {
- console.log('Chat Completions: unable to reset token cache in IndexedDB', e);
+ console.log('Chat Completions: unable to reset token cache', e);
}
}
@@ -298,7 +298,7 @@ function setOpenAIMessages(chat) {
// Apply the "wrap in quotes" option
if (role == 'user' && oai_settings.wrap_in_quotes) content = `"${content}"`;
const name = chat[j]['name'];
- openai_msgs[i] = { "role": role, "content": content, name: name};
+ openai_msgs[i] = { "role": role, "content": content, name: name };
j++;
}
@@ -532,7 +532,7 @@ function populateDialogueExamples(prompts, chatCompletion) {
chatCompletion.freeBudget(newExampleChat);
const chatExamples = chatCompletion.getMessages().getItemByIdentifier('dialogueExamples').getCollection();
- if(chatExamples.length) chatCompletion.insertAtStart(newExampleChat,'dialogueExamples');
+ if (chatExamples.length) chatCompletion.insertAtStart(newExampleChat, 'dialogueExamples');
}
}
@@ -546,7 +546,7 @@ function populateDialogueExamples(prompts, chatCompletion) {
* @param {string} options.quietPrompt - Instruction prompt for extras
* @param {string} options.type - The type of the chat, can be 'impersonate'.
*/
-function populateChatCompletion (prompts, chatCompletion, {bias, quietPrompt, type, cyclePrompt} = {}) {
+function populateChatCompletion(prompts, chatCompletion, { bias, quietPrompt, type, cyclePrompt } = {}) {
// Helper function for preparing a prompt, that already exists within the prompt collection, for completion
const addToChatCompletion = (source, target = null) => {
// We need the prompts array to determine a position for the source.
@@ -616,7 +616,7 @@ function populateChatCompletion (prompts, chatCompletion, {bias, quietPrompt, ty
}
// Persona Description
- if(power_user.persona_description) {
+ if (power_user.persona_description) {
const personaDescription = Message.fromPrompt(prompts.get('personaDescription'));
try {
@@ -678,16 +678,16 @@ function preparePromptsForChatCompletion(Scenario, charPersonality, name2, world
// Create entries for system prompts
const systemPrompts = [
// Ordered prompts for which a marker should exist
- {role: 'system', content: formatWorldInfo(worldInfoBefore), identifier: 'worldInfoBefore'},
- {role: 'system', content: formatWorldInfo(worldInfoAfter), identifier: 'worldInfoAfter'},
- {role: 'system', content: charDescription, identifier: 'charDescription'},
- {role: 'system', content: charPersonalityText, identifier: 'charPersonality'},
- {role: 'system', content: scenarioText, identifier: 'scenario'},
+ { role: 'system', content: formatWorldInfo(worldInfoBefore), identifier: 'worldInfoBefore' },
+ { role: 'system', content: formatWorldInfo(worldInfoAfter), identifier: 'worldInfoAfter' },
+ { role: 'system', content: charDescription, identifier: 'charDescription' },
+ { role: 'system', content: charPersonalityText, identifier: 'charPersonality' },
+ { role: 'system', content: scenarioText, identifier: 'scenario' },
// Unordered prompts without marker
- {role: 'system', content: oai_settings.nsfw_avoidance_prompt, identifier: 'nsfwAvoidance'},
- {role: 'system', content: oai_settings.impersonation_prompt, identifier: 'impersonate'},
- {role: 'system', content: quietPrompt, identifier: 'quietPrompt'},
- {role: 'system', content: bias, identifier: 'bias'}
+ { role: 'system', content: oai_settings.nsfw_avoidance_prompt, identifier: 'nsfwAvoidance' },
+ { role: 'system', content: oai_settings.impersonation_prompt, identifier: 'impersonate' },
+ { role: 'system', content: quietPrompt, identifier: 'quietPrompt' },
+ { role: 'system', content: bias, identifier: 'bias' }
];
// Tavern Extras - Summary
@@ -708,7 +708,7 @@ function preparePromptsForChatCompletion(Scenario, charPersonality, name2, world
// Persona Description
if (power_user.persona_description) {
- systemPrompts.push({role: 'system', content: power_user.persona_description, identifier: 'personaDescription'});
+ systemPrompts.push({ role: 'system', content: power_user.persona_description, identifier: 'personaDescription' });
}
// This is the prompt order defined by the user
@@ -778,18 +778,18 @@ function preparePromptsForChatCompletion(Scenario, charPersonality, name2, world
* @returns {(*[]|boolean)[]} An array where the first element is the prepared chat and the second element is a boolean flag.
*/
function prepareOpenAIMessages({
- name2,
- charDescription,
- charPersonality,
- Scenario,
- worldInfoBefore,
- worldInfoAfter,
- bias,
- type,
- quietPrompt,
- extensionPrompts,
- cyclePrompt
- } = {}, dryRun) {
+ name2,
+ charDescription,
+ charPersonality,
+ Scenario,
+ worldInfoBefore,
+ worldInfoAfter,
+ bias,
+ type,
+ quietPrompt,
+ extensionPrompts,
+ cyclePrompt
+} = {}, dryRun) {
// Without a character selected, there is no way to accurately calculate tokens
if (!promptManager.activeCharacter && dryRun) return [null, false];
@@ -804,13 +804,13 @@ function prepareOpenAIMessages({
const prompts = preparePromptsForChatCompletion(Scenario, charPersonality, name2, worldInfoBefore, worldInfoAfter, charDescription, quietPrompt, bias, extensionPrompts);
// Fill the chat completion with as much context as the budget allows
- populateChatCompletion(prompts, chatCompletion, {bias, quietPrompt, type, cyclePrompt});
+ populateChatCompletion(prompts, chatCompletion, { bias, quietPrompt, type, cyclePrompt });
} catch (error) {
if (error instanceof TokenBudgetExceededError) {
toastr.error('An error occurred while counting tokens: Token budget exceeded.')
chatCompletion.log('Token budget exceeded.');
promptManager.error = 'Not enough free tokens for mandatory prompts. Raise your token Limit or disable custom prompts.';
- } else if (error instanceof InvalidCharacterNameError) {
+ } else if (error instanceof InvalidCharacterNameError) {
toastr.warning('An error occurred while counting tokens: Invalid character name')
chatCompletion.log('Invalid character name');
promptManager.error = 'The name of at least one character contained whitespaces or special characters. Please check your user and character name.';
@@ -1267,7 +1267,7 @@ class TokenHandler {
}
resetCounts() {
- Object.keys(this.counts).forEach((key) => this.counts[key] = 0 );
+ Object.keys(this.counts).forEach((key) => this.counts[key] = 0);
}
setCounts(counts) {
@@ -1397,7 +1397,7 @@ class Message {
this.content = content;
if (this.content) {
- this.tokens = tokenHandler.count({role: this.role, content: this.content})
+ this.tokens = tokenHandler.count({ role: this.role, content: this.content })
} else {
this.tokens = 0;
}
@@ -1421,7 +1421,7 @@ class Message {
* Returns the number of tokens in the message.
* @returns {number} Number of tokens in the message.
*/
- getTokens() {return this.tokens};
+ getTokens() { return this.tokens };
}
/**
@@ -1429,7 +1429,7 @@ class Message {
*
* @class MessageCollection
*/
-class MessageCollection {
+class MessageCollection {
collection = [];
identifier;
@@ -1439,8 +1439,8 @@ class MessageCollection {
* @param {...Object} items - An array of Message or MessageCollection instances to be added to the collection.
*/
constructor(identifier, ...items) {
- for(let item of items) {
- if(!(item instanceof Message || item instanceof MessageCollection)) {
+ for (let item of items) {
+ if (!(item instanceof Message || item instanceof MessageCollection)) {
throw new Error('Only Message and MessageCollection instances can be added to MessageCollection');
}
}
@@ -1456,7 +1456,7 @@ class MessageCollection {
getChat() {
return this.collection.reduce((acc, message) => {
const name = message.name;
- if (message.content) acc.push({role: message.role, ...(name && { name }), content: message.content});
+ if (message.content) acc.push({ role: message.role, ...(name && { name }), content: message.content });
return acc;
}, []);
}
@@ -2450,7 +2450,7 @@ function onSettingsPresetChange() {
settingsToUpdate: settingsToUpdate,
settings: oai_settings,
savePreset: saveOpenAIPreset
- }).finally(r =>{
+ }).finally(r => {
for (const [key, [selector, setting, isCheckbox]] of Object.entries(settingsToUpdate)) {
if (preset[key] !== undefined) {
if (isCheckbox) {
@@ -2799,8 +2799,8 @@ function onProxyPasswordShowClick() {
$(this).toggleClass('fa-eye-slash fa-eye');
}
-$(document).ready(function () {
- loadTokenCache();
+$(document).ready(async function () {
+ await loadTokenCache();
$('#test_api_button').on('click', testApiConnection);
diff --git a/public/scripts/utils.js b/public/scripts/utils.js
index cfa22e81e..94ee9bf30 100644
--- a/public/scripts/utils.js
+++ b/public/scripts/utils.js
@@ -370,99 +370,6 @@ export function splitRecursive(input, length, delimitiers = ['\n\n', '\n', ' ',
return result;
}
-export class IndexedDBStore {
- constructor(dbName, storeName) {
- this.dbName = dbName;
- this.storeName = storeName;
- this.db = null;
- this.version = Date.now();
- }
-
- async open() {
- return new Promise((resolve, reject) => {
- const request = indexedDB.open(this.dbName, this.version);
-
- request.onupgradeneeded = (event) => {
- const db = event.target.result;
- if (!db.objectStoreNames.contains(this.storeName)) {
- db.createObjectStore(this.storeName, { keyPath: null, autoIncrement: false });
- }
- };
-
- request.onsuccess = (event) => {
- console.debug(`IndexedDBStore.open(${this.dbName})`);
- this.db = event.target.result;
- resolve(this.db);
- };
-
- request.onerror = (event) => {
- console.error(`IndexedDBStore.open(${this.dbName})`);
- reject(event.target.error);
- };
- });
- }
-
- async get(key) {
- if (!this.db) await this.open();
-
- return new Promise((resolve, reject) => {
- const transaction = this.db.transaction(this.storeName, "readonly");
- const objectStore = transaction.objectStore(this.storeName);
- const request = objectStore.get(key);
-
- request.onsuccess = (event) => {
- console.debug(`IndexedDBStore.get(${key})`);
- resolve(event.target.result);
- };
-
- request.onerror = (event) => {
- console.error(`IndexedDBStore.get(${key})`);
- reject(event.target.error);
- };
- });
- }
-
- async put(key, object) {
- if (!this.db) await this.open();
-
- return new Promise((resolve, reject) => {
- const transaction = this.db.transaction(this.storeName, "readwrite");
- const objectStore = transaction.objectStore(this.storeName);
- const request = objectStore.put(object, key);
-
- request.onsuccess = (event) => {
- console.debug(`IndexedDBStore.put(${key})`);
- resolve(event.target.result);
- };
-
- request.onerror = (event) => {
- console.error(`IndexedDBStore.put(${key})`);
- reject(event.target.error);
- };
- });
- }
-
- async delete(key) {
- if (!this.db) await this.open();
-
- return new Promise((resolve, reject) => {
- const transaction = this.db.transaction(this.storeName, "readwrite");
- const objectStore = transaction.objectStore(this.storeName);
- const request = objectStore.delete(key);
-
- request.onsuccess = (event) => {
- console.debug(`IndexedDBStore.delete(${key})`);
- resolve(event.target.result);
- };
-
- request.onerror = (event) => {
- console.error(`IndexedDBStore.delete(${key})`);
- reject(event.target.error);
- };
- });
- }
-}
-
export function isDataURL(str) {
const regex = /^data:([a-z]+\/[a-z0-9-+.]+(;[a-z-]+=[a-z0-9-]+)*;?)?(base64)?,([a-z0-9!$&',()*+;=\-_%.~:@\/?#]+)?$/i;
return regex.test(str);