├── .gitignore ├── .vscode └── settings.json ├── LICENSE.md ├── README.md ├── benchmarks ├── imports.ts └── utils │ ├── mk_cache.ts │ ├── repl.ts │ └── sleep.ts ├── examples ├── indexeddb.ts └── memory.ts └── modules ├── pouchdb ├── mod.ts └── mod_test.ts ├── pouchdb_adapter_idb ├── mod.ts └── mod_test.ts ├── pouchdb_adapter_indexeddb ├── mod.ts └── mod_test.ts ├── pouchdb_adapter_memory ├── mod.ts └── mod_test.ts ├── pouchdb_deno_utils ├── capture_plugin.ts └── capture_plugin_test.ts ├── pouchdb_plugin_find ├── mod.ts └── mod_test.ts ├── pouchdb_plugin_upsert ├── mod.ts └── mod_test.ts └── pouchdb_types ├── debug.d.ts ├── ms.d.ts └── pouchdb.ts /.gitignore: -------------------------------------------------------------------------------- 1 | *.sqlite 2 | .coverage 3 | .cache 4 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "editor.tabSize": 2, 3 | "deno.enable": true, 4 | "deno.codeLens.test": true, 5 | "deno.codeLens.testArgs": [ 6 | "--allow-all" 7 | ], 8 | "deno.lint": true, 9 | "deno.suggest.autoImports": true, 10 | "deno.suggest.imports.autoDiscover": true, 11 | "deno.suggest.paths": true, 12 | "deno.unstable": true, 13 | "deno.suggest.imports.hosts": { 14 | "https://deno.land": true 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Copyright 2022 Aaron Huggins 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of 4 | this software and associated documentation files (the "Software"), to deal in 5 | the Software without restriction, including without limitation the rights to 6 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 7 | the Software, and to permit persons to whom the Software is furnished to do so, 8 | subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 15 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 16 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 17 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 18 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 19 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PouchDB for Deno 2 | 3 | [PouchDB](https://github.com/pouchdb/pouchdb) for Deno, leveraging polyfill for 4 | [IndexedDB based on SQLite](https://github.com/aaronhuggins/indexeddb). 5 | 6 | ## Usage 7 | 8 | ```typescript 9 | import PouchDB from "https://deno.land/x/pouchdb_deno@2.1.0-PouchDB+7.3.0/modules/pouchdb/mod.ts"; 10 | 11 | // Use the 'idb' adapter for IndexedDB and persistence to disk. 12 | const db = new PouchDB("mydb", { adapter: "idb" }); 13 | const doc = { hello: "world" }; 14 | const result = await db.post(doc); 15 | 16 | console.log(result); 17 | 18 | const getDoc = await db.get(result.id); 19 | 20 | console.log(getDoc); 21 | 22 | const docs = await db.allDocs(); 23 | 24 | console.log(docs); 25 | ``` 26 | 27 | ## Features 28 | 29 | All working plugins are included in the main export of PouchDB for Deno. 30 | 31 | **Out-of-the-box:** 32 | 33 | - PouchDB-core imports into Deno without issue 34 | - HTTP/S instances appear to work using PouchDB-Server using the http plugin 35 | - PouchDB-Find plugin 36 | - PouchDB-MapReduce plugin 37 | - Replication 38 | 39 | **With work-arounds:** 40 | 41 | - PouchDB-Adapter-IDB 42 | - PouchDB-Adapter-IndexedDB 43 | - PouchDB-Adapter-Memory 44 | 45 | **Original:** 46 | 47 | - PouchDB-Upsert plugin 48 | 49 | ## Documentation 50 | 51 | Nearly all documentation at [PouchDB.com](https://pouchdb.com/) applies to this 52 | library. Known differences are called out below. 53 | 54 | > **WARNING**: The new `indexeddb` adapter is in a beta state. Use with caution. 55 | > Additionally, this new adapter has an underling IndexedDB schema which is 56 | > incompatible with the older `idb` adapter. If switching adapters and data is 57 | > needed, it will need to be migrated manually at this time. It is unknown if 58 | > automatic migration from `idb` to `indexeddb` adapter will be supported in a 59 | > future release. 60 | 61 | ### Adapters 62 | 63 | Currently, the only adapters known to work in Deno are bootstrapped in this 64 | repository. However, new adapters written from scratch targeting Deno _should_ 65 | work out-of-the-box when calling `PouchDB.plugin`. If new adapters written for 66 | Deno do not work, file issues and make sure to cross-link them in this repo and 67 | at [PouchDB's repo](https://github.com/pouchdb/pouchdb/issues). 68 | 69 | ### IndexedDB 70 | 71 | All options work as documented by PouchDB, with two subtle differences and a new 72 | option just for Deno. This applies to both `adapter: "idb"` and 73 | `adapter: "indexeddb"`. 74 | 75 | - Database names are not prefixed with `_pouch_` in Deno like they are on web 76 | - `prefix`: Takes a string argument, and can be used exactly like the LevelDB 77 | adapter to provide a directory for the database(s); **trailing slash is 78 | required** 79 | - `systemPath` (Deno-specific flag): The IndexedDB implementation (see below) 80 | uses a "system" database `__sysdb__` for metadata about databases; supply a 81 | path to store this database in a custom directory 82 | 83 | Since Deno does not ship with an official IndexedDB interface, it must be 84 | polyfilled for the related PouchDB adapter to work. 85 | [IndexedDBShim](https://github.com/indexeddbshim/IndexedDBShim) makes this 86 | possible, on top of a WebSQL ponyfill written specifically for this codebase. 87 | 88 | Should Deno ever 89 | [implement this feature natively](https://github.com/denoland/deno/issues/1699), 90 | the polyfill will be dropped to improve performance. 91 | 92 | ### LevelDOWN 93 | 94 | The only PouchDB adapter based on LevelDOWN known to work is the memory adapter. 95 | Local storage leveldown was tested and found to be incompatible. Other adapters 96 | threw errors from Skypack.dev CDN import; the message reported was related to an 97 | out-of-date version of the `readable-stream` NPM module. 98 | 99 | ### Types 100 | 101 | Augmentation was extremely difficult to perform by directly referencing PouchDB 102 | types from the DefinitelyTyped project. Instead, the relevant types were copied 103 | from DefinitelyTyped and merged by hand. 104 | 105 | ## Why? 106 | 107 | [I did this because I love PouchDB, thought I could get PouchDB working, and I was impatient.](https://github.com/pouchdb/pouchdb/issues/8158) 108 | 109 | ![Thanos picks up Infinity Gauntlet; says "Fine, I'll do it myself."](https://thumbs.gfycat.com/BogusForsakenAsianlion-size_restricted.gif) 110 | -------------------------------------------------------------------------------- /benchmarks/imports.ts: -------------------------------------------------------------------------------- 1 | // Run with `deno run --allow-read --allow-write --allow-run benchmarks/imports.ts` 2 | import { REPL } from "./utils/repl.ts"; 3 | import { mkCache } from "./utils/mk_cache.ts"; 4 | 5 | const REAL_TEMP_CACHE = await mkCache(); 6 | const repl = new REPL({ DENO_DIR: REAL_TEMP_CACHE }); 7 | 8 | performance.mark("imports_start"); 9 | repl.send( 10 | 'await import("https://deno.land/x/pouchdb_deno@v1.0.0-PouchDB+7.2.2/modules/pouchdb/mod.ts")', 11 | ); 12 | await repl.close(); 13 | performance.mark("imports_end"); 14 | performance.measure("imports", "imports_start", "imports_end"); 15 | 16 | const [measure] = performance.getEntriesByName("imports"); 17 | 18 | await Deno.remove(REAL_TEMP_CACHE, { recursive: true }); 19 | 20 | console.log( 21 | "Duration of imports in seconds:", 22 | (measure.duration / 1000).toFixed(3), 23 | ); 24 | console.log("Duration of imports in milliseconds:", measure.duration); 25 | -------------------------------------------------------------------------------- /benchmarks/utils/mk_cache.ts: -------------------------------------------------------------------------------- 1 | export const TEMP_DENO_CACHE = "./.cache"; 2 | 3 | export async function mkCache() { 4 | try { 5 | await Deno.mkdir(TEMP_DENO_CACHE, { recursive: true }); 6 | } catch (_err) { /* Just ensure the dir exists. */ } 7 | 8 | return await Deno.realPath(TEMP_DENO_CACHE); 9 | } 10 | -------------------------------------------------------------------------------- /benchmarks/utils/repl.ts: -------------------------------------------------------------------------------- 1 | import { copyN, StringReader } from "https://deno.land/std@0.100.0/io/mod.ts"; 2 | import { sleep } from "./sleep.ts"; 3 | 4 | export class REPL { 5 | #process: Deno.Process<{ 6 | cmd: string[]; 7 | stdin: "piped"; 8 | }>; 9 | 10 | constructor(env?: Record) { 11 | this.#process = Deno.run({ 12 | cmd: ["deno", "--quiet"], 13 | stdin: "piped", 14 | env: env, 15 | }); 16 | sleep(500); 17 | } 18 | 19 | send(code: string) { 20 | const reader = new StringReader(code + "\n"); 21 | copyN(reader, this.#process.stdin, reader.length); 22 | } 23 | 24 | async close() { 25 | this.send("close()"); 26 | return await this.#process.status(); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /benchmarks/utils/sleep.ts: -------------------------------------------------------------------------------- 1 | const nil = new Int32Array(new SharedArrayBuffer(4)); 2 | 3 | export function sleep(ms: number | bigint) { 4 | if (typeof ms !== "number" && typeof ms !== "bigint") { 5 | throw TypeError("sleep: ms must be a number or bigint"); 6 | } 7 | 8 | if (!(ms > 0 && ms < Infinity)) { 9 | throw RangeError( 10 | "sleep: ms must be a number that is greater than 0 but less than Infinity", 11 | ); 12 | } 13 | 14 | Atomics.wait(nil, 0, 0, Number(ms)); 15 | } 16 | -------------------------------------------------------------------------------- /examples/indexeddb.ts: -------------------------------------------------------------------------------- 1 | import PouchDB from "../modules/pouchdb/mod.ts"; 2 | 3 | const db = new PouchDB("mydb", { 4 | adapter: "indexeddb", 5 | prefix: "./user_db/", 6 | systemPath: "./system_db/", 7 | }); 8 | const doc = { hello: "world" }; 9 | const result = await db.post(doc); 10 | 11 | console.log(result); 12 | 13 | const getDoc = await db.get(result.id); 14 | 15 | console.log(getDoc); 16 | 17 | const docs = await db.allDocs(); 18 | 19 | console.log(docs); 20 | -------------------------------------------------------------------------------- /examples/memory.ts: -------------------------------------------------------------------------------- 1 | import PouchDB from "../modules/pouchdb/mod.ts"; 2 | 3 | const db = new PouchDB("mydb", { adapter: "memory" }); 4 | const doc = { hello: "world" }; 5 | const result = await db.post(doc); 6 | 7 | console.log(result); 8 | 9 | const getDoc = await db.get(result.id); 10 | 11 | console.log(getDoc); 12 | 13 | const docs = await db.allDocs(); 14 | 15 | console.log(docs); 16 | -------------------------------------------------------------------------------- /modules/pouchdb/mod.ts: -------------------------------------------------------------------------------- 1 | import PouchDBImpl from "https://cdn.skypack.dev/pin/pouchdb-core@v7.3.0-89HuCNEcWBT7jv1msAf2/mode=imports/optimized/pouchdb-core.js"; 2 | import HttpPouch from "https://cdn.skypack.dev/pin/pouchdb-adapter-http@v7.3.0-wNzBHi1B5WLNzMPlTnWb/mode=imports/optimized/pouchdb-adapter-http.js"; 3 | import mapreduce from "https://cdn.skypack.dev/pin/pouchdb-mapreduce@v7.3.0-IEG2Gq1jfS0hW8QXVXqd/mode=imports/optimized/pouchdb-mapreduce.js"; 4 | import replication from "https://cdn.skypack.dev/pin/pouchdb-replication@v7.3.0-1sg1NWcwDf6gKFeXsMmq/mode=imports/optimized/pouchdb-replication.js"; 5 | import IDBPouch from "../pouchdb_adapter_idb/mod.ts"; 6 | import MemoryPouch from "../pouchdb_adapter_memory/mod.ts"; 7 | import IndexedDBPouch from "../pouchdb_adapter_indexeddb/mod.ts"; 8 | import find from "../pouchdb_plugin_find/mod.ts"; 9 | import upsert from "../pouchdb_plugin_upsert/mod.ts"; 10 | import type { PouchDB } from "../pouchdb_types/pouchdb.ts"; 11 | 12 | // deno-lint-ignore no-explicit-any 13 | const PouchDBDeno: PouchDB.Static = PouchDBImpl as any; 14 | 15 | PouchDBDeno.plugin(IDBPouch) 16 | .plugin(HttpPouch) 17 | .plugin(MemoryPouch) 18 | .plugin(IndexedDBPouch) 19 | .plugin(find) 20 | .plugin(upsert) 21 | .plugin(mapreduce) 22 | .plugin(replication); 23 | 24 | export default PouchDBDeno; 25 | export type { PouchDB }; 26 | -------------------------------------------------------------------------------- /modules/pouchdb/mod_test.ts: -------------------------------------------------------------------------------- 1 | import { assertEquals } from "https://deno.land/std@0.136.0/testing/asserts.ts"; 2 | import PouchDB from "./mod.ts"; 3 | 4 | const indexedDBAdapters: ["idb", "indexeddb"] = ["idb", "indexeddb"]; 5 | const sysFilepath = "./system_db/__sysdb__.sqlite"; 6 | const filepath = "./user_db/foobar.sqlite"; 7 | 8 | Deno.test("PouchDB", async ({ step }) => { 9 | await step("is a function", () => { 10 | assertEquals(typeof PouchDB, "function"); 11 | }); 12 | 13 | for (const adapter of indexedDBAdapters) { 14 | await step(`adapter ${adapter} writes to file`, async () => { 15 | const Factory = PouchDB.defaults({ 16 | // deno-lint-ignore no-explicit-any 17 | adapter: adapter as any, 18 | prefix: "./user_db/", 19 | systemPath: "./system_db/", 20 | }); 21 | const db = new Factory("foobar"); 22 | const result = await db.post({ hello: "world" }); 23 | const actual = await db.get(result.id); 24 | 25 | assertEquals(result.ok, true); 26 | assertEquals(actual._id, result.id); 27 | 28 | // The two database backends are incompatible due to scema and indices. Destroy them. 29 | await db.destroy(); 30 | // Call this during tests to clean up any hanging file resources before test finishes. Not for production use. 31 | dispatchEvent(new Event("unload")); 32 | 33 | const stat = Deno.statSync(filepath); 34 | const stat2 = Deno.statSync(sysFilepath); 35 | 36 | assertEquals(stat.isFile, true); 37 | assertEquals(stat2.isFile, true); 38 | }); 39 | } 40 | 41 | Deno.removeSync(filepath); 42 | Deno.removeSync(sysFilepath); 43 | }); 44 | -------------------------------------------------------------------------------- /modules/pouchdb_adapter_idb/mod.ts: -------------------------------------------------------------------------------- 1 | // deno-lint-ignore-file no-explicit-any 2 | import "https://deno.land/x/indexeddb@1.3.4/polyfill.ts"; 3 | import { createIndexedDB } from "https://deno.land/x/indexeddb@1.3.4/lib/shim.ts"; 4 | import IDBPouchImpl from "https://cdn.skypack.dev/pin/pouchdb-adapter-idb@v7.3.0-zIdGq675NuTdgkAjGFSh/mode=imports/optimized/pouchdb-adapter-idb.js"; 5 | import type { PouchDB } from "../pouchdb_types/pouchdb.ts"; 6 | 7 | type IDBSignature = ((opts: any, cb: any) => void) & { 8 | valid: () => boolean; 9 | use_prefix: boolean; 10 | }; 11 | 12 | const IDBPouchDeno: (pouchDb: PouchDB.Static) => void = IDBPouchImpl; 13 | let hasIndexedDB = false; 14 | 15 | function IDBDenoWrapper(pouchDb: PouchDB.Static): void { 16 | IDBPouchDeno(pouchDb); 17 | 18 | const adapterIdb: IDBSignature = (pouchDb as any).adapters.idb; 19 | const validIdb = adapterIdb.valid; 20 | 21 | adapterIdb.use_prefix = false; 22 | 23 | function idb( 24 | this: any, 25 | opts: PouchDB.IdbAdapter.IdbAdapterConfiguration, 26 | callback: any, 27 | ) { 28 | if (!hasIndexedDB) { 29 | // Check for system path 30 | if (opts && typeof opts.systemPath === "string") { 31 | createIndexedDB(true, false, opts.systemPath); 32 | } else { 33 | createIndexedDB(true, false); 34 | } 35 | hasIndexedDB = true; 36 | } 37 | adapterIdb.call(this, opts, callback); 38 | } 39 | 40 | idb.valid = validIdb; 41 | idb.use_prefix = adapterIdb.use_prefix; 42 | (pouchDb as any).adapters.idb = idb; 43 | } 44 | 45 | export default IDBDenoWrapper; 46 | -------------------------------------------------------------------------------- /modules/pouchdb_adapter_idb/mod_test.ts: -------------------------------------------------------------------------------- 1 | import { assertEquals } from "https://deno.land/std@0.136.0/testing/asserts.ts"; 2 | import IDBPouch from "./mod.ts"; 3 | 4 | Deno.test("IDBPouch", () => { 5 | assertEquals(typeof IDBPouch, "function"); 6 | }); 7 | -------------------------------------------------------------------------------- /modules/pouchdb_adapter_indexeddb/mod.ts: -------------------------------------------------------------------------------- 1 | // deno-lint-ignore-file no-explicit-any 2 | import "https://deno.land/x/indexeddb@1.3.4/polyfill.ts"; 3 | import { createIndexedDB } from "https://deno.land/x/indexeddb@1.3.4/lib/shim.ts"; 4 | import { capturePlugin } from "../pouchdb_deno_utils/capture_plugin.ts"; 5 | import "https://cdn.skypack.dev/pin/pouchdb@v7.3.0-bcA2ZAvx5a5vy7YRYZRz/mode=imports/unoptimized/dist/pouchdb.indexeddb.js"; 6 | import type { PouchDB } from "../pouchdb_types/pouchdb.ts"; 7 | 8 | type IndexedDBSignature = ((opts: any, cb: any) => void) & { 9 | valid: () => boolean; 10 | use_prefix: boolean; 11 | }; 12 | 13 | // Because we're using the vanilla browser export, the IndexedDB plugin expects 14 | // a PouchDB global. Function capturePlugin fakes the global and capture the 15 | // passed plugin for use later with real PouchDB for Deno. 16 | const IndexedDBPouchDeno: (pouchDb: PouchDB.Static) => void = capturePlugin( 17 | "IndexeddbPouchPlugin", 18 | ); 19 | let hasIndexedDB = false; 20 | 21 | function IndexedDBDenoWrapper(pouchDb: PouchDB.Static): void { 22 | IndexedDBPouchDeno(pouchDb); 23 | 24 | const adapterIndexedDB: IndexedDBSignature = 25 | (pouchDb as any).adapters.indexeddb; 26 | const validIndexedDB = adapterIndexedDB.valid; 27 | 28 | adapterIndexedDB.use_prefix = false; 29 | 30 | function indexeddb( 31 | this: any, 32 | opts: PouchDB.IdbAdapter.IdbAdapterConfiguration, 33 | callback: any, 34 | ) { 35 | if (!hasIndexedDB) { 36 | // Check for system path 37 | if (opts && typeof opts.systemPath === "string") { 38 | createIndexedDB(true, false, opts.systemPath); 39 | } else { 40 | createIndexedDB(true, false); 41 | } 42 | hasIndexedDB = true; 43 | } 44 | adapterIndexedDB.call(this, opts, callback); 45 | } 46 | 47 | indexeddb.valid = validIndexedDB; 48 | indexeddb.use_prefix = adapterIndexedDB.use_prefix; 49 | (pouchDb as any).adapters.indexeddb = indexeddb; 50 | } 51 | 52 | export default IndexedDBDenoWrapper; 53 | -------------------------------------------------------------------------------- /modules/pouchdb_adapter_indexeddb/mod_test.ts: -------------------------------------------------------------------------------- 1 | import { assertEquals } from "https://deno.land/std@0.136.0/testing/asserts.ts"; 2 | import IndexedDBPouch from "./mod.ts"; 3 | 4 | Deno.test("IndexedDBPouch", () => { 5 | assertEquals(typeof IndexedDBPouch, "function"); 6 | }); 7 | -------------------------------------------------------------------------------- /modules/pouchdb_adapter_memory/mod.ts: -------------------------------------------------------------------------------- 1 | import { capturePlugin } from "../pouchdb_deno_utils/capture_plugin.ts"; 2 | import "https://cdn.skypack.dev/pin/pouchdb@v7.3.0-bcA2ZAvx5a5vy7YRYZRz/mode=imports/unoptimized/dist/pouchdb.memory.js"; 3 | import type { PouchDB } from "../pouchdb_types/pouchdb.ts"; 4 | 5 | // Because we're using the vanilla browser export, the Memory plugin expects 6 | // a PouchDB global. Function capturePlugin fakes the global and capture the 7 | // passed plugin for use later with real PouchDB for Deno. 8 | const MemoryPouchDeno: (pouchDb: PouchDB.Static) => void = capturePlugin( 9 | "MemoryPouchPlugin", 10 | ); 11 | 12 | export default MemoryPouchDeno; 13 | -------------------------------------------------------------------------------- /modules/pouchdb_adapter_memory/mod_test.ts: -------------------------------------------------------------------------------- 1 | import { assertEquals } from "https://deno.land/std@0.136.0/testing/asserts.ts"; 2 | import MemoryPouch from "./mod.ts"; 3 | 4 | Deno.test("MemoryPouch", () => { 5 | assertEquals(typeof MemoryPouch, "function"); 6 | }); 7 | -------------------------------------------------------------------------------- /modules/pouchdb_deno_utils/capture_plugin.ts: -------------------------------------------------------------------------------- 1 | // deno-lint-ignore-file no-explicit-any 2 | type PluginSignature = 3 | | [string] 4 | | [string, string] 5 | | [string, string, string] 6 | | [string, string, string, string]; 7 | type FakePouchDBPluginSink = (passedPlugin: any) => void; 8 | 9 | interface FakePouchDB { 10 | __iAmSoFake__: boolean; 11 | plugin: FakePouchDBPluginSink; 12 | } 13 | 14 | const globalAnyRef: { PouchDB: FakePouchDB } = (globalThis as any); 15 | const pluginRefs: Record = {}; 16 | const fakePouchDB: FakePouchDB = { 17 | __iAmSoFake__: true, 18 | plugin(passedPlugin: any): void { 19 | if (typeof passedPlugin === "function") { 20 | pluginRefs[passedPlugin.name] = passedPlugin; 21 | } else if (typeof passedPlugin === "object" && passedPlugin !== null) { 22 | const props = []; 23 | const keys = Object.keys(passedPlugin); 24 | for (let i = 0; i < 4; i++) { 25 | const prop = keys[i]; 26 | if (Object.prototype.hasOwnProperty.call(passedPlugin, prop)) { 27 | props.push(prop); 28 | } 29 | } 30 | const signature = props.join("|"); 31 | pluginRefs[signature] = passedPlugin; 32 | } 33 | }, 34 | }; 35 | const pouchDBType = typeof globalAnyRef.PouchDB; 36 | 37 | if ( 38 | pouchDBType !== "object" || 39 | (pouchDBType === "object" && !globalAnyRef.PouchDB.__iAmSoFake__) 40 | ) { 41 | globalAnyRef.PouchDB = fakePouchDB; 42 | } 43 | 44 | /** Factory for accessing captured plugins from the global scope with a fake PouchDB global. 45 | * @param signature - The runtime function name of the plugin, or an array of up to four object key names. 46 | */ 47 | export function capturePlugin(captureName: string | PluginSignature): any { 48 | if (Array.isArray(captureName)) { 49 | const signature = captureName.join("|"); 50 | 51 | return pluginRefs[signature]; 52 | } 53 | 54 | return pluginRefs[captureName]; 55 | } 56 | -------------------------------------------------------------------------------- /modules/pouchdb_deno_utils/capture_plugin_test.ts: -------------------------------------------------------------------------------- 1 | import { assertEquals } from "https://deno.land/std@0.136.0/testing/asserts.ts"; 2 | 3 | Deno.test("capturePlugin", async ({ step }) => { 4 | // deno-lint-ignore no-explicit-any 5 | const globalAnyRef: any = (globalThis as any); 6 | const fakePouch = function fakePouch() {}; 7 | const { name } = fakePouch; 8 | 9 | await step("should place fake PouchDB in global", async () => { 10 | globalAnyRef.PouchDB = {}; 11 | await import("./capture_plugin.ts"); 12 | assertEquals(typeof globalAnyRef.PouchDB, "object"); 13 | }); 14 | 15 | await step("plugin sink should cache plugin", async () => { 16 | const { capturePlugin } = await import("./capture_plugin.ts"); 17 | globalAnyRef.PouchDB.plugin(fakePouch); 18 | 19 | assertEquals(capturePlugin(name), fakePouch); 20 | }); 21 | }); 22 | -------------------------------------------------------------------------------- /modules/pouchdb_plugin_find/mod.ts: -------------------------------------------------------------------------------- 1 | import { capturePlugin } from "../pouchdb_deno_utils/capture_plugin.ts"; 2 | import "https://cdn.skypack.dev/pin/pouchdb@v7.3.0-bcA2ZAvx5a5vy7YRYZRz/mode=imports/unoptimized/dist/pouchdb.find.js"; 3 | import type { PouchDB } from "../pouchdb_types/pouchdb.ts"; 4 | 5 | // Because we're using the vanilla browser export, the Memory plugin expects 6 | // a PouchDB global. Function capturePlugin fakes the global and capture the 7 | // passed plugin for use later with real PouchDB for Deno. 8 | const FindPluginDeno: PouchDB.Plugin = capturePlugin([ 9 | "createIndex", 10 | "find", 11 | "explain", 12 | "getIndexes", 13 | ]); 14 | 15 | export default FindPluginDeno; 16 | -------------------------------------------------------------------------------- /modules/pouchdb_plugin_find/mod_test.ts: -------------------------------------------------------------------------------- 1 | import { assertEquals } from "https://deno.land/std@0.136.0/testing/asserts.ts"; 2 | import FindPlugin from "./mod.ts"; 3 | 4 | Deno.test("FindPlugin", () => { 5 | assertEquals(typeof FindPlugin, "object"); 6 | }); 7 | -------------------------------------------------------------------------------- /modules/pouchdb_plugin_upsert/mod.ts: -------------------------------------------------------------------------------- 1 | // deno-lint-ignore-file ban-types no-explicit-any 2 | import type { PouchDB } from "../pouchdb_types/pouchdb.ts"; 3 | 4 | type Document = PouchDB.Core.Document<{} & Model> & PouchDB.Core.GetMeta; 5 | type DiffFunc = (doc: Document) => (Document | false); 6 | type PouchDBCallback = PouchDB.Core.Callback; 7 | type PouchDBUpsertResponse = PouchDB.Core.Response & { 8 | updated: boolean; 9 | }; 10 | 11 | function upsertDocument( 12 | db: PouchDB.Database, 13 | docId: string, 14 | diffFunc: DiffFunc, 15 | ): Promise { 16 | if (typeof docId !== "string") { 17 | return Promise.reject(new Error("doc id is required")); 18 | } 19 | 20 | return db.get(docId).catch((error: any) => { 21 | if (error?.status !== 404) throw error; 22 | return {} as Document; 23 | }).then((doc) => { 24 | const docRevision = doc._rev; 25 | const newDocument = diffFunc(doc as Document); 26 | 27 | if (!newDocument) { 28 | return { 29 | updated: false, 30 | rev: docRevision, 31 | id: docId, 32 | ok: true, 33 | }; 34 | } 35 | 36 | newDocument._id = docId; 37 | newDocument._rev = docRevision; 38 | 39 | return tryPutDocument(db, newDocument, diffFunc); 40 | }); 41 | } 42 | 43 | function tryPutDocument( 44 | db: PouchDB.Database, 45 | doc: Document, 46 | diffFunc: DiffFunc, 47 | ): Promise { 48 | return db.put(doc).then( 49 | (response) => ({ 50 | updated: true, 51 | rev: response.rev, 52 | id: doc._id, 53 | ok: response.ok, 54 | }), 55 | (error) => { 56 | if (error?.status !== 409) throw error; 57 | 58 | return upsertDocument(db, doc._id, diffFunc); 59 | }, 60 | ); 61 | } 62 | 63 | /** Perform an upsert of a document using a difference function to provide the upsert algorithm. */ 64 | function upsert( 65 | this: PouchDB.Database, 66 | docId: string, 67 | diffFunc: DiffFunc, 68 | ): Promise; 69 | function upsert( 70 | this: PouchDB.Database, 71 | docId: string, 72 | diffFunc: DiffFunc, 73 | cb: PouchDBCallback, 74 | ): void; 75 | function upsert( 76 | this: PouchDB.Database, 77 | docId: string, 78 | diffFunc: DiffFunc, 79 | cb?: PouchDBCallback, 80 | ): Promise | void { 81 | const promise = upsertDocument(this, docId, diffFunc); 82 | if (typeof cb !== "function") return promise; 83 | promise.then((response): any => cb(null, response), cb as any); 84 | } 85 | 86 | /** Perform an upsert of a document using a shallow merge algorithm. Use `db.upsert` for more complex operations. */ 87 | function upsertAndMerge( 88 | this: PouchDB.Database, 89 | doc: Document, 90 | ): Promise; 91 | function upsertAndMerge( 92 | this: PouchDB.Database, 93 | doc: Document, 94 | cb: PouchDBCallback, 95 | ): void; 96 | function upsertAndMerge( 97 | this: PouchDB.Database, 98 | doc: Document, 99 | cb?: PouchDBCallback, 100 | ): Promise | void { 101 | const promise = upsertDocument(this, doc._id, (existing) => ({ 102 | ...existing, 103 | ...doc, 104 | })); 105 | if (typeof cb !== "function") return promise; 106 | promise.then((response): any => cb(null, response), cb as any); 107 | } 108 | 109 | /** Perform an upsert of a document with a simple replace if exists. Use `db.upsert` for more complex operations. */ 110 | function upsertAndReplace( 111 | this: PouchDB.Database, 112 | doc: Document, 113 | ): Promise; 114 | function upsertAndReplace( 115 | this: PouchDB.Database, 116 | doc: Document, 117 | cb: PouchDBCallback, 118 | ): void; 119 | function upsertAndReplace( 120 | this: PouchDB.Database, 121 | doc: Document, 122 | cb?: PouchDBCallback, 123 | ): Promise | void { 124 | const promise = upsertDocument(this, doc._id, () => doc); 125 | if (typeof cb !== "function") return promise; 126 | promise.then((response): any => cb(null, response), cb as any); 127 | } 128 | 129 | /** Perform a put of a document only if the document does not already exist. */ 130 | function putIfNotExists( 131 | this: PouchDB.Database, 132 | doc: Document, 133 | ): Promise; 134 | function putIfNotExists( 135 | this: PouchDB.Database, 136 | doc: Document, 137 | cb: PouchDBCallback, 138 | ): void; 139 | function putIfNotExists( 140 | this: PouchDB.Database, 141 | docId: string, 142 | doc: Document, 143 | ): Promise; 144 | function putIfNotExists( 145 | this: PouchDB.Database, 146 | docId: string, 147 | doc: Document, 148 | cb: PouchDBCallback, 149 | ): void; 150 | function putIfNotExists( 151 | this: PouchDB.Database, 152 | docId: string | Document, 153 | doc?: Document | PouchDBCallback, 154 | cb?: PouchDBCallback, 155 | ): Promise | void { 156 | if (typeof docId !== "string") { 157 | cb = doc as any; 158 | doc = docId; 159 | docId = doc._id; 160 | } 161 | 162 | const diffFunc = (existing: Document) => { 163 | if (existing._rev) return false; 164 | return doc as any; 165 | }; 166 | const promise = upsertDocument(this, docId, diffFunc); 167 | if (typeof cb !== "function") return promise; 168 | promise.then( 169 | (response): any => (cb as PouchDBCallback)(null, response), 170 | cb as any, 171 | ); 172 | } 173 | 174 | const UpsertPlugin = { 175 | upsert, 176 | upsertAndMerge, 177 | upsertAndReplace, 178 | putIfNotExists, 179 | }; 180 | 181 | export default UpsertPlugin; 182 | -------------------------------------------------------------------------------- /modules/pouchdb_plugin_upsert/mod_test.ts: -------------------------------------------------------------------------------- 1 | import { assertEquals } from "https://deno.land/std@0.136.0/testing/asserts.ts"; 2 | import type { PouchDB as IPouchDB } from "../pouchdb/mod.ts"; 3 | import PouchDB from "../pouchdb/mod.ts"; 4 | import UpsertPlugin from "./mod.ts"; 5 | 6 | Deno.test("UpsertPlugin", async ({ step }) => { 7 | let db: IPouchDB.Database | undefined; 8 | 9 | await step("plugin is an object", () => { 10 | assertEquals(typeof UpsertPlugin, "object"); 11 | assertEquals(typeof UpsertPlugin.putIfNotExists, "function"); 12 | assertEquals(typeof UpsertPlugin.upsert, "function"); 13 | assertEquals(typeof UpsertPlugin.upsertAndMerge, "function"); 14 | assertEquals(typeof UpsertPlugin.upsertAndReplace, "function"); 15 | }); 16 | 17 | await step("plugin adds methods to PouchDB", () => { 18 | PouchDB.plugin(UpsertPlugin); 19 | db = new PouchDB("upsertdb", { adapter: "memory" }); 20 | 21 | assertEquals(typeof db.putIfNotExists, "function"); 22 | assertEquals(typeof db.upsert, "function"); 23 | assertEquals(typeof db.upsertAndMerge, "function"); 24 | assertEquals(typeof db.upsertAndReplace, "function"); 25 | }); 26 | 27 | await step("plugin methods modify database", async () => { 28 | const original = { 29 | _id: "mydoc", 30 | counter: 1, 31 | }; 32 | 33 | const res1 = await db?.putIfNotExists(original); 34 | 35 | assertEquals(res1?.updated, true); 36 | 37 | original.counter++; 38 | 39 | const res2 = await db?.putIfNotExists(original); 40 | 41 | assertEquals(res2?.updated, false); 42 | 43 | original.counter++; 44 | 45 | const res3 = await db?.upsert(original._id, (existing) => { 46 | assertEquals(existing.counter, 1); 47 | assertEquals(original.counter, 3); 48 | 49 | return false; 50 | }); 51 | 52 | assertEquals(res3?.updated, false); 53 | 54 | original.counter++; 55 | 56 | type RecordFoo = { foo: "bar" } & typeof original; 57 | 58 | const res4 = await db?.upsertAndMerge({ 59 | ...original, 60 | foo: "bar", 61 | }); 62 | 63 | assertEquals(res4?.updated, true); 64 | 65 | original.counter++; 66 | 67 | const recordFoo = await db?.get(original._id); 68 | 69 | assertEquals(recordFoo?.foo, "bar"); 70 | 71 | original.counter++; 72 | 73 | const res5 = await db?.upsertAndReplace(original); 74 | 75 | assertEquals(res5?.updated, true); 76 | 77 | const record = await db?.get(original._id); 78 | 79 | assertEquals(record?.counter, 6); 80 | }); 81 | }); 82 | -------------------------------------------------------------------------------- /modules/pouchdb_types/debug.d.ts: -------------------------------------------------------------------------------- 1 | // deno-lint-ignore-file no-explicit-any no-var 2 | // Type definitions for debug 4.1 3 | // Project: https://github.com/visionmedia/debug 4 | // Definitions by: Seon-Wook Park 5 | // Gal Talmor 6 | // John McLaughlin 7 | // Brasten Sager 8 | // Nicolas Penin 9 | // Kristian Brünn 10 | // Caleb Gregory 11 | // Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped 12 | 13 | declare var debug: debug.Debug & { debug: debug.Debug; default: debug.Debug }; 14 | 15 | export default debug; 16 | export as namespace debug; 17 | 18 | declare namespace debug { 19 | interface Debug { 20 | (namespace: string): Debugger; 21 | coerce: (val: any) => any; 22 | disable: () => string; 23 | enable: (namespaces: string) => void; 24 | enabled: (namespaces: string) => boolean; 25 | formatArgs: (this: Debugger, args: any[]) => void; 26 | log: (...args: any[]) => any; 27 | selectColor: (namespace: string) => string | number; 28 | humanize: typeof import("./ms.d.ts"); 29 | 30 | names: RegExp[]; 31 | skips: RegExp[]; 32 | 33 | formatters: Formatters; 34 | } 35 | 36 | type IDebug = Debug; 37 | 38 | interface Formatters { 39 | [formatter: string]: (v: any) => string; 40 | } 41 | 42 | type IDebugger = Debugger; 43 | 44 | interface Debugger { 45 | (formatter: any, ...args: any[]): void; 46 | 47 | color: string; 48 | diff: number; 49 | enabled: boolean; 50 | log: (...args: any[]) => any; 51 | namespace: string; 52 | destroy: () => boolean; 53 | extend: (namespace: string, delimiter?: string) => Debugger; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /modules/pouchdb_types/ms.d.ts: -------------------------------------------------------------------------------- 1 | // Type definitions for ms v0.7.1 2 | // Project: https://github.com/zeit/ms 3 | // Definitions by: Zhiyuan Wang 4 | // Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped 5 | 6 | /** 7 | * Short/Long format for `value`. 8 | * 9 | * @param {Number} value 10 | * @param {{long: boolean}} options 11 | * @return {String} 12 | */ 13 | declare function ms(value: number, options?: { long: boolean }): string; 14 | 15 | /** 16 | * Parse the given `value` and return milliseconds. 17 | * 18 | * @param {String} value 19 | * @return {Number} 20 | */ 21 | declare function ms(value: string): number; 22 | 23 | export = ms; 24 | -------------------------------------------------------------------------------- /modules/pouchdb_types/pouchdb.ts: -------------------------------------------------------------------------------- 1 | // deno-lint-ignore-file no-explicit-any ban-types 2 | // Type definitions for pouchdb-core 7.0 3 | // Project: https://pouchdb.com/, https://github.com/pouchdb/pouchdb 4 | // Definitions by: Simon Paulger , Jakub Navratil , 5 | // Brian Geppert , Frederico Galvão , 6 | // Tobias Bales , Sebastián Ramírez , 7 | // Katy Moe 8 | // Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped 9 | // TypeScript Version: 2.3 10 | import debug from "./debug.d.ts"; 11 | 12 | interface Blob { 13 | readonly size: number; 14 | readonly type: string; 15 | slice(start?: number, end?: number, contentType?: string): Blob; 16 | } 17 | 18 | interface Buffer extends Uint8Array { 19 | write( 20 | string: string, 21 | offset?: number, 22 | length?: number, 23 | encoding?: string, 24 | ): number; 25 | toString(encoding?: string, start?: number, end?: number): string; 26 | toJSON(): { type: "Buffer"; data: any[] }; 27 | equals(otherBuffer: Buffer): boolean; 28 | compare( 29 | otherBuffer: Buffer, 30 | targetStart?: number, 31 | targetEnd?: number, 32 | sourceStart?: number, 33 | sourceEnd?: number, 34 | ): number; 35 | copy( 36 | targetBuffer: Buffer, 37 | targetStart?: number, 38 | sourceStart?: number, 39 | sourceEnd?: number, 40 | ): number; 41 | slice(start?: number, end?: number): Buffer; 42 | writeUIntLE( 43 | value: number, 44 | offset: number, 45 | byteLength: number, 46 | noAssert?: boolean, 47 | ): number; 48 | writeUIntBE( 49 | value: number, 50 | offset: number, 51 | byteLength: number, 52 | noAssert?: boolean, 53 | ): number; 54 | writeIntLE( 55 | value: number, 56 | offset: number, 57 | byteLength: number, 58 | noAssert?: boolean, 59 | ): number; 60 | writeIntBE( 61 | value: number, 62 | offset: number, 63 | byteLength: number, 64 | noAssert?: boolean, 65 | ): number; 66 | readUIntLE(offset: number, byteLength: number, noAssert?: boolean): number; 67 | readUIntBE(offset: number, byteLength: number, noAssert?: boolean): number; 68 | readIntLE(offset: number, byteLength: number, noAssert?: boolean): number; 69 | readIntBE(offset: number, byteLength: number, noAssert?: boolean): number; 70 | readUInt8(offset: number, noAssert?: boolean): number; 71 | readUInt16LE(offset: number, noAssert?: boolean): number; 72 | readUInt16BE(offset: number, noAssert?: boolean): number; 73 | readUInt32LE(offset: number, noAssert?: boolean): number; 74 | readUInt32BE(offset: number, noAssert?: boolean): number; 75 | readInt8(offset: number, noAssert?: boolean): number; 76 | readInt16LE(offset: number, noAssert?: boolean): number; 77 | readInt16BE(offset: number, noAssert?: boolean): number; 78 | readInt32LE(offset: number, noAssert?: boolean): number; 79 | readInt32BE(offset: number, noAssert?: boolean): number; 80 | readFloatLE(offset: number, noAssert?: boolean): number; 81 | readFloatBE(offset: number, noAssert?: boolean): number; 82 | readDoubleLE(offset: number, noAssert?: boolean): number; 83 | readDoubleBE(offset: number, noAssert?: boolean): number; 84 | swap16(): Buffer; 85 | swap32(): Buffer; 86 | swap64(): Buffer; 87 | writeUInt8(value: number, offset: number, noAssert?: boolean): number; 88 | writeUInt16LE(value: number, offset: number, noAssert?: boolean): number; 89 | writeUInt16BE(value: number, offset: number, noAssert?: boolean): number; 90 | writeUInt32LE(value: number, offset: number, noAssert?: boolean): number; 91 | writeUInt32BE(value: number, offset: number, noAssert?: boolean): number; 92 | writeInt8(value: number, offset: number, noAssert?: boolean): number; 93 | writeInt16LE(value: number, offset: number, noAssert?: boolean): number; 94 | writeInt16BE(value: number, offset: number, noAssert?: boolean): number; 95 | writeInt32LE(value: number, offset: number, noAssert?: boolean): number; 96 | writeInt32BE(value: number, offset: number, noAssert?: boolean): number; 97 | writeFloatLE(value: number, offset: number, noAssert?: boolean): number; 98 | writeFloatBE(value: number, offset: number, noAssert?: boolean): number; 99 | writeDoubleLE(value: number, offset: number, noAssert?: boolean): number; 100 | writeDoubleBE(value: number, offset: number, noAssert?: boolean): number; 101 | fill(value: any, offset?: number, end?: number): this; 102 | indexOf( 103 | value: string | number | Buffer, 104 | byteOffset?: number, 105 | encoding?: string, 106 | ): number; 107 | lastIndexOf( 108 | value: string | number | Buffer, 109 | byteOffset?: number, 110 | encoding?: string, 111 | ): number; 112 | entries(): IterableIterator<[number, number]>; 113 | includes( 114 | value: string | number | Buffer, 115 | byteOffset?: number, 116 | encoding?: string, 117 | ): boolean; 118 | keys(): IterableIterator; 119 | values(): IterableIterator; 120 | } 121 | 122 | interface EventEmitter { 123 | addListener(event: string | symbol, listener: Function): this; 124 | on(event: string | symbol, listener: Function): this; 125 | once(event: string | symbol, listener: Function): this; 126 | removeListener(event: string | symbol, listener: Function): this; 127 | removeAllListeners(event?: string | symbol): this; 128 | setMaxListeners(n: number): this; 129 | getMaxListeners(): number; 130 | listeners(event: string | symbol): Function[]; 131 | emit(event: string | symbol, ...args: any[]): boolean; 132 | listenerCount(type: string | symbol): number; 133 | prependListener(event: string | symbol, listener: Function): this; 134 | prependOnceListener(event: string | symbol, listener: Function): this; 135 | eventNames(): Array; 136 | } 137 | 138 | type Fetch = ( 139 | url: string | Request, 140 | opts?: RequestInit, 141 | ) => Promise; 142 | 143 | export declare namespace PouchDB { 144 | namespace Core { 145 | interface Error { 146 | /** 147 | * HTTP Status Code during HTTP or HTTP-like operations 148 | */ 149 | status?: number | undefined; 150 | name?: string | undefined; 151 | message?: string | undefined; 152 | reason?: string | undefined; 153 | error?: string | boolean | undefined; 154 | id?: string | undefined; 155 | rev?: RevisionId | undefined; 156 | } 157 | type Callback = (error: Error | null, result: R | null) => void; 158 | type DocumentId = string; 159 | type DocumentKey = string; 160 | type AttachmentId = string; 161 | type RevisionId = string; 162 | type Availability = "available" | "compacted" | "not compacted" | "missing"; 163 | type AttachmentData = string | Blob | Buffer; 164 | 165 | interface Options { 166 | fetch?: Fetch | undefined; 167 | } 168 | 169 | interface BasicResponse { 170 | /** `true` if the operation was successful; `false` otherwise */ 171 | ok: boolean; 172 | } 173 | interface Response extends BasicResponse { 174 | /** id of the targeted document */ 175 | id: DocumentId; 176 | /** resulting revision of the targeted document */ 177 | rev: RevisionId; 178 | } 179 | 180 | interface DatabaseInfo { 181 | /** Name of the database you gave when you called new PouchDB(), and also the unique identifier for the database. */ 182 | db_name: string; 183 | 184 | /** Total number of non-deleted documents in the database. */ 185 | doc_count: number; 186 | 187 | /** Sequence number of the database. It starts at 0 and gets incremented every time a document is added or modified */ 188 | update_seq: number | string; 189 | } 190 | 191 | interface Revision { 192 | ok: Document & RevisionIdMeta; 193 | } 194 | interface RevisionInfo { 195 | rev: RevisionId; 196 | status: Availability; 197 | } 198 | interface RevisionDiffOptions { 199 | [DocumentId: string]: string[]; 200 | } 201 | interface RevisionDiff { 202 | missing?: string[] | undefined; 203 | possible_ancestors?: string[] | undefined; 204 | } 205 | interface RevisionDiffResponse { 206 | [DocumentId: string]: RevisionDiff; 207 | } 208 | 209 | interface IdMeta { 210 | _id: DocumentId; 211 | } 212 | interface RevisionIdMeta { 213 | _rev: RevisionId; 214 | } 215 | interface GetMeta { 216 | /** 217 | * Conflicting leaf revisions. 218 | * 219 | * Only present if `GetOptions.conflicts` is `true` 220 | */ 221 | _conflicts?: RevisionId[] | undefined; 222 | _rev: RevisionId; 223 | /** Only present if `GetOptions.revs` is `true` */ 224 | _revs_info?: RevisionInfo[] | undefined; 225 | /** Only present if `GetOptions.revs_info` is `true` */ 226 | _revisions?: { 227 | ids: RevisionId[]; 228 | start: number; 229 | } | undefined; 230 | 231 | /** Attachments where index is attachmentId */ 232 | _attachments?: Attachments | undefined; 233 | } 234 | 235 | /** 236 | * Stub attachments are returned by PouchDB by default (attachments option set to false) 237 | */ 238 | interface StubAttachment { 239 | /** 240 | * Mime type of the attachment 241 | */ 242 | content_type: string; 243 | 244 | /** 245 | * Database digest of the attachment 246 | */ 247 | digest: string; 248 | 249 | /** 250 | * Attachment is a stub 251 | */ 252 | stub: true; 253 | 254 | /** 255 | * Length of the attachment 256 | */ 257 | length: number; 258 | } 259 | 260 | /** 261 | * Full attachments are used to create new attachments or returned when the attachments option 262 | * is true. 263 | */ 264 | interface FullAttachment { 265 | /** 266 | * Mime type of the attachment 267 | */ 268 | content_type: string; 269 | 270 | /** MD5 hash, starts with "md5-" prefix; populated by PouchDB for new attachments */ 271 | digest?: string | undefined; 272 | 273 | /** 274 | * {string} if `binary` was `false` 275 | * {Blob|Buffer} if `binary` was `true` 276 | */ 277 | data: AttachmentData; 278 | } 279 | 280 | type Attachment = StubAttachment | FullAttachment; 281 | 282 | interface Attachments { 283 | [attachmentId: string]: Attachment; 284 | } 285 | 286 | type NewDocument = Content; 287 | type Document = Content & IdMeta; 288 | type ExistingDocument = 289 | & Document 290 | & RevisionIdMeta; 291 | 292 | /** Existing doc or just object with `_id` and `_rev` */ 293 | type RemoveDocument = IdMeta & RevisionIdMeta; 294 | 295 | type PostDocument = NewDocument & { 296 | filters?: { [filterName: string]: string } | undefined; 297 | views?: { 298 | [viewName: string]: { 299 | map: string; 300 | reduce?: string | undefined; 301 | }; 302 | } | undefined; 303 | 304 | /** You can update an existing doc using _rev */ 305 | _rev?: RevisionId | undefined; 306 | 307 | _attachments?: Attachments | undefined; 308 | }; 309 | 310 | type PutDocument = 311 | & PostDocument 312 | & ChangesMeta 313 | & { 314 | _id?: DocumentId | undefined; 315 | }; 316 | 317 | interface AllDocsOptions extends Options { 318 | /** 319 | * Include attachment data for each document. 320 | * 321 | * Requires `include_docs` to be `true`. 322 | * 323 | * By default, attachments are Base64-encoded. 324 | * @see binary 325 | */ 326 | attachments?: boolean | undefined; 327 | /** 328 | * Return attachments as Buffers. 329 | * 330 | * Requires `include_docs` to be `true`. 331 | * Requires `attachments` to be `true`. 332 | */ 333 | binary?: boolean | undefined; 334 | /** 335 | * Include conflict information for each document. 336 | * 337 | * Requires `include_docs` to be `true`. 338 | */ 339 | conflicts?: boolean | undefined; 340 | /** Reverse ordering of results. */ 341 | descending?: boolean | undefined; 342 | /** Include contents for each document. */ 343 | include_docs?: boolean | undefined; 344 | /** Maximum number of documents to return. */ 345 | limit?: number | undefined; 346 | /** 347 | * Number of documents to skip before returning. 348 | * 349 | * Causes poor performance on IndexedDB and LevelDB. 350 | */ 351 | skip?: number | undefined; 352 | /** 353 | * Include an update_seq value indicating which sequence id 354 | * of the underlying database the view reflects. 355 | */ 356 | update_seq?: boolean | undefined; 357 | } 358 | interface AllDocsWithKeyOptions extends AllDocsOptions { 359 | /** Constrain results to documents matching this key. */ 360 | key: DocumentKey; 361 | } 362 | interface AllDocsWithKeysOptions extends AllDocsOptions { 363 | /** Constrains results to documents matching any of these keys. */ 364 | keys: DocumentId[]; 365 | } 366 | interface AllDocsWithinRangeOptions extends AllDocsOptions { 367 | /** Low end of range, or high end if `descending` is `true`. */ 368 | startkey: DocumentKey; 369 | /** High end of range, or low end if `descending` is `true`. */ 370 | endkey: DocumentKey; 371 | /** 372 | * Include any documents identified by `endkey`. 373 | * 374 | * Defaults to `true`. 375 | */ 376 | inclusive_end?: boolean | undefined; 377 | } 378 | interface AllDocsMeta { 379 | /** Only present if `conflicts` is `true` */ 380 | _conflicts?: RevisionId[] | undefined; 381 | 382 | _attachments?: Attachments | undefined; 383 | } 384 | interface AllDocsResponse { 385 | /** The `skip` if provided, or in CouchDB the actual offset */ 386 | offset: number; 387 | total_rows: number; 388 | update_seq?: number | string | undefined; 389 | rows: Array<{ 390 | /** Only present if `include_docs` was `true`. */ 391 | doc?: ExistingDocument | undefined; 392 | id: DocumentId; 393 | key: DocumentKey; 394 | value: { 395 | rev: RevisionId; 396 | deleted?: boolean | undefined; 397 | }; 398 | }>; 399 | } 400 | 401 | interface BulkDocsOptions extends Options { 402 | new_edits?: boolean | undefined; 403 | } 404 | 405 | interface BulkGetOptions extends Options { 406 | docs: Array<{ id: string; rev?: RevisionId | undefined }>; 407 | revs?: boolean | undefined; 408 | attachments?: boolean | undefined; 409 | binary?: boolean | undefined; 410 | } 411 | 412 | interface BulkGetResponse { 413 | results: Array<{ 414 | id: string; 415 | docs: Array<{ ok: Content & GetMeta } | { error: Error }>; 416 | }>; 417 | } 418 | 419 | interface ChangesMeta { 420 | _conflicts?: RevisionId[] | undefined; 421 | _deleted?: boolean | undefined; 422 | _attachments?: Attachments | undefined; 423 | } 424 | 425 | interface ChangesOptions { 426 | /** 427 | * Does "live" changes. 428 | */ 429 | live?: boolean | undefined; 430 | 431 | /** 432 | * Start the results from the change immediately after the given sequence number. 433 | * You can also pass `'now'` if you want only new changes (when `live` is `true`). 434 | */ 435 | since?: "now" | number | string | undefined; 436 | 437 | /** 438 | * Request timeout (in milliseconds). 439 | */ 440 | timeout?: number | false | undefined; 441 | 442 | /** Include contents for each document. */ 443 | include_docs?: boolean | undefined; 444 | 445 | /** Maximum number of documents to return. */ 446 | limit?: number | false | undefined; 447 | 448 | /** Include conflicts. */ 449 | conflicts?: boolean | undefined; 450 | 451 | /** Include attachments. */ 452 | attachments?: boolean | undefined; 453 | 454 | /** Return attachment data as Blobs/Buffers, instead of as base64-encoded strings. */ 455 | binary?: boolean | undefined; 456 | 457 | /** Reverse the order of the output documents. */ 458 | descending?: boolean | undefined; 459 | 460 | /** 461 | * For http adapter only, time in milliseconds for server to give a heartbeat to keep long connections open. 462 | * Defaults to 10000 (10 seconds), use false to disable the default. 463 | */ 464 | heartbeat?: number | false | undefined; 465 | 466 | /** 467 | * Reference a filter function from a design document to selectively get updates. 468 | * To use a view function, pass '_view' here and provide a reference to the view function in options.view. 469 | * See filtered changes for details. 470 | */ 471 | filter?: string | ((doc: any, params: any) => any) | undefined; 472 | 473 | /** Only show changes for docs with these ids (array of strings). */ 474 | doc_ids?: string[] | undefined; 475 | 476 | /** 477 | * Object containing properties that are passed to the filter function, e.g. {"foo:"bar"}, 478 | * where "bar" will be available in the filter function as params.query.foo. 479 | * To access the params, define your filter function like function (doc, params). 480 | */ 481 | query_params?: { [paramName: string]: any } | undefined; 482 | 483 | /** 484 | * Specify a view function (e.g. 'design_doc_name/view_name' or 'view_name' as shorthand for 'view_name/view_name') to act as a filter. 485 | * Documents counted as “passed” for a view filter if a map function emits at least one record for them. 486 | * Note: options.filter must be set to '_view' for this option to work. 487 | */ 488 | view?: string | undefined; 489 | 490 | /** 491 | * Filter using a query/pouchdb-find selector. Note: Selectors are not supported in CouchDB 1.x. 492 | * Cannot be used in combination with the filter option. 493 | */ 494 | selector?: Find.Selector | undefined; 495 | 496 | /** 497 | * (previously options.returnDocs): Is available for non-http databases and defaults to true. 498 | * Passing false prevents the changes feed from keeping all the documents in memory – in other 499 | * words complete always has an empty results array, and the change event is the only way to get the event. 500 | * Useful for large change sets where otherwise you would run out of memory. 501 | */ 502 | return_docs?: boolean | undefined; 503 | 504 | /** 505 | * Only available for http databases, this configures how many changes to fetch at a time. 506 | * Increasing this can reduce the number of requests made. Default is 25. 507 | */ 508 | batch_size?: number | undefined; 509 | 510 | /** 511 | * Specifies how many revisions are returned in the changes array. 512 | * The default, 'main_only', will only return the current “winning” revision; 513 | * 'all_docs' will return all leaf revisions (including conflicts and deleted former conflicts). 514 | * Most likely you won’t need this unless you’re writing a replicator. 515 | */ 516 | style?: "main_only" | "all_docs" | undefined; 517 | 518 | /** 519 | * Only available for http databases. Specifies that seq information only be generated every N changes. 520 | * Larger values can improve changes throughput with CouchDB 2.0 and later. 521 | * Note that last_seq is always populated regardless. 522 | */ 523 | seq_interval?: number | undefined; 524 | } 525 | 526 | interface ChangesResponseChange { 527 | id: string; 528 | seq: number | string; 529 | changes: Array<{ rev: string }>; 530 | deleted?: boolean | undefined; 531 | doc?: ExistingDocument | undefined; 532 | } 533 | 534 | interface ChangesResponse { 535 | status: string; 536 | last_seq: number | string; 537 | results: Array>; 538 | } 539 | 540 | interface Changes 541 | extends EventEmitter, Promise> { 542 | on( 543 | event: "change", 544 | listener: (value: ChangesResponseChange) => any, 545 | ): this; 546 | on( 547 | event: "complete", 548 | listener: (value: ChangesResponse) => any, 549 | ): this; 550 | on(event: "error", listener: (value: any) => any): this; 551 | 552 | cancel(): void; 553 | } 554 | 555 | interface GetOptions extends Options { 556 | /** Include list of conflicting leaf revisions. */ 557 | conflicts?: boolean | undefined; 558 | /** Specific revision to fetch */ 559 | rev?: RevisionId | undefined; 560 | /** Include revision history of the document. */ 561 | revs?: boolean | undefined; 562 | /** 563 | * Include a list of revisions of the document, and their 564 | * availability. 565 | */ 566 | revs_info?: boolean | undefined; 567 | 568 | /** Include attachment data. */ 569 | attachments?: boolean | undefined; 570 | 571 | /** Return attachment data as Blobs/Buffers, instead of as base64-encoded strings. */ 572 | binary?: boolean | undefined; 573 | 574 | /** Forces retrieving latest “leaf” revision, no matter what rev was requested. */ 575 | latest?: boolean | undefined; 576 | } 577 | 578 | interface GetOpenRevisions extends Options { 579 | /** 580 | * Fetch all leaf revisions if open_revs="all" or fetch all leaf 581 | * revisions specified in open_revs array. Leaves will be returned 582 | * in the same order as specified in input array. 583 | */ 584 | open_revs: "all" | RevisionId[]; 585 | 586 | /** Include revision history of the document. */ 587 | revs?: boolean | undefined; 588 | } 589 | 590 | interface CompactOptions extends Options { 591 | interval?: number | undefined; 592 | } 593 | 594 | interface PutOptions extends Options { 595 | force?: boolean | undefined; 596 | } 597 | 598 | interface RemoveAttachmentResponse extends BasicResponse { 599 | id: DocumentId; 600 | rev: RevisionId; 601 | } 602 | } 603 | 604 | /** 605 | * Pass this to `PouchDB.plugin()`. 606 | */ 607 | type Plugin = 608 | | PluginProps 609 | | (( 610 | db: 611 | & Database 612 | & { 613 | -readonly [PluginProp in keyof PluginProps]: PluginProps[PluginProp]; 614 | }, 615 | ) => void); 616 | 617 | namespace Configuration { 618 | interface CommonDatabaseConfiguration { 619 | /** 620 | * Database name. 621 | */ 622 | name?: string | undefined; 623 | /** 624 | * Database adapter to use. 625 | * 626 | * If unspecified, PouchDB will infer this automatically, preferring 627 | * IndexedDB to WebSQL in browsers that support both (i.e. Chrome, 628 | * Opera and Android 4.4+). 629 | */ 630 | adapter?: string | undefined; 631 | } 632 | 633 | interface LocalDatabaseConfiguration extends CommonDatabaseConfiguration { 634 | /** 635 | * Enables auto compaction, which means compact() is called after 636 | * every change to the database. 637 | * 638 | * Defaults to false. 639 | */ 640 | auto_compaction?: boolean | undefined; 641 | /** 642 | * How many old revisions we keep track (not a copy) of. 643 | */ 644 | revs_limit?: number | undefined; 645 | /** 646 | * Size of the database (Most significant for Safari) 647 | * option to set the max size in MB that Safari will grant to the local database. Valid options are: 10, 50, 100, 500 and 1000 648 | * ex_ new PouchDB("dbName", {size:100}); 649 | */ 650 | size?: number | undefined; 651 | /** 652 | * A special constructor option, which appends a prefix to the database name 653 | * and can be helpful for URL-based or file-based LevelDOWN path names. 654 | */ 655 | prefix?: string | undefined; 656 | /** 657 | * Use a md5 hash to create a deterministic revision number for documents. 658 | * Setting it to false will mean that the revision number will be a random UUID. 659 | * Defaults to true. 660 | */ 661 | deterministic_revs?: boolean | undefined; 662 | } 663 | 664 | interface RemoteDatabaseConfiguration extends CommonDatabaseConfiguration { 665 | fetch?: Fetch | undefined; 666 | 667 | auth?: { 668 | username?: string | undefined; 669 | password?: string | undefined; 670 | } | undefined; 671 | /** 672 | * Disables automatic creation of databases. 673 | */ 674 | skip_setup?: boolean | undefined; 675 | } 676 | 677 | type DatabaseConfiguration = 678 | | LocalDatabaseConfiguration 679 | | RemoteDatabaseConfiguration; 680 | } 681 | 682 | interface Static extends EventEmitter { 683 | plugin( 684 | plugin: Plugin, 685 | ): Static; 686 | 687 | version: string; 688 | 689 | fetch: Fetch; 690 | 691 | on(event: "created" | "destroyed", listener: (dbName: string) => any): this; 692 | 693 | debug: debug.IDebug; 694 | 695 | new ( 696 | name?: string, 697 | options?: Configuration.DatabaseConfiguration, 698 | ): Database & PluginProps; 699 | new ( 700 | name: string | null, 701 | options: HttpAdapter.HttpAdapterConfiguration, 702 | ): Database & PluginProps; 703 | new ( 704 | name: string | null, 705 | options: MemoryAdapter.MemoryAdapterConfiguration, 706 | ): Database & PluginProps; 707 | new ( 708 | name: string | null, 709 | options: IdbAdapter.IdbAdapterConfiguration, 710 | ): Database & PluginProps; 711 | new ( 712 | name: string | null, 713 | options: IndexedDBAdapter.IndexedDBAdapterConfiguration, 714 | ): Database & PluginProps; 715 | 716 | /** 717 | * The returned object is a constructor function that works the same as PouchDB, 718 | * except that whenever you invoke it (e.g. with new), the given options will be passed in by default. 719 | */ 720 | defaults(options: Configuration.DatabaseConfiguration): { 721 | new ( 722 | name?: string, 723 | options?: Configuration.DatabaseConfiguration, 724 | ): Database & PluginProps; 725 | }; 726 | defaults(options: HttpAdapter.HttpAdapterConfiguration): { 727 | new ( 728 | name?: string, 729 | options?: HttpAdapter.HttpAdapterConfiguration, 730 | ): Database & PluginProps; 731 | }; 732 | defaults(options: MemoryAdapter.MemoryAdapterConfiguration): { 733 | new ( 734 | name?: string, 735 | options?: MemoryAdapter.MemoryAdapterConfiguration, 736 | ): Database & PluginProps; 737 | }; 738 | defaults(options: IdbAdapter.IdbAdapterConfiguration): { 739 | new ( 740 | name?: string, 741 | options?: IdbAdapter.IdbAdapterConfiguration, 742 | ): Database & PluginProps; 743 | }; 744 | defaults(options: IndexedDBAdapter.IndexedDBAdapterConfiguration): { 745 | new ( 746 | name?: string, 747 | options?: IndexedDBAdapter.IndexedDBAdapterConfiguration, 748 | ): Database & PluginProps; 749 | }; 750 | } 751 | 752 | interface Database extends EventEmitter { 753 | /** The name passed to the PouchDB constructor and unique identifier of the database. */ 754 | name: string; 755 | 756 | /** Fetch all documents matching the given options. */ 757 | allDocs( 758 | options?: 759 | | Core.AllDocsWithKeyOptions 760 | | Core.AllDocsWithKeysOptions 761 | | Core.AllDocsWithinRangeOptions 762 | | Core.AllDocsOptions, 763 | ): Promise>; 764 | 765 | /** 766 | * Create, update or delete multiple documents. The docs argument is an array of documents. 767 | * If you omit an _id parameter on a given document, the database will create a new document and assign the ID for you. 768 | * To update a document, you must include both an _id parameter and a _rev parameter, 769 | * which should match the ID and revision of the document on which to base your updates. 770 | * Finally, to delete a document, include a _deleted parameter with the value true. 771 | */ 772 | bulkDocs( 773 | docs: Array>, 774 | options: Core.BulkDocsOptions | null, 775 | callback: Core.Callback>, 776 | ): void; 777 | 778 | /** 779 | * Create, update or delete multiple documents. The docs argument is an array of documents. 780 | * If you omit an _id parameter on a given document, the database will create a new document and assign the ID for you. 781 | * To update a document, you must include both an _id parameter and a _rev parameter, 782 | * which should match the ID and revision of the document on which to base your updates. 783 | * Finally, to delete a document, include a _deleted parameter with the value true. 784 | */ 785 | bulkDocs( 786 | docs: Array>, 787 | options?: Core.BulkDocsOptions, 788 | ): Promise>; 789 | 790 | /** Compact the database */ 791 | compact(options?: Core.CompactOptions): Promise; 792 | 793 | /** Compact the database */ 794 | compact( 795 | options: Core.CompactOptions, 796 | callback: Core.Callback, 797 | ): void; 798 | 799 | /** Destroy the database */ 800 | destroy(options: Core.Options | null, callback: Core.Callback): void; 801 | 802 | /** Destroy the database */ 803 | destroy(options?: Core.Options | null): Promise; 804 | 805 | /** Fetch a document */ 806 | get( 807 | docId: Core.DocumentId, 808 | options: Core.GetOptions | null, 809 | callback: Core.Callback & Core.GetMeta>, 810 | ): void; 811 | 812 | /** Fetch a document */ 813 | get( 814 | docId: Core.DocumentId, 815 | options: Core.GetOpenRevisions, 816 | callback: Core.Callback>>, 817 | ): void; 818 | 819 | /** Fetch a document */ 820 | get( 821 | docId: Core.DocumentId, 822 | options?: Core.GetOptions, 823 | ): Promise & Core.GetMeta>; 824 | 825 | /** Fetch a document */ 826 | get( 827 | docId: Core.DocumentId, 828 | options: Core.GetOpenRevisions, 829 | ): Promise>>; 830 | 831 | /** 832 | * Create a new document without providing an id. 833 | * 834 | * You should prefer put() to post(), because when you post(), you are 835 | * missing an opportunity to use allDocs() to sort documents by _id 836 | * (because your _ids are random). 837 | * 838 | * @see {@link https://pouchdb.com/2014/06/17/12-pro-tips-for-better-code-with-pouchdb.html|PouchDB Pro Tips} 839 | */ 840 | post( 841 | doc: Core.PostDocument, 842 | options: Core.Options | null, 843 | callback: Core.Callback, 844 | ): void; 845 | 846 | /** 847 | * Create a new document without providing an id. 848 | * 849 | * You should prefer put() to post(), because when you post(), you are 850 | * missing an opportunity to use allDocs() to sort documents by _id 851 | * (because your _ids are random). 852 | * 853 | * @see {@link https://pouchdb.com/2014/06/17/12-pro-tips-for-better-code-with-pouchdb.html|PouchDB Pro Tips} 854 | */ 855 | post( 856 | doc: Core.PostDocument, 857 | options?: Core.Options, 858 | ): Promise; 859 | 860 | /** 861 | * Create a new document or update an existing document. 862 | * 863 | * If the document already exists, you must specify its revision _rev, 864 | * otherwise a conflict will occur. 865 | * There are some restrictions on valid property names of the documents. 866 | * If you try to store non-JSON data (for instance Date objects) you may 867 | * see inconsistent results. 868 | */ 869 | put( 870 | doc: Core.PutDocument, 871 | options: Core.PutOptions | null, 872 | callback: Core.Callback, 873 | ): void; 874 | 875 | /** 876 | * Create a new document or update an existing document. 877 | * 878 | * If the document already exists, you must specify its revision _rev, 879 | * otherwise a conflict will occur. 880 | * There are some restrictions on valid property names of the documents. 881 | * If you try to store non-JSON data (for instance Date objects) you may 882 | * see inconsistent results. 883 | */ 884 | put( 885 | doc: Core.PutDocument, 886 | options?: Core.PutOptions, 887 | ): Promise; 888 | 889 | /** Remove a doc from the database */ 890 | remove( 891 | doc: Core.RemoveDocument, 892 | options: Core.Options, 893 | callback: Core.Callback, 894 | ): void; 895 | 896 | /** Remove a doc from the database */ 897 | remove( 898 | docId: Core.DocumentId, 899 | revision: Core.RevisionId, 900 | options: Core.Options, 901 | callback: Core.Callback, 902 | ): void; 903 | 904 | /** Remove a doc from the database */ 905 | remove( 906 | doc: Core.RemoveDocument, 907 | options?: Core.Options, 908 | ): Promise; 909 | 910 | /** Remove a doc from the database */ 911 | remove( 912 | docId: Core.DocumentId, 913 | revision: Core.RevisionId, 914 | options?: Core.Options, 915 | ): Promise; 916 | 917 | /** Get database information */ 918 | info(callback: Core.Callback): void; 919 | 920 | /** Get database information */ 921 | info(): Promise; 922 | 923 | /** 924 | * A list of changes made to documents in the database, in the order they were made. 925 | * It returns an object with the method cancel(), which you call if you don’t want to listen to new changes anymore. 926 | * 927 | * It is an event emitter and will emit a 'change' event on each document change, 928 | * a 'complete' event when all the changes have been processed, and an 'error' event when an error occurs. 929 | * Calling cancel() will unsubscribe all event listeners automatically. 930 | */ 931 | changes( 932 | options: Core.ChangesOptions | null, 933 | callback: Core.Callback>, 934 | ): void; 935 | 936 | /** 937 | * A list of changes made to documents in the database, in the order they were made. 938 | * It returns an object with the method cancel(), which you call if you don’t want to listen to new changes anymore. 939 | * 940 | * It is an event emitter and will emit a 'change' event on each document change, 941 | * a 'complete' event when all the changes have been processed, and an 'error' event when an error occurs. 942 | * Calling cancel() will unsubscribe all event listeners automatically. 943 | */ 944 | changes( 945 | options?: Core.ChangesOptions, 946 | ): Core.Changes; 947 | 948 | /** Close the database */ 949 | close(callback: Core.Callback): void; 950 | 951 | /** Close the database */ 952 | close(): Promise; 953 | 954 | /** 955 | * Attaches a binary object to a document. 956 | * This method will update an existing document to add the attachment, so it requires a rev if the document already exists. 957 | * If the document doesn’t already exist, then this method will create an empty document containing the attachment. 958 | */ 959 | putAttachment( 960 | docId: Core.DocumentId, 961 | attachmentId: Core.AttachmentId, 962 | rev: Core.RevisionId, 963 | attachment: Core.AttachmentData, 964 | type: string, 965 | callback: Core.Callback, 966 | ): void; 967 | 968 | /** 969 | * Attaches a binary object to a document. 970 | * This method will update an existing document to add the attachment, so it requires a rev if the document already exists. 971 | * If the document doesn’t already exist, then this method will create an empty document containing the attachment. 972 | */ 973 | putAttachment( 974 | docId: Core.DocumentId, 975 | attachmentId: Core.AttachmentId, 976 | rev: Core.RevisionId, 977 | attachment: Core.AttachmentData, 978 | type: string, 979 | ): Promise; 980 | 981 | /** 982 | * Attaches a binary object to a document. 983 | * This method will update an existing document to add the attachment, so it requires a rev if the document already exists. 984 | * If the document doesn’t already exist, then this method will create an empty document containing the attachment. 985 | */ 986 | putAttachment( 987 | docId: Core.DocumentId, 988 | attachmentId: Core.AttachmentId, 989 | attachment: Core.AttachmentData, 990 | type: string, 991 | callback: Core.Callback, 992 | ): void; 993 | 994 | /** 995 | * Attaches a binary object to a document. 996 | * This method will update an existing document to add the attachment, so it requires a rev if the document already exists. 997 | * If the document doesn’t already exist, then this method will create an empty document containing the attachment. 998 | */ 999 | putAttachment( 1000 | docId: Core.DocumentId, 1001 | attachmentId: Core.AttachmentId, 1002 | attachment: Core.AttachmentData, 1003 | type: string, 1004 | ): Promise; 1005 | 1006 | /** Get attachment data */ 1007 | getAttachment( 1008 | docId: Core.DocumentId, 1009 | attachmentId: Core.AttachmentId, 1010 | options: { rev?: Core.RevisionId | undefined }, 1011 | callback: Core.Callback, 1012 | ): void; 1013 | 1014 | /** Get attachment data */ 1015 | getAttachment( 1016 | docId: Core.DocumentId, 1017 | attachmentId: Core.AttachmentId, 1018 | options?: { rev?: Core.RevisionId | undefined }, 1019 | ): Promise; 1020 | 1021 | /** Get attachment data */ 1022 | getAttachment( 1023 | docId: Core.DocumentId, 1024 | attachmentId: Core.AttachmentId, 1025 | callback: Core.Callback, 1026 | ): void; 1027 | 1028 | /** Delete an attachment from a doc. You must supply the rev of the existing doc. */ 1029 | removeAttachment( 1030 | docId: Core.DocumentId, 1031 | attachmentId: Core.AttachmentId, 1032 | rev: Core.RevisionId, 1033 | callback: Core.Callback, 1034 | ): void; 1035 | 1036 | /** Delete an attachment from a doc. You must supply the rev of the existing doc. */ 1037 | removeAttachment( 1038 | docId: Core.DocumentId, 1039 | attachmentId: Core.AttachmentId, 1040 | rev: Core.RevisionId, 1041 | ): Promise; 1042 | 1043 | /** Given a set of document/revision IDs, returns the document bodies (and, optionally, attachment data) for each ID/revision pair specified. */ 1044 | bulkGet( 1045 | options: Core.BulkGetOptions, 1046 | callback: Core.Callback>, 1047 | ): void; 1048 | 1049 | /** Given a set of document/revision IDs, returns the document bodies (and, optionally, attachment data) for each ID/revision pair specified. */ 1050 | bulkGet( 1051 | options: Core.BulkGetOptions, 1052 | ): Promise>; 1053 | 1054 | /** Given a set of document/revision IDs, returns the subset of those that do not correspond to revisions stored in the database */ 1055 | revsDiff( 1056 | diff: Core.RevisionDiffOptions, 1057 | callback: Core.Callback, 1058 | ): void; 1059 | 1060 | /** Given a set of document/revision IDs, returns the subset of those that do not correspond to revisions stored in the database */ 1061 | revsDiff( 1062 | diff: Core.RevisionDiffOptions, 1063 | ): Promise; 1064 | } 1065 | 1066 | // HTTP adapter augmentation 1067 | 1068 | namespace HttpAdapter { 1069 | interface HttpAdapterConfiguration 1070 | extends Configuration.RemoteDatabaseConfiguration { 1071 | adapter: "http"; 1072 | } 1073 | } 1074 | 1075 | // IndexedDB adapter augmentation 1076 | 1077 | namespace Core { 1078 | interface DatabaseInfo { 1079 | idb_attachment_format?: "base64" | "binary" | undefined; 1080 | } 1081 | } 1082 | 1083 | namespace IdbAdapter { 1084 | interface IdbAdapterConfiguration 1085 | extends Configuration.LocalDatabaseConfiguration { 1086 | /** 1087 | * Configures storage persistence. 1088 | * 1089 | * Only works in Firefox 26+. 1090 | */ 1091 | storage?: "persistent" | "temporary" | undefined; 1092 | /** 1093 | * Configure the directory path for IndexedDBShim `__sysdb__.sqlite`. 1094 | * 1095 | * Only applies to the first adapter call; subsequent calls will 1096 | * not change the path for the system db file. 1097 | * 1098 | * Only works on module aaronhuggins/indexeddb for Deno; 1099 | * will be removed when Deno implements IndexedDB natively. 1100 | */ 1101 | systemPath?: string; 1102 | adapter: "idb"; 1103 | } 1104 | } 1105 | 1106 | namespace IndexedDBAdapter { 1107 | interface IndexedDBAdapterConfiguration 1108 | extends Configuration.LocalDatabaseConfiguration { 1109 | /** 1110 | * Configure the directory path for IndexedDBShim `__sysdb__.sqlite`. 1111 | * 1112 | * Only applies to the first adapter call; subsequent calls will 1113 | * not change the path for the system db file. 1114 | * 1115 | * Only works on module aaronhuggins/indexeddb for Deno; 1116 | * will be removed when Deno implements IndexedDB natively. 1117 | */ 1118 | systemPath?: string; 1119 | adapter: "indexeddb"; 1120 | } 1121 | } 1122 | 1123 | // Memory adapter augmentation 1124 | 1125 | namespace MemoryAdapter { 1126 | interface MemoryAdapterConfiguration 1127 | extends Configuration.RemoteDatabaseConfiguration { 1128 | adapter: "memory"; 1129 | } 1130 | } 1131 | 1132 | // Find plugin augmentation 1133 | 1134 | namespace Find { 1135 | interface ConditionOperators { 1136 | /** Match fields "less than" this one. */ 1137 | $lt?: any; 1138 | 1139 | /** Match fields "greater than" this one. */ 1140 | $gt?: any; 1141 | 1142 | /** Match fields "less than or equal to" this one. */ 1143 | $lte?: any; 1144 | 1145 | /** Match fields "greater than or equal to" this one. */ 1146 | $gte?: any; 1147 | 1148 | /** Match fields equal to this one. */ 1149 | $eq?: any; 1150 | 1151 | /** Match fields not equal to this one. */ 1152 | $ne?: any; 1153 | 1154 | /** True if the field should exist, false otherwise. */ 1155 | $exists?: boolean | undefined; 1156 | 1157 | /** One of: "null", "boolean", "number", "string", "array", or "object". */ 1158 | $type?: 1159 | | "null" 1160 | | "boolean" 1161 | | "number" 1162 | | "string" 1163 | | "array" 1164 | | "object" 1165 | | undefined; 1166 | 1167 | /** The document field must exist in the list provided. */ 1168 | $in?: any[] | undefined; 1169 | 1170 | /** The document field must not exist in the list provided. */ 1171 | $nin?: any[] | undefined; 1172 | 1173 | /** Special condition to match the length of an array field in a document. Non-array fields cannot match this condition. */ 1174 | $size?: number | undefined; 1175 | 1176 | /** 1177 | * Divisor and Remainder are both positive or negative integers. 1178 | * Non-integer values result in a 404 status. 1179 | * Matches documents where (field % Divisor == Remainder) is true, and only when the document field is an integer. 1180 | * [divisor, remainder] 1181 | */ 1182 | $mod?: [number, number] | undefined; 1183 | 1184 | /** A regular expression pattern to match against the document field. Only matches when the field is a string value and matches the supplied regular expression. */ 1185 | $regex?: string | undefined; 1186 | 1187 | /** Matches an array value if it contains all the elements of the argument array. */ 1188 | $all?: any[] | undefined; 1189 | 1190 | $elemMatch?: ConditionOperators | undefined; 1191 | } 1192 | 1193 | interface CombinationOperators { 1194 | /** Matches if all the selectors in the array match. */ 1195 | $and?: Selector[] | undefined; 1196 | 1197 | /** Matches if any of the selectors in the array match. All selectors must use the same index. */ 1198 | $or?: Selector[] | undefined; 1199 | 1200 | /** Matches if the given selector does not match. */ 1201 | $not?: Selector | undefined; 1202 | 1203 | /** Matches if none of the selectors in the array match. */ 1204 | $nor?: Selector[] | undefined; 1205 | } 1206 | 1207 | interface Selector extends CombinationOperators { 1208 | [field: string]: Selector | Selector[] | ConditionOperators | any; 1209 | 1210 | _id?: string | ConditionOperators | undefined; 1211 | } 1212 | 1213 | interface FindRequest { 1214 | /** Defines a selector to filter the results. Required */ 1215 | selector: Selector; 1216 | 1217 | /** Defines a list of fields that you want to receive. If omitted, you get the full documents. */ 1218 | fields?: string[] | undefined; 1219 | 1220 | /** Defines a list of fields defining how you want to sort. Note that sorted fields also have to be selected in the selector. */ 1221 | sort?: Array | undefined; 1222 | 1223 | /** Maximum number of documents to return. */ 1224 | limit?: number | undefined; 1225 | 1226 | /** Number of docs to skip before returning. */ 1227 | skip?: number | undefined; 1228 | 1229 | /** Set which index to use for the query. It can be “design-doc-name” or “[‘design-doc-name’, ‘name’]”. */ 1230 | use_index?: string | [string, string] | undefined; 1231 | } 1232 | 1233 | interface FindResponse { 1234 | docs: Array>; 1235 | warning?: string | undefined; 1236 | } 1237 | 1238 | interface CreateIndexOptions { 1239 | index: { 1240 | /** List of fields to index */ 1241 | fields: string[]; 1242 | 1243 | /** Name of the index, auto-generated if you don't include it */ 1244 | name?: string | undefined; 1245 | 1246 | /** Design document name (i.e. the part after '_design/', auto-generated if you don't include it */ 1247 | ddoc?: string | undefined; 1248 | 1249 | /** Only supports 'json', and it's also the default */ 1250 | type?: string | undefined; 1251 | }; 1252 | } 1253 | 1254 | interface CreateIndexResponse { 1255 | result: string; 1256 | } 1257 | 1258 | interface Index { 1259 | /** Name of the index, auto-generated if you don't include it */ 1260 | name: string; 1261 | 1262 | /** Design document name (i.e. the part after '_design/', auto-generated if you don't include it */ 1263 | ddoc: string | null; 1264 | 1265 | /** Only supports 'json' */ 1266 | type: string; 1267 | 1268 | def: { 1269 | fields: Array<{ 1270 | [fieldName: string]: string; 1271 | }>; 1272 | }; 1273 | } 1274 | 1275 | interface GetIndexesResponse { 1276 | indexes: Index[]; 1277 | } 1278 | 1279 | interface DeleteIndexOptions { 1280 | /** Name of the index */ 1281 | name: string; 1282 | 1283 | /** Design document name */ 1284 | ddoc: string; 1285 | 1286 | /** Default 'json' */ 1287 | type?: string | undefined; 1288 | } 1289 | 1290 | interface DeleteIndexResponse { 1291 | [propertyName: string]: any; 1292 | } 1293 | } 1294 | 1295 | interface Database { 1296 | /** Query the API to find some documents. */ 1297 | find( 1298 | request: Find.FindRequest, 1299 | callback: Core.Callback>, 1300 | ): void; 1301 | find( 1302 | request?: Find.FindRequest, 1303 | ): Promise>; 1304 | 1305 | /** Create an index if it doesn't exist, or do nothing if it already exists. */ 1306 | createIndex( 1307 | index: Find.CreateIndexOptions, 1308 | callback: Core.Callback>, 1309 | ): void; 1310 | createIndex( 1311 | index?: Find.CreateIndexOptions, 1312 | ): Promise>; 1313 | 1314 | /** Get a list of all the indexes you've created. Also tells you about the special _all_docs index, i.e. the default index on the _id field. */ 1315 | getIndexes(callback: Core.Callback>): void; 1316 | getIndexes(): Promise>; 1317 | 1318 | /** Delete an index and clean up any leftover data on the disk. */ 1319 | deleteIndex( 1320 | index: Find.DeleteIndexOptions, 1321 | callback: Core.Callback>, 1322 | ): void; 1323 | deleteIndex( 1324 | index?: Find.DeleteIndexOptions, 1325 | ): Promise>; 1326 | } 1327 | 1328 | // MapReduce plugin augmentation 1329 | 1330 | type BuiltInReducers = "_sum" | "_count" | "_stats"; 1331 | /** 1332 | * CouchDB-style Map function 1333 | * 1334 | * @param emit CouchDB does not support emit as an argument and maps defined this way will always run locally 1335 | */ 1336 | type Map = ( 1337 | doc: Content, 1338 | emit?: (key: any, value: Content | Result) => void, 1339 | ) => void; 1340 | /** 1341 | * CouchDB-style Reduction function 1342 | * 1343 | * @param keys From CouchDB documentation: Array of pairs of docid-key for related map function results; 1344 | * PouchDB may pass a simple array and also supports complex keys. 1345 | */ 1346 | type Reducer = ( 1347 | keys: any | null, 1348 | values: Content[] | Reduction[], 1349 | rereduce: boolean, 1350 | ) => Reduction[] | Reduction; 1351 | 1352 | interface Filter { 1353 | // Assume that Content | Reduction is enough leverage in most cases to handle intermediate map emits 1354 | map: Map; 1355 | reduce?: Reducer | BuiltInReducers | string | undefined; 1356 | } 1357 | 1358 | namespace Query { 1359 | interface Options { 1360 | /** Reduce function, or the string name of a built-in function: '_sum', '_count', or '_stats'. */ 1361 | reduce?: 1362 | | Reducer 1363 | | BuiltInReducers 1364 | | boolean 1365 | | undefined; 1366 | /** Include the document in each row in the doc field. */ 1367 | include_docs?: boolean | undefined; 1368 | /** Include conflicts in the _conflicts field of a doc. */ 1369 | conflicts?: boolean | undefined; 1370 | /** Include attachment data. */ 1371 | attachments?: boolean | undefined; 1372 | /** Return attachment data as Blobs/Buffers, instead of as base64-encoded strings. */ 1373 | binary?: boolean | undefined; 1374 | /** Get rows with keys in a certain range (inclusive/inclusive). */ 1375 | startkey?: any; 1376 | /** Get rows with keys in a certain range (inclusive/inclusive). */ 1377 | endkey?: any; 1378 | /** Include rows having a key equal to the given options.endkey. */ 1379 | inclusive_end?: boolean | undefined; 1380 | /** Maximum number of rows to return. */ 1381 | limit?: number | undefined; 1382 | /** Number of rows to skip before returning (warning: poor performance on IndexedDB/LevelDB!). */ 1383 | skip?: number | undefined; 1384 | /** Reverse the order of the output rows. */ 1385 | descending?: boolean | undefined; 1386 | /** Only return rows matching this key. */ 1387 | key?: any; 1388 | /** Array of keys to fetch in a single shot. */ 1389 | keys?: any[] | undefined; 1390 | /** True if you want the reduce function to group results by keys, rather than returning a single result. */ 1391 | group?: boolean | undefined; 1392 | /** 1393 | * Number of elements in a key to group by, assuming the keys are arrays. 1394 | * Defaults to the full length of the array. 1395 | */ 1396 | group_level?: number | undefined; 1397 | /** 1398 | * unspecified (default): Returns the latest results, waiting for the view to build if necessary. 1399 | * 'ok': Returns results immediately, even if they’re out-of-date. 1400 | * 'update_after': Returns results immediately, but kicks off a build afterwards. 1401 | */ 1402 | stale?: "ok" | "update_after" | undefined; 1403 | /** 1404 | * Include an update_seq value indicating which sequence id 1405 | * of the underlying database the view reflects. 1406 | */ 1407 | update_seq?: boolean | undefined; 1408 | } 1409 | 1410 | interface Response { 1411 | total_rows: number; 1412 | offset: number; 1413 | rows: Array<{ 1414 | id: any; 1415 | key: any; 1416 | value: any; 1417 | doc?: Core.ExistingDocument | undefined; 1418 | }>; 1419 | } 1420 | } 1421 | 1422 | interface Database { 1423 | /** 1424 | * Cleans up any stale map/reduce indexes. 1425 | * 1426 | * As design docs are deleted or modified, their associated index 1427 | * files(in CouchDB) or companion databases (in local PouchDBs) continue 1428 | * to take up space on disk. viewCleanup() removes these unnecessary 1429 | * index files. 1430 | */ 1431 | viewCleanup(callback: Core.Callback): void; 1432 | /** 1433 | * Cleans up any stale map/reduce indexes. 1434 | * 1435 | * As design docs are deleted or modified, their associated index 1436 | * files(in CouchDB) or companion databases (in local PouchDBs) continue 1437 | * to take up space on disk. viewCleanup() removes these unnecessary 1438 | * index files. 1439 | */ 1440 | viewCleanup(): Promise; 1441 | 1442 | /** 1443 | * Invoke a map/reduce function, which allows you to perform more complex queries 1444 | * on PouchDB than what you get with allDocs(). 1445 | */ 1446 | query( 1447 | fun: string | Map | Filter, 1448 | opts: Query.Options, 1449 | callback: Core.Callback>, 1450 | ): void; 1451 | /** 1452 | * Invoke a map/reduce function, which allows you to perform more complex queries 1453 | * on PouchDB than what you get with allDocs(). 1454 | */ 1455 | query( 1456 | fun: string | Map | Filter, 1457 | callback: Core.Callback>, 1458 | ): void; 1459 | /** 1460 | * Invoke a map/reduce function, which allows you to perform more complex queries 1461 | * on PouchDB than what you get with allDocs(). 1462 | */ 1463 | query( 1464 | fun: string | Map | Filter, 1465 | opts?: Query.Options, 1466 | ): Promise>; 1467 | } 1468 | 1469 | // Replication plugin augmentation 1470 | 1471 | namespace Replication { 1472 | interface ReplicateOptions { 1473 | /** If true, starts subscribing to future changes in the source database and continue replicating them. */ 1474 | live?: boolean | undefined; 1475 | 1476 | /** 1477 | * If true will attempt to retry replications in the case of failure (due to being offline), 1478 | * using a backoff algorithm that retries at longer and longer intervals until a connection is re-established, 1479 | * with a maximum delay of 10 minutes. Only applicable if options.live is also true. 1480 | */ 1481 | retry?: boolean | undefined; 1482 | 1483 | /** 1484 | * Reference a filter function from a design document to selectively get updates. 1485 | * To use a view function, pass '_view' here and provide a reference to the view function in options.view. 1486 | * See filtered changes for details. 1487 | */ 1488 | filter?: string | ((doc: any, params: any) => any) | undefined; 1489 | 1490 | /** Only show changes for docs with these ids (array of strings). */ 1491 | doc_ids?: string[] | undefined; 1492 | 1493 | /** 1494 | * Object containing properties that are passed to the filter function, e.g. {"foo:"bar"}, 1495 | * where "bar" will be available in the filter function as params.query.foo. 1496 | * To access the params, define your filter function like function (doc, params). 1497 | */ 1498 | query_params?: { [paramName: string]: any } | undefined; 1499 | 1500 | /** 1501 | * Specify a view function (e.g. 'design_doc_name/view_name' or 'view_name' as shorthand for 'view_name/view_name') to act as a filter. 1502 | * Documents counted as “passed” for a view filter if a map function emits at least one record for them. 1503 | * Note: options.filter must be set to '_view' for this option to work. 1504 | */ 1505 | view?: string | undefined; 1506 | 1507 | /** 1508 | * Filter using a query/pouchdb-find selector. Note: Selectors are not supported in CouchDB 1.x. 1509 | */ 1510 | selector?: Find.Selector | undefined; 1511 | 1512 | /** Replicate changes after the given sequence number. */ 1513 | since?: any; 1514 | 1515 | /** Configure the heartbeat supported by CouchDB which keeps the change connection alive. */ 1516 | heartbeat?: any; 1517 | 1518 | /** Request timeout (in milliseconds). */ 1519 | timeout?: number | false | undefined; 1520 | 1521 | /** 1522 | * Number of change feed items to process at a time. Defaults to 100. 1523 | * This affects the number of docs and attachments held in memory and the number sent at a time to the target server. 1524 | * You may need to adjust downward if targeting devices with low amounts of memory 1525 | * e.g. or if the documents and/or attachments are large in size or if there are many conflicted revisions. 1526 | * If your documents are small in size, then increasing this number will probably speed replication up. 1527 | */ 1528 | batch_size?: number | undefined; 1529 | 1530 | /** 1531 | * Number of batches to process at a time. Defaults to 10. 1532 | * This (along wtih batch_size) controls how many docs are kept in memory at a time, 1533 | * so the maximum docs in memory at once would equal batch_size × batches_limit. 1534 | */ 1535 | batches_limit?: number | undefined; 1536 | 1537 | /** 1538 | * Backoff function to be used in retry replication. This is a function that takes the current 1539 | * backoff as input (or 0 the first time) and returns a new backoff in milliseconds. 1540 | * You can use this to tweak when and how replication will try to reconnect to a remote database when the user goes offline. 1541 | * Defaults to a function that chooses a random backoff between 0 and 2 seconds and doubles every time it fails to connect. 1542 | * The default delay will never exceed 10 minutes. 1543 | */ 1544 | back_off_function?(delay: number): number; 1545 | 1546 | /** 1547 | * Can be used if you want to disable checkpoints on the source, target, or both. 1548 | * Setting this option to false will prevent writing checkpoints on both source and target. 1549 | * Setting it to source will only write checkpoints on the source. 1550 | * Setting it to target will only write checkpoints on the target. 1551 | */ 1552 | checkpoint?: boolean | "target" | "source" | undefined; 1553 | } 1554 | 1555 | interface ReplicationEventEmitter 1556 | extends EventEmitter { 1557 | on(event: "change", listener: (info: C) => any): this; 1558 | on( 1559 | event: "paused" | "denied" | "error", 1560 | listener: (err: {}) => any, 1561 | ): this; 1562 | on(event: "active", listener: () => any): this; 1563 | on(event: "complete", listener: (info: F) => any): this; 1564 | 1565 | cancel(): void; 1566 | } 1567 | 1568 | interface Replication extends 1569 | ReplicationEventEmitter< 1570 | Content, 1571 | ReplicationResult, 1572 | ReplicationResultComplete 1573 | >, 1574 | Promise> { 1575 | } 1576 | 1577 | interface ReplicationResult { 1578 | doc_write_failures: number; 1579 | docs_read: number; 1580 | docs_written: number; 1581 | last_seq: number; 1582 | start_time: Date; 1583 | ok: boolean; 1584 | errors: any[]; 1585 | docs: Array>; 1586 | } 1587 | 1588 | interface ReplicationResultComplete 1589 | extends ReplicationResult { 1590 | end_time: Date; 1591 | status: string; 1592 | } 1593 | 1594 | interface SyncOptions extends ReplicateOptions { 1595 | push?: ReplicateOptions | undefined; 1596 | pull?: ReplicateOptions | undefined; 1597 | } 1598 | 1599 | interface Sync extends 1600 | ReplicationEventEmitter< 1601 | Content, 1602 | SyncResult, 1603 | SyncResultComplete 1604 | >, 1605 | Promise> { 1606 | } 1607 | 1608 | interface SyncResult { 1609 | direction: "push" | "pull"; 1610 | change: ReplicationResult; 1611 | } 1612 | 1613 | interface SyncResultComplete { 1614 | push?: ReplicationResultComplete | undefined; 1615 | pull?: ReplicationResultComplete | undefined; 1616 | } 1617 | } 1618 | 1619 | interface Static { 1620 | /** 1621 | * Replicate data from source to target. Both the source and target can be a PouchDB instance or a string 1622 | * representing a CouchDB database URL or the name of a local PouchDB database. If options.live is true, 1623 | * then this will track future changes and also replicate them automatically. 1624 | * This method returns an object with the method cancel(), which you call if you want to cancel live replication. 1625 | */ 1626 | replicate( 1627 | source: string | Database, 1628 | target: string | Database, 1629 | options?: Replication.ReplicateOptions, 1630 | callback?: Core.Callback>, 1631 | ): Replication.Replication; 1632 | 1633 | /** 1634 | * Sync data from src to target and target to src. This is a convenience method for bidirectional data replication. 1635 | * 1636 | * In other words, this code: 1637 | * `PouchDB.replicate('mydb', 'http://localhost:5984/mydb')`; 1638 | * `PouchDB.replicate('http://localhost:5984/mydb', 'mydb')`; 1639 | * is equivalent to this code: 1640 | * `PouchDB.sync('mydb', 'http://localhost:5984/mydb')`; 1641 | */ 1642 | sync( 1643 | source: string | Database, 1644 | target: string | Database, 1645 | options?: Replication.SyncOptions, 1646 | callback?: Core.Callback>, 1647 | ): Replication.Sync; 1648 | } 1649 | 1650 | interface Database { 1651 | replicate: { 1652 | /** 1653 | * Replicate data to `target`. Both the source and target can be a PouchDB instance 1654 | * or a string representing a CouchDB database URL or the name of a local PouchDB database. 1655 | * If options.live is true, then this will track future changes and also replicate them automatically. 1656 | * This method returns an object with the method cancel(), which you call if you want to cancel live replication. 1657 | */ 1658 | to( 1659 | target: string | Database, 1660 | options?: Replication.ReplicateOptions, 1661 | callback?: Core.Callback< 1662 | Replication.ReplicationResultComplete 1663 | >, 1664 | ): Replication.Replication; 1665 | 1666 | /** 1667 | * Replicate data from `source`. Both the source and target can be a PouchDB instance 1668 | * or a string representing a CouchDB database URL or the name of a local PouchDB database. 1669 | * If options.live is true, then this will track future changes and also replicate them automatically. 1670 | * This method returns an object with the method cancel(), which you call if you want to cancel live replication. 1671 | */ 1672 | from( 1673 | source: string | Database, 1674 | options?: Replication.ReplicateOptions, 1675 | callback?: Core.Callback< 1676 | Replication.ReplicationResultComplete 1677 | >, 1678 | ): Replication.Replication; 1679 | }; 1680 | 1681 | /** 1682 | * Sync data from src to target and target to src. This is a convenience method for bidirectional data replication. 1683 | * 1684 | * In other words, this code: 1685 | * `PouchDB.replicate('mydb', 'http://localhost:5984/mydb')`; 1686 | * `PouchDB.replicate('http://localhost:5984/mydb', 'mydb')`; 1687 | * is equivalent to this code: 1688 | * `PouchDB.sync('mydb', 'http://localhost:5984/mydb')`; 1689 | */ 1690 | sync( 1691 | remote: string | Database, 1692 | options?: Replication.SyncOptions, 1693 | callback?: Core.Callback>, 1694 | ): Replication.Sync; 1695 | } 1696 | 1697 | namespace Upsert { 1698 | type DiffFunc = (doc: T) => (Core.Document | false); 1699 | 1700 | interface Response extends Core.Response { 1701 | updated: boolean; 1702 | } 1703 | } 1704 | 1705 | interface Database { 1706 | /** Perform an upsert of a document using a difference function to provide the upsert algorithm. */ 1707 | upsert( 1708 | docId: string, 1709 | diffFunc: Upsert.DiffFunc>, 1710 | ): Promise; 1711 | upsert( 1712 | docId: string, 1713 | diffFunc: Upsert.DiffFunc>, 1714 | cb: Core.Callback, 1715 | ): void; 1716 | 1717 | /** Perform an upsert of a document using a shallow merge algorithm. Use `db.upsert` for more complex operations. */ 1718 | upsertAndMerge( 1719 | doc: Core.Document, 1720 | ): Promise; 1721 | upsertAndMerge( 1722 | doc: Core.Document, 1723 | cb: Core.Callback, 1724 | ): void; 1725 | 1726 | /** Perform an upsert of a document with a simple replace if exists. Use `db.upsert` for more complex operations. */ 1727 | upsertAndReplace( 1728 | doc: Core.Document, 1729 | ): Promise; 1730 | upsertAndReplace( 1731 | doc: Core.Document, 1732 | cb: Core.Callback, 1733 | ): void; 1734 | 1735 | /** Perform a put of a document only if the document does not already exist. */ 1736 | putIfNotExists( 1737 | doc: Core.Document, 1738 | ): Promise; 1739 | putIfNotExists( 1740 | doc: Core.Document, 1741 | cb: Core.Callback, 1742 | ): void; 1743 | putIfNotExists( 1744 | docId: string, 1745 | doc: Core.Document, 1746 | ): Promise; 1747 | putIfNotExists( 1748 | docId: string, 1749 | doc: Core.Document, 1750 | cb: Core.Callback, 1751 | ): void; 1752 | } 1753 | } 1754 | --------------------------------------------------------------------------------