From 547bc4529e034d15e29c81e38ffec6af28050e03 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 11 Mar 2024 22:12:11 +0000 Subject: [PATCH] BUILD --- docs/404.html | 4 ++-- docs/adapters.html | 4 ++-- docs/alternatives.html | 4 ++-- docs/articles/angular-database.html | 4 ++-- docs/articles/browser-database.html | 4 ++-- docs/articles/browser-storage.html | 4 ++-- docs/articles/data-base.html | 4 ++-- docs/articles/embedded-database.html | 4 ++-- docs/articles/flutter-database.html | 4 ++-- docs/articles/frontend-database.html | 4 ++-- docs/articles/in-memory-nosql-database.html | 4 ++-- docs/articles/ionic-database.html | 4 ++-- docs/articles/json-database.html | 4 ++-- docs/articles/localstorage.html | 4 ++-- docs/articles/mobile-database.html | 4 ++-- docs/articles/progressive-web-app-database.html | 4 ++-- docs/articles/react-database.html | 4 ++-- docs/articles/realtime-database.html | 4 ++-- docs/assets/js/8b0a0922.3e8b982e.js | 1 - docs/assets/js/8b0a0922.764803c2.js | 1 + docs/assets/js/{main.5dbc8e9b.js => main.cc3fdfd5.js} | 4 ++-- ...9b.js.LICENSE.txt => main.cc3fdfd5.js.LICENSE.txt} | 0 ...time~main.b89eda5e.js => runtime~main.aa3d2845.js} | 2 +- docs/backup.html | 4 ++-- docs/capacitor-database.html | 4 ++-- docs/chat/index.html | 4 ++-- docs/cleanup.html | 4 ++-- docs/code/index.html | 4 ++-- docs/contribution.html | 4 ++-- docs/crdt.html | 4 ++-- docs/data-migration/index.html | 4 ++-- docs/dev-mode.html | 4 ++-- docs/downsides-of-offline-first.html | 4 ++-- docs/electron-database.html | 4 ++-- docs/electron.html | 4 ++-- docs/encryption.html | 4 ++-- docs/index.html | 4 ++-- docs/install.html | 4 ++-- docs/key-compression.html | 4 ++-- docs/leader-election.html | 4 ++-- docs/legal-notice/index.html | 4 ++-- docs/license/index.html | 4 ++-- docs/logger.html | 4 ++-- docs/lunr-index-1710160459670.json | 1 - docs/lunr-index-1710195091135.json | 1 + docs/lunr-index.json | 2 +- docs/markdown-page/index.html | 4 ++-- docs/meeting/index.html | 4 ++-- docs/middleware.html | 4 ++-- docs/migration-schema.html | 4 ++-- docs/migration-storage.html | 4 ++-- docs/newsletter/index.html | 4 ++-- docs/nodejs-database.html | 4 ++-- docs/nosql-performance-tips.html | 4 ++-- docs/offline-first.html | 4 ++-- docs/orm.html | 4 ++-- docs/plugins.html | 4 ++-- docs/population.html | 4 ++-- docs/premium-submitted/index.html | 4 ++-- docs/premium/index.html | 4 ++-- docs/query-cache.html | 4 ++-- docs/query-optimizer.html | 4 ++-- docs/questions-answers.html | 4 ++-- docs/quickstart.html | 4 ++-- docs/react-native-database.html | 4 ++-- docs/reactivity.html | 4 ++-- docs/releases/10.0.0.html | 4 ++-- docs/releases/11.0.0.html | 4 ++-- docs/releases/12.0.0.html | 4 ++-- docs/releases/13.0.0.html | 4 ++-- docs/releases/14.0.0.html | 4 ++-- docs/releases/15.0.0.html | 4 ++-- docs/releases/8.0.0.html | 4 ++-- docs/releases/9.0.0.html | 4 ++-- docs/replication-couchdb.html | 4 ++-- docs/replication-firestore.html | 4 ++-- docs/replication-graphql.html | 4 ++-- docs/replication-http.html | 4 ++-- docs/replication-nats.html | 4 ++-- docs/replication-p2p.html | 4 ++-- docs/replication-server/index.html | 4 ++-- docs/replication-webrtc.html | 4 ++-- docs/replication-websocket.html | 4 ++-- docs/replication.html | 4 ++-- docs/rx-attachment.html | 4 ++-- docs/rx-collection.html | 4 ++-- docs/rx-database.html | 4 ++-- docs/rx-document.html | 4 ++-- docs/rx-local-document.html | 4 ++-- docs/rx-query.html | 4 ++-- docs/rx-schema.html | 4 ++-- docs/rx-server-scaling.html | 4 ++-- docs/rx-server.html | 4 ++-- docs/rx-state.html | 4 ++-- docs/rx-storage-denokv.html | 4 ++-- docs/rx-storage-dexie.html | 4 ++-- docs/rx-storage-filesystem-node.html | 4 ++-- docs/rx-storage-foundationdb.html | 4 ++-- docs/rx-storage-indexeddb.html | 4 ++-- docs/rx-storage-localstorage-meta-optimizer.html | 4 ++-- docs/rx-storage-lokijs.html | 4 ++-- docs/rx-storage-memory-synced.html | 4 ++-- docs/rx-storage-memory.html | 4 ++-- docs/rx-storage-mongodb.html | 4 ++-- docs/rx-storage-opfs.html | 4 ++-- docs/rx-storage-performance.html | 4 ++-- docs/rx-storage-pouchdb.html | 4 ++-- docs/rx-storage-remote.html | 4 ++-- docs/rx-storage-sharding.html | 4 ++-- docs/rx-storage-shared-worker.html | 4 ++-- docs/rx-storage-sqlite.html | 4 ++-- docs/rx-storage-worker.html | 4 ++-- docs/rx-storage.html | 4 ++-- docs/rxdb-tradeoffs.html | 4 ++-- docs/schema-validation.html | 4 ++-- docs/search-doc-1710160459670.json | 1 - docs/search-doc-1710195091135.json | 1 + docs/search-doc.json | 2 +- docs/slow-indexeddb.html | 11 ++++------- docs/survey/index.html | 4 ++-- docs/third-party-plugins.html | 4 ++-- docs/transactions-conflicts-revisions.html | 4 ++-- docs/tutorials/typescript.html | 4 ++-- docs/why-nosql.html | 4 ++-- 124 files changed, 236 insertions(+), 239 deletions(-) delete mode 100644 docs/assets/js/8b0a0922.3e8b982e.js create mode 100644 docs/assets/js/8b0a0922.764803c2.js rename docs/assets/js/{main.5dbc8e9b.js => main.cc3fdfd5.js} (99%) rename docs/assets/js/{main.5dbc8e9b.js.LICENSE.txt => main.cc3fdfd5.js.LICENSE.txt} (100%) rename docs/assets/js/{runtime~main.b89eda5e.js => runtime~main.aa3d2845.js} (99%) delete mode 100644 docs/lunr-index-1710160459670.json create mode 100644 docs/lunr-index-1710195091135.json delete mode 100644 docs/search-doc-1710160459670.json create mode 100644 docs/search-doc-1710195091135.json diff --git a/docs/404.html b/docs/404.html index 45262703cf6..1c57b89ef97 100644 --- a/docs/404.html +++ b/docs/404.html @@ -15,8 +15,8 @@ - - + +
diff --git a/docs/adapters.html b/docs/adapters.html index 07c1e755fe8..92925c689b5 100644 --- a/docs/adapters.html +++ b/docs/adapters.html @@ -15,8 +15,8 @@ - - + + diff --git a/docs/alternatives.html b/docs/alternatives.html index d8ce179fc24..a4c574cc7cd 100644 --- a/docs/alternatives.html +++ b/docs/alternatives.html @@ -15,8 +15,8 @@ - - + + diff --git a/docs/articles/angular-database.html b/docs/articles/angular-database.html index 1fb46b83062..e7e536dedbd 100644 --- a/docs/articles/angular-database.html +++ b/docs/articles/angular-database.html @@ -15,8 +15,8 @@ - - + + diff --git a/docs/articles/browser-database.html b/docs/articles/browser-database.html index 3105cf68311..153ff26aec5 100644 --- a/docs/articles/browser-database.html +++ b/docs/articles/browser-database.html @@ -15,8 +15,8 @@ - - + + diff --git a/docs/articles/browser-storage.html b/docs/articles/browser-storage.html index 53fd4e881fc..f89ec82e4f5 100644 --- a/docs/articles/browser-storage.html +++ b/docs/articles/browser-storage.html @@ -15,8 +15,8 @@ - - + + diff --git a/docs/articles/data-base.html b/docs/articles/data-base.html index 891821bfcb6..ba149da3f10 100644 --- a/docs/articles/data-base.html +++ b/docs/articles/data-base.html @@ -15,8 +15,8 @@ - - + + diff --git a/docs/articles/embedded-database.html b/docs/articles/embedded-database.html index a713546d71f..bb85e31e2e8 100644 --- a/docs/articles/embedded-database.html +++ b/docs/articles/embedded-database.html @@ -15,8 +15,8 @@ - - + + diff --git a/docs/articles/flutter-database.html b/docs/articles/flutter-database.html index c8c9ed6b624..36d28d704c6 100644 --- a/docs/articles/flutter-database.html +++ b/docs/articles/flutter-database.html @@ -15,8 +15,8 @@ - - + + diff --git a/docs/articles/frontend-database.html b/docs/articles/frontend-database.html index 87cbd51bf24..30b141f0551 100644 --- a/docs/articles/frontend-database.html +++ b/docs/articles/frontend-database.html @@ -15,8 +15,8 @@ - - + + diff --git a/docs/articles/in-memory-nosql-database.html b/docs/articles/in-memory-nosql-database.html index e386af66e3a..09eef4ceac5 100644 --- a/docs/articles/in-memory-nosql-database.html +++ b/docs/articles/in-memory-nosql-database.html @@ -15,8 +15,8 @@ - - + + diff --git a/docs/articles/ionic-database.html b/docs/articles/ionic-database.html index 5e3ca6eec40..576bfdcd5a7 100644 --- a/docs/articles/ionic-database.html +++ b/docs/articles/ionic-database.html @@ -15,8 +15,8 @@ - - + + diff --git a/docs/articles/json-database.html b/docs/articles/json-database.html index 8b5e6ca9dac..9a7bc678444 100644 --- a/docs/articles/json-database.html +++ b/docs/articles/json-database.html @@ -15,8 +15,8 @@ - - + + diff --git a/docs/articles/localstorage.html b/docs/articles/localstorage.html index f269ac2760c..16152518663 100644 --- a/docs/articles/localstorage.html +++ b/docs/articles/localstorage.html @@ -15,8 +15,8 @@ - - + + diff --git a/docs/articles/mobile-database.html b/docs/articles/mobile-database.html index 29fd1d5625d..16caac5fbd4 100644 --- a/docs/articles/mobile-database.html +++ b/docs/articles/mobile-database.html @@ -15,8 +15,8 @@ - - + + diff --git a/docs/articles/progressive-web-app-database.html b/docs/articles/progressive-web-app-database.html index e2478fc22e8..ac660518f66 100644 --- a/docs/articles/progressive-web-app-database.html +++ b/docs/articles/progressive-web-app-database.html @@ -15,8 +15,8 @@ - - + + diff --git a/docs/articles/react-database.html b/docs/articles/react-database.html index ca077e7b92b..d32c7805159 100644 --- a/docs/articles/react-database.html +++ b/docs/articles/react-database.html @@ -15,8 +15,8 @@ - - + + diff --git a/docs/articles/realtime-database.html b/docs/articles/realtime-database.html index 5f561ba1dfe..9f42b2c997d 100644 --- a/docs/articles/realtime-database.html +++ b/docs/articles/realtime-database.html @@ -15,8 +15,8 @@ - - + + diff --git a/docs/assets/js/8b0a0922.3e8b982e.js b/docs/assets/js/8b0a0922.3e8b982e.js deleted file mode 100644 index 9ad626267ef..00000000000 --- a/docs/assets/js/8b0a0922.3e8b982e.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkrxdb=self.webpackChunkrxdb||[]).push([[4557],{767:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>d,contentTitle:()=>i,default:()=>c,frontMatter:()=>r,metadata:()=>o,toc:()=>l});var s=t(4848),a=t(8453);const r={title:"Slow IndexedDB",slug:"slow-indexeddb.html"},i="Why IndexedDB is slow and what to use instead",o={id:"slow-indexeddb",title:"Slow IndexedDB",description:"So you have a JavaScript web application that needs to store data at the client side, either to make it offline usable, just for caching purposes or for other reasons.",source:"@site/docs/slow-indexeddb.md",sourceDirName:".",slug:"/slow-indexeddb.html",permalink:"/slow-indexeddb.html",draft:!1,unlisted:!1,tags:[],version:"current",frontMatter:{title:"Slow IndexedDB",slug:"slow-indexeddb.html"},sidebar:"tutorialSidebar",previous:{title:"Downsides of Local First / Offline First",permalink:"/downsides-of-offline-first.html"},next:{title:"Why NOSQL",permalink:"/why-nosql.html"}},d={},l=[{value:"UPDATE April 2023: Since beginning of 2023, all modern browsers ship the File System Access API which allows to persistently store data in the browser with a way better performance. For RxDB you can use the OPFS RxStorage to get about 4x performance improvement compared to IndexedDB.",id:"update-april-2023-since-beginning-of-2023-all-modern-browsers-ship-the-file-system-access-api-which-allows-to-persistently-store-data-in-the-browser-with-a-way-better-performance-for-rxdb-you-can-use-the-opfs-rxstorage-to-get-about-4x-performance-improvement-compared-to-indexeddb",level:3},{value:"Batched Cursor",id:"batched-cursor",level:2},{value:"IndexedDB Sharding",id:"indexeddb-sharding",level:2},{value:"Custom Indexes",id:"custom-indexes",level:2},{value:"Relaxed durability",id:"relaxed-durability",level:2},{value:"Explicit transaction commits",id:"explicit-transaction-commits",level:2},{value:"In-Memory on top of IndexedDB",id:"in-memory-on-top-of-indexeddb",level:2},{value:"In-Memory: Persistence",id:"in-memory-persistence",level:3},{value:"In-Memory: Multi Tab Support",id:"in-memory-multi-tab-support",level:3},{value:"Further read",id:"further-read",level:2}];function h(e){const n={a:"a",blockquote:"blockquote",code:"code",h1:"h1",h2:"h2",h3:"h3",hr:"hr",li:"li",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,a.R)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(n.h1,{id:"why-indexeddb-is-slow-and-what-to-use-instead",children:"Why IndexedDB is slow and what to use instead"}),"\n",(0,s.jsx)(n.p,{children:"So you have a JavaScript web application that needs to store data at the client side, either to make it offline usable, just for caching purposes or for other reasons."}),"\n",(0,s.jsxs)(n.p,{children:["For ",(0,s.jsx)(n.a,{href:"/articles/browser-database.html",children:"in-browser data storage"}),", you have some options:"]}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.strong,{children:"Cookies"})," are sent with each HTTP request, so you cannot store more then a few strings in them."]}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.strong,{children:"WebSQL"})," ",(0,s.jsx)(n.a,{href:"https://hacks.mozilla.org/2010/06/beyond-html5-database-apis-and-the-road-to-indexeddb/",children:"is deprecated"})," because it never was a real standard and turning it into a standard would have been too difficult."]}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.a,{href:"/articles/localstorage.html",children:"LocalStorage"})," is a synchronous API over asynchronous IO-access. Storing and reading data can fully block the JavaScript process so you cannot use LocalStorage for more then few simple key-value pairs."]}),"\n",(0,s.jsxs)(n.li,{children:["The ",(0,s.jsx)(n.strong,{children:"FileSystem API"})," could be used to store plain binary files, but it is ",(0,s.jsx)(n.a,{href:"https://caniuse.com/filesystem",children:"only supported in chrome"})," for now."]}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.strong,{children:"IndexedDB"})," is an indexed key-object database. It can store json data and iterate over its indexes. It is ",(0,s.jsx)(n.a,{href:"https://caniuse.com/indexeddb",children:"widely supported"})," and stable."]}),"\n"]}),"\n",(0,s.jsx)(n.hr,{}),"\n",(0,s.jsxs)(n.h3,{id:"update-april-2023-since-beginning-of-2023-all-modern-browsers-ship-the-file-system-access-api-which-allows-to-persistently-store-data-in-the-browser-with-a-way-better-performance-for-rxdb-you-can-use-the-opfs-rxstorage-to-get-about-4x-performance-improvement-compared-to-indexeddb",children:[(0,s.jsx)(n.strong,{children:"UPDATE April 2023:"})," Since beginning of 2023, all modern browsers ship the ",(0,s.jsx)(n.strong,{children:"File System Access API"})," which allows to persistently store data in the browser with a way better performance. For ",(0,s.jsx)(n.a,{href:"https://rxdb.info/",children:"RxDB"})," you can use the ",(0,s.jsx)(n.a,{href:"/rx-storage-opfs.html",children:"OPFS RxStorage"})," to get about 4x performance improvement compared to IndexedDB."]}),"\n",(0,s.jsx)("center",{children:(0,s.jsx)("a",{href:"https://rxdb.info/",children:(0,s.jsx)("img",{src:"./files/logo/rxdb_javascript_database.svg",alt:"IndexedDB Database",width:"250"})})}),"\n",(0,s.jsx)(n.hr,{}),"\n",(0,s.jsxs)(n.p,{children:["It becomes clear that the only way to go is IndexedDB. You start developing your app and everything goes fine.\nBut as soon as your app gets bigger, more complex or just handles more data, you might notice something. ",(0,s.jsx)(n.strong,{children:"IndexedDB is slow"}),". Not slow like a database on a cheap server, ",(0,s.jsx)(n.strong,{children:"even slower"}),"! Inserting a few hundred documents can take up several seconds. Time which can be critical for a fast page load. Even sending data over the internet to the backend can be faster then storing it inside of an IndexedDB database."]}),"\n",(0,s.jsxs)(n.blockquote,{children:["\n",(0,s.jsx)(n.p,{children:"Transactions vs Throughput"}),"\n"]}),"\n",(0,s.jsxs)(n.p,{children:["So before we start complaining, lets analyze what exactly is slow. When you run tests on Nolans ",(0,s.jsx)(n.a,{href:"http://nolanlawson.github.io/database-comparison/",children:"Browser Database Comparison"})," you can see that inserting 1k documents into IndexedDB takes about 80 milliseconds, 0.08ms per document. This is not really slow. It is quite fast and it is very unlikely that you want to store that many document at the same time at the client side. But the key point here is that all these documents get written in a ",(0,s.jsx)(n.code,{children:"single transaction"}),"."]}),"\n",(0,s.jsxs)(n.p,{children:["I forked the comparison tool ",(0,s.jsx)(n.a,{href:"https://pubkey.github.io/client-side-databases/database-comparison/index.html",children:"here"})," and changed it to use one transaction per document write. And there we have it. Inserting 1k documents with one transaction per write, takes about 2 seconds. Interestingly if we increase the document size to be 100x bigger, it still takes about the same time to store them. This makes clear that the limiting factor to IndexedDB performance is the transaction handling, not the data throughput."]}),"\n",(0,s.jsx)("p",{align:"center",children:(0,s.jsx)("img",{src:"./files/indexeddb-transaction-throughput.png",alt:"IndexedDB transaction throughput",width:"700"})}),"\n",(0,s.jsxs)(n.p,{children:["To fix your IndexedDB performance problems you have to make sure to use as less data transfers/transactions as possible.\nSometimes this is easy, as instead of iterating over a documents list and calling single inserts, with RxDB you could use the ",(0,s.jsx)(n.a,{href:"https://rxdb.info/rx-collection.html#bulkinsert",children:"bulk methods"})," to store many document at once.\nBut most of the time is not so easy. Your user clicks around, data gets replicated from the backend, another browser tab writes data. All these things can happen at random time and you cannot crunch all that data in a single transaction."]}),"\n",(0,s.jsxs)(n.p,{children:["Another solution is to just not care about performance at all. In a few releases the browser vendors will have optimized IndexedDB and everything is fast again. Well, IndexedDB was slow ",(0,s.jsx)(n.a,{href:"https://www.researchgate.net/publication/281065948_Performance_Testing_and_Comparison_of_Client_Side_Databases_Versus_Server_Side",children:"in 2013"})," and it is still slow today. If this trend continues, it will still be slow in a few years from now. Waiting is not an option. The chromium devs made ",(0,s.jsx)(n.a,{href:"https://bugs.chromium.org/p/chromium/issues/detail?id=1025456#c15",children:"a statement"})," to focus on optimizing read performance, not write performance."]}),"\n",(0,s.jsxs)(n.p,{children:["Switching to WebSQL (even if it is deprecated) is also not an option because, like ",(0,s.jsx)(n.a,{href:"https://pubkey.github.io/client-side-databases/database-comparison/index.html",children:"the comparison tool shows"}),", it has even slower transactions."]}),"\n",(0,s.jsxs)(n.p,{children:["So you need a way to ",(0,s.jsx)(n.strong,{children:"make IndexedDB faster"}),". In the following I lay out some performance optimizations than can be made to have faster reads and writes in IndexedDB."]}),"\n",(0,s.jsxs)(n.p,{children:[(0,s.jsx)(n.strong,{children:"HINT:"})," You can reproduce all performance tests ",(0,s.jsx)(n.a,{href:"https://github.com/pubkey/indexeddb-performance-tests",children:"in this repo"}),". In all tests we work on a dataset of 40000 ",(0,s.jsx)(n.code,{children:"human"})," documents with a random ",(0,s.jsx)(n.code,{children:"age"})," between ",(0,s.jsx)(n.code,{children:"1"})," and ",(0,s.jsx)(n.code,{children:"100"}),"."]}),"\n",(0,s.jsx)(n.h2,{id:"batched-cursor",children:"Batched Cursor"}),"\n",(0,s.jsxs)(n.p,{children:["With ",(0,s.jsx)(n.a,{href:"https://caniuse.com/indexeddb2",children:"IndexedDB 2.0"}),", new methods were introduced which can be utilized to improve performance. With the ",(0,s.jsx)(n.code,{children:"getAll()"})," method, a faster alternative to the old ",(0,s.jsx)(n.code,{children:"openCursor()"})," can be created which improves performance when reading data from the IndexedDB store."]}),"\n",(0,s.jsxs)(n.p,{children:["Lets say we want to query all user documents that have an ",(0,s.jsx)(n.code,{children:"age"})," greater then ",(0,s.jsx)(n.code,{children:"25"})," out of the store.\nTo implement a fast batched cursor that only needs calls to ",(0,s.jsx)(n.code,{children:"getAll()"})," and not to ",(0,s.jsx)(n.code,{children:"getAllKeys()"}),", we first need to create an ",(0,s.jsx)(n.code,{children:"age"})," index that contains the primary ",(0,s.jsx)(n.code,{children:"id"})," as last field."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-ts",children:"myIndexedDBObjectStore.createIndex(\n 'age-index',\n [\n 'age',\n 'id'\n ]\n);\n"})}),"\n",(0,s.jsxs)(n.p,{children:["This is required because the ",(0,s.jsx)(n.code,{children:"age"})," field is not unique, and we need a way to checkpoint the last returned batch so we can continue from there in the next call to ",(0,s.jsx)(n.code,{children:"getAll()"}),"."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-ts",children:"const maxAge = 25;\nlet result = [];\nconst tx: IDBTransaction = db.transaction([storeName], 'readonly', TRANSACTION_SETTINGS);\nconst store = tx.objectStore(storeName);\nconst index = store.index('age-index');\nlet lastDoc;\nlet done = false;\n/**\n * Run the batched cursor until all results are retrieved\n * or the end of the index is reached.\n */\nwhile (done === false) {\n await new Promise((res, rej) => {\n const range = IDBKeyRange.bound(\n /**\n * If we have a previous document as checkpoint,\n * we have to continue from it's age and id values.\n */\n [\n lastDoc ? lastDoc.age : -Infinity,\n lastDoc ? lastDoc.id : -Infinity,\n ],\n [\n maxAge + 0.00000001,\n String.fromCharCode(65535)\n ],\n true,\n false\n );\n const openCursorRequest = index.getAll(range, batchSize);\n openCursorRequest.onerror = err => rej(err);\n openCursorRequest.onsuccess = e => {\n const subResult: TestDocument[] = e.target.result;\n lastDoc = lastOfArray(subResult);\n if (subResult.length === 0) {\n done = true;\n } else {\n result = result.concat(subResult);\n }\n res();\n };\n });\n}\nconsole.dir(result);\n"})}),"\n",(0,s.jsx)("p",{align:"center",children:(0,s.jsx)("img",{src:"./files/indexeddb-batched-cursor.png",alt:"IndexedDB batched cursor",width:"100%"})}),"\n",(0,s.jsxs)(n.p,{children:["As the performance test results show, using a batched cursor can give a huge improvement. Interestingly choosing a high batch size is important. When you known that all results of a given ",(0,s.jsx)(n.code,{children:"IDBKeyRange"})," are needed, you should not set a batch size at all and just directly query all documents via ",(0,s.jsx)(n.code,{children:"getAll()"}),"."]}),"\n",(0,s.jsxs)(n.p,{children:["RxDB uses batched cursors in the ",(0,s.jsx)(n.a,{href:"/rx-storage-indexeddb.html",children:"IndexedDB RxStorage"}),"."]}),"\n",(0,s.jsx)(n.h2,{id:"indexeddb-sharding",children:"IndexedDB Sharding"}),"\n",(0,s.jsxs)(n.p,{children:["Sharding is a technique, normally used in server side databases, where the database is partitioned horizontally. Instead of storing all documents at one table/collection, the documents are split into so called ",(0,s.jsx)(n.strong,{children:"shards"})," and each shard is stored on one table/collection. This is done in server side architectures to spread the load between multiple physical servers which ",(0,s.jsx)(n.strong,{children:"increases scalability"}),"."]}),"\n",(0,s.jsxs)(n.p,{children:["When you use IndexedDB in a browser, there is of course no way to split the load between the client and other servers. But you can still benefit from sharding. Partitioning the documents horizontally into ",(0,s.jsx)(n.strong,{children:"multiple IndexedDB stores"}),", has shown to have a big performance improvement in write- and read operations while only increasing initial pageload slightly."]}),"\n",(0,s.jsx)("p",{align:"center",children:(0,s.jsx)("img",{src:"./files/indexeddb-sharding-performance.png",alt:"IndexedDB sharding performance",width:"100%"})}),"\n",(0,s.jsxs)(n.p,{children:["As shown in the performance test results, sharding should always be done by ",(0,s.jsx)(n.code,{children:"IDBObjectStore"})," and not by database. Running a batched cursor over the whole dataset with 10 store shards in parallel is about ",(0,s.jsx)(n.strong,{children:"28% faster"})," then running it over a single store. Initialization time increases minimal from ",(0,s.jsx)(n.code,{children:"9"})," to ",(0,s.jsx)(n.code,{children:"17"})," milliseconds.\nGetting a quarter of the dataset by batched iterating over an index, is even ",(0,s.jsx)(n.strong,{children:"43%"})," faster with sharding then when a single store is queried."]}),"\n",(0,s.jsx)(n.p,{children:"As downside, getting 10k documents by their id is slower when it has to run over the shards.\nAlso it can be much effort to recombined the results from the different shards into the required query result. When a query without a limit is done, the sharding method might cause a data load huge overhead."}),"\n",(0,s.jsxs)(n.p,{children:["Sharding can be used with RxDB with the ",(0,s.jsx)(n.a,{href:"/rx-storage-sharding.html",children:"Sharding Plugin"}),"."]}),"\n",(0,s.jsx)(n.h2,{id:"custom-indexes",children:"Custom Indexes"}),"\n",(0,s.jsx)(n.p,{children:"Indexes improve the query performance of IndexedDB significant. Instead of fetching all data from the storage when you search for a subset of it, you can iterate over the index and stop iterating when all relevant data has been found."}),"\n",(0,s.jsxs)(n.p,{children:["For example to query for all user documents that have an ",(0,s.jsx)(n.code,{children:"age"})," greater than ",(0,s.jsx)(n.code,{children:"25"}),", you would create an ",(0,s.jsx)(n.code,{children:"age+id"})," index.\nTo be able to run a batched cursor over the index, we always need our primary key (",(0,s.jsx)(n.code,{children:"id"}),") as the last index field."]}),"\n",(0,s.jsxs)(n.p,{children:["Instead of doing this, you can use a ",(0,s.jsx)(n.code,{children:"custom index"})," which can improve the performance. The custom index runs over a helper field ",(0,s.jsx)(n.code,{children:"ageIdCustomIndex"})," which is added to each document on write. Our index now only contains a single ",(0,s.jsx)(n.code,{children:"string"})," field instead of two (age-",(0,s.jsx)(n.code,{children:"number"})," and id-",(0,s.jsx)(n.code,{children:"string"}),")."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-ts",children:"// On document insert add the ageIdCustomIndex field.\nconst idMaxLength = 20; // must be known to craft a custom index \ndocData.ageIdCustomIndex = docData.age + docData.id.padStart(idMaxLength, ' ');\nstore.put(docData);\n// ...\n"})}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-ts",children:"// normal index\nmyIndexedDBObjectStore.createIndex(\n 'age-index',\n [\n 'age',\n 'id'\n ]\n);\n\n// custom index\nmyIndexedDBObjectStore.createIndex(\n 'age-index-custom',\n [\n 'ageIdCustomIndex'\n ]\n);\n\n"})}),"\n",(0,s.jsxs)(n.p,{children:["To iterate over the index, you also use a custom crafted keyrange, depending on the last batched cursor checkpoint. Therefore the ",(0,s.jsx)(n.code,{children:"maxLength"})," of ",(0,s.jsx)(n.code,{children:"id"})," must be known."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-ts",children:"// keyrange for normal index\nconst range = IDBKeyRange.bound(\n [25, ''],\n [Infinity, Infinity],\n true,\n false\n);\n\n// keyrange for custom index\nconst range = IDBKeyRange.bound(\n // combine both values to a single string\n 25 + ''.padStart(idMaxLength, ' '),\n Infinity,\n true,\n false\n);\n"})}),"\n",(0,s.jsx)("p",{align:"center",children:(0,s.jsx)("img",{src:"./files/indexeddb-custom-index.png",alt:"IndexedDB custom index",width:"700"})}),"\n",(0,s.jsxs)(n.p,{children:["As shown, using a custom index can further improve the performance of running a batched cursor by about ",(0,s.jsx)(n.code,{children:"10%"}),"."]}),"\n",(0,s.jsxs)(n.p,{children:["Another big benefit of using custom indexes, is that you can also encode ",(0,s.jsx)(n.code,{children:"boolean"})," values in them, which ",(0,s.jsx)(n.a,{href:"https://github.com/w3c/IndexedDB/issues/76",children:"cannot be done"})," with normal IndexedDB indexes."]}),"\n",(0,s.jsxs)(n.p,{children:["RxDB uses custom indexes in the ",(0,s.jsx)(n.a,{href:"/rx-storage-indexeddb.html",children:"IndexedDB RxStorage"}),"."]}),"\n",(0,s.jsx)(n.h2,{id:"relaxed-durability",children:"Relaxed durability"}),"\n",(0,s.jsxs)(n.p,{children:["Chromium based browsers allow to set ",(0,s.jsx)(n.a,{href:"https://developer.mozilla.org/en-US/docs/Web/API/IDBTransaction/durability",children:"durability"})," to ",(0,s.jsx)(n.code,{children:"relaxed"})," when creating an IndexedDB transaction. Which runs the transaction in a less secure durability mode, which can improve the performance."]}),"\n",(0,s.jsxs)(n.blockquote,{children:["\n",(0,s.jsx)(n.p,{children:"The user agent may consider that the transaction has successfully committed as soon as all outstanding changes have been written to the operating system, without subsequent verification."}),"\n"]}),"\n",(0,s.jsxs)(n.p,{children:["As shown ",(0,s.jsx)(n.a,{href:"https://nolanlawson.com/2021/08/22/speeding-up-indexeddb-reads-and-writes/",children:"here"}),", using the relaxed durability mode can improve performance slightly. The best performance improvement could be measured when many small transactions have to be run. Less, bigger transaction do not benefit that much."]}),"\n",(0,s.jsx)(n.h2,{id:"explicit-transaction-commits",children:"Explicit transaction commits"}),"\n",(0,s.jsxs)(n.p,{children:["By explicitly committing a transaction, another slight performance improvement can be achieved. Instead of waiting for the browser to commit an open transaction, we call the ",(0,s.jsx)(n.code,{children:"commit()"})," method to explicitly close it."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-ts",children:"// .commit() is not available on all browsers, so first check if it exists.\nif (transaction.commit) {\n transaction.commit()\n}\n"})}),"\n",(0,s.jsxs)(n.p,{children:["The improvement of this technique is minimal, but observable as ",(0,s.jsx)(n.a,{href:"https://nolanlawson.com/2021/08/22/speeding-up-indexeddb-reads-and-writes/",children:"these tests"})," show."]}),"\n",(0,s.jsx)(n.h2,{id:"in-memory-on-top-of-indexeddb",children:"In-Memory on top of IndexedDB"}),"\n",(0,s.jsxs)(n.p,{children:["To prevent transaction handling and to fix the performance problems, we need to stop using IndexedDB as a database. Instead all data is loaded into the memory on the initial page load. Here all reads and writes happen in memory which is about 100x faster. Only some time after a write occurred, the memory state is persisted into IndexedDB with a ",(0,s.jsx)(n.strong,{children:"single write transaction"}),". In this scenario IndexedDB is used as a filesystem, not as a database."]}),"\n",(0,s.jsx)(n.p,{children:"There are some libraries that already do that:"}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsxs)(n.li,{children:["LokiJS with the ",(0,s.jsx)(n.a,{href:"https://techfort.github.io/LokiJS/LokiIndexedAdapter.html",children:"IndexedDB Adapter"})]}),"\n",(0,s.jsx)(n.li,{children:(0,s.jsx)(n.a,{href:"https://github.com/jlongster/absurd-sql",children:"Absurd-SQL"})}),"\n",(0,s.jsxs)(n.li,{children:["SQL.js with the ",(0,s.jsx)(n.a,{href:"https://emscripten.org/docs/api_reference/Filesystem-API.html#filesystem-api-idbfs",children:"empscripten Filesystem API"})]}),"\n",(0,s.jsx)(n.li,{children:(0,s.jsx)(n.a,{href:"https://duckdb.org/2021/10/29/duckdb-wasm.html",children:"DuckDB Wasm"})}),"\n"]}),"\n",(0,s.jsx)(n.h3,{id:"in-memory-persistence",children:"In-Memory: Persistence"}),"\n",(0,s.jsxs)(n.p,{children:["One downside of not directly using IndexedDB, is that your data is not persistent all the time. And when the JavaScript process exists without having persisted to IndexedDB, data can be lost. To prevent this from happening, we have to ensure that the in-memory state is written down to the disc. One point is make persisting as fast as possible. LokiJS for example has the ",(0,s.jsx)(n.code,{children:"incremental-indexeddb-adapter"})," which only saves new writes to the disc instead of persisting the whole state. Another point is to run the persisting at the correct point in time. For example the RxDB ",(0,s.jsx)(n.a,{href:"https://rxdb.info/rx-storage-lokijs.html",children:"LokiJS storage"})," persists in the following situations:"]}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsx)(n.li,{children:"When the database is idle and no write or query is running. In that time we can persist the state if any new writes appeared before."}),"\n",(0,s.jsxs)(n.li,{children:["When the ",(0,s.jsx)(n.code,{children:"window"})," fires the ",(0,s.jsx)(n.a,{href:"https://developer.mozilla.org/en-US/docs/Web/API/WindowEventHandlers/onbeforeunload",children:"beforeunload event"})," we can assume that the JavaScript process is exited any moment and we have to persist the state. After ",(0,s.jsx)(n.code,{children:"beforeunload"})," there are several seconds time which are sufficient to store all new changes. This has shown to work quite reliable."]}),"\n"]}),"\n",(0,s.jsx)(n.p,{children:"The only missing event that can happen is when the browser exists unexpectedly like when it crashes or when the power of the computer is shut of."}),"\n",(0,s.jsx)(n.h3,{id:"in-memory-multi-tab-support",children:"In-Memory: Multi Tab Support"}),"\n",(0,s.jsx)(n.p,{children:"One big difference between a web application and a 'normal' app, is that your users can use the app in multiple browser tabs at the same time. But when you have all database state in memory and only periodically write it to disc, multiple browser tabs could overwrite each other and you would loose data. This might not be a problem when you rely on a client-server replication, because the lost data might already be replicated with the backend and therefore with the other tabs. But this would not work when the client is offline."}),"\n",(0,s.jsxs)(n.p,{children:["The ideal way to solve that problem, is to use a ",(0,s.jsx)(n.a,{href:"https://developer.mozilla.org/en/docs/Web/API/SharedWorker",children:"SharedWorker"}),". A SharedWorker is like a ",(0,s.jsx)(n.a,{href:"https://developer.mozilla.org/en/docs/Web/API/Web_Workers_API",children:"WebWorker"})," that runs its own JavaScript process only that the SharedWorker is shared between multiple contexts. You could create the database in the SharedWorker and then all browser tabs could request the Worker for data instead of having their own database. But unfortunately the SharedWorker API does ",(0,s.jsx)(n.a,{href:"https://caniuse.com/sharedworkers",children:"not work"})," in all browsers. Safari ",(0,s.jsx)(n.a,{href:"https://bugs.webkit.org/show_bug.cgi?id=140344",children:"dropped"})," its support and InternetExplorer or Android Chrome, never adopted it. Also it cannot be polyfilled. ",(0,s.jsx)(n.strong,{children:"UPDATE:"})," ",(0,s.jsx)(n.a,{href:"https://developer.apple.com/safari/technology-preview/release-notes/",children:"Apple added SharedWorkers back in Safari 142"})]}),"\n",(0,s.jsxs)(n.p,{children:["Instead, we could use the ",(0,s.jsx)(n.a,{href:"https://developer.mozilla.org/en-US/docs/Web/API/Broadcast_Channel_API",children:"BroadcastChannel API"})," to communicate between tabs and then apply a ",(0,s.jsx)(n.a,{href:"https://github.com/pubkey/broadcast-channel#using-the-leaderelection",children:"leader election"})," between them. The leader election ensures that, no matter how many tabs are open, always one tab is the ",(0,s.jsx)(n.code,{children:"Leader"}),"."]}),"\n",(0,s.jsx)("p",{align:"center",children:(0,s.jsx)("img",{src:"./files/leader-election.gif",alt:"Leader Election",width:"500"})}),"\n",(0,s.jsx)(n.p,{children:"The disadvantage is that the leader election process takes some time on the initial page load (about 150 milliseconds). Also the leader election can break when a JavaScript process is fully blocked for a longer time. When this happens, a good way is to just reload the browser tab to restart the election process."}),"\n",(0,s.jsxs)(n.p,{children:["Using a leader election is implemented in the ",(0,s.jsx)(n.a,{href:"/rx-storage-lokijs.html",children:"RxDB LokiJS Storage"}),"."]}),"\n",(0,s.jsx)(n.h2,{id:"further-read",children:"Further read"}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsx)(n.li,{children:(0,s.jsx)(n.a,{href:"https://github.com/pubkey/client-side-databases",children:"Offline First Database Comparison"})}),"\n",(0,s.jsx)(n.li,{children:(0,s.jsx)(n.a,{href:"https://nolanlawson.com/2021/08/22/speeding-up-indexeddb-reads-and-writes/",children:"Speeding up IndexedDB reads and writes"})}),"\n",(0,s.jsx)(n.li,{children:(0,s.jsx)(n.a,{href:"https://hackaday.com/2021/08/24/sqlite-on-the-web-absurd-sql/",children:"SQLITE ON THE WEB: ABSURD-SQL"})}),"\n",(0,s.jsx)(n.li,{children:(0,s.jsx)(n.a,{href:"https://anita-app.com/blog/articles/sqlite-in-a-pwa-with-file-system-access-api.html",children:"SQLite in a PWA with FileSystemAccessAPI"})}),"\n",(0,s.jsx)(n.li,{children:(0,s.jsx)(n.a,{href:"https://ravendb.net/articles/re-why-indexeddb-is-slow-and-what-to-use-instead",children:"Response to this article by Oren Eini"})}),"\n"]})]})}function c(e={}){const{wrapper:n}={...(0,a.R)(),...e.components};return n?(0,s.jsx)(n,{...e,children:(0,s.jsx)(h,{...e})}):h(e)}},8453:(e,n,t)=>{t.d(n,{R:()=>i,x:()=>o});var s=t(6540);const a={},r=s.createContext(a);function i(e){const n=s.useContext(r);return s.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function o(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(a):e.components||a:i(e.components),s.createElement(r.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/docs/assets/js/8b0a0922.764803c2.js b/docs/assets/js/8b0a0922.764803c2.js new file mode 100644 index 00000000000..7163584b180 --- /dev/null +++ b/docs/assets/js/8b0a0922.764803c2.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkrxdb=self.webpackChunkrxdb||[]).push([[4557],{767:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>d,contentTitle:()=>r,default:()=>c,frontMatter:()=>i,metadata:()=>o,toc:()=>l});var s=t(4848),a=t(8453);const i={title:"Slow IndexedDB",slug:"slow-indexeddb.html"},r="Why IndexedDB is slow and what to use instead",o={id:"slow-indexeddb",title:"Slow IndexedDB",description:"So you have a JavaScript web application that needs to store data at the client side, either to make it offline usable, just for caching purposes or for other reasons.",source:"@site/docs/slow-indexeddb.md",sourceDirName:".",slug:"/slow-indexeddb.html",permalink:"/slow-indexeddb.html",draft:!1,unlisted:!1,tags:[],version:"current",frontMatter:{title:"Slow IndexedDB",slug:"slow-indexeddb.html"},sidebar:"tutorialSidebar",previous:{title:"Downsides of Local First / Offline First",permalink:"/downsides-of-offline-first.html"},next:{title:"Why NOSQL",permalink:"/why-nosql.html"}},d={},l=[{value:"Batched Cursor",id:"batched-cursor",level:2},{value:"IndexedDB Sharding",id:"indexeddb-sharding",level:2},{value:"Custom Indexes",id:"custom-indexes",level:2},{value:"Relaxed durability",id:"relaxed-durability",level:2},{value:"Explicit transaction commits",id:"explicit-transaction-commits",level:2},{value:"In-Memory on top of IndexedDB",id:"in-memory-on-top-of-indexeddb",level:2},{value:"In-Memory: Persistence",id:"in-memory-persistence",level:3},{value:"In-Memory: Multi Tab Support",id:"in-memory-multi-tab-support",level:3},{value:"Further read",id:"further-read",level:2}];function h(e){const n={a:"a",admonition:"admonition",blockquote:"blockquote",code:"code",h1:"h1",h2:"h2",h3:"h3",li:"li",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,a.R)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(n.h1,{id:"why-indexeddb-is-slow-and-what-to-use-instead",children:"Why IndexedDB is slow and what to use instead"}),"\n",(0,s.jsx)(n.p,{children:"So you have a JavaScript web application that needs to store data at the client side, either to make it offline usable, just for caching purposes or for other reasons."}),"\n",(0,s.jsxs)(n.p,{children:["For ",(0,s.jsx)(n.a,{href:"/articles/browser-database.html",children:"in-browser data storage"}),", you have some options:"]}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.strong,{children:"Cookies"})," are sent with each HTTP request, so you cannot store more then a few strings in them."]}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.strong,{children:"WebSQL"})," ",(0,s.jsx)(n.a,{href:"https://hacks.mozilla.org/2010/06/beyond-html5-database-apis-and-the-road-to-indexeddb/",children:"is deprecated"})," because it never was a real standard and turning it into a standard would have been too difficult."]}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.a,{href:"/articles/localstorage.html",children:"LocalStorage"})," is a synchronous API over asynchronous IO-access. Storing and reading data can fully block the JavaScript process so you cannot use LocalStorage for more then few simple key-value pairs."]}),"\n",(0,s.jsxs)(n.li,{children:["The ",(0,s.jsx)(n.strong,{children:"FileSystem API"})," could be used to store plain binary files, but it is ",(0,s.jsx)(n.a,{href:"https://caniuse.com/filesystem",children:"only supported in chrome"})," for now."]}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.strong,{children:"IndexedDB"})," is an indexed key-object database. It can store json data and iterate over its indexes. It is ",(0,s.jsx)(n.a,{href:"https://caniuse.com/indexeddb",children:"widely supported"})," and stable."]}),"\n"]}),"\n",(0,s.jsxs)(n.admonition,{title:"UPDATE April 2023",type:"note",children:[(0,s.jsxs)(n.p,{children:["Since beginning of 2023, all modern browsers ship the ",(0,s.jsx)(n.strong,{children:"File System Access API"})," which allows to persistently store data in the browser with a way better performance. For ",(0,s.jsx)(n.a,{href:"https://rxdb.info/",children:"RxDB"})," you can use the ",(0,s.jsx)(n.a,{href:"/rx-storage-opfs.html",children:"OPFS RxStorage"})," to get about 4x performance improvement compared to IndexedDB."]}),(0,s.jsx)("center",{children:(0,s.jsx)("a",{href:"https://rxdb.info/",children:(0,s.jsx)("img",{src:"./files/logo/rxdb_javascript_database.svg",alt:"IndexedDB Database",width:"250"})})})]}),"\n",(0,s.jsxs)(n.p,{children:["It becomes clear that the only way to go is IndexedDB. You start developing your app and everything goes fine.\nBut as soon as your app gets bigger, more complex or just handles more data, you might notice something. ",(0,s.jsx)(n.strong,{children:"IndexedDB is slow"}),". Not slow like a database on a cheap server, ",(0,s.jsx)(n.strong,{children:"even slower"}),"! Inserting a few hundred documents can take up several seconds. Time which can be critical for a fast page load. Even sending data over the internet to the backend can be faster then storing it inside of an IndexedDB database."]}),"\n",(0,s.jsxs)(n.blockquote,{children:["\n",(0,s.jsx)(n.p,{children:"Transactions vs Throughput"}),"\n"]}),"\n",(0,s.jsxs)(n.p,{children:["So before we start complaining, lets analyze what exactly is slow. When you run tests on Nolans ",(0,s.jsx)(n.a,{href:"http://nolanlawson.github.io/database-comparison/",children:"Browser Database Comparison"})," you can see that inserting 1k documents into IndexedDB takes about 80 milliseconds, 0.08ms per document. This is not really slow. It is quite fast and it is very unlikely that you want to store that many document at the same time at the client side. But the key point here is that all these documents get written in a ",(0,s.jsx)(n.code,{children:"single transaction"}),"."]}),"\n",(0,s.jsxs)(n.p,{children:["I forked the comparison tool ",(0,s.jsx)(n.a,{href:"https://pubkey.github.io/client-side-databases/database-comparison/index.html",children:"here"})," and changed it to use one transaction per document write. And there we have it. Inserting 1k documents with one transaction per write, takes about 2 seconds. Interestingly if we increase the document size to be 100x bigger, it still takes about the same time to store them. This makes clear that the limiting factor to IndexedDB performance is the transaction handling, not the data throughput."]}),"\n",(0,s.jsx)("p",{align:"center",children:(0,s.jsx)("img",{src:"./files/indexeddb-transaction-throughput.png",alt:"IndexedDB transaction throughput",width:"700"})}),"\n",(0,s.jsxs)(n.p,{children:["To fix your IndexedDB performance problems you have to make sure to use as less data transfers/transactions as possible.\nSometimes this is easy, as instead of iterating over a documents list and calling single inserts, with RxDB you could use the ",(0,s.jsx)(n.a,{href:"https://rxdb.info/rx-collection.html#bulkinsert",children:"bulk methods"})," to store many document at once.\nBut most of the time is not so easy. Your user clicks around, data gets replicated from the backend, another browser tab writes data. All these things can happen at random time and you cannot crunch all that data in a single transaction."]}),"\n",(0,s.jsxs)(n.p,{children:["Another solution is to just not care about performance at all. In a few releases the browser vendors will have optimized IndexedDB and everything is fast again. Well, IndexedDB was slow ",(0,s.jsx)(n.a,{href:"https://www.researchgate.net/publication/281065948_Performance_Testing_and_Comparison_of_Client_Side_Databases_Versus_Server_Side",children:"in 2013"})," and it is still slow today. If this trend continues, it will still be slow in a few years from now. Waiting is not an option. The chromium devs made ",(0,s.jsx)(n.a,{href:"https://bugs.chromium.org/p/chromium/issues/detail?id=1025456#c15",children:"a statement"})," to focus on optimizing read performance, not write performance."]}),"\n",(0,s.jsxs)(n.p,{children:["Switching to WebSQL (even if it is deprecated) is also not an option because, like ",(0,s.jsx)(n.a,{href:"https://pubkey.github.io/client-side-databases/database-comparison/index.html",children:"the comparison tool shows"}),", it has even slower transactions."]}),"\n",(0,s.jsxs)(n.p,{children:["So you need a way to ",(0,s.jsx)(n.strong,{children:"make IndexedDB faster"}),". In the following I lay out some performance optimizations than can be made to have faster reads and writes in IndexedDB."]}),"\n",(0,s.jsxs)(n.p,{children:[(0,s.jsx)(n.strong,{children:"HINT:"})," You can reproduce all performance tests ",(0,s.jsx)(n.a,{href:"https://github.com/pubkey/indexeddb-performance-tests",children:"in this repo"}),". In all tests we work on a dataset of 40000 ",(0,s.jsx)(n.code,{children:"human"})," documents with a random ",(0,s.jsx)(n.code,{children:"age"})," between ",(0,s.jsx)(n.code,{children:"1"})," and ",(0,s.jsx)(n.code,{children:"100"}),"."]}),"\n",(0,s.jsx)(n.h2,{id:"batched-cursor",children:"Batched Cursor"}),"\n",(0,s.jsxs)(n.p,{children:["With ",(0,s.jsx)(n.a,{href:"https://caniuse.com/indexeddb2",children:"IndexedDB 2.0"}),", new methods were introduced which can be utilized to improve performance. With the ",(0,s.jsx)(n.code,{children:"getAll()"})," method, a faster alternative to the old ",(0,s.jsx)(n.code,{children:"openCursor()"})," can be created which improves performance when reading data from the IndexedDB store."]}),"\n",(0,s.jsxs)(n.p,{children:["Lets say we want to query all user documents that have an ",(0,s.jsx)(n.code,{children:"age"})," greater then ",(0,s.jsx)(n.code,{children:"25"})," out of the store.\nTo implement a fast batched cursor that only needs calls to ",(0,s.jsx)(n.code,{children:"getAll()"})," and not to ",(0,s.jsx)(n.code,{children:"getAllKeys()"}),", we first need to create an ",(0,s.jsx)(n.code,{children:"age"})," index that contains the primary ",(0,s.jsx)(n.code,{children:"id"})," as last field."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-ts",children:"myIndexedDBObjectStore.createIndex(\n 'age-index',\n [\n 'age',\n 'id'\n ]\n);\n"})}),"\n",(0,s.jsxs)(n.p,{children:["This is required because the ",(0,s.jsx)(n.code,{children:"age"})," field is not unique, and we need a way to checkpoint the last returned batch so we can continue from there in the next call to ",(0,s.jsx)(n.code,{children:"getAll()"}),"."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-ts",children:"const maxAge = 25;\nlet result = [];\nconst tx: IDBTransaction = db.transaction([storeName], 'readonly', TRANSACTION_SETTINGS);\nconst store = tx.objectStore(storeName);\nconst index = store.index('age-index');\nlet lastDoc;\nlet done = false;\n/**\n * Run the batched cursor until all results are retrieved\n * or the end of the index is reached.\n */\nwhile (done === false) {\n await new Promise((res, rej) => {\n const range = IDBKeyRange.bound(\n /**\n * If we have a previous document as checkpoint,\n * we have to continue from it's age and id values.\n */\n [\n lastDoc ? lastDoc.age : -Infinity,\n lastDoc ? lastDoc.id : -Infinity,\n ],\n [\n maxAge + 0.00000001,\n String.fromCharCode(65535)\n ],\n true,\n false\n );\n const openCursorRequest = index.getAll(range, batchSize);\n openCursorRequest.onerror = err => rej(err);\n openCursorRequest.onsuccess = e => {\n const subResult: TestDocument[] = e.target.result;\n lastDoc = lastOfArray(subResult);\n if (subResult.length === 0) {\n done = true;\n } else {\n result = result.concat(subResult);\n }\n res();\n };\n });\n}\nconsole.dir(result);\n"})}),"\n",(0,s.jsx)("p",{align:"center",children:(0,s.jsx)("img",{src:"./files/indexeddb-batched-cursor.png",alt:"IndexedDB batched cursor",width:"100%"})}),"\n",(0,s.jsxs)(n.p,{children:["As the performance test results show, using a batched cursor can give a huge improvement. Interestingly choosing a high batch size is important. When you known that all results of a given ",(0,s.jsx)(n.code,{children:"IDBKeyRange"})," are needed, you should not set a batch size at all and just directly query all documents via ",(0,s.jsx)(n.code,{children:"getAll()"}),"."]}),"\n",(0,s.jsxs)(n.p,{children:["RxDB uses batched cursors in the ",(0,s.jsx)(n.a,{href:"/rx-storage-indexeddb.html",children:"IndexedDB RxStorage"}),"."]}),"\n",(0,s.jsx)(n.h2,{id:"indexeddb-sharding",children:"IndexedDB Sharding"}),"\n",(0,s.jsxs)(n.p,{children:["Sharding is a technique, normally used in server side databases, where the database is partitioned horizontally. Instead of storing all documents at one table/collection, the documents are split into so called ",(0,s.jsx)(n.strong,{children:"shards"})," and each shard is stored on one table/collection. This is done in server side architectures to spread the load between multiple physical servers which ",(0,s.jsx)(n.strong,{children:"increases scalability"}),"."]}),"\n",(0,s.jsxs)(n.p,{children:["When you use IndexedDB in a browser, there is of course no way to split the load between the client and other servers. But you can still benefit from sharding. Partitioning the documents horizontally into ",(0,s.jsx)(n.strong,{children:"multiple IndexedDB stores"}),", has shown to have a big performance improvement in write- and read operations while only increasing initial pageload slightly."]}),"\n",(0,s.jsx)("p",{align:"center",children:(0,s.jsx)("img",{src:"./files/indexeddb-sharding-performance.png",alt:"IndexedDB sharding performance",width:"100%"})}),"\n",(0,s.jsxs)(n.p,{children:["As shown in the performance test results, sharding should always be done by ",(0,s.jsx)(n.code,{children:"IDBObjectStore"})," and not by database. Running a batched cursor over the whole dataset with 10 store shards in parallel is about ",(0,s.jsx)(n.strong,{children:"28% faster"})," then running it over a single store. Initialization time increases minimal from ",(0,s.jsx)(n.code,{children:"9"})," to ",(0,s.jsx)(n.code,{children:"17"})," milliseconds.\nGetting a quarter of the dataset by batched iterating over an index, is even ",(0,s.jsx)(n.strong,{children:"43%"})," faster with sharding then when a single store is queried."]}),"\n",(0,s.jsx)(n.p,{children:"As downside, getting 10k documents by their id is slower when it has to run over the shards.\nAlso it can be much effort to recombined the results from the different shards into the required query result. When a query without a limit is done, the sharding method might cause a data load huge overhead."}),"\n",(0,s.jsxs)(n.p,{children:["Sharding can be used with RxDB with the ",(0,s.jsx)(n.a,{href:"/rx-storage-sharding.html",children:"Sharding Plugin"}),"."]}),"\n",(0,s.jsx)(n.h2,{id:"custom-indexes",children:"Custom Indexes"}),"\n",(0,s.jsx)(n.p,{children:"Indexes improve the query performance of IndexedDB significant. Instead of fetching all data from the storage when you search for a subset of it, you can iterate over the index and stop iterating when all relevant data has been found."}),"\n",(0,s.jsxs)(n.p,{children:["For example to query for all user documents that have an ",(0,s.jsx)(n.code,{children:"age"})," greater than ",(0,s.jsx)(n.code,{children:"25"}),", you would create an ",(0,s.jsx)(n.code,{children:"age+id"})," index.\nTo be able to run a batched cursor over the index, we always need our primary key (",(0,s.jsx)(n.code,{children:"id"}),") as the last index field."]}),"\n",(0,s.jsxs)(n.p,{children:["Instead of doing this, you can use a ",(0,s.jsx)(n.code,{children:"custom index"})," which can improve the performance. The custom index runs over a helper field ",(0,s.jsx)(n.code,{children:"ageIdCustomIndex"})," which is added to each document on write. Our index now only contains a single ",(0,s.jsx)(n.code,{children:"string"})," field instead of two (age-",(0,s.jsx)(n.code,{children:"number"})," and id-",(0,s.jsx)(n.code,{children:"string"}),")."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-ts",children:"// On document insert add the ageIdCustomIndex field.\nconst idMaxLength = 20; // must be known to craft a custom index \ndocData.ageIdCustomIndex = docData.age + docData.id.padStart(idMaxLength, ' ');\nstore.put(docData);\n// ...\n"})}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-ts",children:"// normal index\nmyIndexedDBObjectStore.createIndex(\n 'age-index',\n [\n 'age',\n 'id'\n ]\n);\n\n// custom index\nmyIndexedDBObjectStore.createIndex(\n 'age-index-custom',\n [\n 'ageIdCustomIndex'\n ]\n);\n\n"})}),"\n",(0,s.jsxs)(n.p,{children:["To iterate over the index, you also use a custom crafted keyrange, depending on the last batched cursor checkpoint. Therefore the ",(0,s.jsx)(n.code,{children:"maxLength"})," of ",(0,s.jsx)(n.code,{children:"id"})," must be known."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-ts",children:"// keyrange for normal index\nconst range = IDBKeyRange.bound(\n [25, ''],\n [Infinity, Infinity],\n true,\n false\n);\n\n// keyrange for custom index\nconst range = IDBKeyRange.bound(\n // combine both values to a single string\n 25 + ''.padStart(idMaxLength, ' '),\n Infinity,\n true,\n false\n);\n"})}),"\n",(0,s.jsx)("p",{align:"center",children:(0,s.jsx)("img",{src:"./files/indexeddb-custom-index.png",alt:"IndexedDB custom index",width:"700"})}),"\n",(0,s.jsxs)(n.p,{children:["As shown, using a custom index can further improve the performance of running a batched cursor by about ",(0,s.jsx)(n.code,{children:"10%"}),"."]}),"\n",(0,s.jsxs)(n.p,{children:["Another big benefit of using custom indexes, is that you can also encode ",(0,s.jsx)(n.code,{children:"boolean"})," values in them, which ",(0,s.jsx)(n.a,{href:"https://github.com/w3c/IndexedDB/issues/76",children:"cannot be done"})," with normal IndexedDB indexes."]}),"\n",(0,s.jsxs)(n.p,{children:["RxDB uses custom indexes in the ",(0,s.jsx)(n.a,{href:"/rx-storage-indexeddb.html",children:"IndexedDB RxStorage"}),"."]}),"\n",(0,s.jsx)(n.h2,{id:"relaxed-durability",children:"Relaxed durability"}),"\n",(0,s.jsxs)(n.p,{children:["Chromium based browsers allow to set ",(0,s.jsx)(n.a,{href:"https://developer.mozilla.org/en-US/docs/Web/API/IDBTransaction/durability",children:"durability"})," to ",(0,s.jsx)(n.code,{children:"relaxed"})," when creating an IndexedDB transaction. Which runs the transaction in a less secure durability mode, which can improve the performance."]}),"\n",(0,s.jsxs)(n.blockquote,{children:["\n",(0,s.jsx)(n.p,{children:"The user agent may consider that the transaction has successfully committed as soon as all outstanding changes have been written to the operating system, without subsequent verification."}),"\n"]}),"\n",(0,s.jsxs)(n.p,{children:["As shown ",(0,s.jsx)(n.a,{href:"https://nolanlawson.com/2021/08/22/speeding-up-indexeddb-reads-and-writes/",children:"here"}),", using the relaxed durability mode can improve performance slightly. The best performance improvement could be measured when many small transactions have to be run. Less, bigger transaction do not benefit that much."]}),"\n",(0,s.jsx)(n.h2,{id:"explicit-transaction-commits",children:"Explicit transaction commits"}),"\n",(0,s.jsxs)(n.p,{children:["By explicitly committing a transaction, another slight performance improvement can be achieved. Instead of waiting for the browser to commit an open transaction, we call the ",(0,s.jsx)(n.code,{children:"commit()"})," method to explicitly close it."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-ts",children:"// .commit() is not available on all browsers, so first check if it exists.\nif (transaction.commit) {\n transaction.commit()\n}\n"})}),"\n",(0,s.jsxs)(n.p,{children:["The improvement of this technique is minimal, but observable as ",(0,s.jsx)(n.a,{href:"https://nolanlawson.com/2021/08/22/speeding-up-indexeddb-reads-and-writes/",children:"these tests"})," show."]}),"\n",(0,s.jsx)(n.h2,{id:"in-memory-on-top-of-indexeddb",children:"In-Memory on top of IndexedDB"}),"\n",(0,s.jsxs)(n.p,{children:["To prevent transaction handling and to fix the performance problems, we need to stop using IndexedDB as a database. Instead all data is loaded into the memory on the initial page load. Here all reads and writes happen in memory which is about 100x faster. Only some time after a write occurred, the memory state is persisted into IndexedDB with a ",(0,s.jsx)(n.strong,{children:"single write transaction"}),". In this scenario IndexedDB is used as a filesystem, not as a database."]}),"\n",(0,s.jsx)(n.p,{children:"There are some libraries that already do that:"}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsxs)(n.li,{children:["LokiJS with the ",(0,s.jsx)(n.a,{href:"https://techfort.github.io/LokiJS/LokiIndexedAdapter.html",children:"IndexedDB Adapter"})]}),"\n",(0,s.jsx)(n.li,{children:(0,s.jsx)(n.a,{href:"https://github.com/jlongster/absurd-sql",children:"Absurd-SQL"})}),"\n",(0,s.jsxs)(n.li,{children:["SQL.js with the ",(0,s.jsx)(n.a,{href:"https://emscripten.org/docs/api_reference/Filesystem-API.html#filesystem-api-idbfs",children:"empscripten Filesystem API"})]}),"\n",(0,s.jsx)(n.li,{children:(0,s.jsx)(n.a,{href:"https://duckdb.org/2021/10/29/duckdb-wasm.html",children:"DuckDB Wasm"})}),"\n"]}),"\n",(0,s.jsx)(n.h3,{id:"in-memory-persistence",children:"In-Memory: Persistence"}),"\n",(0,s.jsxs)(n.p,{children:["One downside of not directly using IndexedDB, is that your data is not persistent all the time. And when the JavaScript process exists without having persisted to IndexedDB, data can be lost. To prevent this from happening, we have to ensure that the in-memory state is written down to the disc. One point is make persisting as fast as possible. LokiJS for example has the ",(0,s.jsx)(n.code,{children:"incremental-indexeddb-adapter"})," which only saves new writes to the disc instead of persisting the whole state. Another point is to run the persisting at the correct point in time. For example the RxDB ",(0,s.jsx)(n.a,{href:"https://rxdb.info/rx-storage-lokijs.html",children:"LokiJS storage"})," persists in the following situations:"]}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsx)(n.li,{children:"When the database is idle and no write or query is running. In that time we can persist the state if any new writes appeared before."}),"\n",(0,s.jsxs)(n.li,{children:["When the ",(0,s.jsx)(n.code,{children:"window"})," fires the ",(0,s.jsx)(n.a,{href:"https://developer.mozilla.org/en-US/docs/Web/API/WindowEventHandlers/onbeforeunload",children:"beforeunload event"})," we can assume that the JavaScript process is exited any moment and we have to persist the state. After ",(0,s.jsx)(n.code,{children:"beforeunload"})," there are several seconds time which are sufficient to store all new changes. This has shown to work quite reliable."]}),"\n"]}),"\n",(0,s.jsx)(n.p,{children:"The only missing event that can happen is when the browser exists unexpectedly like when it crashes or when the power of the computer is shut of."}),"\n",(0,s.jsx)(n.h3,{id:"in-memory-multi-tab-support",children:"In-Memory: Multi Tab Support"}),"\n",(0,s.jsx)(n.p,{children:"One big difference between a web application and a 'normal' app, is that your users can use the app in multiple browser tabs at the same time. But when you have all database state in memory and only periodically write it to disc, multiple browser tabs could overwrite each other and you would loose data. This might not be a problem when you rely on a client-server replication, because the lost data might already be replicated with the backend and therefore with the other tabs. But this would not work when the client is offline."}),"\n",(0,s.jsxs)(n.p,{children:["The ideal way to solve that problem, is to use a ",(0,s.jsx)(n.a,{href:"https://developer.mozilla.org/en/docs/Web/API/SharedWorker",children:"SharedWorker"}),". A SharedWorker is like a ",(0,s.jsx)(n.a,{href:"https://developer.mozilla.org/en/docs/Web/API/Web_Workers_API",children:"WebWorker"})," that runs its own JavaScript process only that the SharedWorker is shared between multiple contexts. You could create the database in the SharedWorker and then all browser tabs could request the Worker for data instead of having their own database. But unfortunately the SharedWorker API does ",(0,s.jsx)(n.a,{href:"https://caniuse.com/sharedworkers",children:"not work"})," in all browsers. Safari ",(0,s.jsx)(n.a,{href:"https://bugs.webkit.org/show_bug.cgi?id=140344",children:"dropped"})," its support and InternetExplorer or Android Chrome, never adopted it. Also it cannot be polyfilled. ",(0,s.jsx)(n.strong,{children:"UPDATE:"})," ",(0,s.jsx)(n.a,{href:"https://developer.apple.com/safari/technology-preview/release-notes/",children:"Apple added SharedWorkers back in Safari 142"})]}),"\n",(0,s.jsxs)(n.p,{children:["Instead, we could use the ",(0,s.jsx)(n.a,{href:"https://developer.mozilla.org/en-US/docs/Web/API/Broadcast_Channel_API",children:"BroadcastChannel API"})," to communicate between tabs and then apply a ",(0,s.jsx)(n.a,{href:"https://github.com/pubkey/broadcast-channel#using-the-leaderelection",children:"leader election"})," between them. The leader election ensures that, no matter how many tabs are open, always one tab is the ",(0,s.jsx)(n.code,{children:"Leader"}),"."]}),"\n",(0,s.jsx)("p",{align:"center",children:(0,s.jsx)("img",{src:"./files/leader-election.gif",alt:"Leader Election",width:"500"})}),"\n",(0,s.jsx)(n.p,{children:"The disadvantage is that the leader election process takes some time on the initial page load (about 150 milliseconds). Also the leader election can break when a JavaScript process is fully blocked for a longer time. When this happens, a good way is to just reload the browser tab to restart the election process."}),"\n",(0,s.jsxs)(n.p,{children:["Using a leader election is implemented in the ",(0,s.jsx)(n.a,{href:"/rx-storage-lokijs.html",children:"RxDB LokiJS Storage"}),"."]}),"\n",(0,s.jsx)(n.h2,{id:"further-read",children:"Further read"}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsx)(n.li,{children:(0,s.jsx)(n.a,{href:"https://github.com/pubkey/client-side-databases",children:"Offline First Database Comparison"})}),"\n",(0,s.jsx)(n.li,{children:(0,s.jsx)(n.a,{href:"https://nolanlawson.com/2021/08/22/speeding-up-indexeddb-reads-and-writes/",children:"Speeding up IndexedDB reads and writes"})}),"\n",(0,s.jsx)(n.li,{children:(0,s.jsx)(n.a,{href:"https://hackaday.com/2021/08/24/sqlite-on-the-web-absurd-sql/",children:"SQLITE ON THE WEB: ABSURD-SQL"})}),"\n",(0,s.jsx)(n.li,{children:(0,s.jsx)(n.a,{href:"https://anita-app.com/blog/articles/sqlite-in-a-pwa-with-file-system-access-api.html",children:"SQLite in a PWA with FileSystemAccessAPI"})}),"\n",(0,s.jsx)(n.li,{children:(0,s.jsx)(n.a,{href:"https://ravendb.net/articles/re-why-indexeddb-is-slow-and-what-to-use-instead",children:"Response to this article by Oren Eini"})}),"\n"]})]})}function c(e={}){const{wrapper:n}={...(0,a.R)(),...e.components};return n?(0,s.jsx)(n,{...e,children:(0,s.jsx)(h,{...e})}):h(e)}},8453:(e,n,t)=>{t.d(n,{R:()=>r,x:()=>o});var s=t(6540);const a={},i=s.createContext(a);function r(e){const n=s.useContext(i);return s.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function o(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(a):e.components||a:r(e.components),s.createElement(i.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/docs/assets/js/main.5dbc8e9b.js b/docs/assets/js/main.cc3fdfd5.js similarity index 99% rename from docs/assets/js/main.5dbc8e9b.js rename to docs/assets/js/main.cc3fdfd5.js index ac7141adfee..9277e721e72 100644 --- a/docs/assets/js/main.5dbc8e9b.js +++ b/docs/assets/js/main.cc3fdfd5.js @@ -1,2 +1,2 @@ -/*! For license information please see main.5dbc8e9b.js.LICENSE.txt */ -(self.webpackChunkrxdb=self.webpackChunkrxdb||[]).push([[8792],{8328:(e,t,n)=>{"use strict";n.d(t,{A:()=>p});n(6540);var r=n(3259),a=n.n(r),o=n(4054);const i={"0027230a":[()=>n.e(8382).then(n.bind(n,2081)),"@site/docs/rx-storage-lokijs.md",2081],"01684a0a":[()=>n.e(6616).then(n.bind(n,3395)),"@site/docs/rx-storage-memory-synced.md",3395],"03e37916":[()=>n.e(6465).then(n.bind(n,3184)),"@site/docs/transactions-conflicts-revisions.md",3184],"045bd6f5":[()=>n.e(4475).then(n.bind(n,8201)),"@site/docs/encryption.md",8201],"04b0214f":[()=>n.e(6264).then(n.t.bind(n,4061,19)),"/home/runner/work/rxdb/rxdb/docs-src/.docusaurus/docusaurus-plugin-content-pages/default/plugin-route-context-module-100.json",4061],"0e268d20":[()=>Promise.all([n.e(5106),n.e(2584)]).then(n.bind(n,5607)),"@site/src/pages/premium.tsx",5607],"0e945c41":[()=>n.e(9796).then(n.bind(n,9722)),"@site/docs/replication-server.md",9722],"0f6e10f0":[()=>n.e(1475).then(n.bind(n,654)),"@site/docs/articles/progressive-web-app-database.md",654],"118cde4c":[()=>n.e(5272).then(n.bind(n,7245)),"@site/docs/replication-couchdb.md",7245],"14d72841":[()=>n.e(9772).then(n.bind(n,5221)),"@site/src/pages/newsletter.tsx",5221],17896441:[()=>Promise.all([n.e(1869),n.e(1968),n.e(8401)]).then(n.bind(n,242)),"@theme/DocItem",242],"187b985e":[()=>n.e(6866).then(n.bind(n,844)),"@site/docs/replication-webrtc.md",844],"1b0f8c91":[()=>n.e(3129).then(n.bind(n,9642)),"@site/docs/backup.md",9642],"1b238727":[()=>n.e(4013).then(n.bind(n,3721)),"@site/docs/rx-storage-performance.md",3721],"1c0701dd":[()=>n.e(6953).then(n.bind(n,668)),"@site/docs/middleware.md",668],"1da545ff":[()=>n.e(9743).then(n.bind(n,2678)),"@site/docs/releases/9.0.0.md",2678],"1df93b7f":[()=>Promise.all([n.e(1869),n.e(5106),n.e(4579),n.e(4583)]).then(n.bind(n,6866)),"@site/src/pages/index.tsx",6866],"1e0353aa":[()=>n.e(8588).then(n.bind(n,142)),"@site/docs/rx-storage.md",142],"1f391b9e":[()=>Promise.all([n.e(1869),n.e(1968),n.e(6061)]).then(n.bind(n,7973)),"@theme/MDXPage",7973],"21fa2740":[()=>n.e(5694).then(n.bind(n,763)),"@site/docs/releases/15.0.0.md",763],"2456d5e0":[()=>n.e(2966).then(n.bind(n,5654)),"@site/docs/rx-database.md",5654],"25626d15":[()=>n.e(268).then(n.bind(n,7258)),"@site/src/pages/chat.tsx",7258],"2564bf4f":[()=>n.e(6724).then(n.bind(n,5705)),"@site/docs/rxdb-tradeoffs.md",5705],"25a43fd4":[()=>n.e(4812).then(n.bind(n,3917)),"@site/docs/rx-storage-shared-worker.md",3917],"26b8a621":[()=>n.e(2055).then(n.bind(n,3439)),"@site/docs/replication-p2p.md",3439],"280a2389":[()=>Promise.all([n.e(5106),n.e(176)]).then(n.bind(n,8141)),"@site/src/pages/meeting.tsx",8141],"294ac9d5":[()=>n.e(8744).then(n.bind(n,958)),"@site/docs/plugins.md",958],"2efd0200":[()=>n.e(4132).then(n.bind(n,9839)),"@site/docs/tutorials/typescript.md",9839],"32667c41":[()=>n.e(8191).then(n.bind(n,6895)),"@site/docs/nosql-performance-tips.md",6895],"326aca46":[()=>n.e(4853).then(n.bind(n,3142)),"@site/docs/offline-first.md",3142],"34f94d1b":[()=>n.e(5832).then(n.bind(n,7746)),"@site/docs/electron-database.md",7746],36715375:[()=>n.e(2076).then(n.bind(n,2323)),"@site/src/pages/code.tsx",2323],"380cc66a":[()=>n.e(2061).then(n.bind(n,5668)),"@site/docs/rx-storage-dexie.md",5668],"38bbf12a":[()=>n.e(2078).then(n.bind(n,3762)),"@site/docs/articles/data-base.md",3762],"393be207":[()=>n.e(4134).then(n.bind(n,6602)),"@site/src/pages/markdown-page.md",6602],"39600c95":[()=>n.e(3148).then(n.bind(n,755)),"@site/docs/rx-query.md",755],"401008a8":[()=>n.e(5219).then(n.bind(n,6805)),"@site/docs/nodejs-database.md",6805],"41f941a1":[()=>n.e(5966).then(n.bind(n,3057)),"@site/docs/leader-election.md",3057],"432b83f9":[()=>n.e(4424).then(n.bind(n,9429)),"@site/docs/releases/8.0.0.md",9429],"4616b86a":[()=>n.e(465).then(n.bind(n,81)),"@site/docs/rx-storage-mongodb.md",81],"4777fd9a":[()=>n.e(6386).then(n.bind(n,1600)),"@site/docs/alternatives.md",1600],"4adf80bb":[()=>n.e(9548).then(n.bind(n,4442)),"@site/docs/rx-storage-pouchdb.md",4442],"4af60d2e":[()=>n.e(8545).then(n.bind(n,9249)),"@site/docs/articles/realtime-database.md",9249],"4ba7e5a3":[()=>n.e(9591).then(n.bind(n,6467)),"@site/docs/contribute.md",6467],"4ed9495b":[()=>n.e(1199).then(n.bind(n,1787)),"@site/docs/rx-storage-sqlite.md",1787],"502d8946":[()=>n.e(7817).then(n.bind(n,732)),"@site/src/pages/legal-notice.tsx",732],51334108:[()=>n.e(8926).then(n.bind(n,2644)),"@site/docs/articles/mobile-database.md",2644],"55a5b596":[()=>n.e(6717).then(n.bind(n,5536)),"@site/docs/rx-schema.md",5536],"5a273530":[()=>n.e(3881).then(n.bind(n,7589)),"@site/docs/rx-storage-remote.md",7589],"5e95c892":[()=>n.e(9647).then(n.bind(n,7121)),"@theme/DocsRoot",7121],"5e9f5e1a":[()=>Promise.resolve().then(n.bind(n,4784)),"@generated/docusaurus.config",4784],"60c23941":[()=>n.e(2915).then(n.t.bind(n,1966,19)),"/home/runner/work/rxdb/rxdb/docs-src/.docusaurus/docusaurus-plugin-content-docs/default/plugin-route-context-module-100.json",1966],"6187b59a":[()=>n.e(5866).then(n.bind(n,7409)),"@site/docs/rx-storage-worker.md",7409],"68a466be":[()=>n.e(3997).then(n.bind(n,3923)),"@site/docs/downsides-of-offline-first.md",3923],"6ae3580c":[()=>n.e(5320).then(n.bind(n,5376)),"@site/docs/replication.md",5376],"6bfb0089":[()=>n.e(6422).then(n.bind(n,300)),"@site/docs/adapters.md",300],"6cbff7c2":[()=>n.e(7408).then(n.bind(n,5943)),"@site/docs/rx-storage-opfs.md",5943],"6fd28feb":[()=>n.e(4618).then(n.bind(n,9408)),"@site/docs/rx-storage-foundationdb.md",9408],"714575d7":[()=>n.e(3185).then(n.bind(n,4880)),"@site/docs/rx-local-document.md",4880],"77d975e6":[()=>n.e(3949).then(n.bind(n,5707)),"@site/docs/articles/in-memory-nosql-database.md",5707],"7815dd0c":[()=>n.e(5335).then(n.bind(n,5515)),"@site/docs/population.md",5515],"7f02c700":[()=>n.e(9592).then(n.bind(n,9640)),"@site/docs/replication-firestore.md",9640],"8070e160":[()=>n.e(3822).then(n.bind(n,1685)),"@site/docs/quickstart.md",1685],"8288c265":[()=>n.e(9881).then(n.bind(n,1839)),"@site/docs/releases/11.0.0.md",1839],"84a3af36":[()=>n.e(6861).then(n.bind(n,8160)),"@site/docs/articles/json-database.md",8160],"84ae55a4":[()=>n.e(588).then(n.bind(n,2045)),"@site/docs/replication-nats.md",2045],"86b4e356":[()=>n.e(2786).then(n.bind(n,9278)),"@site/docs/orm.md",9278],"8aa53ed7":[()=>n.e(6723).then(n.bind(n,5870)),"@site/docs/articles/angular-database.md",5870],"8b0a0922":[()=>n.e(4557).then(n.bind(n,767)),"@site/docs/slow-indexeddb.md",767],"8bc07e20":[()=>n.e(1850).then(n.bind(n,5054)),"@site/docs/capacitor-database.md",5054],"91b454ee":[()=>n.e(4202).then(n.bind(n,9107)),"@site/docs/rx-storage-sharding.md",9107],"924d6dd6":[()=>n.e(5122).then(n.bind(n,2414)),"@site/docs/electron.md",2414],"92698a99":[()=>n.e(4166).then(n.bind(n,8568)),"@site/docs/rx-storage-indexeddb.md",8568],"931f4566":[()=>n.e(3595).then(n.bind(n,2439)),"@site/docs/schema-validation.md",2439],"935f2afb":[()=>n.e(8581).then(n.t.bind(n,5610,19)),"~docs/default/version-current-metadata-prop-751.json",5610],98405524:[()=>n.e(5504).then(n.bind(n,1934)),"@site/src/pages/survey.tsx",1934],"9dd8ea89":[()=>n.e(1715).then(n.bind(n,7919)),"@site/docs/logger.md",7919],"9e91b6f0":[()=>n.e(3021).then(n.bind(n,1844)),"@site/docs/why-nosql.md",1844],a406dc27:[()=>n.e(1500).then(n.bind(n,8306)),"@site/docs/migration-storage.md",8306],a442adcd:[()=>n.e(8760).then(n.bind(n,188)),"@site/docs/reactivity.md",188],a574e172:[()=>n.e(7149).then(n.bind(n,9329)),"@site/docs/replication-http.md",9329],a69eebfc:[()=>n.e(9408).then(n.bind(n,4120)),"@site/docs/query-optimizer.md",4120],a7bd4aaa:[()=>n.e(7098).then(n.bind(n,4532)),"@theme/DocVersionRoot",4532],a7f10198:[()=>n.e(1098).then(n.bind(n,769)),"@site/docs/data-migration.md",769],a94703ab:[()=>Promise.all([n.e(1869),n.e(9048)]).then(n.bind(n,2559)),"@theme/DocRoot",2559],aa14e6b1:[()=>n.e(9824).then(n.bind(n,3268)),"@site/docs/replication-graphql.md",3268],ab919a1f:[()=>n.e(6491).then(n.bind(n,4760)),"@site/docs/articles/embedded-database.md",4760],ac62b32d:[()=>n.e(9192).then(n.bind(n,9585)),"@site/docs/replication-websocket.md",9585],ad16b3ea:[()=>n.e(8674).then(n.bind(n,2462)),"@site/docs/dev-mode.md",2462],b0889a22:[()=>n.e(1107).then(n.bind(n,1798)),"@site/docs/cleanup.md",1798],b30f4f1f:[()=>n.e(3779).then(n.bind(n,5830)),"@site/docs/rx-attachment.md",5830],b8c49ce4:[()=>n.e(6355).then(n.bind(n,1605)),"@site/docs/releases/13.0.0.md",1605],badcd764:[()=>n.e(8318).then(n.bind(n,6042)),"@site/docs/articles/flutter-database.md",6042],c3bc9c50:[()=>n.e(9167).then(n.bind(n,4337)),"@site/docs/articles/react-database.md",4337],c44853e1:[()=>n.e(6584).then(n.bind(n,7390)),"@site/docs/rx-state.md",7390],c4de80f8:[()=>n.e(2777).then(n.bind(n,1173)),"@site/docs/install.md",1173],c6349bb6:[()=>n.e(5740).then(n.bind(n,2964)),"@site/docs/releases/14.0.0.md",2964],c6fdd490:[()=>n.e(4141).then(n.bind(n,5008)),"@site/docs/rx-server-scaling.md",5008],c843a053:[()=>n.e(9146).then(n.bind(n,8723)),"@site/docs/third-party-plugins.md",8723],c9c8e0b6:[()=>n.e(7249).then(n.bind(n,7674)),"@site/docs/articles/ionic-database.md",7674],cbbe8f0a:[()=>n.e(3852).then(n.bind(n,8783)),"@site/docs/rx-collection.md",8783],cde77f4f:[()=>Promise.all([n.e(5106),n.e(6287)]).then(n.bind(n,6465)),"@site/src/pages/premium-submitted.tsx",6465],d20e74b4:[()=>n.e(5123).then(n.bind(n,2853)),"@site/docs/crdt.md",2853],d2758528:[()=>n.e(2586).then(n.bind(n,7108)),"@site/docs/articles/browser-storage.md",7108],d4da9db3:[()=>n.e(1400).then(n.bind(n,4228)),"@site/docs/rx-storage-memory.md",4228],d622bd51:[()=>n.e(2845).then(n.bind(n,9804)),"@site/docs/migration-schema.md",9804],db34d6b0:[()=>Promise.all([n.e(5106),n.e(7320)]).then(n.bind(n,9891)),"@site/src/pages/license.tsx",9891],dbde2ffe:[()=>n.e(6543).then(n.bind(n,118)),"@site/docs/rx-document.md",118],dc42ba65:[()=>n.e(4962).then(n.bind(n,4494)),"@site/docs/key-compression.md",4494],e24529eb:[()=>n.e(6797).then(n.bind(n,9263)),"@site/docs/rx-storage-localstorage-meta-optimizer.md",9263],e6b4453d:[()=>n.e(2360).then(n.bind(n,9133)),"@site/docs/query-cache.md",9133],e7478ff0:[()=>n.e(5416).then(n.bind(n,1873)),"@site/docs/questions-answers.md",1873],eadd9b3c:[()=>n.e(4886).then(n.bind(n,8041)),"@site/docs/rx-storage-filesystem-node.md",8041],ebace26e:[()=>n.e(4028).then(n.bind(n,7016)),"@site/docs/releases/10.0.0.md",7016],ec526260:[()=>n.e(7396).then(n.bind(n,9592)),"@site/docs/articles/browser-database.md",9592],ed2d6610:[()=>n.e(3469).then(n.bind(n,9222)),"@site/docs/releases/12.0.0.md",9222],ee1b9f21:[()=>n.e(6998).then(n.bind(n,3179)),"@site/docs/react-native-database.md",3179],f15938da:[()=>n.e(4630).then(n.bind(n,5674)),"@site/docs/articles/localstorage.md",5674],f43e80a8:[()=>n.e(1558).then(n.bind(n,9544)),"@site/docs/rx-server.md",9544],f44bb875:[()=>n.e(561).then(n.bind(n,46)),"@site/docs/articles/frontend-database.md",46],fe7a07ee:[()=>n.e(2085).then(n.bind(n,9378)),"@site/docs/rx-storage-denokv.md",9378]};var l=n(4848);function s(e){let{error:t,retry:n,pastDelay:r}=e;return t?(0,l.jsxs)("div",{style:{textAlign:"center",color:"#fff",backgroundColor:"#fa383e",borderColor:"#fa383e",borderStyle:"solid",borderRadius:"0.25rem",borderWidth:"1px",boxSizing:"border-box",display:"block",padding:"1rem",flex:"0 0 50%",marginLeft:"25%",marginRight:"25%",marginTop:"5rem",maxWidth:"50%",width:"100%"},children:[(0,l.jsx)("p",{children:String(t)}),(0,l.jsx)("div",{children:(0,l.jsx)("button",{type:"button",onClick:n,children:"Retry"})})]}):r?(0,l.jsx)("div",{style:{display:"flex",justifyContent:"center",alignItems:"center",height:"100vh"},children:(0,l.jsx)("svg",{id:"loader",style:{width:128,height:110,position:"absolute",top:"calc(100vh - 64%)"},viewBox:"0 0 45 45",xmlns:"http://www.w3.org/2000/svg",stroke:"#61dafb",children:(0,l.jsxs)("g",{fill:"none",fillRule:"evenodd",transform:"translate(1 1)",strokeWidth:"2",children:[(0,l.jsxs)("circle",{cx:"22",cy:"22",r:"6",strokeOpacity:"0",children:[(0,l.jsx)("animate",{attributeName:"r",begin:"1.5s",dur:"3s",values:"6;22",calcMode:"linear",repeatCount:"indefinite"}),(0,l.jsx)("animate",{attributeName:"stroke-opacity",begin:"1.5s",dur:"3s",values:"1;0",calcMode:"linear",repeatCount:"indefinite"}),(0,l.jsx)("animate",{attributeName:"stroke-width",begin:"1.5s",dur:"3s",values:"2;0",calcMode:"linear",repeatCount:"indefinite"})]}),(0,l.jsxs)("circle",{cx:"22",cy:"22",r:"6",strokeOpacity:"0",children:[(0,l.jsx)("animate",{attributeName:"r",begin:"3s",dur:"3s",values:"6;22",calcMode:"linear",repeatCount:"indefinite"}),(0,l.jsx)("animate",{attributeName:"stroke-opacity",begin:"3s",dur:"3s",values:"1;0",calcMode:"linear",repeatCount:"indefinite"}),(0,l.jsx)("animate",{attributeName:"stroke-width",begin:"3s",dur:"3s",values:"2;0",calcMode:"linear",repeatCount:"indefinite"})]}),(0,l.jsx)("circle",{cx:"22",cy:"22",r:"8",children:(0,l.jsx)("animate",{attributeName:"r",begin:"0s",dur:"1.5s",values:"6;1;2;3;4;5;6",calcMode:"linear",repeatCount:"indefinite"})})]})})}):null}var c=n(6921),u=n(3102);function d(e,t){if("*"===e)return a()({loading:s,loader:()=>n.e(9293).then(n.bind(n,9293)),modules:["@theme/NotFound"],webpack:()=>[9293],render(e,t){const n=e.default;return(0,l.jsx)(u.W,{value:{plugin:{name:"native",id:"default"}},children:(0,l.jsx)(n,{...t})})}});const r=o[`${e}-${t}`],d={},p=[],f=[],m=(0,c.A)(r);return Object.entries(m).forEach((e=>{let[t,n]=e;const r=i[n];r&&(d[t]=r[0],p.push(r[1]),f.push(r[2]))})),a().Map({loading:s,loader:d,modules:p,webpack:()=>f,render(t,n){const a=JSON.parse(JSON.stringify(r));Object.entries(t).forEach((t=>{let[n,r]=t;const o=r.default;if(!o)throw new Error(`The page component at ${e} doesn't have a default export. This makes it impossible to render anything. Consider default-exporting a React component.`);"object"!=typeof o&&"function"!=typeof o||Object.keys(r).filter((e=>"default"!==e)).forEach((e=>{o[e]=r[e]}));let i=a;const l=n.split(".");l.slice(0,-1).forEach((e=>{i=i[e]})),i[l[l.length-1]]=o}));const o=a.__comp;delete a.__comp;const i=a.__context;return delete a.__context,(0,l.jsx)(u.W,{value:i,children:(0,l.jsx)(o,{...a,...n})})}})}const p=[{path:"/chat",component:d("/chat","fd7"),exact:!0},{path:"/code",component:d("/code","8ef"),exact:!0},{path:"/legal-notice",component:d("/legal-notice","cfc"),exact:!0},{path:"/license",component:d("/license","d06"),exact:!0},{path:"/markdown-page",component:d("/markdown-page","784"),exact:!0},{path:"/meeting",component:d("/meeting","6b0"),exact:!0},{path:"/newsletter",component:d("/newsletter","d15"),exact:!0},{path:"/premium",component:d("/premium","d94"),exact:!0},{path:"/premium-submitted",component:d("/premium-submitted","714"),exact:!0},{path:"/survey",component:d("/survey","9e0"),exact:!0},{path:"/",component:d("/","d82"),exact:!0},{path:"/",component:d("/","f6a"),routes:[{path:"/",component:d("/","854"),routes:[{path:"/",component:d("/","1b8"),routes:[{path:"/adapters.html",component:d("/adapters.html","fb4"),exact:!0},{path:"/alternatives.html",component:d("/alternatives.html","d53"),exact:!0,sidebar:"tutorialSidebar"},{path:"/articles/angular-database.html",component:d("/articles/angular-database.html","e30"),exact:!0,sidebar:"tutorialSidebar"},{path:"/articles/browser-database.html",component:d("/articles/browser-database.html","b0a"),exact:!0,sidebar:"tutorialSidebar"},{path:"/articles/browser-storage.html",component:d("/articles/browser-storage.html","286"),exact:!0,sidebar:"tutorialSidebar"},{path:"/articles/data-base.html",component:d("/articles/data-base.html","797"),exact:!0,sidebar:"tutorialSidebar"},{path:"/articles/embedded-database.html",component:d("/articles/embedded-database.html","596"),exact:!0,sidebar:"tutorialSidebar"},{path:"/articles/flutter-database.html",component:d("/articles/flutter-database.html","f8a"),exact:!0,sidebar:"tutorialSidebar"},{path:"/articles/frontend-database.html",component:d("/articles/frontend-database.html","a83"),exact:!0,sidebar:"tutorialSidebar"},{path:"/articles/in-memory-nosql-database.html",component:d("/articles/in-memory-nosql-database.html","ead"),exact:!0,sidebar:"tutorialSidebar"},{path:"/articles/ionic-database.html",component:d("/articles/ionic-database.html","df6"),exact:!0,sidebar:"tutorialSidebar"},{path:"/articles/json-database.html",component:d("/articles/json-database.html","bff"),exact:!0,sidebar:"tutorialSidebar"},{path:"/articles/localstorage.html",component:d("/articles/localstorage.html","b1b"),exact:!0,sidebar:"tutorialSidebar"},{path:"/articles/mobile-database.html",component:d("/articles/mobile-database.html","1d7"),exact:!0,sidebar:"tutorialSidebar"},{path:"/articles/progressive-web-app-database.html",component:d("/articles/progressive-web-app-database.html","862"),exact:!0,sidebar:"tutorialSidebar"},{path:"/articles/react-database.html",component:d("/articles/react-database.html","179"),exact:!0,sidebar:"tutorialSidebar"},{path:"/articles/realtime-database.html",component:d("/articles/realtime-database.html","bc3"),exact:!0,sidebar:"tutorialSidebar"},{path:"/backup.html",component:d("/backup.html","123"),exact:!0,sidebar:"tutorialSidebar"},{path:"/capacitor-database.html",component:d("/capacitor-database.html","71f"),exact:!0,sidebar:"tutorialSidebar"},{path:"/cleanup.html",component:d("/cleanup.html","d7f"),exact:!0,sidebar:"tutorialSidebar"},{path:"/contribution.html",component:d("/contribution.html","129"),exact:!0,sidebar:"tutorialSidebar"},{path:"/crdt.html",component:d("/crdt.html","c69"),exact:!0,sidebar:"tutorialSidebar"},{path:"/data-migration",component:d("/data-migration","7c7"),exact:!0},{path:"/dev-mode.html",component:d("/dev-mode.html","11d"),exact:!0,sidebar:"tutorialSidebar"},{path:"/downsides-of-offline-first.html",component:d("/downsides-of-offline-first.html","ba4"),exact:!0,sidebar:"tutorialSidebar"},{path:"/electron-database.html",component:d("/electron-database.html","44e"),exact:!0,sidebar:"tutorialSidebar"},{path:"/electron.html",component:d("/electron.html","693"),exact:!0,sidebar:"tutorialSidebar"},{path:"/encryption.html",component:d("/encryption.html","265"),exact:!0,sidebar:"tutorialSidebar"},{path:"/install.html",component:d("/install.html","9ec"),exact:!0,sidebar:"tutorialSidebar"},{path:"/key-compression.html",component:d("/key-compression.html","171"),exact:!0,sidebar:"tutorialSidebar"},{path:"/leader-election.html",component:d("/leader-election.html","9aa"),exact:!0,sidebar:"tutorialSidebar"},{path:"/logger.html",component:d("/logger.html","949"),exact:!0,sidebar:"tutorialSidebar"},{path:"/middleware.html",component:d("/middleware.html","34f"),exact:!0,sidebar:"tutorialSidebar"},{path:"/migration-schema.html",component:d("/migration-schema.html","618"),exact:!0,sidebar:"tutorialSidebar"},{path:"/migration-storage.html",component:d("/migration-storage.html","34a"),exact:!0,sidebar:"tutorialSidebar"},{path:"/nodejs-database.html",component:d("/nodejs-database.html","6a2"),exact:!0,sidebar:"tutorialSidebar"},{path:"/nosql-performance-tips.html",component:d("/nosql-performance-tips.html","fd8"),exact:!0,sidebar:"tutorialSidebar"},{path:"/offline-first.html",component:d("/offline-first.html","e1b"),exact:!0,sidebar:"tutorialSidebar"},{path:"/orm.html",component:d("/orm.html","798"),exact:!0,sidebar:"tutorialSidebar"},{path:"/plugins.html",component:d("/plugins.html","f25"),exact:!0,sidebar:"tutorialSidebar"},{path:"/population.html",component:d("/population.html","b89"),exact:!0,sidebar:"tutorialSidebar"},{path:"/query-cache.html",component:d("/query-cache.html","45f"),exact:!0,sidebar:"tutorialSidebar"},{path:"/query-optimizer.html",component:d("/query-optimizer.html","bd3"),exact:!0,sidebar:"tutorialSidebar"},{path:"/questions-answers.html",component:d("/questions-answers.html","840"),exact:!0,sidebar:"tutorialSidebar"},{path:"/quickstart.html",component:d("/quickstart.html","417"),exact:!0,sidebar:"tutorialSidebar"},{path:"/react-native-database.html",component:d("/react-native-database.html","7b4"),exact:!0,sidebar:"tutorialSidebar"},{path:"/reactivity.html",component:d("/reactivity.html","4d4"),exact:!0,sidebar:"tutorialSidebar"},{path:"/releases/10.0.0.html",component:d("/releases/10.0.0.html","8ce"),exact:!0,sidebar:"tutorialSidebar"},{path:"/releases/11.0.0.html",component:d("/releases/11.0.0.html","712"),exact:!0,sidebar:"tutorialSidebar"},{path:"/releases/12.0.0.html",component:d("/releases/12.0.0.html","a36"),exact:!0,sidebar:"tutorialSidebar"},{path:"/releases/13.0.0.html",component:d("/releases/13.0.0.html","605"),exact:!0,sidebar:"tutorialSidebar"},{path:"/releases/14.0.0.html",component:d("/releases/14.0.0.html","14c"),exact:!0,sidebar:"tutorialSidebar"},{path:"/releases/15.0.0.html",component:d("/releases/15.0.0.html","4dd"),exact:!0,sidebar:"tutorialSidebar"},{path:"/releases/8.0.0.html",component:d("/releases/8.0.0.html","fdc"),exact:!0,sidebar:"tutorialSidebar"},{path:"/releases/9.0.0.html",component:d("/releases/9.0.0.html","f4b"),exact:!0,sidebar:"tutorialSidebar"},{path:"/replication-couchdb.html",component:d("/replication-couchdb.html","6d5"),exact:!0,sidebar:"tutorialSidebar"},{path:"/replication-firestore.html",component:d("/replication-firestore.html","bcb"),exact:!0,sidebar:"tutorialSidebar"},{path:"/replication-graphql.html",component:d("/replication-graphql.html","a6c"),exact:!0,sidebar:"tutorialSidebar"},{path:"/replication-http.html",component:d("/replication-http.html","16a"),exact:!0,sidebar:"tutorialSidebar"},{path:"/replication-nats.html",component:d("/replication-nats.html","ac4"),exact:!0,sidebar:"tutorialSidebar"},{path:"/replication-p2p.html",component:d("/replication-p2p.html","ec6"),exact:!0},{path:"/replication-server",component:d("/replication-server","aa6"),exact:!0,sidebar:"tutorialSidebar"},{path:"/replication-webrtc.html",component:d("/replication-webrtc.html","ff6"),exact:!0,sidebar:"tutorialSidebar"},{path:"/replication-websocket.html",component:d("/replication-websocket.html","4f9"),exact:!0,sidebar:"tutorialSidebar"},{path:"/replication.html",component:d("/replication.html","62b"),exact:!0,sidebar:"tutorialSidebar"},{path:"/rx-attachment.html",component:d("/rx-attachment.html","7d7"),exact:!0,sidebar:"tutorialSidebar"},{path:"/rx-collection.html",component:d("/rx-collection.html","7dc"),exact:!0,sidebar:"tutorialSidebar"},{path:"/rx-database.html",component:d("/rx-database.html","e4e"),exact:!0,sidebar:"tutorialSidebar"},{path:"/rx-document.html",component:d("/rx-document.html","e09"),exact:!0,sidebar:"tutorialSidebar"},{path:"/rx-local-document.html",component:d("/rx-local-document.html","0db"),exact:!0,sidebar:"tutorialSidebar"},{path:"/rx-query.html",component:d("/rx-query.html","2cf"),exact:!0,sidebar:"tutorialSidebar"},{path:"/rx-schema.html",component:d("/rx-schema.html","671"),exact:!0,sidebar:"tutorialSidebar"},{path:"/rx-server-scaling.html",component:d("/rx-server-scaling.html","da1"),exact:!0,sidebar:"tutorialSidebar"},{path:"/rx-server.html",component:d("/rx-server.html","ed5"),exact:!0,sidebar:"tutorialSidebar"},{path:"/rx-state.html",component:d("/rx-state.html","198"),exact:!0,sidebar:"tutorialSidebar"},{path:"/rx-storage-denokv.html",component:d("/rx-storage-denokv.html","b6e"),exact:!0,sidebar:"tutorialSidebar"},{path:"/rx-storage-dexie.html",component:d("/rx-storage-dexie.html","bb3"),exact:!0,sidebar:"tutorialSidebar"},{path:"/rx-storage-filesystem-node.html",component:d("/rx-storage-filesystem-node.html","a57"),exact:!0,sidebar:"tutorialSidebar"},{path:"/rx-storage-foundationdb.html",component:d("/rx-storage-foundationdb.html","3c8"),exact:!0,sidebar:"tutorialSidebar"},{path:"/rx-storage-indexeddb.html",component:d("/rx-storage-indexeddb.html","631"),exact:!0,sidebar:"tutorialSidebar"},{path:"/rx-storage-localstorage-meta-optimizer.html",component:d("/rx-storage-localstorage-meta-optimizer.html","064"),exact:!0,sidebar:"tutorialSidebar"},{path:"/rx-storage-lokijs.html",component:d("/rx-storage-lokijs.html","1be"),exact:!0,sidebar:"tutorialSidebar"},{path:"/rx-storage-memory-synced.html",component:d("/rx-storage-memory-synced.html","65f"),exact:!0,sidebar:"tutorialSidebar"},{path:"/rx-storage-memory.html",component:d("/rx-storage-memory.html","c21"),exact:!0,sidebar:"tutorialSidebar"},{path:"/rx-storage-mongodb.html",component:d("/rx-storage-mongodb.html","5ad"),exact:!0,sidebar:"tutorialSidebar"},{path:"/rx-storage-opfs.html",component:d("/rx-storage-opfs.html","6f7"),exact:!0,sidebar:"tutorialSidebar"},{path:"/rx-storage-performance.html",component:d("/rx-storage-performance.html","b12"),exact:!0,sidebar:"tutorialSidebar"},{path:"/rx-storage-pouchdb.html",component:d("/rx-storage-pouchdb.html","d82"),exact:!0},{path:"/rx-storage-remote.html",component:d("/rx-storage-remote.html","5df"),exact:!0,sidebar:"tutorialSidebar"},{path:"/rx-storage-sharding.html",component:d("/rx-storage-sharding.html","b30"),exact:!0,sidebar:"tutorialSidebar"},{path:"/rx-storage-shared-worker.html",component:d("/rx-storage-shared-worker.html","0f4"),exact:!0,sidebar:"tutorialSidebar"},{path:"/rx-storage-sqlite.html",component:d("/rx-storage-sqlite.html","ad7"),exact:!0,sidebar:"tutorialSidebar"},{path:"/rx-storage-worker.html",component:d("/rx-storage-worker.html","a4e"),exact:!0,sidebar:"tutorialSidebar"},{path:"/rx-storage.html",component:d("/rx-storage.html","144"),exact:!0,sidebar:"tutorialSidebar"},{path:"/rxdb-tradeoffs.html",component:d("/rxdb-tradeoffs.html","5cb"),exact:!0},{path:"/schema-validation.html",component:d("/schema-validation.html","3f1"),exact:!0},{path:"/slow-indexeddb.html",component:d("/slow-indexeddb.html","a40"),exact:!0,sidebar:"tutorialSidebar"},{path:"/third-party-plugins.html",component:d("/third-party-plugins.html","549"),exact:!0,sidebar:"tutorialSidebar"},{path:"/transactions-conflicts-revisions.html",component:d("/transactions-conflicts-revisions.html","53a"),exact:!0,sidebar:"tutorialSidebar"},{path:"/tutorials/typescript.html",component:d("/tutorials/typescript.html","a33"),exact:!0,sidebar:"tutorialSidebar"},{path:"/why-nosql.html",component:d("/why-nosql.html","ad0"),exact:!0,sidebar:"tutorialSidebar"}]}]}]},{path:"*",component:d("*")}]},6125:(e,t,n)=>{"use strict";n.d(t,{o:()=>o,x:()=>i});var r=n(6540),a=n(4848);const o=r.createContext(!1);function i(e){let{children:t}=e;const[n,i]=(0,r.useState)(!1);return(0,r.useEffect)((()=>{i(!0)}),[]),(0,a.jsx)(o.Provider,{value:n,children:t})}},8522:(e,t,n)=>{"use strict";var r=n(6540),a=n(5338),o=n(4625),i=n(545),l=n(8193);const s=[n(1911),n(119),n(6134),n(6294),n(1043)];var c=n(8328),u=n(6347),d=n(2831),p=n(2303),f=n(4848);function m(e){let{children:t}=e;const n=(0,p.A)();return(0,r.useEffect)((()=>{n&&(function(){const e="fixed-chat-button";if(document.getElementById(e))return;const t=document.createElement("a");t.id=e,t.href="/chat",t.target="_blank",t.innerHTML="\ud83d\udcac Community Chat";const n=document.createElement("style");n.type="text/css",n.innerText="#"+e+" {color: white;position: fixed;right: 0;bottom: 0;background-color: var(--color-top);padding-left: 17px;padding-right: 17px;padding-top: 10px;padding-bottom: 5px;text-align: center;margin-right: 50px;font-weight: bold;border-top-left-radius: 9px;border-top-right-radius: 9px;z-index: 11;}#fixed-chat-button:hover {box-shadow: 2px 2px 13px #ca007c, -2px -1px 14px #ff009e;text-decoration: underline;}",document.head.appendChild(n),document.body.appendChild(t)}(),function(){if("/"===location.pathname)return;const e=[{text:"Follow",keyword:"@twitter",url:"https://twitter.com/intent/user?screen_name=rxdbjs",icon:"\ud83d\udc26"},{text:"Follow",keyword:"@LinkedIn",url:"https://www.linkedin.com/company/rxdb",icon:"[in]"},{text:"Chat",keyword:"@discord",url:"https://rxdb.info/chat",icon:"\ud83d\udcac"},{text:"Star",keyword:"@github",url:"https://rxdb.info/code",icon:"\ud83d\udc19\ud83d\udcbb"},{text:"Subscribe",keyword:"@newsletter",url:"https://rxdb.info/newsletter",icon:"\ud83d\udcf0"}];function t(e,t){e.parentNode.insertBefore(t,e.nextSibling)}const n="rxdb-call-to-action-button";function r(){console.log("set call to action button");const r=6e5,a=Date.now(),o=(a-a%r)/r;console.log("timeslot "+o);const i=o%e.length;console.log("randid: "+i);const l=e[i],s=document.querySelector(".call-to-action");s&&s.parentNode.removeChild(s);const c=document.querySelector(".navbar__items");if(!c)return;const u=document.createElement("div");u.classList.add("call-to-action");const d=document.createElement("a");d.onclick=()=>{window.trigger("call-to-action",.35)},d.classList.add("hover-shadow-top"),d.id=n,d.innerHTML=l.text+' '+l.keyword+''+l.icon+"",d.href=l.url,d.target="_blank",u.append(d),t(c,u)}r()}())})),(0,f.jsx)(f.Fragment,{children:t})}var h=n(5260),g=n(4586),b=n(6025),y=n(6342),v=n(1003),w=n(2131),x=n(4090),k=n(2967),S=n(440),E=n(1463);function _(){const{i18n:{currentLocale:e,defaultLocale:t,localeConfigs:n}}=(0,g.A)(),r=(0,w.o)(),a=n[e].htmlLang,o=e=>e.replace("-","_");return(0,f.jsxs)(h.A,{children:[Object.entries(n).map((e=>{let[t,{htmlLang:n}]=e;return(0,f.jsx)("link",{rel:"alternate",href:r.createUrl({locale:t,fullyQualified:!0}),hrefLang:n},t)})),(0,f.jsx)("link",{rel:"alternate",href:r.createUrl({locale:t,fullyQualified:!0}),hrefLang:"x-default"}),(0,f.jsx)("meta",{property:"og:locale",content:o(a)}),Object.values(n).filter((e=>a!==e.htmlLang)).map((e=>(0,f.jsx)("meta",{property:"og:locale:alternate",content:o(e.htmlLang)},`meta-og-${e.htmlLang}`)))]})}function C(e){let{permalink:t}=e;const{siteConfig:{url:n}}=(0,g.A)(),r=function(){const{siteConfig:{url:e,baseUrl:t,trailingSlash:n}}=(0,g.A)(),{pathname:r}=(0,u.zy)();return e+(0,S.applyTrailingSlash)((0,b.A)(r),{trailingSlash:n,baseUrl:t})}(),a=t?`${n}${t}`:r;return(0,f.jsxs)(h.A,{children:[(0,f.jsx)("meta",{property:"og:url",content:a}),(0,f.jsx)("link",{rel:"canonical",href:a})]})}function T(){const{i18n:{currentLocale:e}}=(0,g.A)(),{metadata:t,image:n}=(0,y.p)();return(0,f.jsxs)(f.Fragment,{children:[(0,f.jsxs)(h.A,{children:[(0,f.jsx)("meta",{name:"twitter:card",content:"summary_large_image"}),(0,f.jsx)("body",{className:x.w})]}),n&&(0,f.jsx)(v.be,{image:n}),(0,f.jsx)(C,{}),(0,f.jsx)(_,{}),(0,f.jsx)(E.A,{tag:k.Cy,locale:e}),(0,f.jsx)(h.A,{children:t.map(((e,t)=>(0,f.jsx)("meta",{...e},t)))})]})}const A=new Map;function j(e){if(A.has(e.pathname))return{...e,pathname:A.get(e.pathname)};if((0,d.u)(c.A,e.pathname).some((e=>{let{route:t}=e;return!0===t.exact})))return A.set(e.pathname,e.pathname),e;const t=e.pathname.trim().replace(/(?:\/index)?\.html$/,"")||"/";return A.set(e.pathname,t),{...e,pathname:t}}var N=n(6125),R=n(6988),L=n(205);function P(e){for(var t=arguments.length,n=new Array(t>1?t-1:0),r=1;rYour Docusaurus site did not load properly.
\nA very common reason is a wrong site baseUrl configuration.
\nCurrent configured baseUrl = ${e} ${"/"===e?" (default value)":""}
\nWe suggest trying baseUrl =
\n.comment
can become .namespace--comment
) or replace them with your defined ones (like .editor__comment
). You can even add new classes.",owner:"dvkndn",noCSS:!0},"file-highlight":{title:"File Highlight",description:"Fetch external files and highlight them with Prism. Used on the Prism website itself.",noCSS:!0},"show-language":{title:"Show Language",description:"Display the highlighted language in code blocks (inline code does not show the label).",owner:"nauzilus",noCSS:!0,require:"toolbar"},"jsonp-highlight":{title:"JSONP Highlight",description:"Fetch content with JSONP and highlight some interesting content (e.g. GitHub/Gists or Bitbucket API).",noCSS:!0,owner:"nauzilus"},"highlight-keywords":{title:"Highlight Keywords",description:"Adds special CSS classes for each keyword for fine-grained highlighting.",owner:"vkbansal",noCSS:!0},"remove-initial-line-feed":{title:"Remove initial line feed",description:"Removes the initial line feed in code blocks.",owner:"Golmote",noCSS:!0},"inline-color":{title:"Inline color",description:"Adds a small inline preview for colors in style sheets.",require:"css-extras",owner:"RunDevelopment"},previewers:{title:"Previewers",description:"Previewers for angles, colors, gradients, easing and time.",require:"css-extras",owner:"Golmote"},autoloader:{title:"Autoloader",description:"Automatically loads the needed languages to highlight the code blocks.",owner:"Golmote",noCSS:!0},"keep-markup":{title:"Keep Markup",description:"Prevents custom markup from being dropped out during highlighting.",owner:"Golmote",optional:"normalize-whitespace",noCSS:!0},"command-line":{title:"Command Line",description:"Display a command line with a prompt and, optionally, the output/response from the commands.",owner:"chriswells0"},"unescaped-markup":{title:"Unescaped Markup",description:"Write markup without having to escape anything."},"normalize-whitespace":{title:"Normalize Whitespace",description:"Supports multiple operations to normalize whitespace in code blocks.",owner:"zeitgeist87",optional:"unescaped-markup",noCSS:!0},"data-uri-highlight":{title:"Data-URI Highlight",description:"Highlights data-URI contents.",owner:"Golmote",noCSS:!0},toolbar:{title:"Toolbar",description:"Attach a toolbar for plugins to easily register buttons on the top of a code block.",owner:"mAAdhaTTah"},"copy-to-clipboard":{title:"Copy to Clipboard Button",description:"Add a button that copies the code block to the clipboard when clicked.",owner:"mAAdhaTTah",require:"toolbar",noCSS:!0},"download-button":{title:"Download Button",description:"A button in the toolbar of a code block adding a convenient way to download a code file.",owner:"Golmote",require:"toolbar",noCSS:!0},"match-braces":{title:"Match braces",description:"Highlights matching braces.",owner:"RunDevelopment"},"diff-highlight":{title:"Diff Highlight",description:"Highlights the code inside diff blocks.",owner:"RunDevelopment",require:"diff"},"filter-highlight-all":{title:"Filter highlightAll",description:"Filters the elements the highlightAll
and highlightAllUnder
methods actually highlight.",owner:"RunDevelopment",noCSS:!0},treeview:{title:"Treeview",description:"A language with special styles to highlight file system tree structures.",owner:"Golmote"}}})},8722:(e,t,n)=>{const r=n(6969),a=n(8380),o=new Set;function i(e){void 0===e?e=Object.keys(r.languages).filter((e=>"meta"!=e)):Array.isArray(e)||(e=[e]);const t=[...o,...Object.keys(Prism.languages)];a(r,e,t).load((e=>{if(!(e in r.languages))return void(i.silent||console.warn("Language does not exist: "+e));const t="./prism-"+e;delete n.c[n(3157).resolve(t)],delete Prism.languages[e],n(3157)(t),o.add(e)}))}i.silent=!1,e.exports=i},9700:()=>{!function(e){function t(e,t){return"___"+e.toUpperCase()+t+"___"}Object.defineProperties(e.languages["markup-templating"]={},{buildPlaceholders:{value:function(n,r,a,o){if(n.language===r){var i=n.tokenStack=[];n.code=n.code.replace(a,(function(e){if("function"==typeof o&&!o(e))return e;for(var a,l=i.length;-1!==n.code.indexOf(a=t(r,l));)++l;return i[l]=e,a})),n.grammar=e.languages.markup}}},tokenizePlaceholders:{value:function(n,r){if(n.language===r&&n.tokenStack){n.grammar=e.languages[r];var a=0,o=Object.keys(n.tokenStack);!function i(l){for(var s=0;s{const o=t.toLowerCase(),i=((e,t)=>{const[n,r]=(0,u.useState)(Q(t,e)),a=(0,u.useRef)(),o=(0,u.useRef)();return(0,u.useEffect)((()=>{t===a.current&&e===o.current||(a.current=t,o.current=e,r(Q(t,e)))}),[e,t]),n})(o,r),l=(e=>(0,u.useCallback)((t=>{var n=t,{className:r,style:a,line:o}=n,i=_(n,["className","style","line"]);const l=E(S({},i),{className:(0,d.A)("token-line",r)});return"object"==typeof e&&"plain"in e&&(l.style=e.plain),"object"==typeof a&&(l.style=S(S({},l.style||{}),a)),l}),[e]))(i),s=(e=>{const t=(0,u.useCallback)((({types:t,empty:n})=>{if(null!=e)return 1===t.length&&"plain"===t[0]?null!=n?{display:"inline-block"}:void 0:1===t.length&&null!=n?e[t[0]]:Object.assign(null!=n?{display:"inline-block"}:{},...t.map((t=>e[t])))}),[e]);return(0,u.useCallback)((e=>{var n=e,{token:r,className:a,style:o}=n,i=_(n,["token","className","style"]);const l=E(S({},i),{className:(0,d.A)("token",...r.types,a),children:r.content,style:t(r)});return null!=o&&(l.style=S(S({},l.style||{}),o)),l}),[t])})(i),c=(({prism:e,code:t,grammar:n,language:r})=>{const a=(0,u.useRef)(e);return(0,u.useMemo)((()=>{if(null==n)return Z([t]);const e={code:t,grammar:n,language:r,tokens:[]};return a.current.hooks.run("before-tokenize",e),e.tokens=a.current.tokenize(t,n),a.current.hooks.run("after-tokenize",e),Z(e.tokens)}),[t,n,r])})({prism:a,language:o,code:n,grammar:a.languages[o]});return e({tokens:c,className:`prism-code language-${o}`,style:null!=i?i.root:{},getLineProps:l,getTokenProps:s})},ee=e=>(0,u.createElement)(X,E(S({},e),{prism:e.prism||T,theme:e.theme||U,code:e.code,language:e.language}))},1561:(e,t,n)=>{"use strict";n.d(t,{A:()=>o});var r=!0,a="Invariant failed";function o(e,t){if(!e){if(r)throw new Error(a);var n="function"==typeof t?t():t,o=n?"".concat(a,": ").concat(n):a;throw new Error(o)}}},2654:e=>{"use strict";e.exports={}},4054:e=>{"use strict";e.exports=JSON.parse('{"/chat-fd7":{"__comp":"25626d15","__context":{"plugin":"04b0214f"},"config":"5e9f5e1a"},"/code-8ef":{"__comp":"36715375","__context":{"plugin":"04b0214f"},"config":"5e9f5e1a"},"/legal-notice-cfc":{"__comp":"502d8946","__context":{"plugin":"04b0214f"},"config":"5e9f5e1a"},"/license-d06":{"__comp":"db34d6b0","__context":{"plugin":"04b0214f"},"config":"5e9f5e1a"},"/markdown-page-784":{"__comp":"1f391b9e","__context":{"plugin":"04b0214f"},"content":"393be207"},"/meeting-6b0":{"__comp":"280a2389","__context":{"plugin":"04b0214f"},"config":"5e9f5e1a"},"/newsletter-d15":{"__comp":"14d72841","__context":{"plugin":"04b0214f"},"config":"5e9f5e1a"},"/premium-d94":{"__comp":"0e268d20","__context":{"plugin":"04b0214f"},"config":"5e9f5e1a"},"/premium-submitted-714":{"__comp":"cde77f4f","__context":{"plugin":"04b0214f"},"config":"5e9f5e1a"},"/survey-9e0":{"__comp":"98405524","__context":{"plugin":"04b0214f"},"config":"5e9f5e1a"},"/-d82":{"__comp":"1df93b7f","__context":{"plugin":"04b0214f"},"config":"5e9f5e1a"},"/-f6a":{"__comp":"5e95c892","__context":{"plugin":"60c23941"}},"/-854":{"__comp":"a7bd4aaa","version":"935f2afb"},"/-1b8":{"__comp":"a94703ab"},"/adapters.html-fb4":{"__comp":"17896441","content":"6bfb0089"},"/alternatives.html-d53":{"__comp":"17896441","content":"4777fd9a"},"/articles/angular-database.html-e30":{"__comp":"17896441","content":"8aa53ed7"},"/articles/browser-database.html-b0a":{"__comp":"17896441","content":"ec526260"},"/articles/browser-storage.html-286":{"__comp":"17896441","content":"d2758528"},"/articles/data-base.html-797":{"__comp":"17896441","content":"38bbf12a"},"/articles/embedded-database.html-596":{"__comp":"17896441","content":"ab919a1f"},"/articles/flutter-database.html-f8a":{"__comp":"17896441","content":"badcd764"},"/articles/frontend-database.html-a83":{"__comp":"17896441","content":"f44bb875"},"/articles/in-memory-nosql-database.html-ead":{"__comp":"17896441","content":"77d975e6"},"/articles/ionic-database.html-df6":{"__comp":"17896441","content":"c9c8e0b6"},"/articles/json-database.html-bff":{"__comp":"17896441","content":"84a3af36"},"/articles/localstorage.html-b1b":{"__comp":"17896441","content":"f15938da"},"/articles/mobile-database.html-1d7":{"__comp":"17896441","content":"51334108"},"/articles/progressive-web-app-database.html-862":{"__comp":"17896441","content":"0f6e10f0"},"/articles/react-database.html-179":{"__comp":"17896441","content":"c3bc9c50"},"/articles/realtime-database.html-bc3":{"__comp":"17896441","content":"4af60d2e"},"/backup.html-123":{"__comp":"17896441","content":"1b0f8c91"},"/capacitor-database.html-71f":{"__comp":"17896441","content":"8bc07e20"},"/cleanup.html-d7f":{"__comp":"17896441","content":"b0889a22"},"/contribution.html-129":{"__comp":"17896441","content":"4ba7e5a3"},"/crdt.html-c69":{"__comp":"17896441","content":"d20e74b4"},"/data-migration-7c7":{"__comp":"17896441","content":"a7f10198"},"/dev-mode.html-11d":{"__comp":"17896441","content":"ad16b3ea"},"/downsides-of-offline-first.html-ba4":{"__comp":"17896441","content":"68a466be"},"/electron-database.html-44e":{"__comp":"17896441","content":"34f94d1b"},"/electron.html-693":{"__comp":"17896441","content":"924d6dd6"},"/encryption.html-265":{"__comp":"17896441","content":"045bd6f5"},"/install.html-9ec":{"__comp":"17896441","content":"c4de80f8"},"/key-compression.html-171":{"__comp":"17896441","content":"dc42ba65"},"/leader-election.html-9aa":{"__comp":"17896441","content":"41f941a1"},"/logger.html-949":{"__comp":"17896441","content":"9dd8ea89"},"/middleware.html-34f":{"__comp":"17896441","content":"1c0701dd"},"/migration-schema.html-618":{"__comp":"17896441","content":"d622bd51"},"/migration-storage.html-34a":{"__comp":"17896441","content":"a406dc27"},"/nodejs-database.html-6a2":{"__comp":"17896441","content":"401008a8"},"/nosql-performance-tips.html-fd8":{"__comp":"17896441","content":"32667c41"},"/offline-first.html-e1b":{"__comp":"17896441","content":"326aca46"},"/orm.html-798":{"__comp":"17896441","content":"86b4e356"},"/plugins.html-f25":{"__comp":"17896441","content":"294ac9d5"},"/population.html-b89":{"__comp":"17896441","content":"7815dd0c"},"/query-cache.html-45f":{"__comp":"17896441","content":"e6b4453d"},"/query-optimizer.html-bd3":{"__comp":"17896441","content":"a69eebfc"},"/questions-answers.html-840":{"__comp":"17896441","content":"e7478ff0"},"/quickstart.html-417":{"__comp":"17896441","content":"8070e160"},"/react-native-database.html-7b4":{"__comp":"17896441","content":"ee1b9f21"},"/reactivity.html-4d4":{"__comp":"17896441","content":"a442adcd"},"/releases/10.0.0.html-8ce":{"__comp":"17896441","content":"ebace26e"},"/releases/11.0.0.html-712":{"__comp":"17896441","content":"8288c265"},"/releases/12.0.0.html-a36":{"__comp":"17896441","content":"ed2d6610"},"/releases/13.0.0.html-605":{"__comp":"17896441","content":"b8c49ce4"},"/releases/14.0.0.html-14c":{"__comp":"17896441","content":"c6349bb6"},"/releases/15.0.0.html-4dd":{"__comp":"17896441","content":"21fa2740"},"/releases/8.0.0.html-fdc":{"__comp":"17896441","content":"432b83f9"},"/releases/9.0.0.html-f4b":{"__comp":"17896441","content":"1da545ff"},"/replication-couchdb.html-6d5":{"__comp":"17896441","content":"118cde4c"},"/replication-firestore.html-bcb":{"__comp":"17896441","content":"7f02c700"},"/replication-graphql.html-a6c":{"__comp":"17896441","content":"aa14e6b1"},"/replication-http.html-16a":{"__comp":"17896441","content":"a574e172"},"/replication-nats.html-ac4":{"__comp":"17896441","content":"84ae55a4"},"/replication-p2p.html-ec6":{"__comp":"17896441","content":"26b8a621"},"/replication-server-aa6":{"__comp":"17896441","content":"0e945c41"},"/replication-webrtc.html-ff6":{"__comp":"17896441","content":"187b985e"},"/replication-websocket.html-4f9":{"__comp":"17896441","content":"ac62b32d"},"/replication.html-62b":{"__comp":"17896441","content":"6ae3580c"},"/rx-attachment.html-7d7":{"__comp":"17896441","content":"b30f4f1f"},"/rx-collection.html-7dc":{"__comp":"17896441","content":"cbbe8f0a"},"/rx-database.html-e4e":{"__comp":"17896441","content":"2456d5e0"},"/rx-document.html-e09":{"__comp":"17896441","content":"dbde2ffe"},"/rx-local-document.html-0db":{"__comp":"17896441","content":"714575d7"},"/rx-query.html-2cf":{"__comp":"17896441","content":"39600c95"},"/rx-schema.html-671":{"__comp":"17896441","content":"55a5b596"},"/rx-server-scaling.html-da1":{"__comp":"17896441","content":"c6fdd490"},"/rx-server.html-ed5":{"__comp":"17896441","content":"f43e80a8"},"/rx-state.html-198":{"__comp":"17896441","content":"c44853e1"},"/rx-storage-denokv.html-b6e":{"__comp":"17896441","content":"fe7a07ee"},"/rx-storage-dexie.html-bb3":{"__comp":"17896441","content":"380cc66a"},"/rx-storage-filesystem-node.html-a57":{"__comp":"17896441","content":"eadd9b3c"},"/rx-storage-foundationdb.html-3c8":{"__comp":"17896441","content":"6fd28feb"},"/rx-storage-indexeddb.html-631":{"__comp":"17896441","content":"92698a99"},"/rx-storage-localstorage-meta-optimizer.html-064":{"__comp":"17896441","content":"e24529eb"},"/rx-storage-lokijs.html-1be":{"__comp":"17896441","content":"0027230a"},"/rx-storage-memory-synced.html-65f":{"__comp":"17896441","content":"01684a0a"},"/rx-storage-memory.html-c21":{"__comp":"17896441","content":"d4da9db3"},"/rx-storage-mongodb.html-5ad":{"__comp":"17896441","content":"4616b86a"},"/rx-storage-opfs.html-6f7":{"__comp":"17896441","content":"6cbff7c2"},"/rx-storage-performance.html-b12":{"__comp":"17896441","content":"1b238727"},"/rx-storage-pouchdb.html-d82":{"__comp":"17896441","content":"4adf80bb"},"/rx-storage-remote.html-5df":{"__comp":"17896441","content":"5a273530"},"/rx-storage-sharding.html-b30":{"__comp":"17896441","content":"91b454ee"},"/rx-storage-shared-worker.html-0f4":{"__comp":"17896441","content":"25a43fd4"},"/rx-storage-sqlite.html-ad7":{"__comp":"17896441","content":"4ed9495b"},"/rx-storage-worker.html-a4e":{"__comp":"17896441","content":"6187b59a"},"/rx-storage.html-144":{"__comp":"17896441","content":"1e0353aa"},"/rxdb-tradeoffs.html-5cb":{"__comp":"17896441","content":"2564bf4f"},"/schema-validation.html-3f1":{"__comp":"17896441","content":"931f4566"},"/slow-indexeddb.html-a40":{"__comp":"17896441","content":"8b0a0922"},"/third-party-plugins.html-549":{"__comp":"17896441","content":"c843a053"},"/transactions-conflicts-revisions.html-53a":{"__comp":"17896441","content":"03e37916"},"/tutorials/typescript.html-a33":{"__comp":"17896441","content":"2efd0200"},"/why-nosql.html-ad0":{"__comp":"17896441","content":"9e91b6f0"}}')}},e=>{e.O(0,[1869],(()=>{return t=8522,e(e.s=t);var t}));e.O()}]);
\ No newline at end of file
+/*! For license information please see main.cc3fdfd5.js.LICENSE.txt */
+(self.webpackChunkrxdb=self.webpackChunkrxdb||[]).push([[8792],{8328:(e,t,n)=>{"use strict";n.d(t,{A:()=>p});n(6540);var r=n(3259),a=n.n(r),o=n(4054);const i={"0027230a":[()=>n.e(8382).then(n.bind(n,2081)),"@site/docs/rx-storage-lokijs.md",2081],"01684a0a":[()=>n.e(6616).then(n.bind(n,3395)),"@site/docs/rx-storage-memory-synced.md",3395],"03e37916":[()=>n.e(6465).then(n.bind(n,3184)),"@site/docs/transactions-conflicts-revisions.md",3184],"045bd6f5":[()=>n.e(4475).then(n.bind(n,8201)),"@site/docs/encryption.md",8201],"04b0214f":[()=>n.e(6264).then(n.t.bind(n,4061,19)),"/home/runner/work/rxdb/rxdb/docs-src/.docusaurus/docusaurus-plugin-content-pages/default/plugin-route-context-module-100.json",4061],"0e268d20":[()=>Promise.all([n.e(5106),n.e(2584)]).then(n.bind(n,5607)),"@site/src/pages/premium.tsx",5607],"0e945c41":[()=>n.e(9796).then(n.bind(n,9722)),"@site/docs/replication-server.md",9722],"0f6e10f0":[()=>n.e(1475).then(n.bind(n,654)),"@site/docs/articles/progressive-web-app-database.md",654],"118cde4c":[()=>n.e(5272).then(n.bind(n,7245)),"@site/docs/replication-couchdb.md",7245],"14d72841":[()=>n.e(9772).then(n.bind(n,5221)),"@site/src/pages/newsletter.tsx",5221],17896441:[()=>Promise.all([n.e(1869),n.e(1968),n.e(8401)]).then(n.bind(n,242)),"@theme/DocItem",242],"187b985e":[()=>n.e(6866).then(n.bind(n,844)),"@site/docs/replication-webrtc.md",844],"1b0f8c91":[()=>n.e(3129).then(n.bind(n,9642)),"@site/docs/backup.md",9642],"1b238727":[()=>n.e(4013).then(n.bind(n,3721)),"@site/docs/rx-storage-performance.md",3721],"1c0701dd":[()=>n.e(6953).then(n.bind(n,668)),"@site/docs/middleware.md",668],"1da545ff":[()=>n.e(9743).then(n.bind(n,2678)),"@site/docs/releases/9.0.0.md",2678],"1df93b7f":[()=>Promise.all([n.e(1869),n.e(5106),n.e(4579),n.e(4583)]).then(n.bind(n,6866)),"@site/src/pages/index.tsx",6866],"1e0353aa":[()=>n.e(8588).then(n.bind(n,142)),"@site/docs/rx-storage.md",142],"1f391b9e":[()=>Promise.all([n.e(1869),n.e(1968),n.e(6061)]).then(n.bind(n,7973)),"@theme/MDXPage",7973],"21fa2740":[()=>n.e(5694).then(n.bind(n,763)),"@site/docs/releases/15.0.0.md",763],"2456d5e0":[()=>n.e(2966).then(n.bind(n,5654)),"@site/docs/rx-database.md",5654],"25626d15":[()=>n.e(268).then(n.bind(n,7258)),"@site/src/pages/chat.tsx",7258],"2564bf4f":[()=>n.e(6724).then(n.bind(n,5705)),"@site/docs/rxdb-tradeoffs.md",5705],"25a43fd4":[()=>n.e(4812).then(n.bind(n,3917)),"@site/docs/rx-storage-shared-worker.md",3917],"26b8a621":[()=>n.e(2055).then(n.bind(n,3439)),"@site/docs/replication-p2p.md",3439],"280a2389":[()=>Promise.all([n.e(5106),n.e(176)]).then(n.bind(n,8141)),"@site/src/pages/meeting.tsx",8141],"294ac9d5":[()=>n.e(8744).then(n.bind(n,958)),"@site/docs/plugins.md",958],"2efd0200":[()=>n.e(4132).then(n.bind(n,9839)),"@site/docs/tutorials/typescript.md",9839],"32667c41":[()=>n.e(8191).then(n.bind(n,6895)),"@site/docs/nosql-performance-tips.md",6895],"326aca46":[()=>n.e(4853).then(n.bind(n,3142)),"@site/docs/offline-first.md",3142],"34f94d1b":[()=>n.e(5832).then(n.bind(n,7746)),"@site/docs/electron-database.md",7746],36715375:[()=>n.e(2076).then(n.bind(n,2323)),"@site/src/pages/code.tsx",2323],"380cc66a":[()=>n.e(2061).then(n.bind(n,5668)),"@site/docs/rx-storage-dexie.md",5668],"38bbf12a":[()=>n.e(2078).then(n.bind(n,3762)),"@site/docs/articles/data-base.md",3762],"393be207":[()=>n.e(4134).then(n.bind(n,6602)),"@site/src/pages/markdown-page.md",6602],"39600c95":[()=>n.e(3148).then(n.bind(n,755)),"@site/docs/rx-query.md",755],"401008a8":[()=>n.e(5219).then(n.bind(n,6805)),"@site/docs/nodejs-database.md",6805],"41f941a1":[()=>n.e(5966).then(n.bind(n,3057)),"@site/docs/leader-election.md",3057],"432b83f9":[()=>n.e(4424).then(n.bind(n,9429)),"@site/docs/releases/8.0.0.md",9429],"4616b86a":[()=>n.e(465).then(n.bind(n,81)),"@site/docs/rx-storage-mongodb.md",81],"4777fd9a":[()=>n.e(6386).then(n.bind(n,1600)),"@site/docs/alternatives.md",1600],"4adf80bb":[()=>n.e(9548).then(n.bind(n,4442)),"@site/docs/rx-storage-pouchdb.md",4442],"4af60d2e":[()=>n.e(8545).then(n.bind(n,9249)),"@site/docs/articles/realtime-database.md",9249],"4ba7e5a3":[()=>n.e(9591).then(n.bind(n,6467)),"@site/docs/contribute.md",6467],"4ed9495b":[()=>n.e(1199).then(n.bind(n,1787)),"@site/docs/rx-storage-sqlite.md",1787],"502d8946":[()=>n.e(7817).then(n.bind(n,732)),"@site/src/pages/legal-notice.tsx",732],51334108:[()=>n.e(8926).then(n.bind(n,2644)),"@site/docs/articles/mobile-database.md",2644],"55a5b596":[()=>n.e(6717).then(n.bind(n,5536)),"@site/docs/rx-schema.md",5536],"5a273530":[()=>n.e(3881).then(n.bind(n,7589)),"@site/docs/rx-storage-remote.md",7589],"5e95c892":[()=>n.e(9647).then(n.bind(n,7121)),"@theme/DocsRoot",7121],"5e9f5e1a":[()=>Promise.resolve().then(n.bind(n,4784)),"@generated/docusaurus.config",4784],"60c23941":[()=>n.e(2915).then(n.t.bind(n,1966,19)),"/home/runner/work/rxdb/rxdb/docs-src/.docusaurus/docusaurus-plugin-content-docs/default/plugin-route-context-module-100.json",1966],"6187b59a":[()=>n.e(5866).then(n.bind(n,7409)),"@site/docs/rx-storage-worker.md",7409],"68a466be":[()=>n.e(3997).then(n.bind(n,3923)),"@site/docs/downsides-of-offline-first.md",3923],"6ae3580c":[()=>n.e(5320).then(n.bind(n,5376)),"@site/docs/replication.md",5376],"6bfb0089":[()=>n.e(6422).then(n.bind(n,300)),"@site/docs/adapters.md",300],"6cbff7c2":[()=>n.e(7408).then(n.bind(n,5943)),"@site/docs/rx-storage-opfs.md",5943],"6fd28feb":[()=>n.e(4618).then(n.bind(n,9408)),"@site/docs/rx-storage-foundationdb.md",9408],"714575d7":[()=>n.e(3185).then(n.bind(n,4880)),"@site/docs/rx-local-document.md",4880],"77d975e6":[()=>n.e(3949).then(n.bind(n,5707)),"@site/docs/articles/in-memory-nosql-database.md",5707],"7815dd0c":[()=>n.e(5335).then(n.bind(n,5515)),"@site/docs/population.md",5515],"7f02c700":[()=>n.e(9592).then(n.bind(n,9640)),"@site/docs/replication-firestore.md",9640],"8070e160":[()=>n.e(3822).then(n.bind(n,1685)),"@site/docs/quickstart.md",1685],"8288c265":[()=>n.e(9881).then(n.bind(n,1839)),"@site/docs/releases/11.0.0.md",1839],"84a3af36":[()=>n.e(6861).then(n.bind(n,8160)),"@site/docs/articles/json-database.md",8160],"84ae55a4":[()=>n.e(588).then(n.bind(n,2045)),"@site/docs/replication-nats.md",2045],"86b4e356":[()=>n.e(2786).then(n.bind(n,9278)),"@site/docs/orm.md",9278],"8aa53ed7":[()=>n.e(6723).then(n.bind(n,5870)),"@site/docs/articles/angular-database.md",5870],"8b0a0922":[()=>n.e(4557).then(n.bind(n,767)),"@site/docs/slow-indexeddb.md",767],"8bc07e20":[()=>n.e(1850).then(n.bind(n,5054)),"@site/docs/capacitor-database.md",5054],"91b454ee":[()=>n.e(4202).then(n.bind(n,9107)),"@site/docs/rx-storage-sharding.md",9107],"924d6dd6":[()=>n.e(5122).then(n.bind(n,2414)),"@site/docs/electron.md",2414],"92698a99":[()=>n.e(4166).then(n.bind(n,8568)),"@site/docs/rx-storage-indexeddb.md",8568],"931f4566":[()=>n.e(3595).then(n.bind(n,2439)),"@site/docs/schema-validation.md",2439],"935f2afb":[()=>n.e(8581).then(n.t.bind(n,5610,19)),"~docs/default/version-current-metadata-prop-751.json",5610],98405524:[()=>n.e(5504).then(n.bind(n,1934)),"@site/src/pages/survey.tsx",1934],"9dd8ea89":[()=>n.e(1715).then(n.bind(n,7919)),"@site/docs/logger.md",7919],"9e91b6f0":[()=>n.e(3021).then(n.bind(n,1844)),"@site/docs/why-nosql.md",1844],a406dc27:[()=>n.e(1500).then(n.bind(n,8306)),"@site/docs/migration-storage.md",8306],a442adcd:[()=>n.e(8760).then(n.bind(n,188)),"@site/docs/reactivity.md",188],a574e172:[()=>n.e(7149).then(n.bind(n,9329)),"@site/docs/replication-http.md",9329],a69eebfc:[()=>n.e(9408).then(n.bind(n,4120)),"@site/docs/query-optimizer.md",4120],a7bd4aaa:[()=>n.e(7098).then(n.bind(n,4532)),"@theme/DocVersionRoot",4532],a7f10198:[()=>n.e(1098).then(n.bind(n,769)),"@site/docs/data-migration.md",769],a94703ab:[()=>Promise.all([n.e(1869),n.e(9048)]).then(n.bind(n,2559)),"@theme/DocRoot",2559],aa14e6b1:[()=>n.e(9824).then(n.bind(n,3268)),"@site/docs/replication-graphql.md",3268],ab919a1f:[()=>n.e(6491).then(n.bind(n,4760)),"@site/docs/articles/embedded-database.md",4760],ac62b32d:[()=>n.e(9192).then(n.bind(n,9585)),"@site/docs/replication-websocket.md",9585],ad16b3ea:[()=>n.e(8674).then(n.bind(n,2462)),"@site/docs/dev-mode.md",2462],b0889a22:[()=>n.e(1107).then(n.bind(n,1798)),"@site/docs/cleanup.md",1798],b30f4f1f:[()=>n.e(3779).then(n.bind(n,5830)),"@site/docs/rx-attachment.md",5830],b8c49ce4:[()=>n.e(6355).then(n.bind(n,1605)),"@site/docs/releases/13.0.0.md",1605],badcd764:[()=>n.e(8318).then(n.bind(n,6042)),"@site/docs/articles/flutter-database.md",6042],c3bc9c50:[()=>n.e(9167).then(n.bind(n,4337)),"@site/docs/articles/react-database.md",4337],c44853e1:[()=>n.e(6584).then(n.bind(n,7390)),"@site/docs/rx-state.md",7390],c4de80f8:[()=>n.e(2777).then(n.bind(n,1173)),"@site/docs/install.md",1173],c6349bb6:[()=>n.e(5740).then(n.bind(n,2964)),"@site/docs/releases/14.0.0.md",2964],c6fdd490:[()=>n.e(4141).then(n.bind(n,5008)),"@site/docs/rx-server-scaling.md",5008],c843a053:[()=>n.e(9146).then(n.bind(n,8723)),"@site/docs/third-party-plugins.md",8723],c9c8e0b6:[()=>n.e(7249).then(n.bind(n,7674)),"@site/docs/articles/ionic-database.md",7674],cbbe8f0a:[()=>n.e(3852).then(n.bind(n,8783)),"@site/docs/rx-collection.md",8783],cde77f4f:[()=>Promise.all([n.e(5106),n.e(6287)]).then(n.bind(n,6465)),"@site/src/pages/premium-submitted.tsx",6465],d20e74b4:[()=>n.e(5123).then(n.bind(n,2853)),"@site/docs/crdt.md",2853],d2758528:[()=>n.e(2586).then(n.bind(n,7108)),"@site/docs/articles/browser-storage.md",7108],d4da9db3:[()=>n.e(1400).then(n.bind(n,4228)),"@site/docs/rx-storage-memory.md",4228],d622bd51:[()=>n.e(2845).then(n.bind(n,9804)),"@site/docs/migration-schema.md",9804],db34d6b0:[()=>Promise.all([n.e(5106),n.e(7320)]).then(n.bind(n,9891)),"@site/src/pages/license.tsx",9891],dbde2ffe:[()=>n.e(6543).then(n.bind(n,118)),"@site/docs/rx-document.md",118],dc42ba65:[()=>n.e(4962).then(n.bind(n,4494)),"@site/docs/key-compression.md",4494],e24529eb:[()=>n.e(6797).then(n.bind(n,9263)),"@site/docs/rx-storage-localstorage-meta-optimizer.md",9263],e6b4453d:[()=>n.e(2360).then(n.bind(n,9133)),"@site/docs/query-cache.md",9133],e7478ff0:[()=>n.e(5416).then(n.bind(n,1873)),"@site/docs/questions-answers.md",1873],eadd9b3c:[()=>n.e(4886).then(n.bind(n,8041)),"@site/docs/rx-storage-filesystem-node.md",8041],ebace26e:[()=>n.e(4028).then(n.bind(n,7016)),"@site/docs/releases/10.0.0.md",7016],ec526260:[()=>n.e(7396).then(n.bind(n,9592)),"@site/docs/articles/browser-database.md",9592],ed2d6610:[()=>n.e(3469).then(n.bind(n,9222)),"@site/docs/releases/12.0.0.md",9222],ee1b9f21:[()=>n.e(6998).then(n.bind(n,3179)),"@site/docs/react-native-database.md",3179],f15938da:[()=>n.e(4630).then(n.bind(n,5674)),"@site/docs/articles/localstorage.md",5674],f43e80a8:[()=>n.e(1558).then(n.bind(n,9544)),"@site/docs/rx-server.md",9544],f44bb875:[()=>n.e(561).then(n.bind(n,46)),"@site/docs/articles/frontend-database.md",46],fe7a07ee:[()=>n.e(2085).then(n.bind(n,9378)),"@site/docs/rx-storage-denokv.md",9378]};var l=n(4848);function s(e){let{error:t,retry:n,pastDelay:r}=e;return t?(0,l.jsxs)("div",{style:{textAlign:"center",color:"#fff",backgroundColor:"#fa383e",borderColor:"#fa383e",borderStyle:"solid",borderRadius:"0.25rem",borderWidth:"1px",boxSizing:"border-box",display:"block",padding:"1rem",flex:"0 0 50%",marginLeft:"25%",marginRight:"25%",marginTop:"5rem",maxWidth:"50%",width:"100%"},children:[(0,l.jsx)("p",{children:String(t)}),(0,l.jsx)("div",{children:(0,l.jsx)("button",{type:"button",onClick:n,children:"Retry"})})]}):r?(0,l.jsx)("div",{style:{display:"flex",justifyContent:"center",alignItems:"center",height:"100vh"},children:(0,l.jsx)("svg",{id:"loader",style:{width:128,height:110,position:"absolute",top:"calc(100vh - 64%)"},viewBox:"0 0 45 45",xmlns:"http://www.w3.org/2000/svg",stroke:"#61dafb",children:(0,l.jsxs)("g",{fill:"none",fillRule:"evenodd",transform:"translate(1 1)",strokeWidth:"2",children:[(0,l.jsxs)("circle",{cx:"22",cy:"22",r:"6",strokeOpacity:"0",children:[(0,l.jsx)("animate",{attributeName:"r",begin:"1.5s",dur:"3s",values:"6;22",calcMode:"linear",repeatCount:"indefinite"}),(0,l.jsx)("animate",{attributeName:"stroke-opacity",begin:"1.5s",dur:"3s",values:"1;0",calcMode:"linear",repeatCount:"indefinite"}),(0,l.jsx)("animate",{attributeName:"stroke-width",begin:"1.5s",dur:"3s",values:"2;0",calcMode:"linear",repeatCount:"indefinite"})]}),(0,l.jsxs)("circle",{cx:"22",cy:"22",r:"6",strokeOpacity:"0",children:[(0,l.jsx)("animate",{attributeName:"r",begin:"3s",dur:"3s",values:"6;22",calcMode:"linear",repeatCount:"indefinite"}),(0,l.jsx)("animate",{attributeName:"stroke-opacity",begin:"3s",dur:"3s",values:"1;0",calcMode:"linear",repeatCount:"indefinite"}),(0,l.jsx)("animate",{attributeName:"stroke-width",begin:"3s",dur:"3s",values:"2;0",calcMode:"linear",repeatCount:"indefinite"})]}),(0,l.jsx)("circle",{cx:"22",cy:"22",r:"8",children:(0,l.jsx)("animate",{attributeName:"r",begin:"0s",dur:"1.5s",values:"6;1;2;3;4;5;6",calcMode:"linear",repeatCount:"indefinite"})})]})})}):null}var c=n(6921),u=n(3102);function d(e,t){if("*"===e)return a()({loading:s,loader:()=>n.e(9293).then(n.bind(n,9293)),modules:["@theme/NotFound"],webpack:()=>[9293],render(e,t){const n=e.default;return(0,l.jsx)(u.W,{value:{plugin:{name:"native",id:"default"}},children:(0,l.jsx)(n,{...t})})}});const r=o[`${e}-${t}`],d={},p=[],f=[],m=(0,c.A)(r);return Object.entries(m).forEach((e=>{let[t,n]=e;const r=i[n];r&&(d[t]=r[0],p.push(r[1]),f.push(r[2]))})),a().Map({loading:s,loader:d,modules:p,webpack:()=>f,render(t,n){const a=JSON.parse(JSON.stringify(r));Object.entries(t).forEach((t=>{let[n,r]=t;const o=r.default;if(!o)throw new Error(`The page component at ${e} doesn't have a default export. This makes it impossible to render anything. Consider default-exporting a React component.`);"object"!=typeof o&&"function"!=typeof o||Object.keys(r).filter((e=>"default"!==e)).forEach((e=>{o[e]=r[e]}));let i=a;const l=n.split(".");l.slice(0,-1).forEach((e=>{i=i[e]})),i[l[l.length-1]]=o}));const o=a.__comp;delete a.__comp;const i=a.__context;return delete a.__context,(0,l.jsx)(u.W,{value:i,children:(0,l.jsx)(o,{...a,...n})})}})}const p=[{path:"/chat",component:d("/chat","fd7"),exact:!0},{path:"/code",component:d("/code","8ef"),exact:!0},{path:"/legal-notice",component:d("/legal-notice","cfc"),exact:!0},{path:"/license",component:d("/license","d06"),exact:!0},{path:"/markdown-page",component:d("/markdown-page","784"),exact:!0},{path:"/meeting",component:d("/meeting","6b0"),exact:!0},{path:"/newsletter",component:d("/newsletter","d15"),exact:!0},{path:"/premium",component:d("/premium","d94"),exact:!0},{path:"/premium-submitted",component:d("/premium-submitted","714"),exact:!0},{path:"/survey",component:d("/survey","9e0"),exact:!0},{path:"/",component:d("/","d82"),exact:!0},{path:"/",component:d("/","f6a"),routes:[{path:"/",component:d("/","854"),routes:[{path:"/",component:d("/","1b8"),routes:[{path:"/adapters.html",component:d("/adapters.html","fb4"),exact:!0},{path:"/alternatives.html",component:d("/alternatives.html","d53"),exact:!0,sidebar:"tutorialSidebar"},{path:"/articles/angular-database.html",component:d("/articles/angular-database.html","e30"),exact:!0,sidebar:"tutorialSidebar"},{path:"/articles/browser-database.html",component:d("/articles/browser-database.html","b0a"),exact:!0,sidebar:"tutorialSidebar"},{path:"/articles/browser-storage.html",component:d("/articles/browser-storage.html","286"),exact:!0,sidebar:"tutorialSidebar"},{path:"/articles/data-base.html",component:d("/articles/data-base.html","797"),exact:!0,sidebar:"tutorialSidebar"},{path:"/articles/embedded-database.html",component:d("/articles/embedded-database.html","596"),exact:!0,sidebar:"tutorialSidebar"},{path:"/articles/flutter-database.html",component:d("/articles/flutter-database.html","f8a"),exact:!0,sidebar:"tutorialSidebar"},{path:"/articles/frontend-database.html",component:d("/articles/frontend-database.html","a83"),exact:!0,sidebar:"tutorialSidebar"},{path:"/articles/in-memory-nosql-database.html",component:d("/articles/in-memory-nosql-database.html","ead"),exact:!0,sidebar:"tutorialSidebar"},{path:"/articles/ionic-database.html",component:d("/articles/ionic-database.html","df6"),exact:!0,sidebar:"tutorialSidebar"},{path:"/articles/json-database.html",component:d("/articles/json-database.html","bff"),exact:!0,sidebar:"tutorialSidebar"},{path:"/articles/localstorage.html",component:d("/articles/localstorage.html","b1b"),exact:!0,sidebar:"tutorialSidebar"},{path:"/articles/mobile-database.html",component:d("/articles/mobile-database.html","1d7"),exact:!0,sidebar:"tutorialSidebar"},{path:"/articles/progressive-web-app-database.html",component:d("/articles/progressive-web-app-database.html","862"),exact:!0,sidebar:"tutorialSidebar"},{path:"/articles/react-database.html",component:d("/articles/react-database.html","179"),exact:!0,sidebar:"tutorialSidebar"},{path:"/articles/realtime-database.html",component:d("/articles/realtime-database.html","bc3"),exact:!0,sidebar:"tutorialSidebar"},{path:"/backup.html",component:d("/backup.html","123"),exact:!0,sidebar:"tutorialSidebar"},{path:"/capacitor-database.html",component:d("/capacitor-database.html","71f"),exact:!0,sidebar:"tutorialSidebar"},{path:"/cleanup.html",component:d("/cleanup.html","d7f"),exact:!0,sidebar:"tutorialSidebar"},{path:"/contribution.html",component:d("/contribution.html","129"),exact:!0,sidebar:"tutorialSidebar"},{path:"/crdt.html",component:d("/crdt.html","c69"),exact:!0,sidebar:"tutorialSidebar"},{path:"/data-migration",component:d("/data-migration","7c7"),exact:!0},{path:"/dev-mode.html",component:d("/dev-mode.html","11d"),exact:!0,sidebar:"tutorialSidebar"},{path:"/downsides-of-offline-first.html",component:d("/downsides-of-offline-first.html","ba4"),exact:!0,sidebar:"tutorialSidebar"},{path:"/electron-database.html",component:d("/electron-database.html","44e"),exact:!0,sidebar:"tutorialSidebar"},{path:"/electron.html",component:d("/electron.html","693"),exact:!0,sidebar:"tutorialSidebar"},{path:"/encryption.html",component:d("/encryption.html","265"),exact:!0,sidebar:"tutorialSidebar"},{path:"/install.html",component:d("/install.html","9ec"),exact:!0,sidebar:"tutorialSidebar"},{path:"/key-compression.html",component:d("/key-compression.html","171"),exact:!0,sidebar:"tutorialSidebar"},{path:"/leader-election.html",component:d("/leader-election.html","9aa"),exact:!0,sidebar:"tutorialSidebar"},{path:"/logger.html",component:d("/logger.html","949"),exact:!0,sidebar:"tutorialSidebar"},{path:"/middleware.html",component:d("/middleware.html","34f"),exact:!0,sidebar:"tutorialSidebar"},{path:"/migration-schema.html",component:d("/migration-schema.html","618"),exact:!0,sidebar:"tutorialSidebar"},{path:"/migration-storage.html",component:d("/migration-storage.html","34a"),exact:!0,sidebar:"tutorialSidebar"},{path:"/nodejs-database.html",component:d("/nodejs-database.html","6a2"),exact:!0,sidebar:"tutorialSidebar"},{path:"/nosql-performance-tips.html",component:d("/nosql-performance-tips.html","fd8"),exact:!0,sidebar:"tutorialSidebar"},{path:"/offline-first.html",component:d("/offline-first.html","e1b"),exact:!0,sidebar:"tutorialSidebar"},{path:"/orm.html",component:d("/orm.html","798"),exact:!0,sidebar:"tutorialSidebar"},{path:"/plugins.html",component:d("/plugins.html","f25"),exact:!0,sidebar:"tutorialSidebar"},{path:"/population.html",component:d("/population.html","b89"),exact:!0,sidebar:"tutorialSidebar"},{path:"/query-cache.html",component:d("/query-cache.html","45f"),exact:!0,sidebar:"tutorialSidebar"},{path:"/query-optimizer.html",component:d("/query-optimizer.html","bd3"),exact:!0,sidebar:"tutorialSidebar"},{path:"/questions-answers.html",component:d("/questions-answers.html","840"),exact:!0,sidebar:"tutorialSidebar"},{path:"/quickstart.html",component:d("/quickstart.html","417"),exact:!0,sidebar:"tutorialSidebar"},{path:"/react-native-database.html",component:d("/react-native-database.html","7b4"),exact:!0,sidebar:"tutorialSidebar"},{path:"/reactivity.html",component:d("/reactivity.html","4d4"),exact:!0,sidebar:"tutorialSidebar"},{path:"/releases/10.0.0.html",component:d("/releases/10.0.0.html","8ce"),exact:!0,sidebar:"tutorialSidebar"},{path:"/releases/11.0.0.html",component:d("/releases/11.0.0.html","712"),exact:!0,sidebar:"tutorialSidebar"},{path:"/releases/12.0.0.html",component:d("/releases/12.0.0.html","a36"),exact:!0,sidebar:"tutorialSidebar"},{path:"/releases/13.0.0.html",component:d("/releases/13.0.0.html","605"),exact:!0,sidebar:"tutorialSidebar"},{path:"/releases/14.0.0.html",component:d("/releases/14.0.0.html","14c"),exact:!0,sidebar:"tutorialSidebar"},{path:"/releases/15.0.0.html",component:d("/releases/15.0.0.html","4dd"),exact:!0,sidebar:"tutorialSidebar"},{path:"/releases/8.0.0.html",component:d("/releases/8.0.0.html","fdc"),exact:!0,sidebar:"tutorialSidebar"},{path:"/releases/9.0.0.html",component:d("/releases/9.0.0.html","f4b"),exact:!0,sidebar:"tutorialSidebar"},{path:"/replication-couchdb.html",component:d("/replication-couchdb.html","6d5"),exact:!0,sidebar:"tutorialSidebar"},{path:"/replication-firestore.html",component:d("/replication-firestore.html","bcb"),exact:!0,sidebar:"tutorialSidebar"},{path:"/replication-graphql.html",component:d("/replication-graphql.html","a6c"),exact:!0,sidebar:"tutorialSidebar"},{path:"/replication-http.html",component:d("/replication-http.html","16a"),exact:!0,sidebar:"tutorialSidebar"},{path:"/replication-nats.html",component:d("/replication-nats.html","ac4"),exact:!0,sidebar:"tutorialSidebar"},{path:"/replication-p2p.html",component:d("/replication-p2p.html","ec6"),exact:!0},{path:"/replication-server",component:d("/replication-server","aa6"),exact:!0,sidebar:"tutorialSidebar"},{path:"/replication-webrtc.html",component:d("/replication-webrtc.html","ff6"),exact:!0,sidebar:"tutorialSidebar"},{path:"/replication-websocket.html",component:d("/replication-websocket.html","4f9"),exact:!0,sidebar:"tutorialSidebar"},{path:"/replication.html",component:d("/replication.html","62b"),exact:!0,sidebar:"tutorialSidebar"},{path:"/rx-attachment.html",component:d("/rx-attachment.html","7d7"),exact:!0,sidebar:"tutorialSidebar"},{path:"/rx-collection.html",component:d("/rx-collection.html","7dc"),exact:!0,sidebar:"tutorialSidebar"},{path:"/rx-database.html",component:d("/rx-database.html","e4e"),exact:!0,sidebar:"tutorialSidebar"},{path:"/rx-document.html",component:d("/rx-document.html","e09"),exact:!0,sidebar:"tutorialSidebar"},{path:"/rx-local-document.html",component:d("/rx-local-document.html","0db"),exact:!0,sidebar:"tutorialSidebar"},{path:"/rx-query.html",component:d("/rx-query.html","2cf"),exact:!0,sidebar:"tutorialSidebar"},{path:"/rx-schema.html",component:d("/rx-schema.html","671"),exact:!0,sidebar:"tutorialSidebar"},{path:"/rx-server-scaling.html",component:d("/rx-server-scaling.html","da1"),exact:!0,sidebar:"tutorialSidebar"},{path:"/rx-server.html",component:d("/rx-server.html","ed5"),exact:!0,sidebar:"tutorialSidebar"},{path:"/rx-state.html",component:d("/rx-state.html","198"),exact:!0,sidebar:"tutorialSidebar"},{path:"/rx-storage-denokv.html",component:d("/rx-storage-denokv.html","b6e"),exact:!0,sidebar:"tutorialSidebar"},{path:"/rx-storage-dexie.html",component:d("/rx-storage-dexie.html","bb3"),exact:!0,sidebar:"tutorialSidebar"},{path:"/rx-storage-filesystem-node.html",component:d("/rx-storage-filesystem-node.html","a57"),exact:!0,sidebar:"tutorialSidebar"},{path:"/rx-storage-foundationdb.html",component:d("/rx-storage-foundationdb.html","3c8"),exact:!0,sidebar:"tutorialSidebar"},{path:"/rx-storage-indexeddb.html",component:d("/rx-storage-indexeddb.html","631"),exact:!0,sidebar:"tutorialSidebar"},{path:"/rx-storage-localstorage-meta-optimizer.html",component:d("/rx-storage-localstorage-meta-optimizer.html","064"),exact:!0,sidebar:"tutorialSidebar"},{path:"/rx-storage-lokijs.html",component:d("/rx-storage-lokijs.html","1be"),exact:!0,sidebar:"tutorialSidebar"},{path:"/rx-storage-memory-synced.html",component:d("/rx-storage-memory-synced.html","65f"),exact:!0,sidebar:"tutorialSidebar"},{path:"/rx-storage-memory.html",component:d("/rx-storage-memory.html","c21"),exact:!0,sidebar:"tutorialSidebar"},{path:"/rx-storage-mongodb.html",component:d("/rx-storage-mongodb.html","5ad"),exact:!0,sidebar:"tutorialSidebar"},{path:"/rx-storage-opfs.html",component:d("/rx-storage-opfs.html","6f7"),exact:!0,sidebar:"tutorialSidebar"},{path:"/rx-storage-performance.html",component:d("/rx-storage-performance.html","b12"),exact:!0,sidebar:"tutorialSidebar"},{path:"/rx-storage-pouchdb.html",component:d("/rx-storage-pouchdb.html","d82"),exact:!0},{path:"/rx-storage-remote.html",component:d("/rx-storage-remote.html","5df"),exact:!0,sidebar:"tutorialSidebar"},{path:"/rx-storage-sharding.html",component:d("/rx-storage-sharding.html","b30"),exact:!0,sidebar:"tutorialSidebar"},{path:"/rx-storage-shared-worker.html",component:d("/rx-storage-shared-worker.html","0f4"),exact:!0,sidebar:"tutorialSidebar"},{path:"/rx-storage-sqlite.html",component:d("/rx-storage-sqlite.html","ad7"),exact:!0,sidebar:"tutorialSidebar"},{path:"/rx-storage-worker.html",component:d("/rx-storage-worker.html","a4e"),exact:!0,sidebar:"tutorialSidebar"},{path:"/rx-storage.html",component:d("/rx-storage.html","144"),exact:!0,sidebar:"tutorialSidebar"},{path:"/rxdb-tradeoffs.html",component:d("/rxdb-tradeoffs.html","5cb"),exact:!0},{path:"/schema-validation.html",component:d("/schema-validation.html","3f1"),exact:!0},{path:"/slow-indexeddb.html",component:d("/slow-indexeddb.html","a40"),exact:!0,sidebar:"tutorialSidebar"},{path:"/third-party-plugins.html",component:d("/third-party-plugins.html","549"),exact:!0,sidebar:"tutorialSidebar"},{path:"/transactions-conflicts-revisions.html",component:d("/transactions-conflicts-revisions.html","53a"),exact:!0,sidebar:"tutorialSidebar"},{path:"/tutorials/typescript.html",component:d("/tutorials/typescript.html","a33"),exact:!0,sidebar:"tutorialSidebar"},{path:"/why-nosql.html",component:d("/why-nosql.html","ad0"),exact:!0,sidebar:"tutorialSidebar"}]}]}]},{path:"*",component:d("*")}]},6125:(e,t,n)=>{"use strict";n.d(t,{o:()=>o,x:()=>i});var r=n(6540),a=n(4848);const o=r.createContext(!1);function i(e){let{children:t}=e;const[n,i]=(0,r.useState)(!1);return(0,r.useEffect)((()=>{i(!0)}),[]),(0,a.jsx)(o.Provider,{value:n,children:t})}},8522:(e,t,n)=>{"use strict";var r=n(6540),a=n(5338),o=n(4625),i=n(545),l=n(8193);const s=[n(1911),n(119),n(6134),n(6294),n(1043)];var c=n(8328),u=n(6347),d=n(2831),p=n(2303),f=n(4848);function m(e){let{children:t}=e;const n=(0,p.A)();return(0,r.useEffect)((()=>{n&&(function(){const e="fixed-chat-button";if(document.getElementById(e))return;const t=document.createElement("a");t.id=e,t.href="/chat",t.target="_blank",t.innerHTML="\ud83d\udcac Community Chat";const n=document.createElement("style");n.type="text/css",n.innerText="#"+e+" {color: white;position: fixed;right: 0;bottom: 0;background-color: var(--color-top);padding-left: 17px;padding-right: 17px;padding-top: 10px;padding-bottom: 5px;text-align: center;margin-right: 50px;font-weight: bold;border-top-left-radius: 9px;border-top-right-radius: 9px;z-index: 11;}#fixed-chat-button:hover {box-shadow: 2px 2px 13px #ca007c, -2px -1px 14px #ff009e;text-decoration: underline;}",document.head.appendChild(n),document.body.appendChild(t)}(),function(){if("/"===location.pathname)return;const e=[{text:"Follow",keyword:"@twitter",url:"https://twitter.com/intent/user?screen_name=rxdbjs",icon:"\ud83d\udc26"},{text:"Follow",keyword:"@LinkedIn",url:"https://www.linkedin.com/company/rxdb",icon:"[in]"},{text:"Chat",keyword:"@discord",url:"https://rxdb.info/chat",icon:"\ud83d\udcac"},{text:"Star",keyword:"@github",url:"https://rxdb.info/code",icon:"\ud83d\udc19\ud83d\udcbb"},{text:"Subscribe",keyword:"@newsletter",url:"https://rxdb.info/newsletter",icon:"\ud83d\udcf0"}];function t(e,t){e.parentNode.insertBefore(t,e.nextSibling)}const n="rxdb-call-to-action-button";function r(){console.log("set call to action button");const r=6e5,a=Date.now(),o=(a-a%r)/r;console.log("timeslot "+o);const i=o%e.length;console.log("randid: "+i);const l=e[i],s=document.querySelector(".call-to-action");s&&s.parentNode.removeChild(s);const c=document.querySelector(".navbar__items");if(!c)return;const u=document.createElement("div");u.classList.add("call-to-action");const d=document.createElement("a");d.onclick=()=>{window.trigger("call-to-action",.35)},d.classList.add("hover-shadow-top"),d.id=n,d.innerHTML=l.text+' '+l.keyword+''+l.icon+"",d.href=l.url,d.target="_blank",u.append(d),t(c,u)}r()}())})),(0,f.jsx)(f.Fragment,{children:t})}var h=n(5260),g=n(4586),b=n(6025),y=n(6342),v=n(1003),w=n(2131),x=n(4090),k=n(2967),S=n(440),E=n(1463);function _(){const{i18n:{currentLocale:e,defaultLocale:t,localeConfigs:n}}=(0,g.A)(),r=(0,w.o)(),a=n[e].htmlLang,o=e=>e.replace("-","_");return(0,f.jsxs)(h.A,{children:[Object.entries(n).map((e=>{let[t,{htmlLang:n}]=e;return(0,f.jsx)("link",{rel:"alternate",href:r.createUrl({locale:t,fullyQualified:!0}),hrefLang:n},t)})),(0,f.jsx)("link",{rel:"alternate",href:r.createUrl({locale:t,fullyQualified:!0}),hrefLang:"x-default"}),(0,f.jsx)("meta",{property:"og:locale",content:o(a)}),Object.values(n).filter((e=>a!==e.htmlLang)).map((e=>(0,f.jsx)("meta",{property:"og:locale:alternate",content:o(e.htmlLang)},`meta-og-${e.htmlLang}`)))]})}function C(e){let{permalink:t}=e;const{siteConfig:{url:n}}=(0,g.A)(),r=function(){const{siteConfig:{url:e,baseUrl:t,trailingSlash:n}}=(0,g.A)(),{pathname:r}=(0,u.zy)();return e+(0,S.applyTrailingSlash)((0,b.A)(r),{trailingSlash:n,baseUrl:t})}(),a=t?`${n}${t}`:r;return(0,f.jsxs)(h.A,{children:[(0,f.jsx)("meta",{property:"og:url",content:a}),(0,f.jsx)("link",{rel:"canonical",href:a})]})}function T(){const{i18n:{currentLocale:e}}=(0,g.A)(),{metadata:t,image:n}=(0,y.p)();return(0,f.jsxs)(f.Fragment,{children:[(0,f.jsxs)(h.A,{children:[(0,f.jsx)("meta",{name:"twitter:card",content:"summary_large_image"}),(0,f.jsx)("body",{className:x.w})]}),n&&(0,f.jsx)(v.be,{image:n}),(0,f.jsx)(C,{}),(0,f.jsx)(_,{}),(0,f.jsx)(E.A,{tag:k.Cy,locale:e}),(0,f.jsx)(h.A,{children:t.map(((e,t)=>(0,f.jsx)("meta",{...e},t)))})]})}const A=new Map;function j(e){if(A.has(e.pathname))return{...e,pathname:A.get(e.pathname)};if((0,d.u)(c.A,e.pathname).some((e=>{let{route:t}=e;return!0===t.exact})))return A.set(e.pathname,e.pathname),e;const t=e.pathname.trim().replace(/(?:\/index)?\.html$/,"")||"/";return A.set(e.pathname,t),{...e,pathname:t}}var N=n(6125),R=n(6988),L=n(205);function P(e){for(var t=arguments.length,n=new Array(t>1?t-1:0),r=1;r Your Docusaurus site did not load properly. A very common reason is a wrong site baseUrl configuration. Current configured baseUrl = ${e} ${"/"===e?" (default value)":""} We suggest trying baseUrl = {const o=t.toLowerCase(),i=((e,t)=>{const[n,r]=(0,u.useState)(Q(t,e)),a=(0,u.useRef)(),o=(0,u.useRef)();return(0,u.useEffect)((()=>{t===a.current&&e===o.current||(a.current=t,o.current=e,r(Q(t,e)))}),[e,t]),n})(o,r),l=(e=>(0,u.useCallback)((t=>{var n=t,{className:r,style:a,line:o}=n,i=_(n,["className","style","line"]);const l=E(S({},i),{className:(0,d.A)("token-line",r)});return"object"==typeof e&&"plain"in e&&(l.style=e.plain),"object"==typeof a&&(l.style=S(S({},l.style||{}),a)),l}),[e]))(i),s=(e=>{const t=(0,u.useCallback)((({types:t,empty:n})=>{if(null!=e)return 1===t.length&&"plain"===t[0]?null!=n?{display:"inline-block"}:void 0:1===t.length&&null!=n?e[t[0]]:Object.assign(null!=n?{display:"inline-block"}:{},...t.map((t=>e[t])))}),[e]);return(0,u.useCallback)((e=>{var n=e,{token:r,className:a,style:o}=n,i=_(n,["token","className","style"]);const l=E(S({},i),{className:(0,d.A)("token",...r.types,a),children:r.content,style:t(r)});return null!=o&&(l.style=S(S({},l.style||{}),o)),l}),[t])})(i),c=(({prism:e,code:t,grammar:n,language:r})=>{const a=(0,u.useRef)(e);return(0,u.useMemo)((()=>{if(null==n)return Z([t]);const e={code:t,grammar:n,language:r,tokens:[]};return a.current.hooks.run("before-tokenize",e),e.tokens=a.current.tokenize(t,n),a.current.hooks.run("after-tokenize",e),Z(e.tokens)}),[t,n,r])})({prism:a,language:o,code:n,grammar:a.languages[o]});return e({tokens:c,className:`prism-code language-${o}`,style:null!=i?i.root:{},getLineProps:l,getTokenProps:s})},ee=e=>(0,u.createElement)(X,E(S({},e),{prism:e.prism||T,theme:e.theme||U,code:e.code,language:e.language}))},1561:(e,t,n)=>{"use strict";n.d(t,{A:()=>o});var r=!0,a="Invariant failed";function o(e,t){if(!e){if(r)throw new Error(a);var n="function"==typeof t?t():t,o=n?"".concat(a,": ").concat(n):a;throw new Error(o)}}},2654:e=>{"use strict";e.exports={}},4054:e=>{"use strict";e.exports=JSON.parse('{"/chat-fd7":{"__comp":"25626d15","__context":{"plugin":"04b0214f"},"config":"5e9f5e1a"},"/code-8ef":{"__comp":"36715375","__context":{"plugin":"04b0214f"},"config":"5e9f5e1a"},"/legal-notice-cfc":{"__comp":"502d8946","__context":{"plugin":"04b0214f"},"config":"5e9f5e1a"},"/license-d06":{"__comp":"db34d6b0","__context":{"plugin":"04b0214f"},"config":"5e9f5e1a"},"/markdown-page-784":{"__comp":"1f391b9e","__context":{"plugin":"04b0214f"},"content":"393be207"},"/meeting-6b0":{"__comp":"280a2389","__context":{"plugin":"04b0214f"},"config":"5e9f5e1a"},"/newsletter-d15":{"__comp":"14d72841","__context":{"plugin":"04b0214f"},"config":"5e9f5e1a"},"/premium-d94":{"__comp":"0e268d20","__context":{"plugin":"04b0214f"},"config":"5e9f5e1a"},"/premium-submitted-714":{"__comp":"cde77f4f","__context":{"plugin":"04b0214f"},"config":"5e9f5e1a"},"/survey-9e0":{"__comp":"98405524","__context":{"plugin":"04b0214f"},"config":"5e9f5e1a"},"/-d82":{"__comp":"1df93b7f","__context":{"plugin":"04b0214f"},"config":"5e9f5e1a"},"/-f6a":{"__comp":"5e95c892","__context":{"plugin":"60c23941"}},"/-854":{"__comp":"a7bd4aaa","version":"935f2afb"},"/-1b8":{"__comp":"a94703ab"},"/adapters.html-fb4":{"__comp":"17896441","content":"6bfb0089"},"/alternatives.html-d53":{"__comp":"17896441","content":"4777fd9a"},"/articles/angular-database.html-e30":{"__comp":"17896441","content":"8aa53ed7"},"/articles/browser-database.html-b0a":{"__comp":"17896441","content":"ec526260"},"/articles/browser-storage.html-286":{"__comp":"17896441","content":"d2758528"},"/articles/data-base.html-797":{"__comp":"17896441","content":"38bbf12a"},"/articles/embedded-database.html-596":{"__comp":"17896441","content":"ab919a1f"},"/articles/flutter-database.html-f8a":{"__comp":"17896441","content":"badcd764"},"/articles/frontend-database.html-a83":{"__comp":"17896441","content":"f44bb875"},"/articles/in-memory-nosql-database.html-ead":{"__comp":"17896441","content":"77d975e6"},"/articles/ionic-database.html-df6":{"__comp":"17896441","content":"c9c8e0b6"},"/articles/json-database.html-bff":{"__comp":"17896441","content":"84a3af36"},"/articles/localstorage.html-b1b":{"__comp":"17896441","content":"f15938da"},"/articles/mobile-database.html-1d7":{"__comp":"17896441","content":"51334108"},"/articles/progressive-web-app-database.html-862":{"__comp":"17896441","content":"0f6e10f0"},"/articles/react-database.html-179":{"__comp":"17896441","content":"c3bc9c50"},"/articles/realtime-database.html-bc3":{"__comp":"17896441","content":"4af60d2e"},"/backup.html-123":{"__comp":"17896441","content":"1b0f8c91"},"/capacitor-database.html-71f":{"__comp":"17896441","content":"8bc07e20"},"/cleanup.html-d7f":{"__comp":"17896441","content":"b0889a22"},"/contribution.html-129":{"__comp":"17896441","content":"4ba7e5a3"},"/crdt.html-c69":{"__comp":"17896441","content":"d20e74b4"},"/data-migration-7c7":{"__comp":"17896441","content":"a7f10198"},"/dev-mode.html-11d":{"__comp":"17896441","content":"ad16b3ea"},"/downsides-of-offline-first.html-ba4":{"__comp":"17896441","content":"68a466be"},"/electron-database.html-44e":{"__comp":"17896441","content":"34f94d1b"},"/electron.html-693":{"__comp":"17896441","content":"924d6dd6"},"/encryption.html-265":{"__comp":"17896441","content":"045bd6f5"},"/install.html-9ec":{"__comp":"17896441","content":"c4de80f8"},"/key-compression.html-171":{"__comp":"17896441","content":"dc42ba65"},"/leader-election.html-9aa":{"__comp":"17896441","content":"41f941a1"},"/logger.html-949":{"__comp":"17896441","content":"9dd8ea89"},"/middleware.html-34f":{"__comp":"17896441","content":"1c0701dd"},"/migration-schema.html-618":{"__comp":"17896441","content":"d622bd51"},"/migration-storage.html-34a":{"__comp":"17896441","content":"a406dc27"},"/nodejs-database.html-6a2":{"__comp":"17896441","content":"401008a8"},"/nosql-performance-tips.html-fd8":{"__comp":"17896441","content":"32667c41"},"/offline-first.html-e1b":{"__comp":"17896441","content":"326aca46"},"/orm.html-798":{"__comp":"17896441","content":"86b4e356"},"/plugins.html-f25":{"__comp":"17896441","content":"294ac9d5"},"/population.html-b89":{"__comp":"17896441","content":"7815dd0c"},"/query-cache.html-45f":{"__comp":"17896441","content":"e6b4453d"},"/query-optimizer.html-bd3":{"__comp":"17896441","content":"a69eebfc"},"/questions-answers.html-840":{"__comp":"17896441","content":"e7478ff0"},"/quickstart.html-417":{"__comp":"17896441","content":"8070e160"},"/react-native-database.html-7b4":{"__comp":"17896441","content":"ee1b9f21"},"/reactivity.html-4d4":{"__comp":"17896441","content":"a442adcd"},"/releases/10.0.0.html-8ce":{"__comp":"17896441","content":"ebace26e"},"/releases/11.0.0.html-712":{"__comp":"17896441","content":"8288c265"},"/releases/12.0.0.html-a36":{"__comp":"17896441","content":"ed2d6610"},"/releases/13.0.0.html-605":{"__comp":"17896441","content":"b8c49ce4"},"/releases/14.0.0.html-14c":{"__comp":"17896441","content":"c6349bb6"},"/releases/15.0.0.html-4dd":{"__comp":"17896441","content":"21fa2740"},"/releases/8.0.0.html-fdc":{"__comp":"17896441","content":"432b83f9"},"/releases/9.0.0.html-f4b":{"__comp":"17896441","content":"1da545ff"},"/replication-couchdb.html-6d5":{"__comp":"17896441","content":"118cde4c"},"/replication-firestore.html-bcb":{"__comp":"17896441","content":"7f02c700"},"/replication-graphql.html-a6c":{"__comp":"17896441","content":"aa14e6b1"},"/replication-http.html-16a":{"__comp":"17896441","content":"a574e172"},"/replication-nats.html-ac4":{"__comp":"17896441","content":"84ae55a4"},"/replication-p2p.html-ec6":{"__comp":"17896441","content":"26b8a621"},"/replication-server-aa6":{"__comp":"17896441","content":"0e945c41"},"/replication-webrtc.html-ff6":{"__comp":"17896441","content":"187b985e"},"/replication-websocket.html-4f9":{"__comp":"17896441","content":"ac62b32d"},"/replication.html-62b":{"__comp":"17896441","content":"6ae3580c"},"/rx-attachment.html-7d7":{"__comp":"17896441","content":"b30f4f1f"},"/rx-collection.html-7dc":{"__comp":"17896441","content":"cbbe8f0a"},"/rx-database.html-e4e":{"__comp":"17896441","content":"2456d5e0"},"/rx-document.html-e09":{"__comp":"17896441","content":"dbde2ffe"},"/rx-local-document.html-0db":{"__comp":"17896441","content":"714575d7"},"/rx-query.html-2cf":{"__comp":"17896441","content":"39600c95"},"/rx-schema.html-671":{"__comp":"17896441","content":"55a5b596"},"/rx-server-scaling.html-da1":{"__comp":"17896441","content":"c6fdd490"},"/rx-server.html-ed5":{"__comp":"17896441","content":"f43e80a8"},"/rx-state.html-198":{"__comp":"17896441","content":"c44853e1"},"/rx-storage-denokv.html-b6e":{"__comp":"17896441","content":"fe7a07ee"},"/rx-storage-dexie.html-bb3":{"__comp":"17896441","content":"380cc66a"},"/rx-storage-filesystem-node.html-a57":{"__comp":"17896441","content":"eadd9b3c"},"/rx-storage-foundationdb.html-3c8":{"__comp":"17896441","content":"6fd28feb"},"/rx-storage-indexeddb.html-631":{"__comp":"17896441","content":"92698a99"},"/rx-storage-localstorage-meta-optimizer.html-064":{"__comp":"17896441","content":"e24529eb"},"/rx-storage-lokijs.html-1be":{"__comp":"17896441","content":"0027230a"},"/rx-storage-memory-synced.html-65f":{"__comp":"17896441","content":"01684a0a"},"/rx-storage-memory.html-c21":{"__comp":"17896441","content":"d4da9db3"},"/rx-storage-mongodb.html-5ad":{"__comp":"17896441","content":"4616b86a"},"/rx-storage-opfs.html-6f7":{"__comp":"17896441","content":"6cbff7c2"},"/rx-storage-performance.html-b12":{"__comp":"17896441","content":"1b238727"},"/rx-storage-pouchdb.html-d82":{"__comp":"17896441","content":"4adf80bb"},"/rx-storage-remote.html-5df":{"__comp":"17896441","content":"5a273530"},"/rx-storage-sharding.html-b30":{"__comp":"17896441","content":"91b454ee"},"/rx-storage-shared-worker.html-0f4":{"__comp":"17896441","content":"25a43fd4"},"/rx-storage-sqlite.html-ad7":{"__comp":"17896441","content":"4ed9495b"},"/rx-storage-worker.html-a4e":{"__comp":"17896441","content":"6187b59a"},"/rx-storage.html-144":{"__comp":"17896441","content":"1e0353aa"},"/rxdb-tradeoffs.html-5cb":{"__comp":"17896441","content":"2564bf4f"},"/schema-validation.html-3f1":{"__comp":"17896441","content":"931f4566"},"/slow-indexeddb.html-a40":{"__comp":"17896441","content":"8b0a0922"},"/third-party-plugins.html-549":{"__comp":"17896441","content":"c843a053"},"/transactions-conflicts-revisions.html-53a":{"__comp":"17896441","content":"03e37916"},"/tutorials/typescript.html-a33":{"__comp":"17896441","content":"2efd0200"},"/why-nosql.html-ad0":{"__comp":"17896441","content":"9e91b6f0"}}')}},e=>{e.O(0,[1869],(()=>{return t=8522,e(e.s=t);var t}));e.O()}]);
\ No newline at end of file
diff --git a/docs/assets/js/main.5dbc8e9b.js.LICENSE.txt b/docs/assets/js/main.cc3fdfd5.js.LICENSE.txt
similarity index 100%
rename from docs/assets/js/main.5dbc8e9b.js.LICENSE.txt
rename to docs/assets/js/main.cc3fdfd5.js.LICENSE.txt
diff --git a/docs/assets/js/runtime~main.b89eda5e.js b/docs/assets/js/runtime~main.aa3d2845.js
similarity index 99%
rename from docs/assets/js/runtime~main.b89eda5e.js
rename to docs/assets/js/runtime~main.aa3d2845.js
index ccadfe9a69c..91dc24f71df 100644
--- a/docs/assets/js/runtime~main.b89eda5e.js
+++ b/docs/assets/js/runtime~main.aa3d2845.js
@@ -1 +1 @@
-(()=>{"use strict";var e,a,f,d,b,c={},t={};function r(e){var a=t[e];if(void 0!==a)return a.exports;var f=t[e]={id:e,loaded:!1,exports:{}};return c[e].call(f.exports,f,f.exports,r),f.loaded=!0,f.exports}r.m=c,r.c=t,e=[],r.O=(a,f,d,b)=>{if(!f){var c=1/0;for(i=0;i Since beginning of 2023, all modern browsers ship the File System Access API which allows to persistently store data in the browser with a way better performance. For RxDB you can use the OPFS RxStorage to get about 4x performance improvement compared to IndexedDB. It becomes clear that the only way to go is IndexedDB. You start developing your app and everything goes fine.
But as soon as your app gets bigger, more complex or just handles more data, you might notice something. IndexedDB is slow. Not slow like a database on a cheap server, even slower! Inserting a few hundred documents can take up several seconds. Time which can be critical for a fast page load. Even sending data over the internet to the backend can be faster then storing it inside of an IndexedDB database.{if(!e)return;const r=t.location.hash;if(r?document.getElementById(r.substring(1)):void 0)return a.current=!0,void n(!1);n(!0)})),{navbarRef:i,isNavbarVisible:t}}(n);return(0,u.jsxs)("nav",{ref:l,"aria-label":(0,s.T)({id:"theme.NavBar.navAriaLabel",message:"Main",description:"The ARIA label for the main navigation"}),className:(0,a.A)("navbar","navbar--fixed-top",n&&[Oe.navbarHideable,!d&&Oe.navbarHidden],{"navbar--dark":"dark"===o,"navbar--primary":"primary"===o,"navbar-sidebar--show":i.shown}),children:[t,(0,u.jsx)(Ie,{onClick:i.toggle}),(0,u.jsx)(Pe,{})]})}var Me=n(440);const Fe={errorBoundaryError:"errorBoundaryError_a6uf",errorBoundaryFallback:"errorBoundaryFallback_VBag"};function ze(e){return(0,u.jsx)("button",{type:"button",...e,children:(0,u.jsx)(s.A,{id:"theme.ErrorPageContent.tryAgain",description:"The label of the button to try again rendering when the React error boundary captures an error",children:"Try again"})})}function Be(e){let{error:t}=e;const n=(0,Me.getErrorCausalChain)(t).map((e=>e.message)).join("\n\nCause:\n");return(0,u.jsx)("p",{className:Fe.errorBoundaryError,children:n})}class $e extends r.Component{componentDidCatch(e,t){throw this.props.onError(e,t)}render(){return this.props.children}}const Ue="right";function qe(e){let{width:t=30,height:n=30,className:r,...a}=e;return(0,u.jsx)("svg",{className:r,width:t,height:n,viewBox:"0 0 30 30","aria-hidden":"true",...a,children:(0,u.jsx)("path",{stroke:"currentColor",strokeLinecap:"round",strokeMiterlimit:"10",strokeWidth:"2",d:"M4 7h22M4 15h22M4 23h22"})})}function He(){const{toggle:e,shown:t}=(0,j.M)();return(0,u.jsx)("button",{onClick:e,"aria-label":(0,s.T)({id:"theme.docs.sidebar.toggleSidebarButtonAriaLabel",message:"Toggle navigation bar",description:"The ARIA label for hamburger menu button of mobile navigation"}),"aria-expanded":t,className:"navbar__toggle clean-btn",type:"button",children:(0,u.jsx)(qe,{})})}const Ge={colorModeToggle:"colorModeToggle_DEke"};function We(e){let{items:t}=e;return(0,u.jsx)(u.Fragment,{children:t.map(((e,t)=>(0,u.jsx)($e,{onError:t=>new Error(`A theme navbar item failed to render.\nPlease double-check the following navbar item (themeConfig.navbar.items) of your Docusaurus config:\n${JSON.stringify(e,null,2)}`,{cause:t}),children:(0,u.jsx)(je,{...e})},t)))})}function Ve(e){let{left:t,right:n}=e;return(0,u.jsxs)("div",{className:"navbar__inner",children:[(0,u.jsx)("div",{className:"navbar__items",children:t}),(0,u.jsx)("div",{className:"navbar__items navbar__items--right",children:n})]})}function Qe(){const e=(0,j.M)(),t=(0,w.p)().navbar.items,[n,r]=function(e){function t(e){return"left"===(e.position??Ue)}return[e.filter(t),e.filter((e=>!t(e)))]}(t),a=t.find((e=>"search"===e.type));return(0,u.jsx)(Ve,{left:(0,u.jsxs)(u.Fragment,{children:[!e.disabled&&(0,u.jsx)(He,{}),(0,u.jsx)(Q,{}),(0,u.jsx)(We,{items:n})]}),right:(0,u.jsxs)(u.Fragment,{children:[(0,u.jsx)(We,{items:r}),(0,u.jsx)(W,{className:Ge.colorModeToggle}),!a&&(0,u.jsx)(Se,{children:(0,u.jsx)(xe,{})})]})})}function Ke(){return(0,u.jsx)(De,{children:(0,u.jsx)(Qe,{})})}function Ye(e){let{item:t}=e;const{to:n,href:r,label:a,prependBaseUrlToHref:o,...i}=t,l=(0,Z.A)(n),s=(0,Z.A)(r,{forcePrependBaseUrl:!0});return(0,u.jsxs)(J.A,{className:"footer__link-item",...r?{href:o?s:r}:{to:l},...i,children:[a,r&&!(0,X.A)(r)&&(0,u.jsx)(te.A,{})]})}function Je(e){let{item:t}=e;return t.html?(0,u.jsx)("li",{className:"footer__item",dangerouslySetInnerHTML:{__html:t.html}}):(0,u.jsx)("li",{className:"footer__item",children:(0,u.jsx)(Ye,{item:t})},t.href??t.to)}function Ze(e){let{column:t}=e;return(0,u.jsxs)("div",{className:"col footer__col",children:[(0,u.jsx)("div",{className:"footer__title",children:t.title}),(0,u.jsx)("ul",{className:"footer__items clean-list",children:t.items.map(((e,t)=>(0,u.jsx)(Je,{item:e},t)))})]})}function Xe(e){let{columns:t}=e;return(0,u.jsx)("div",{className:"row footer__links",children:t.map(((e,t)=>(0,u.jsx)(Ze,{column:e},t)))})}function et(){return(0,u.jsx)("span",{className:"footer__link-separator",children:"\xb7"})}function tt(e){let{item:t}=e;return t.html?(0,u.jsx)("span",{className:"footer__link-item",dangerouslySetInnerHTML:{__html:t.html}}):(0,u.jsx)(Ye,{item:t})}function nt(e){let{links:t}=e;return(0,u.jsx)("div",{className:"footer__links text--center",children:(0,u.jsx)("div",{className:"footer__links",children:t.map(((e,n)=>(0,u.jsxs)(r.Fragment,{children:[(0,u.jsx)(tt,{item:e}),t.length!==n+1&&(0,u.jsx)(et,{})]},n)))})})}function rt(e){let{links:t}=e;return function(e){return"title"in e[0]}(t)?(0,u.jsx)(Xe,{columns:t}):(0,u.jsx)(nt,{links:t})}var at=n(1122);const ot={footerLogoLink:"footerLogoLink_BH7S"};function it(e){let{logo:t}=e;const{withBaseUrl:n}=(0,Z.h)(),r={light:n(t.src),dark:n(t.srcDark??t.src)};return(0,u.jsx)(at.A,{className:(0,a.A)("footer__logo",t.className),alt:t.alt,sources:r,width:t.width,height:t.height,style:t.style})}function lt(e){let{logo:t}=e;return t.href?(0,u.jsx)(J.A,{href:t.href,className:ot.footerLogoLink,target:t.target,children:(0,u.jsx)(it,{logo:t})}):(0,u.jsx)(it,{logo:t})}function st(e){let{copyright:t}=e;return(0,u.jsx)("div",{className:"footer__copyright",dangerouslySetInnerHTML:{__html:t}})}function ct(e){let{style:t,links:n,logo:r,copyright:o}=e;return(0,u.jsx)("footer",{className:(0,a.A)("footer",{"footer--dark":"dark"===t}),children:(0,u.jsxs)("div",{className:"container container-fluid",children:[n,(r||o)&&(0,u.jsxs)("div",{className:"footer__bottom text--center",children:[r&&(0,u.jsx)("div",{className:"margin-bottom--sm",children:r}),o]})]})})}function ut(){const{footer:e}=(0,w.p)();if(!e)return null;const{copyright:t,links:n,logo:r,style:a}=e;return(0,u.jsx)(ct,{style:a,links:n&&n.length>0&&(0,u.jsx)(rt,{links:n}),logo:r&&(0,u.jsx)(lt,{logo:r}),copyright:t&&(0,u.jsx)(st,{copyright:t})})}const dt=r.memo(ut),pt=(0,R.fM)([F.a,x.oq,N.Tv,Ce.VQ,i.Jx,function(e){let{children:t}=e;return(0,u.jsx)(L.y_,{children:(0,u.jsx)(j.e,{children:(0,u.jsx)(O,{children:t})})})}]);function ft(e){let{children:t}=e;return(0,u.jsx)(pt,{children:t})}var mt=n(1107);function ht(e){let{error:t,tryAgain:n}=e;return(0,u.jsx)("main",{className:"container margin-vert--xl",children:(0,u.jsx)("div",{className:"row",children:(0,u.jsxs)("div",{className:"col col--6 col--offset-3",children:[(0,u.jsx)(mt.A,{as:"h1",className:"hero__title",children:(0,u.jsx)(s.A,{id:"theme.ErrorPageContent.title",description:"The title of the fallback page when the page crashed",children:"This page crashed."})}),(0,u.jsx)("div",{className:"margin-vert--lg",children:(0,u.jsx)(ze,{onClick:n,className:"button button--primary shadow--lw"})}),(0,u.jsx)("hr",{}),(0,u.jsx)("div",{className:"margin-vert--md",children:(0,u.jsx)(Be,{error:t})})]})})})}const gt={mainWrapper:"mainWrapper_z2l0"};function bt(e){const{children:t,noFooter:n,wrapperClassName:r,title:l,description:s}=e;return(0,b.J)(),(0,u.jsxs)(ft,{children:[(0,u.jsx)(i.be,{title:l,description:s}),(0,u.jsx)(v,{}),(0,u.jsx)(A,{}),(0,u.jsx)(Ke,{}),(0,u.jsx)("div",{id:d,className:(0,a.A)(g.G.wrapper.main,gt.mainWrapper,r),children:(0,u.jsx)(o.A,{fallback:e=>(0,u.jsx)(ht,{...e}),children:t})}),!n&&(0,u.jsx)(dt,{})]})}},3465:(e,t,n)=>{"use strict";n.d(t,{A:()=>u});n(6540);var r=n(5489),a=n(6025),o=n(4586),i=n(6342),l=n(1122),s=n(4848);function c(e){let{logo:t,alt:n,imageClassName:r}=e;const o={light:(0,a.A)(t.src),dark:(0,a.A)(t.srcDark||t.src)},i=(0,s.jsx)(l.A,{className:t.className,sources:o,height:t.height,width:t.width,alt:n,style:t.style});return r?(0,s.jsx)("div",{className:r,children:i}):i}function u(e){const{siteConfig:{title:t}}=(0,o.A)(),{navbar:{title:n,logo:l}}=(0,i.p)(),{imageClassName:u,titleClassName:d,...p}=e,f=(0,a.A)(l?.href||"/"),m=n?"":t,h=l?.alt??m;return(0,s.jsxs)(r.A,{to:f,...p,...l?.target&&{target:l.target},children:[l&&(0,s.jsx)(c,{logo:l,alt:h,imageClassName:u}),null!=n&&(0,s.jsx)("b",{className:d,children:n})]})}},1463:(e,t,n)=>{"use strict";n.d(t,{A:()=>o});n(6540);var r=n(5260),a=n(4848);function o(e){let{locale:t,version:n,tag:o}=e;const i=t;return(0,a.jsxs)(r.A,{children:[t&&(0,a.jsx)("meta",{name:"docusaurus_locale",content:t}),n&&(0,a.jsx)("meta",{name:"docusaurus_version",content:n}),o&&(0,a.jsx)("meta",{name:"docusaurus_tag",content:o}),i&&(0,a.jsx)("meta",{name:"docsearch:language",content:i}),n&&(0,a.jsx)("meta",{name:"docsearch:version",content:n}),o&&(0,a.jsx)("meta",{name:"docsearch:docusaurus_tag",content:o})]})}},1122:(e,t,n)=>{"use strict";n.d(t,{A:()=>u});var r=n(6540),a=n(4164),o=n(2303),i=n(5293);const l={themedComponent:"themedComponent_mlkZ","themedComponent--light":"themedComponent--light_NVdE","themedComponent--dark":"themedComponent--dark_xIcU"};var s=n(4848);function c(e){let{className:t,children:n}=e;const c=(0,o.A)(),{colorMode:u}=(0,i.G)();return(0,s.jsx)(s.Fragment,{children:(c?"dark"===u?["dark"]:["light"]:["light","dark"]).map((e=>{const o=n({theme:e,className:(0,a.A)(t,l.themedComponent,l[`themedComponent--${e}`])});return(0,s.jsx)(r.Fragment,{children:o},e)}))})}function u(e){const{sources:t,className:n,alt:r,...a}=e;return(0,s.jsx)(c,{className:n,children:e=>{let{theme:n,className:o}=e;return(0,s.jsx)("img",{src:t[n],alt:r,className:o,...a})}})}},1422:(e,t,n)=>{"use strict";n.d(t,{N:()=>b,u:()=>c});var r=n(6540),a=n(8193),o=n(205),i=n(3109),l=n(4848);const s="ease-in-out";function c(e){let{initialState:t}=e;const[n,a]=(0,r.useState)(t??!1),o=(0,r.useCallback)((()=>{a((e=>!e))}),[]);return{collapsed:n,setCollapsed:a,toggleCollapsed:o}}const u={display:"none",overflow:"hidden",height:"0px"},d={display:"block",overflow:"visible",height:"auto"};function p(e,t){const n=t?u:d;e.style.display=n.display,e.style.overflow=n.overflow,e.style.height=n.height}function f(e){let{collapsibleRef:t,collapsed:n,animation:a}=e;const o=(0,r.useRef)(!1);(0,r.useEffect)((()=>{const e=t.current;function r(){const t=e.scrollHeight,n=a?.duration??function(e){if((0,i.O)())return 1;const t=e/36;return Math.round(10*(4+15*t**.25+t/5))}(t);return{transition:`height ${n}ms ${a?.easing??s}`,height:`${t}px`}}function l(){const t=r();e.style.transition=t.transition,e.style.height=t.height}if(!o.current)return p(e,n),void(o.current=!0);return e.style.willChange="height",function(){const t=requestAnimationFrame((()=>{n?(l(),requestAnimationFrame((()=>{e.style.height=u.height,e.style.overflow=u.overflow}))):(e.style.display="block",requestAnimationFrame((()=>{l()})))}));return()=>cancelAnimationFrame(t)}()}),[t,n,a])}function m(e){if(!a.A.canUseDOM)return e?u:d}function h(e){let{as:t="div",collapsed:n,children:a,animation:o,onCollapseTransitionEnd:i,className:s,disableSSRStyle:c}=e;const u=(0,r.useRef)(null);return f({collapsibleRef:u,collapsed:n,animation:o}),(0,l.jsx)(t,{ref:u,style:c?void 0:m(n),onTransitionEnd:e=>{"height"===e.propertyName&&(p(u.current,n),i?.(n))},className:s,children:a})}function g(e){let{collapsed:t,...n}=e;const[a,i]=(0,r.useState)(!t),[s,c]=(0,r.useState)(t);return(0,o.A)((()=>{t||i(!0)}),[t]),(0,o.A)((()=>{a&&c(t)}),[a,t]),a?(0,l.jsx)(h,{...n,collapsed:s}):null}function b(e){let{lazy:t,...n}=e;const r=t?g:h;return(0,l.jsx)(r,{...n})}},5041:(e,t,n)=>{"use strict";n.d(t,{Mj:()=>h,oq:()=>m});var r=n(6540),a=n(2303),o=n(9466),i=n(9532),l=n(6342),s=n(4848);const c=(0,o.Wf)("docusaurus.announcement.dismiss"),u=(0,o.Wf)("docusaurus.announcement.id"),d=()=>"true"===c.get(),p=e=>c.set(String(e)),f=r.createContext(null);function m(e){let{children:t}=e;const n=function(){const{announcementBar:e}=(0,l.p)(),t=(0,a.A)(),[n,o]=(0,r.useState)((()=>!!t&&d()));(0,r.useEffect)((()=>{o(d())}),[]);const i=(0,r.useCallback)((()=>{p(!0),o(!0)}),[]);return(0,r.useEffect)((()=>{if(!e)return;const{id:t}=e;let n=u.get();"annoucement-bar"===n&&(n="announcement-bar");const r=t!==n;u.set(t),r&&p(!1),!r&&d()||o(!1)}),[e]),(0,r.useMemo)((()=>({isActive:!!e&&!n,close:i})),[e,n,i])}();return(0,s.jsx)(f.Provider,{value:n,children:t})}function h(){const e=(0,r.useContext)(f);if(!e)throw new i.dV("AnnouncementBarProvider");return e}},5293:(e,t,n)=>{"use strict";n.d(t,{G:()=>b,a:()=>g});var r=n(6540),a=n(8193),o=n(9532),i=n(9466),l=n(6342),s=n(4848);const c=r.createContext(void 0),u="theme",d=(0,i.Wf)(u),p={light:"light",dark:"dark"},f=e=>e===p.dark?p.dark:p.light,m=e=>a.A.canUseDOM?f(document.documentElement.getAttribute("data-theme")):f(e),h=e=>{d.set(f(e))};function g(e){let{children:t}=e;const n=function(){const{colorMode:{defaultMode:e,disableSwitch:t,respectPrefersColorScheme:n}}=(0,l.p)(),[a,o]=(0,r.useState)(m(e));(0,r.useEffect)((()=>{t&&d.del()}),[t]);const i=(0,r.useCallback)((function(t,r){void 0===r&&(r={});const{persist:a=!0}=r;t?(o(t),a&&h(t)):(o(n?window.matchMedia("(prefers-color-scheme: dark)").matches?p.dark:p.light:e),d.del())}),[n,e]);(0,r.useEffect)((()=>{document.documentElement.setAttribute("data-theme",f(a))}),[a]),(0,r.useEffect)((()=>{if(t)return;const e=e=>{if(e.key!==u)return;const t=d.get();null!==t&&i(f(t))};return window.addEventListener("storage",e),()=>window.removeEventListener("storage",e)}),[t,i]);const s=(0,r.useRef)(!1);return(0,r.useEffect)((()=>{if(t&&!n)return;const e=window.matchMedia("(prefers-color-scheme: dark)"),r=()=>{window.matchMedia("print").matches||s.current?s.current=window.matchMedia("print").matches:i(null)};return e.addListener(r),()=>e.removeListener(r)}),[i,t,n]),(0,r.useMemo)((()=>({colorMode:a,setColorMode:i,get isDarkTheme(){return a===p.dark},setLightTheme(){i(p.light)},setDarkTheme(){i(p.dark)}})),[a,i])}();return(0,s.jsx)(c.Provider,{value:n,children:t})}function b(){const e=(0,r.useContext)(c);if(null==e)throw new o.dV("ColorModeProvider","Please see https://docusaurus.io/docs/api/themes/configuration#use-color-mode.");return e}},5597:(e,t,n)=>{"use strict";n.d(t,{VQ:()=>b,g1:()=>v});var r=n(6540),a=n(8295),o=n(7065),i=n(6342),l=n(1754),s=n(9532),c=n(9466),u=n(4848);const d=e=>`docs-preferred-version-${e}`,p={save:(e,t,n)=>{(0,c.Wf)(d(e),{persistence:t}).set(n)},read:(e,t)=>(0,c.Wf)(d(e),{persistence:t}).get(),clear:(e,t)=>{(0,c.Wf)(d(e),{persistence:t}).del()}},f=e=>Object.fromEntries(e.map((e=>[e,{preferredVersionName:null}])));const m=r.createContext(null);function h(){const e=(0,a.Gy)(),t=(0,i.p)().docs.versionPersistence,n=(0,r.useMemo)((()=>Object.keys(e)),[e]),[o,l]=(0,r.useState)((()=>f(n)));(0,r.useEffect)((()=>{l(function(e){let{pluginIds:t,versionPersistence:n,allDocsData:r}=e;function a(e){const t=p.read(e,n);return r[e].versions.some((e=>e.name===t))?{preferredVersionName:t}:(p.clear(e,n),{preferredVersionName:null})}return Object.fromEntries(t.map((e=>[e,a(e)])))}({allDocsData:e,versionPersistence:t,pluginIds:n}))}),[e,t,n]);return[o,(0,r.useMemo)((()=>({savePreferredVersion:function(e,n){p.save(e,t,n),l((t=>({...t,[e]:{preferredVersionName:n}})))}})),[t])]}function g(e){let{children:t}=e;const n=h();return(0,u.jsx)(m.Provider,{value:n,children:t})}function b(e){let{children:t}=e;return l.C5?(0,u.jsx)(g,{children:t}):(0,u.jsx)(u.Fragment,{children:t})}function y(){const e=(0,r.useContext)(m);if(!e)throw new s.dV("DocsPreferredVersionContextProvider");return e}function v(e){void 0===e&&(e=o.W);const t=(0,a.ht)(e),[n,i]=y(),{preferredVersionName:l}=n[e];return{preferredVersion:t.versions.find((e=>e.name===l))??null,savePreferredVersionName:(0,r.useCallback)((t=>{i.savePreferredVersion(e,t)}),[i,e])}}},4207:(e,t,n)=>{"use strict";n.d(t,{V:()=>s,t:()=>c});var r=n(6540),a=n(9532),o=n(4848);const i=Symbol("EmptyContext"),l=r.createContext(i);function s(e){let{children:t,name:n,items:a}=e;const i=(0,r.useMemo)((()=>n&&a?{name:n,items:a}:null),[n,a]);return(0,o.jsx)(l.Provider,{value:i,children:t})}function c(){const e=(0,r.useContext)(l);if(e===i)throw new a.dV("DocsSidebarProvider");return e}},2252:(e,t,n)=>{"use strict";n.d(t,{n:()=>l,r:()=>s});var r=n(6540),a=n(9532),o=n(4848);const i=r.createContext(null);function l(e){let{children:t,version:n}=e;return(0,o.jsx)(i.Provider,{value:n,children:t})}function s(){const e=(0,r.useContext)(i);if(null===e)throw new a.dV("DocsVersionProvider");return e}},9876:(e,t,n)=>{"use strict";n.d(t,{e:()=>f,M:()=>m});var r=n(6540),a=n(5600),o=n(4581),i=n(6347),l=n(9532);function s(e){!function(e){const t=(0,i.W6)(),n=(0,l._q)(e);(0,r.useEffect)((()=>t.block(((e,t)=>n(e,t)))),[t,n])}(((t,n)=>{if("POP"===n)return e(t,n)}))}var c=n(6342),u=n(4848);const d=r.createContext(void 0);function p(){const e=function(){const e=(0,a.YL)(),{items:t}=(0,c.p)().navbar;return 0===t.length&&!e.component}(),t=(0,o.l)(),n=!e&&"mobile"===t,[i,l]=(0,r.useState)(!1);s((()=>{if(i)return l(!1),!1}));const u=(0,r.useCallback)((()=>{l((e=>!e))}),[]);return(0,r.useEffect)((()=>{"desktop"===t&&l(!1)}),[t]),(0,r.useMemo)((()=>({disabled:e,shouldRender:n,toggle:u,shown:i})),[e,n,u,i])}function f(e){let{children:t}=e;const n=p();return(0,u.jsx)(d.Provider,{value:n,children:t})}function m(){const e=r.useContext(d);if(void 0===e)throw new l.dV("NavbarMobileSidebarProvider");return e}},5600:(e,t,n)=>{"use strict";n.d(t,{GX:()=>c,YL:()=>s,y_:()=>l});var r=n(6540),a=n(9532),o=n(4848);const i=r.createContext(null);function l(e){let{children:t}=e;const n=(0,r.useState)({component:null,props:null});return(0,o.jsx)(i.Provider,{value:n,children:t})}function s(){const e=(0,r.useContext)(i);if(!e)throw new a.dV("NavbarSecondaryMenuContentProvider");return e[0]}function c(e){let{component:t,props:n}=e;const o=(0,r.useContext)(i);if(!o)throw new a.dV("NavbarSecondaryMenuContentProvider");const[,l]=o,s=(0,a.Be)(n);return(0,r.useEffect)((()=>{l({component:t,props:s})}),[l,t,s]),(0,r.useEffect)((()=>()=>l({component:null,props:null})),[l]),null}},4090:(e,t,n)=>{"use strict";n.d(t,{w:()=>a,J:()=>o});var r=n(6540);const a="navigation-with-keyboard";function o(){(0,r.useEffect)((()=>{function e(e){"keydown"===e.type&&"Tab"===e.key&&document.body.classList.add(a),"mousedown"===e.type&&document.body.classList.remove(a)}return document.addEventListener("keydown",e),document.addEventListener("mousedown",e),()=>{document.body.classList.remove(a),document.removeEventListener("keydown",e),document.removeEventListener("mousedown",e)}}),[])}},4581:(e,t,n)=>{"use strict";n.d(t,{l:()=>l});var r=n(6540),a=n(8193);const o={desktop:"desktop",mobile:"mobile",ssr:"ssr"},i=996;function l(){const[e,t]=(0,r.useState)((()=>"ssr"));return(0,r.useEffect)((()=>{function e(){t(function(){if(!a.A.canUseDOM)throw new Error("getWindowSize() should only be called after React hydration");return window.innerWidth>i?o.desktop:o.mobile}())}return e(),window.addEventListener("resize",e),()=>{window.removeEventListener("resize",e)}}),[]),e}},7559:(e,t,n)=>{"use strict";n.d(t,{G:()=>r});const r={page:{blogListPage:"blog-list-page",blogPostPage:"blog-post-page",blogTagsListPage:"blog-tags-list-page",blogTagPostListPage:"blog-tags-post-list-page",docsDocPage:"docs-doc-page",docsTagsListPage:"docs-tags-list-page",docsTagDocListPage:"docs-tags-doc-list-page",mdxPage:"mdx-page"},wrapper:{main:"main-wrapper",blogPages:"blog-wrapper",docsPages:"docs-wrapper",mdxPages:"mdx-wrapper"},common:{editThisPage:"theme-edit-this-page",lastUpdated:"theme-last-updated",backToTopButton:"theme-back-to-top-button",codeBlock:"theme-code-block",admonition:"theme-admonition",unlistedBanner:"theme-unlisted-banner",admonitionType:e=>`theme-admonition-${e}`},layout:{},docs:{docVersionBanner:"theme-doc-version-banner",docVersionBadge:"theme-doc-version-badge",docBreadcrumbs:"theme-doc-breadcrumbs",docMarkdown:"theme-doc-markdown",docTocMobile:"theme-doc-toc-mobile",docTocDesktop:"theme-doc-toc-desktop",docFooter:"theme-doc-footer",docFooterTagsRow:"theme-doc-footer-tags-row",docFooterEditMetaRow:"theme-doc-footer-edit-meta-row",docSidebarContainer:"theme-doc-sidebar-container",docSidebarMenu:"theme-doc-sidebar-menu",docSidebarItemCategory:"theme-doc-sidebar-item-category",docSidebarItemLink:"theme-doc-sidebar-item-link",docSidebarItemCategoryLevel:e=>`theme-doc-sidebar-item-category-level-${e}`,docSidebarItemLinkLevel:e=>`theme-doc-sidebar-item-link-level-${e}`},blog:{}}},3109:(e,t,n)=>{"use strict";function r(){return window.matchMedia("(prefers-reduced-motion: reduce)").matches}n.d(t,{O:()=>r})},1754:(e,t,n)=>{"use strict";n.d(t,{Nr:()=>f,w8:()=>g,C5:()=>p,B5:()=>E,Vd:()=>x,QB:()=>S,fW:()=>k,OF:()=>w,Y:()=>y});var r=n(6540),a=n(6347),o=n(2831),i=n(8295),l=n(5597),s=n(2252),c=n(4207);function u(e){return Array.from(new Set(e))}var d=n(9169);const p=!!i.Gy;function f(e){return"link"!==e.type||e.unlisted?"category"===e.type?function(e){if(e.href&&!e.linkUnlisted)return e.href;for(const t of e.items){const e=f(t);if(e)return e}}(e):void 0:e.href}const m=(e,t)=>void 0!==e&&(0,d.ys)(e,t),h=(e,t)=>e.some((e=>g(e,t)));function g(e,t){return"link"===e.type?m(e.href,t):"category"===e.type&&(m(e.href,t)||h(e.items,t))}function b(e,t){switch(e.type){case"category":return g(e,t)||e.items.some((e=>b(e,t)));case"link":return!e.unlisted||g(e,t);default:return!0}}function y(e,t){return(0,r.useMemo)((()=>e.filter((e=>b(e,t)))),[e,t])}function v(e){let{sidebarItems:t,pathname:n,onlyCategories:r=!1}=e;const a=[];return function e(t){for(const o of t)if("category"===o.type&&((0,d.ys)(o.href,n)||e(o.items))||"link"===o.type&&(0,d.ys)(o.href,n)){return r&&"category"!==o.type||a.unshift(o),!0}return!1}(t),a}function w(){const e=(0,c.t)(),{pathname:t}=(0,a.zy)(),n=(0,i.vT)()?.pluginData.breadcrumbs;return!1!==n&&e?v({sidebarItems:e.items,pathname:t}):null}function x(e){const{activeVersion:t}=(0,i.zK)(e),{preferredVersion:n}=(0,l.g1)(e),a=(0,i.r7)(e);return(0,r.useMemo)((()=>u([t,n,a].filter(Boolean))),[t,n,a])}function k(e,t){const n=x(t);return(0,r.useMemo)((()=>{const t=n.flatMap((e=>e.sidebars?Object.entries(e.sidebars):[])),r=t.find((t=>t[0]===e));if(!r)throw new Error(`Can't find any sidebar with id "${e}" in version${n.length>1?"s":""} ${n.map((e=>e.name)).join(", ")}".\nAvailable sidebar ids are:\n- ${t.map((e=>e[0])).join("\n- ")}`);return r[1]}),[e,n])}function S(e,t){const n=x(t);return(0,r.useMemo)((()=>{const t=n.flatMap((e=>e.docs)),r=t.find((t=>t.id===e));if(!r){if(n.flatMap((e=>e.draftIds)).includes(e))return null;throw new Error(`Couldn't find any doc with id "${e}" in version${n.length>1?"s":""} "${n.map((e=>e.name)).join(", ")}".\nAvailable doc ids are:\n- ${u(t.map((e=>e.id))).join("\n- ")}`)}return r}),[e,n])}function E(e){let{route:t}=e;const n=(0,a.zy)(),r=(0,s.r)(),i=t.routes,l=i.find((e=>(0,a.B6)(n.pathname,e)));if(!l)return null;const c=l.sidebar,u=c?r.docsSidebars[c]:void 0;return{docElement:(0,o.v)(i),sidebarName:c,sidebarItems:u}}},1003:(e,t,n)=>{"use strict";n.d(t,{e3:()=>f,be:()=>d,Jx:()=>m});var r=n(6540),a=n(4164),o=n(5260),i=n(3102);function l(){const e=r.useContext(i.o);if(!e)throw new Error("Unexpected: no Docusaurus route context found");return e}var s=n(6025),c=n(4586);var u=n(4848);function d(e){let{title:t,description:n,keywords:r,image:a,children:i}=e;const l=function(e){const{siteConfig:t}=(0,c.A)(),{title:n,titleDelimiter:r}=t;return e?.trim().length?`${e.trim()} ${r} ${n}`:n}(t),{withBaseUrl:d}=(0,s.h)(),p=a?d(a,{absolute:!0}):void 0;return(0,u.jsxs)(o.A,{children:[t&&(0,u.jsx)("title",{children:l}),t&&(0,u.jsx)("meta",{property:"og:title",content:l}),n&&(0,u.jsx)("meta",{name:"description",content:n}),n&&(0,u.jsx)("meta",{property:"og:description",content:n}),r&&(0,u.jsx)("meta",{name:"keywords",content:Array.isArray(r)?r.join(","):r}),p&&(0,u.jsx)("meta",{property:"og:image",content:p}),p&&(0,u.jsx)("meta",{name:"twitter:image",content:p}),i]})}const p=r.createContext(void 0);function f(e){let{className:t,children:n}=e;const i=r.useContext(p),l=(0,a.A)(i,t);return(0,u.jsxs)(p.Provider,{value:l,children:[(0,u.jsx)(o.A,{children:(0,u.jsx)("html",{className:l})}),n]})}function m(e){let{children:t}=e;const n=l(),r=`plugin-${n.plugin.name.replace(/docusaurus-(?:plugin|theme)-(?:content-)?/gi,"")}`;const o=`plugin-id-${n.plugin.id}`;return(0,u.jsx)(f,{className:(0,a.A)(r,o),children:t})}},9532:(e,t,n)=>{"use strict";n.d(t,{Be:()=>c,ZC:()=>l,_q:()=>i,dV:()=>s,fM:()=>u});var r=n(6540),a=n(205),o=n(4848);function i(e){const t=(0,r.useRef)(e);return(0,a.A)((()=>{t.current=e}),[e]),(0,r.useCallback)((function(){return t.current(...arguments)}),[])}function l(e){const t=(0,r.useRef)();return(0,a.A)((()=>{t.current=e})),t.current}class s extends Error{constructor(e,t){super(),this.name="ReactContextError",this.message=`Hook ${this.stack?.split("\n")[1]?.match(/at (?:\w+\.)?(?.comment
can become .namespace--comment
) or replace them with your defined ones (like .editor__comment
). You can even add new classes.",owner:"dvkndn",noCSS:!0},"file-highlight":{title:"File Highlight",description:"Fetch external files and highlight them with Prism. Used on the Prism website itself.",noCSS:!0},"show-language":{title:"Show Language",description:"Display the highlighted language in code blocks (inline code does not show the label).",owner:"nauzilus",noCSS:!0,require:"toolbar"},"jsonp-highlight":{title:"JSONP Highlight",description:"Fetch content with JSONP and highlight some interesting content (e.g. GitHub/Gists or Bitbucket API).",noCSS:!0,owner:"nauzilus"},"highlight-keywords":{title:"Highlight Keywords",description:"Adds special CSS classes for each keyword for fine-grained highlighting.",owner:"vkbansal",noCSS:!0},"remove-initial-line-feed":{title:"Remove initial line feed",description:"Removes the initial line feed in code blocks.",owner:"Golmote",noCSS:!0},"inline-color":{title:"Inline color",description:"Adds a small inline preview for colors in style sheets.",require:"css-extras",owner:"RunDevelopment"},previewers:{title:"Previewers",description:"Previewers for angles, colors, gradients, easing and time.",require:"css-extras",owner:"Golmote"},autoloader:{title:"Autoloader",description:"Automatically loads the needed languages to highlight the code blocks.",owner:"Golmote",noCSS:!0},"keep-markup":{title:"Keep Markup",description:"Prevents custom markup from being dropped out during highlighting.",owner:"Golmote",optional:"normalize-whitespace",noCSS:!0},"command-line":{title:"Command Line",description:"Display a command line with a prompt and, optionally, the output/response from the commands.",owner:"chriswells0"},"unescaped-markup":{title:"Unescaped Markup",description:"Write markup without having to escape anything."},"normalize-whitespace":{title:"Normalize Whitespace",description:"Supports multiple operations to normalize whitespace in code blocks.",owner:"zeitgeist87",optional:"unescaped-markup",noCSS:!0},"data-uri-highlight":{title:"Data-URI Highlight",description:"Highlights data-URI contents.",owner:"Golmote",noCSS:!0},toolbar:{title:"Toolbar",description:"Attach a toolbar for plugins to easily register buttons on the top of a code block.",owner:"mAAdhaTTah"},"copy-to-clipboard":{title:"Copy to Clipboard Button",description:"Add a button that copies the code block to the clipboard when clicked.",owner:"mAAdhaTTah",require:"toolbar",noCSS:!0},"download-button":{title:"Download Button",description:"A button in the toolbar of a code block adding a convenient way to download a code file.",owner:"Golmote",require:"toolbar",noCSS:!0},"match-braces":{title:"Match braces",description:"Highlights matching braces.",owner:"RunDevelopment"},"diff-highlight":{title:"Diff Highlight",description:"Highlights the code inside diff blocks.",owner:"RunDevelopment",require:"diff"},"filter-highlight-all":{title:"Filter highlightAll",description:"Filters the elements the highlightAll
and highlightAllUnder
methods actually highlight.",owner:"RunDevelopment",noCSS:!0},treeview:{title:"Treeview",description:"A language with special styles to highlight file system tree structures.",owner:"Golmote"}}})},8722:(e,t,n)=>{const r=n(6969),a=n(8380),o=new Set;function i(e){void 0===e?e=Object.keys(r.languages).filter((e=>"meta"!=e)):Array.isArray(e)||(e=[e]);const t=[...o,...Object.keys(Prism.languages)];a(r,e,t).load((e=>{if(!(e in r.languages))return void(i.silent||console.warn("Language does not exist: "+e));const t="./prism-"+e;delete n.c[n(3157).resolve(t)],delete Prism.languages[e],n(3157)(t),o.add(e)}))}i.silent=!1,e.exports=i},9700:()=>{!function(e){function t(e,t){return"___"+e.toUpperCase()+t+"___"}Object.defineProperties(e.languages["markup-templating"]={},{buildPlaceholders:{value:function(n,r,a,o){if(n.language===r){var i=n.tokenStack=[];n.code=n.code.replace(a,(function(e){if("function"==typeof o&&!o(e))return e;for(var a,l=i.length;-1!==n.code.indexOf(a=t(r,l));)++l;return i[l]=e,a})),n.grammar=e.languages.markup}}},tokenizePlaceholders:{value:function(n,r){if(n.language===r&&n.tokenStack){n.grammar=e.languages[r];var a=0,o=Object.keys(n.tokenStack);!function i(l){for(var s=0;s{"use strict";e.exports=n(5287)},4848:(e,t,n)=>{"use strict";e.exports=n(1020)},7463:(e,t)=>{"use strict";function n(e,t){var n=e.length;e.push(t);e:for(;0|\+|~|\|\|/,punctuation:/[(),]/}},e.languages.css.atrule.inside["selector-function-argument"].inside=t,e.languages.insertBefore("css","property",{variable:{pattern:/(^|[^-\w\xA0-\uFFFF])--(?!\s)[-_a-z\xA0-\uFFFF](?:(?!\s)[-\w\xA0-\uFFFF])*/i,lookbehind:!0}}),{pattern:/(\b\d+)(?:%|[a-z]+(?![\w-]))/,lookbehind:!0}),{pattern:/(^|[^\w.-])-?(?:\d+(?:\.\d+)?|\.\d+)/,lookbehind:!0});e.languages.insertBefore("css","function",{operator:{pattern:/(\s)[+\-*\/](?=\s)/,lookbehind:!0},hexcode:{pattern:/\B#[\da-f]{3,8}\b/i,alias:"color"},color:[{pattern:/(^|[^\w-])(?:AliceBlue|AntiqueWhite|Aqua|Aquamarine|Azure|Beige|Bisque|Black|BlanchedAlmond|Blue|BlueViolet|Brown|BurlyWood|CadetBlue|Chartreuse|Chocolate|Coral|CornflowerBlue|Cornsilk|Crimson|Cyan|DarkBlue|DarkCyan|DarkGoldenRod|DarkGr[ae]y|DarkGreen|DarkKhaki|DarkMagenta|DarkOliveGreen|DarkOrange|DarkOrchid|DarkRed|DarkSalmon|DarkSeaGreen|DarkSlateBlue|DarkSlateGr[ae]y|DarkTurquoise|DarkViolet|DeepPink|DeepSkyBlue|DimGr[ae]y|DodgerBlue|FireBrick|FloralWhite|ForestGreen|Fuchsia|Gainsboro|GhostWhite|Gold|GoldenRod|Gr[ae]y|Green|GreenYellow|HoneyDew|HotPink|IndianRed|Indigo|Ivory|Khaki|Lavender|LavenderBlush|LawnGreen|LemonChiffon|LightBlue|LightCoral|LightCyan|LightGoldenRodYellow|LightGr[ae]y|LightGreen|LightPink|LightSalmon|LightSeaGreen|LightSkyBlue|LightSlateGr[ae]y|LightSteelBlue|LightYellow|Lime|LimeGreen|Linen|Magenta|Maroon|MediumAquaMarine|MediumBlue|MediumOrchid|MediumPurple|MediumSeaGreen|MediumSlateBlue|MediumSpringGreen|MediumTurquoise|MediumVioletRed|MidnightBlue|MintCream|MistyRose|Moccasin|NavajoWhite|Navy|OldLace|Olive|OliveDrab|Orange|OrangeRed|Orchid|PaleGoldenRod|PaleGreen|PaleTurquoise|PaleVioletRed|PapayaWhip|PeachPuff|Peru|Pink|Plum|PowderBlue|Purple|RebeccaPurple|Red|RosyBrown|RoyalBlue|SaddleBrown|Salmon|SandyBrown|SeaGreen|SeaShell|Sienna|Silver|SkyBlue|SlateBlue|SlateGr[ae]y|Snow|SpringGreen|SteelBlue|Tan|Teal|Thistle|Tomato|Transparent|Turquoise|Violet|Wheat|White|WhiteSmoke|Yellow|YellowGreen)(?![\w-])/i,lookbehind:!0},{pattern:/\b(?:hsl|rgb)\(\s*\d{1,3}\s*,\s*\d{1,3}%?\s*,\s*\d{1,3}%?\s*\)\B|\b(?:hsl|rgb)a\(\s*\d{1,3}\s*,\s*\d{1,3}%?\s*,\s*\d{1,3}%?\s*,\s*(?:0|0?\.\d+|1)\s*\)\B/i,inside:{unit:t,number:n,function:/[\w-]+(?=\()/,punctuation:/[(),]/}}],entity:/\\[\da-f]{1,8}/i,unit:t,number:n})}(T),function(e){var t=/[*&][^\s[\]{},]+/,n=/!(?:<[\w\-%#;/?:@&=+$,.!~*'()[\]]+>|(?:[a-zA-Z\d-]*!)?[\w\-%#;/?:@&=+$.~*'()]+)?/,r="(?:"+n.source+"(?:[ \t]+"+t.source+")?|"+t.source+"(?:[ \t]+"+n.source+")?)",a=/(?:[^\s\x00-\x08\x0e-\x1f!"#%&'*,\-:>?@[\]`{|}\x7f-\x84\x86-\x9f\ud800-\udfff\ufffe\uffff]|[?:-]/g,(function(){return n})).replace(/*\/?)?>/.source),e.languages.jsx.tag.inside.tag.pattern=/^<\/?[^\s>\/]*/,e.languages.jsx.tag.inside["attr-value"].pattern=/=(?!\{)(?:"(?:\\[\s\S]|[^\\"])*"|'(?:\\[\s\S]|[^\\'])*'|[^\s'">]+)/,e.languages.jsx.tag.inside.tag.inside["class-name"]=/^[A-Z]\w*(?:\.[A-Z]\w*)*$/,e.languages.jsx.tag.inside.comment=t.comment,e.languages.insertBefore("inside","attr-name",{spread:{pattern:o(/
-UPDATE April 2023: Since beginning of 2023, all modern browsers ship the File System Access API which allows to persistently store data in the browser with a way better performance. For RxDB you can use the OPFS RxStorage to get about 4x performance improvement compared to IndexedDB.
-
+
@@ -122,6 +119,6 @@
Further readSQLITE ON THE WEB: ABSURD-SQL