/* THIS IS A GENERATED/BUNDLED FILE BY ESBUILD if you want to view the source, please visit the github repository of this plugin */ "use strict"; var __create = Object.create; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __getProtoOf = Object.getPrototypeOf; var __hasOwnProp = Object.prototype.hasOwnProperty; var __commonJS = (cb, mod) => function __require() { return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports; }; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod )); var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // node_modules/diff-match-patch/index.js var require_diff_match_patch = __commonJS({ "node_modules/diff-match-patch/index.js"(exports, module2) { var diff_match_patch4 = function() { this.Diff_Timeout = 1; this.Diff_EditCost = 4; this.Match_Threshold = 0.5; this.Match_Distance = 1e3; this.Patch_DeleteThreshold = 0.5; this.Patch_Margin = 4; this.Match_MaxBits = 32; }; var DIFF_DELETE5 = -1; var DIFF_INSERT5 = 1; var DIFF_EQUAL4 = 0; diff_match_patch4.Diff = function(op, text2) { return [op, text2]; }; diff_match_patch4.prototype.diff_main = function(text1, text2, opt_checklines, opt_deadline) { if (typeof opt_deadline == "undefined") { if (this.Diff_Timeout <= 0) { opt_deadline = Number.MAX_VALUE; } else { opt_deadline = new Date().getTime() + this.Diff_Timeout * 1e3; } } var deadline = opt_deadline; if (text1 == null || text2 == null) { throw new Error("Null input. (diff_main)"); } if (text1 == text2) { if (text1) { return [new diff_match_patch4.Diff(DIFF_EQUAL4, text1)]; } return []; } if (typeof opt_checklines == "undefined") { opt_checklines = true; } var checklines = opt_checklines; var commonlength = this.diff_commonPrefix(text1, text2); var commonprefix = text1.substring(0, commonlength); text1 = text1.substring(commonlength); text2 = text2.substring(commonlength); commonlength = this.diff_commonSuffix(text1, text2); var commonsuffix = text1.substring(text1.length - commonlength); text1 = text1.substring(0, text1.length - commonlength); text2 = text2.substring(0, text2.length - commonlength); var diffs = this.diff_compute_(text1, text2, checklines, deadline); if (commonprefix) { diffs.unshift(new diff_match_patch4.Diff(DIFF_EQUAL4, commonprefix)); } if (commonsuffix) { diffs.push(new diff_match_patch4.Diff(DIFF_EQUAL4, commonsuffix)); } this.diff_cleanupMerge(diffs); return diffs; }; diff_match_patch4.prototype.diff_compute_ = function(text1, text2, checklines, deadline) { var diffs; if (!text1) { return [new diff_match_patch4.Diff(DIFF_INSERT5, text2)]; } if (!text2) { return [new diff_match_patch4.Diff(DIFF_DELETE5, text1)]; } var longtext = text1.length > text2.length ? text1 : text2; var shorttext = text1.length > text2.length ? text2 : text1; var i = longtext.indexOf(shorttext); if (i != -1) { diffs = [ new diff_match_patch4.Diff(DIFF_INSERT5, longtext.substring(0, i)), new diff_match_patch4.Diff(DIFF_EQUAL4, shorttext), new diff_match_patch4.Diff( DIFF_INSERT5, longtext.substring(i + shorttext.length) ) ]; if (text1.length > text2.length) { diffs[0][0] = diffs[2][0] = DIFF_DELETE5; } return diffs; } if (shorttext.length == 1) { return [ new diff_match_patch4.Diff(DIFF_DELETE5, text1), new diff_match_patch4.Diff(DIFF_INSERT5, text2) ]; } var hm = this.diff_halfMatch_(text1, text2); if (hm) { var text1_a = hm[0]; var text1_b = hm[1]; var text2_a = hm[2]; var text2_b = hm[3]; var mid_common = hm[4]; var diffs_a = this.diff_main(text1_a, text2_a, checklines, deadline); var diffs_b = this.diff_main(text1_b, text2_b, checklines, deadline); return diffs_a.concat( [new diff_match_patch4.Diff(DIFF_EQUAL4, mid_common)], diffs_b ); } if (checklines && text1.length > 100 && text2.length > 100) { return this.diff_lineMode_(text1, text2, deadline); } return this.diff_bisect_(text1, text2, deadline); }; diff_match_patch4.prototype.diff_lineMode_ = function(text1, text2, deadline) { var a2 = this.diff_linesToChars_(text1, text2); text1 = a2.chars1; text2 = a2.chars2; var linearray = a2.lineArray; var diffs = this.diff_main(text1, text2, false, deadline); this.diff_charsToLines_(diffs, linearray); this.diff_cleanupSemantic(diffs); diffs.push(new diff_match_patch4.Diff(DIFF_EQUAL4, "")); var pointer = 0; var count_delete = 0; var count_insert = 0; var text_delete = ""; var text_insert = ""; while (pointer < diffs.length) { switch (diffs[pointer][0]) { case DIFF_INSERT5: count_insert++; text_insert += diffs[pointer][1]; break; case DIFF_DELETE5: count_delete++; text_delete += diffs[pointer][1]; break; case DIFF_EQUAL4: if (count_delete >= 1 && count_insert >= 1) { diffs.splice( pointer - count_delete - count_insert, count_delete + count_insert ); pointer = pointer - count_delete - count_insert; var subDiff = this.diff_main(text_delete, text_insert, false, deadline); for (var j = subDiff.length - 1; j >= 0; j--) { diffs.splice(pointer, 0, subDiff[j]); } pointer = pointer + subDiff.length; } count_insert = 0; count_delete = 0; text_delete = ""; text_insert = ""; break; } pointer++; } diffs.pop(); return diffs; }; diff_match_patch4.prototype.diff_bisect_ = function(text1, text2, deadline) { var text1_length = text1.length; var text2_length = text2.length; var max_d = Math.ceil((text1_length + text2_length) / 2); var v_offset = max_d; var v_length = 2 * max_d; var v1 = new Array(v_length); var v2 = new Array(v_length); for (var x = 0; x < v_length; x++) { v1[x] = -1; v2[x] = -1; } v1[v_offset + 1] = 0; v2[v_offset + 1] = 0; var delta = text1_length - text2_length; var front = delta % 2 != 0; var k1start = 0; var k1end = 0; var k2start = 0; var k2end = 0; for (var d = 0; d < max_d; d++) { if (new Date().getTime() > deadline) { break; } for (var k1 = -d + k1start; k1 <= d - k1end; k1 += 2) { var k1_offset = v_offset + k1; var x1; if (k1 == -d || k1 != d && v1[k1_offset - 1] < v1[k1_offset + 1]) { x1 = v1[k1_offset + 1]; } else { x1 = v1[k1_offset - 1] + 1; } var y1 = x1 - k1; while (x1 < text1_length && y1 < text2_length && text1.charAt(x1) == text2.charAt(y1)) { x1++; y1++; } v1[k1_offset] = x1; if (x1 > text1_length) { k1end += 2; } else if (y1 > text2_length) { k1start += 2; } else if (front) { var k2_offset = v_offset + delta - k1; if (k2_offset >= 0 && k2_offset < v_length && v2[k2_offset] != -1) { var x2 = text1_length - v2[k2_offset]; if (x1 >= x2) { return this.diff_bisectSplit_(text1, text2, x1, y1, deadline); } } } } for (var k2 = -d + k2start; k2 <= d - k2end; k2 += 2) { var k2_offset = v_offset + k2; var x2; if (k2 == -d || k2 != d && v2[k2_offset - 1] < v2[k2_offset + 1]) { x2 = v2[k2_offset + 1]; } else { x2 = v2[k2_offset - 1] + 1; } var y2 = x2 - k2; while (x2 < text1_length && y2 < text2_length && text1.charAt(text1_length - x2 - 1) == text2.charAt(text2_length - y2 - 1)) { x2++; y2++; } v2[k2_offset] = x2; if (x2 > text1_length) { k2end += 2; } else if (y2 > text2_length) { k2start += 2; } else if (!front) { var k1_offset = v_offset + delta - k2; if (k1_offset >= 0 && k1_offset < v_length && v1[k1_offset] != -1) { var x1 = v1[k1_offset]; var y1 = v_offset + x1 - k1_offset; x2 = text1_length - x2; if (x1 >= x2) { return this.diff_bisectSplit_(text1, text2, x1, y1, deadline); } } } } } return [ new diff_match_patch4.Diff(DIFF_DELETE5, text1), new diff_match_patch4.Diff(DIFF_INSERT5, text2) ]; }; diff_match_patch4.prototype.diff_bisectSplit_ = function(text1, text2, x, y, deadline) { var text1a = text1.substring(0, x); var text2a = text2.substring(0, y); var text1b = text1.substring(x); var text2b = text2.substring(y); var diffs = this.diff_main(text1a, text2a, false, deadline); var diffsb = this.diff_main(text1b, text2b, false, deadline); return diffs.concat(diffsb); }; diff_match_patch4.prototype.diff_linesToChars_ = function(text1, text2) { var lineArray = []; var lineHash = {}; lineArray[0] = ""; function diff_linesToCharsMunge_(text3) { var chars = ""; var lineStart = 0; var lineEnd = -1; var lineArrayLength = lineArray.length; while (lineEnd < text3.length - 1) { lineEnd = text3.indexOf("\n", lineStart); if (lineEnd == -1) { lineEnd = text3.length - 1; } var line = text3.substring(lineStart, lineEnd + 1); if (lineHash.hasOwnProperty ? lineHash.hasOwnProperty(line) : lineHash[line] !== void 0) { chars += String.fromCharCode(lineHash[line]); } else { if (lineArrayLength == maxLines) { line = text3.substring(lineStart); lineEnd = text3.length; } chars += String.fromCharCode(lineArrayLength); lineHash[line] = lineArrayLength; lineArray[lineArrayLength++] = line; } lineStart = lineEnd + 1; } return chars; } var maxLines = 4e4; var chars1 = diff_linesToCharsMunge_(text1); maxLines = 65535; var chars2 = diff_linesToCharsMunge_(text2); return { chars1, chars2, lineArray }; }; diff_match_patch4.prototype.diff_charsToLines_ = function(diffs, lineArray) { for (var i = 0; i < diffs.length; i++) { var chars = diffs[i][1]; var text2 = []; for (var j = 0; j < chars.length; j++) { text2[j] = lineArray[chars.charCodeAt(j)]; } diffs[i][1] = text2.join(""); } }; diff_match_patch4.prototype.diff_commonPrefix = function(text1, text2) { if (!text1 || !text2 || text1.charAt(0) != text2.charAt(0)) { return 0; } var pointermin = 0; var pointermax = Math.min(text1.length, text2.length); var pointermid = pointermax; var pointerstart = 0; while (pointermin < pointermid) { if (text1.substring(pointerstart, pointermid) == text2.substring(pointerstart, pointermid)) { pointermin = pointermid; pointerstart = pointermin; } else { pointermax = pointermid; } pointermid = Math.floor((pointermax - pointermin) / 2 + pointermin); } return pointermid; }; diff_match_patch4.prototype.diff_commonSuffix = function(text1, text2) { if (!text1 || !text2 || text1.charAt(text1.length - 1) != text2.charAt(text2.length - 1)) { return 0; } var pointermin = 0; var pointermax = Math.min(text1.length, text2.length); var pointermid = pointermax; var pointerend = 0; while (pointermin < pointermid) { if (text1.substring(text1.length - pointermid, text1.length - pointerend) == text2.substring(text2.length - pointermid, text2.length - pointerend)) { pointermin = pointermid; pointerend = pointermin; } else { pointermax = pointermid; } pointermid = Math.floor((pointermax - pointermin) / 2 + pointermin); } return pointermid; }; diff_match_patch4.prototype.diff_commonOverlap_ = function(text1, text2) { var text1_length = text1.length; var text2_length = text2.length; if (text1_length == 0 || text2_length == 0) { return 0; } if (text1_length > text2_length) { text1 = text1.substring(text1_length - text2_length); } else if (text1_length < text2_length) { text2 = text2.substring(0, text1_length); } var text_length = Math.min(text1_length, text2_length); if (text1 == text2) { return text_length; } var best = 0; var length = 1; while (true) { var pattern = text1.substring(text_length - length); var found = text2.indexOf(pattern); if (found == -1) { return best; } length += found; if (found == 0 || text1.substring(text_length - length) == text2.substring(0, length)) { best = length; length++; } } }; diff_match_patch4.prototype.diff_halfMatch_ = function(text1, text2) { if (this.Diff_Timeout <= 0) { return null; } var longtext = text1.length > text2.length ? text1 : text2; var shorttext = text1.length > text2.length ? text2 : text1; if (longtext.length < 4 || shorttext.length * 2 < longtext.length) { return null; } var dmp = this; function diff_halfMatchI_(longtext2, shorttext2, i) { var seed = longtext2.substring(i, i + Math.floor(longtext2.length / 4)); var j = -1; var best_common = ""; var best_longtext_a, best_longtext_b, best_shorttext_a, best_shorttext_b; while ((j = shorttext2.indexOf(seed, j + 1)) != -1) { var prefixLength = dmp.diff_commonPrefix( longtext2.substring(i), shorttext2.substring(j) ); var suffixLength = dmp.diff_commonSuffix( longtext2.substring(0, i), shorttext2.substring(0, j) ); if (best_common.length < suffixLength + prefixLength) { best_common = shorttext2.substring(j - suffixLength, j) + shorttext2.substring(j, j + prefixLength); best_longtext_a = longtext2.substring(0, i - suffixLength); best_longtext_b = longtext2.substring(i + prefixLength); best_shorttext_a = shorttext2.substring(0, j - suffixLength); best_shorttext_b = shorttext2.substring(j + prefixLength); } } if (best_common.length * 2 >= longtext2.length) { return [ best_longtext_a, best_longtext_b, best_shorttext_a, best_shorttext_b, best_common ]; } else { return null; } } var hm1 = diff_halfMatchI_( longtext, shorttext, Math.ceil(longtext.length / 4) ); var hm2 = diff_halfMatchI_( longtext, shorttext, Math.ceil(longtext.length / 2) ); var hm; if (!hm1 && !hm2) { return null; } else if (!hm2) { hm = hm1; } else if (!hm1) { hm = hm2; } else { hm = hm1[4].length > hm2[4].length ? hm1 : hm2; } var text1_a, text1_b, text2_a, text2_b; if (text1.length > text2.length) { text1_a = hm[0]; text1_b = hm[1]; text2_a = hm[2]; text2_b = hm[3]; } else { text2_a = hm[0]; text2_b = hm[1]; text1_a = hm[2]; text1_b = hm[3]; } var mid_common = hm[4]; return [text1_a, text1_b, text2_a, text2_b, mid_common]; }; diff_match_patch4.prototype.diff_cleanupSemantic = function(diffs) { var changes3 = false; var equalities = []; var equalitiesLength = 0; var lastEquality = null; var pointer = 0; var length_insertions1 = 0; var length_deletions1 = 0; var length_insertions2 = 0; var length_deletions2 = 0; while (pointer < diffs.length) { if (diffs[pointer][0] == DIFF_EQUAL4) { equalities[equalitiesLength++] = pointer; length_insertions1 = length_insertions2; length_deletions1 = length_deletions2; length_insertions2 = 0; length_deletions2 = 0; lastEquality = diffs[pointer][1]; } else { if (diffs[pointer][0] == DIFF_INSERT5) { length_insertions2 += diffs[pointer][1].length; } else { length_deletions2 += diffs[pointer][1].length; } if (lastEquality && lastEquality.length <= Math.max(length_insertions1, length_deletions1) && lastEquality.length <= Math.max( length_insertions2, length_deletions2 )) { diffs.splice( equalities[equalitiesLength - 1], 0, new diff_match_patch4.Diff(DIFF_DELETE5, lastEquality) ); diffs[equalities[equalitiesLength - 1] + 1][0] = DIFF_INSERT5; equalitiesLength--; equalitiesLength--; pointer = equalitiesLength > 0 ? equalities[equalitiesLength - 1] : -1; length_insertions1 = 0; length_deletions1 = 0; length_insertions2 = 0; length_deletions2 = 0; lastEquality = null; changes3 = true; } } pointer++; } if (changes3) { this.diff_cleanupMerge(diffs); } this.diff_cleanupSemanticLossless(diffs); pointer = 1; while (pointer < diffs.length) { if (diffs[pointer - 1][0] == DIFF_DELETE5 && diffs[pointer][0] == DIFF_INSERT5) { var deletion = diffs[pointer - 1][1]; var insertion = diffs[pointer][1]; var overlap_length1 = this.diff_commonOverlap_(deletion, insertion); var overlap_length2 = this.diff_commonOverlap_(insertion, deletion); if (overlap_length1 >= overlap_length2) { if (overlap_length1 >= deletion.length / 2 || overlap_length1 >= insertion.length / 2) { diffs.splice(pointer, 0, new diff_match_patch4.Diff( DIFF_EQUAL4, insertion.substring(0, overlap_length1) )); diffs[pointer - 1][1] = deletion.substring(0, deletion.length - overlap_length1); diffs[pointer + 1][1] = insertion.substring(overlap_length1); pointer++; } } else { if (overlap_length2 >= deletion.length / 2 || overlap_length2 >= insertion.length / 2) { diffs.splice(pointer, 0, new diff_match_patch4.Diff( DIFF_EQUAL4, deletion.substring(0, overlap_length2) )); diffs[pointer - 1][0] = DIFF_INSERT5; diffs[pointer - 1][1] = insertion.substring(0, insertion.length - overlap_length2); diffs[pointer + 1][0] = DIFF_DELETE5; diffs[pointer + 1][1] = deletion.substring(overlap_length2); pointer++; } } pointer++; } pointer++; } }; diff_match_patch4.prototype.diff_cleanupSemanticLossless = function(diffs) { function diff_cleanupSemanticScore_(one, two) { if (!one || !two) { return 6; } var char1 = one.charAt(one.length - 1); var char2 = two.charAt(0); var nonAlphaNumeric1 = char1.match(diff_match_patch4.nonAlphaNumericRegex_); var nonAlphaNumeric2 = char2.match(diff_match_patch4.nonAlphaNumericRegex_); var whitespace1 = nonAlphaNumeric1 && char1.match(diff_match_patch4.whitespaceRegex_); var whitespace2 = nonAlphaNumeric2 && char2.match(diff_match_patch4.whitespaceRegex_); var lineBreak1 = whitespace1 && char1.match(diff_match_patch4.linebreakRegex_); var lineBreak2 = whitespace2 && char2.match(diff_match_patch4.linebreakRegex_); var blankLine1 = lineBreak1 && one.match(diff_match_patch4.blanklineEndRegex_); var blankLine2 = lineBreak2 && two.match(diff_match_patch4.blanklineStartRegex_); if (blankLine1 || blankLine2) { return 5; } else if (lineBreak1 || lineBreak2) { return 4; } else if (nonAlphaNumeric1 && !whitespace1 && whitespace2) { return 3; } else if (whitespace1 || whitespace2) { return 2; } else if (nonAlphaNumeric1 || nonAlphaNumeric2) { return 1; } return 0; } var pointer = 1; while (pointer < diffs.length - 1) { if (diffs[pointer - 1][0] == DIFF_EQUAL4 && diffs[pointer + 1][0] == DIFF_EQUAL4) { var equality1 = diffs[pointer - 1][1]; var edit = diffs[pointer][1]; var equality2 = diffs[pointer + 1][1]; var commonOffset = this.diff_commonSuffix(equality1, edit); if (commonOffset) { var commonString = edit.substring(edit.length - commonOffset); equality1 = equality1.substring(0, equality1.length - commonOffset); edit = commonString + edit.substring(0, edit.length - commonOffset); equality2 = commonString + equality2; } var bestEquality1 = equality1; var bestEdit = edit; var bestEquality2 = equality2; var bestScore = diff_cleanupSemanticScore_(equality1, edit) + diff_cleanupSemanticScore_(edit, equality2); while (edit.charAt(0) === equality2.charAt(0)) { equality1 += edit.charAt(0); edit = edit.substring(1) + equality2.charAt(0); equality2 = equality2.substring(1); var score = diff_cleanupSemanticScore_(equality1, edit) + diff_cleanupSemanticScore_(edit, equality2); if (score >= bestScore) { bestScore = score; bestEquality1 = equality1; bestEdit = edit; bestEquality2 = equality2; } } if (diffs[pointer - 1][1] != bestEquality1) { if (bestEquality1) { diffs[pointer - 1][1] = bestEquality1; } else { diffs.splice(pointer - 1, 1); pointer--; } diffs[pointer][1] = bestEdit; if (bestEquality2) { diffs[pointer + 1][1] = bestEquality2; } else { diffs.splice(pointer + 1, 1); pointer--; } } } pointer++; } }; diff_match_patch4.nonAlphaNumericRegex_ = /[^a-zA-Z0-9]/; diff_match_patch4.whitespaceRegex_ = /\s/; diff_match_patch4.linebreakRegex_ = /[\r\n]/; diff_match_patch4.blanklineEndRegex_ = /\n\r?\n$/; diff_match_patch4.blanklineStartRegex_ = /^\r?\n\r?\n/; diff_match_patch4.prototype.diff_cleanupEfficiency = function(diffs) { var changes3 = false; var equalities = []; var equalitiesLength = 0; var lastEquality = null; var pointer = 0; var pre_ins = false; var pre_del = false; var post_ins = false; var post_del = false; while (pointer < diffs.length) { if (diffs[pointer][0] == DIFF_EQUAL4) { if (diffs[pointer][1].length < this.Diff_EditCost && (post_ins || post_del)) { equalities[equalitiesLength++] = pointer; pre_ins = post_ins; pre_del = post_del; lastEquality = diffs[pointer][1]; } else { equalitiesLength = 0; lastEquality = null; } post_ins = post_del = false; } else { if (diffs[pointer][0] == DIFF_DELETE5) { post_del = true; } else { post_ins = true; } if (lastEquality && (pre_ins && pre_del && post_ins && post_del || lastEquality.length < this.Diff_EditCost / 2 && pre_ins + pre_del + post_ins + post_del == 3)) { diffs.splice( equalities[equalitiesLength - 1], 0, new diff_match_patch4.Diff(DIFF_DELETE5, lastEquality) ); diffs[equalities[equalitiesLength - 1] + 1][0] = DIFF_INSERT5; equalitiesLength--; lastEquality = null; if (pre_ins && pre_del) { post_ins = post_del = true; equalitiesLength = 0; } else { equalitiesLength--; pointer = equalitiesLength > 0 ? equalities[equalitiesLength - 1] : -1; post_ins = post_del = false; } changes3 = true; } } pointer++; } if (changes3) { this.diff_cleanupMerge(diffs); } }; diff_match_patch4.prototype.diff_cleanupMerge = function(diffs) { diffs.push(new diff_match_patch4.Diff(DIFF_EQUAL4, "")); var pointer = 0; var count_delete = 0; var count_insert = 0; var text_delete = ""; var text_insert = ""; var commonlength; while (pointer < diffs.length) { switch (diffs[pointer][0]) { case DIFF_INSERT5: count_insert++; text_insert += diffs[pointer][1]; pointer++; break; case DIFF_DELETE5: count_delete++; text_delete += diffs[pointer][1]; pointer++; break; case DIFF_EQUAL4: if (count_delete + count_insert > 1) { if (count_delete !== 0 && count_insert !== 0) { commonlength = this.diff_commonPrefix(text_insert, text_delete); if (commonlength !== 0) { if (pointer - count_delete - count_insert > 0 && diffs[pointer - count_delete - count_insert - 1][0] == DIFF_EQUAL4) { diffs[pointer - count_delete - count_insert - 1][1] += text_insert.substring(0, commonlength); } else { diffs.splice(0, 0, new diff_match_patch4.Diff( DIFF_EQUAL4, text_insert.substring(0, commonlength) )); pointer++; } text_insert = text_insert.substring(commonlength); text_delete = text_delete.substring(commonlength); } commonlength = this.diff_commonSuffix(text_insert, text_delete); if (commonlength !== 0) { diffs[pointer][1] = text_insert.substring(text_insert.length - commonlength) + diffs[pointer][1]; text_insert = text_insert.substring(0, text_insert.length - commonlength); text_delete = text_delete.substring(0, text_delete.length - commonlength); } } pointer -= count_delete + count_insert; diffs.splice(pointer, count_delete + count_insert); if (text_delete.length) { diffs.splice( pointer, 0, new diff_match_patch4.Diff(DIFF_DELETE5, text_delete) ); pointer++; } if (text_insert.length) { diffs.splice( pointer, 0, new diff_match_patch4.Diff(DIFF_INSERT5, text_insert) ); pointer++; } pointer++; } else if (pointer !== 0 && diffs[pointer - 1][0] == DIFF_EQUAL4) { diffs[pointer - 1][1] += diffs[pointer][1]; diffs.splice(pointer, 1); } else { pointer++; } count_insert = 0; count_delete = 0; text_delete = ""; text_insert = ""; break; } } if (diffs[diffs.length - 1][1] === "") { diffs.pop(); } var changes3 = false; pointer = 1; while (pointer < diffs.length - 1) { if (diffs[pointer - 1][0] == DIFF_EQUAL4 && diffs[pointer + 1][0] == DIFF_EQUAL4) { if (diffs[pointer][1].substring(diffs[pointer][1].length - diffs[pointer - 1][1].length) == diffs[pointer - 1][1]) { diffs[pointer][1] = diffs[pointer - 1][1] + diffs[pointer][1].substring(0, diffs[pointer][1].length - diffs[pointer - 1][1].length); diffs[pointer + 1][1] = diffs[pointer - 1][1] + diffs[pointer + 1][1]; diffs.splice(pointer - 1, 1); changes3 = true; } else if (diffs[pointer][1].substring(0, diffs[pointer + 1][1].length) == diffs[pointer + 1][1]) { diffs[pointer - 1][1] += diffs[pointer + 1][1]; diffs[pointer][1] = diffs[pointer][1].substring(diffs[pointer + 1][1].length) + diffs[pointer + 1][1]; diffs.splice(pointer + 1, 1); changes3 = true; } } pointer++; } if (changes3) { this.diff_cleanupMerge(diffs); } }; diff_match_patch4.prototype.diff_xIndex = function(diffs, loc) { var chars1 = 0; var chars2 = 0; var last_chars1 = 0; var last_chars2 = 0; var x; for (x = 0; x < diffs.length; x++) { if (diffs[x][0] !== DIFF_INSERT5) { chars1 += diffs[x][1].length; } if (diffs[x][0] !== DIFF_DELETE5) { chars2 += diffs[x][1].length; } if (chars1 > loc) { break; } last_chars1 = chars1; last_chars2 = chars2; } if (diffs.length != x && diffs[x][0] === DIFF_DELETE5) { return last_chars2; } return last_chars2 + (loc - last_chars1); }; diff_match_patch4.prototype.diff_prettyHtml = function(diffs) { var html = []; var pattern_amp = /&/g; var pattern_lt = //g; var pattern_para = /\n/g; for (var x = 0; x < diffs.length; x++) { var op = diffs[x][0]; var data = diffs[x][1]; var text2 = data.replace(pattern_amp, "&").replace(pattern_lt, "<").replace(pattern_gt, ">").replace(pattern_para, "¶
"); switch (op) { case DIFF_INSERT5: html[x] = '' + text2 + ""; break; case DIFF_DELETE5: html[x] = '' + text2 + ""; break; case DIFF_EQUAL4: html[x] = "" + text2 + ""; break; } } return html.join(""); }; diff_match_patch4.prototype.diff_text1 = function(diffs) { var text2 = []; for (var x = 0; x < diffs.length; x++) { if (diffs[x][0] !== DIFF_INSERT5) { text2[x] = diffs[x][1]; } } return text2.join(""); }; diff_match_patch4.prototype.diff_text2 = function(diffs) { var text2 = []; for (var x = 0; x < diffs.length; x++) { if (diffs[x][0] !== DIFF_DELETE5) { text2[x] = diffs[x][1]; } } return text2.join(""); }; diff_match_patch4.prototype.diff_levenshtein = function(diffs) { var levenshtein = 0; var insertions = 0; var deletions = 0; for (var x = 0; x < diffs.length; x++) { var op = diffs[x][0]; var data = diffs[x][1]; switch (op) { case DIFF_INSERT5: insertions += data.length; break; case DIFF_DELETE5: deletions += data.length; break; case DIFF_EQUAL4: levenshtein += Math.max(insertions, deletions); insertions = 0; deletions = 0; break; } } levenshtein += Math.max(insertions, deletions); return levenshtein; }; diff_match_patch4.prototype.diff_toDelta = function(diffs) { var text2 = []; for (var x = 0; x < diffs.length; x++) { switch (diffs[x][0]) { case DIFF_INSERT5: text2[x] = "+" + encodeURI(diffs[x][1]); break; case DIFF_DELETE5: text2[x] = "-" + diffs[x][1].length; break; case DIFF_EQUAL4: text2[x] = "=" + diffs[x][1].length; break; } } return text2.join(" ").replace(/%20/g, " "); }; diff_match_patch4.prototype.diff_fromDelta = function(text1, delta) { var diffs = []; var diffsLength = 0; var pointer = 0; var tokens = delta.split(/\t/g); for (var x = 0; x < tokens.length; x++) { var param = tokens[x].substring(1); switch (tokens[x].charAt(0)) { case "+": try { diffs[diffsLength++] = new diff_match_patch4.Diff(DIFF_INSERT5, decodeURI(param)); } catch (ex) { throw new Error("Illegal escape in diff_fromDelta: " + param); } break; case "-": case "=": var n2 = parseInt(param, 10); if (isNaN(n2) || n2 < 0) { throw new Error("Invalid number in diff_fromDelta: " + param); } var text2 = text1.substring(pointer, pointer += n2); if (tokens[x].charAt(0) == "=") { diffs[diffsLength++] = new diff_match_patch4.Diff(DIFF_EQUAL4, text2); } else { diffs[diffsLength++] = new diff_match_patch4.Diff(DIFF_DELETE5, text2); } break; default: if (tokens[x]) { throw new Error("Invalid diff operation in diff_fromDelta: " + tokens[x]); } } } if (pointer != text1.length) { throw new Error("Delta length (" + pointer + ") does not equal source text length (" + text1.length + ")."); } return diffs; }; diff_match_patch4.prototype.match_main = function(text2, pattern, loc) { if (text2 == null || pattern == null || loc == null) { throw new Error("Null input. (match_main)"); } loc = Math.max(0, Math.min(loc, text2.length)); if (text2 == pattern) { return 0; } else if (!text2.length) { return -1; } else if (text2.substring(loc, loc + pattern.length) == pattern) { return loc; } else { return this.match_bitap_(text2, pattern, loc); } }; diff_match_patch4.prototype.match_bitap_ = function(text2, pattern, loc) { if (pattern.length > this.Match_MaxBits) { throw new Error("Pattern too long for this browser."); } var s = this.match_alphabet_(pattern); var dmp = this; function match_bitapScore_(e2, x) { var accuracy = e2 / pattern.length; var proximity = Math.abs(loc - x); if (!dmp.Match_Distance) { return proximity ? 1 : accuracy; } return accuracy + proximity / dmp.Match_Distance; } var score_threshold = this.Match_Threshold; var best_loc = text2.indexOf(pattern, loc); if (best_loc != -1) { score_threshold = Math.min(match_bitapScore_(0, best_loc), score_threshold); best_loc = text2.lastIndexOf(pattern, loc + pattern.length); if (best_loc != -1) { score_threshold = Math.min(match_bitapScore_(0, best_loc), score_threshold); } } var matchmask = 1 << pattern.length - 1; best_loc = -1; var bin_min, bin_mid; var bin_max = pattern.length + text2.length; var last_rd; for (var d = 0; d < pattern.length; d++) { bin_min = 0; bin_mid = bin_max; while (bin_min < bin_mid) { if (match_bitapScore_(d, loc + bin_mid) <= score_threshold) { bin_min = bin_mid; } else { bin_max = bin_mid; } bin_mid = Math.floor((bin_max - bin_min) / 2 + bin_min); } bin_max = bin_mid; var start = Math.max(1, loc - bin_mid + 1); var finish = Math.min(loc + bin_mid, text2.length) + pattern.length; var rd = Array(finish + 2); rd[finish + 1] = (1 << d) - 1; for (var j = finish; j >= start; j--) { var charMatch = s[text2.charAt(j - 1)]; if (d === 0) { rd[j] = (rd[j + 1] << 1 | 1) & charMatch; } else { rd[j] = (rd[j + 1] << 1 | 1) & charMatch | ((last_rd[j + 1] | last_rd[j]) << 1 | 1) | last_rd[j + 1]; } if (rd[j] & matchmask) { var score = match_bitapScore_(d, j - 1); if (score <= score_threshold) { score_threshold = score; best_loc = j - 1; if (best_loc > loc) { start = Math.max(1, 2 * loc - best_loc); } else { break; } } } } if (match_bitapScore_(d + 1, loc) > score_threshold) { break; } last_rd = rd; } return best_loc; }; diff_match_patch4.prototype.match_alphabet_ = function(pattern) { var s = {}; for (var i = 0; i < pattern.length; i++) { s[pattern.charAt(i)] = 0; } for (var i = 0; i < pattern.length; i++) { s[pattern.charAt(i)] |= 1 << pattern.length - i - 1; } return s; }; diff_match_patch4.prototype.patch_addContext_ = function(patch, text2) { if (text2.length == 0) { return; } if (patch.start2 === null) { throw Error("patch not initialized"); } var pattern = text2.substring(patch.start2, patch.start2 + patch.length1); var padding = 0; while (text2.indexOf(pattern) != text2.lastIndexOf(pattern) && pattern.length < this.Match_MaxBits - this.Patch_Margin - this.Patch_Margin) { padding += this.Patch_Margin; pattern = text2.substring( patch.start2 - padding, patch.start2 + patch.length1 + padding ); } padding += this.Patch_Margin; var prefix = text2.substring(patch.start2 - padding, patch.start2); if (prefix) { patch.diffs.unshift(new diff_match_patch4.Diff(DIFF_EQUAL4, prefix)); } var suffix = text2.substring( patch.start2 + patch.length1, patch.start2 + patch.length1 + padding ); if (suffix) { patch.diffs.push(new diff_match_patch4.Diff(DIFF_EQUAL4, suffix)); } patch.start1 -= prefix.length; patch.start2 -= prefix.length; patch.length1 += prefix.length + suffix.length; patch.length2 += prefix.length + suffix.length; }; diff_match_patch4.prototype.patch_make = function(a2, opt_b, opt_c) { var text1, diffs; if (typeof a2 == "string" && typeof opt_b == "string" && typeof opt_c == "undefined") { text1 = a2; diffs = this.diff_main(text1, opt_b, true); if (diffs.length > 2) { this.diff_cleanupSemantic(diffs); this.diff_cleanupEfficiency(diffs); } } else if (a2 && typeof a2 == "object" && typeof opt_b == "undefined" && typeof opt_c == "undefined") { diffs = a2; text1 = this.diff_text1(diffs); } else if (typeof a2 == "string" && opt_b && typeof opt_b == "object" && typeof opt_c == "undefined") { text1 = a2; diffs = opt_b; } else if (typeof a2 == "string" && typeof opt_b == "string" && opt_c && typeof opt_c == "object") { text1 = a2; diffs = opt_c; } else { throw new Error("Unknown call format to patch_make."); } if (diffs.length === 0) { return []; } var patches = []; var patch = new diff_match_patch4.patch_obj(); var patchDiffLength = 0; var char_count1 = 0; var char_count2 = 0; var prepatch_text = text1; var postpatch_text = text1; for (var x = 0; x < diffs.length; x++) { var diff_type = diffs[x][0]; var diff_text = diffs[x][1]; if (!patchDiffLength && diff_type !== DIFF_EQUAL4) { patch.start1 = char_count1; patch.start2 = char_count2; } switch (diff_type) { case DIFF_INSERT5: patch.diffs[patchDiffLength++] = diffs[x]; patch.length2 += diff_text.length; postpatch_text = postpatch_text.substring(0, char_count2) + diff_text + postpatch_text.substring(char_count2); break; case DIFF_DELETE5: patch.length1 += diff_text.length; patch.diffs[patchDiffLength++] = diffs[x]; postpatch_text = postpatch_text.substring(0, char_count2) + postpatch_text.substring(char_count2 + diff_text.length); break; case DIFF_EQUAL4: if (diff_text.length <= 2 * this.Patch_Margin && patchDiffLength && diffs.length != x + 1) { patch.diffs[patchDiffLength++] = diffs[x]; patch.length1 += diff_text.length; patch.length2 += diff_text.length; } else if (diff_text.length >= 2 * this.Patch_Margin) { if (patchDiffLength) { this.patch_addContext_(patch, prepatch_text); patches.push(patch); patch = new diff_match_patch4.patch_obj(); patchDiffLength = 0; prepatch_text = postpatch_text; char_count1 = char_count2; } } break; } if (diff_type !== DIFF_INSERT5) { char_count1 += diff_text.length; } if (diff_type !== DIFF_DELETE5) { char_count2 += diff_text.length; } } if (patchDiffLength) { this.patch_addContext_(patch, prepatch_text); patches.push(patch); } return patches; }; diff_match_patch4.prototype.patch_deepCopy = function(patches) { var patchesCopy = []; for (var x = 0; x < patches.length; x++) { var patch = patches[x]; var patchCopy = new diff_match_patch4.patch_obj(); patchCopy.diffs = []; for (var y = 0; y < patch.diffs.length; y++) { patchCopy.diffs[y] = new diff_match_patch4.Diff(patch.diffs[y][0], patch.diffs[y][1]); } patchCopy.start1 = patch.start1; patchCopy.start2 = patch.start2; patchCopy.length1 = patch.length1; patchCopy.length2 = patch.length2; patchesCopy[x] = patchCopy; } return patchesCopy; }; diff_match_patch4.prototype.patch_apply = function(patches, text2) { if (patches.length == 0) { return [text2, []]; } patches = this.patch_deepCopy(patches); var nullPadding = this.patch_addPadding(patches); text2 = nullPadding + text2 + nullPadding; this.patch_splitMax(patches); var delta = 0; var results = []; for (var x = 0; x < patches.length; x++) { var expected_loc = patches[x].start2 + delta; var text1 = this.diff_text1(patches[x].diffs); var start_loc; var end_loc = -1; if (text1.length > this.Match_MaxBits) { start_loc = this.match_main( text2, text1.substring(0, this.Match_MaxBits), expected_loc ); if (start_loc != -1) { end_loc = this.match_main( text2, text1.substring(text1.length - this.Match_MaxBits), expected_loc + text1.length - this.Match_MaxBits ); if (end_loc == -1 || start_loc >= end_loc) { start_loc = -1; } } } else { start_loc = this.match_main(text2, text1, expected_loc); } if (start_loc == -1) { results[x] = false; delta -= patches[x].length2 - patches[x].length1; } else { results[x] = true; delta = start_loc - expected_loc; var text22; if (end_loc == -1) { text22 = text2.substring(start_loc, start_loc + text1.length); } else { text22 = text2.substring(start_loc, end_loc + this.Match_MaxBits); } if (text1 == text22) { text2 = text2.substring(0, start_loc) + this.diff_text2(patches[x].diffs) + text2.substring(start_loc + text1.length); } else { var diffs = this.diff_main(text1, text22, false); if (text1.length > this.Match_MaxBits && this.diff_levenshtein(diffs) / text1.length > this.Patch_DeleteThreshold) { results[x] = false; } else { this.diff_cleanupSemanticLossless(diffs); var index1 = 0; var index22; for (var y = 0; y < patches[x].diffs.length; y++) { var mod = patches[x].diffs[y]; if (mod[0] !== DIFF_EQUAL4) { index22 = this.diff_xIndex(diffs, index1); } if (mod[0] === DIFF_INSERT5) { text2 = text2.substring(0, start_loc + index22) + mod[1] + text2.substring(start_loc + index22); } else if (mod[0] === DIFF_DELETE5) { text2 = text2.substring(0, start_loc + index22) + text2.substring(start_loc + this.diff_xIndex( diffs, index1 + mod[1].length )); } if (mod[0] !== DIFF_DELETE5) { index1 += mod[1].length; } } } } } } text2 = text2.substring(nullPadding.length, text2.length - nullPadding.length); return [text2, results]; }; diff_match_patch4.prototype.patch_addPadding = function(patches) { var paddingLength = this.Patch_Margin; var nullPadding = ""; for (var x = 1; x <= paddingLength; x++) { nullPadding += String.fromCharCode(x); } for (var x = 0; x < patches.length; x++) { patches[x].start1 += paddingLength; patches[x].start2 += paddingLength; } var patch = patches[0]; var diffs = patch.diffs; if (diffs.length == 0 || diffs[0][0] != DIFF_EQUAL4) { diffs.unshift(new diff_match_patch4.Diff(DIFF_EQUAL4, nullPadding)); patch.start1 -= paddingLength; patch.start2 -= paddingLength; patch.length1 += paddingLength; patch.length2 += paddingLength; } else if (paddingLength > diffs[0][1].length) { var extraLength = paddingLength - diffs[0][1].length; diffs[0][1] = nullPadding.substring(diffs[0][1].length) + diffs[0][1]; patch.start1 -= extraLength; patch.start2 -= extraLength; patch.length1 += extraLength; patch.length2 += extraLength; } patch = patches[patches.length - 1]; diffs = patch.diffs; if (diffs.length == 0 || diffs[diffs.length - 1][0] != DIFF_EQUAL4) { diffs.push(new diff_match_patch4.Diff(DIFF_EQUAL4, nullPadding)); patch.length1 += paddingLength; patch.length2 += paddingLength; } else if (paddingLength > diffs[diffs.length - 1][1].length) { var extraLength = paddingLength - diffs[diffs.length - 1][1].length; diffs[diffs.length - 1][1] += nullPadding.substring(0, extraLength); patch.length1 += extraLength; patch.length2 += extraLength; } return nullPadding; }; diff_match_patch4.prototype.patch_splitMax = function(patches) { var patch_size = this.Match_MaxBits; for (var x = 0; x < patches.length; x++) { if (patches[x].length1 <= patch_size) { continue; } var bigpatch = patches[x]; patches.splice(x--, 1); var start1 = bigpatch.start1; var start2 = bigpatch.start2; var precontext = ""; while (bigpatch.diffs.length !== 0) { var patch = new diff_match_patch4.patch_obj(); var empty2 = true; patch.start1 = start1 - precontext.length; patch.start2 = start2 - precontext.length; if (precontext !== "") { patch.length1 = patch.length2 = precontext.length; patch.diffs.push(new diff_match_patch4.Diff(DIFF_EQUAL4, precontext)); } while (bigpatch.diffs.length !== 0 && patch.length1 < patch_size - this.Patch_Margin) { var diff_type = bigpatch.diffs[0][0]; var diff_text = bigpatch.diffs[0][1]; if (diff_type === DIFF_INSERT5) { patch.length2 += diff_text.length; start2 += diff_text.length; patch.diffs.push(bigpatch.diffs.shift()); empty2 = false; } else if (diff_type === DIFF_DELETE5 && patch.diffs.length == 1 && patch.diffs[0][0] == DIFF_EQUAL4 && diff_text.length > 2 * patch_size) { patch.length1 += diff_text.length; start1 += diff_text.length; empty2 = false; patch.diffs.push(new diff_match_patch4.Diff(diff_type, diff_text)); bigpatch.diffs.shift(); } else { diff_text = diff_text.substring( 0, patch_size - patch.length1 - this.Patch_Margin ); patch.length1 += diff_text.length; start1 += diff_text.length; if (diff_type === DIFF_EQUAL4) { patch.length2 += diff_text.length; start2 += diff_text.length; } else { empty2 = false; } patch.diffs.push(new diff_match_patch4.Diff(diff_type, diff_text)); if (diff_text == bigpatch.diffs[0][1]) { bigpatch.diffs.shift(); } else { bigpatch.diffs[0][1] = bigpatch.diffs[0][1].substring(diff_text.length); } } } precontext = this.diff_text2(patch.diffs); precontext = precontext.substring(precontext.length - this.Patch_Margin); var postcontext = this.diff_text1(bigpatch.diffs).substring(0, this.Patch_Margin); if (postcontext !== "") { patch.length1 += postcontext.length; patch.length2 += postcontext.length; if (patch.diffs.length !== 0 && patch.diffs[patch.diffs.length - 1][0] === DIFF_EQUAL4) { patch.diffs[patch.diffs.length - 1][1] += postcontext; } else { patch.diffs.push(new diff_match_patch4.Diff(DIFF_EQUAL4, postcontext)); } } if (!empty2) { patches.splice(++x, 0, patch); } } } }; diff_match_patch4.prototype.patch_toText = function(patches) { var text2 = []; for (var x = 0; x < patches.length; x++) { text2[x] = patches[x]; } return text2.join(""); }; diff_match_patch4.prototype.patch_fromText = function(textline) { var patches = []; if (!textline) { return patches; } var text2 = textline.split("\n"); var textPointer = 0; var patchHeader = /^@@ -(\d+),?(\d*) \+(\d+),?(\d*) @@$/; while (textPointer < text2.length) { var m = text2[textPointer].match(patchHeader); if (!m) { throw new Error("Invalid patch string: " + text2[textPointer]); } var patch = new diff_match_patch4.patch_obj(); patches.push(patch); patch.start1 = parseInt(m[1], 10); if (m[2] === "") { patch.start1--; patch.length1 = 1; } else if (m[2] == "0") { patch.length1 = 0; } else { patch.start1--; patch.length1 = parseInt(m[2], 10); } patch.start2 = parseInt(m[3], 10); if (m[4] === "") { patch.start2--; patch.length2 = 1; } else if (m[4] == "0") { patch.length2 = 0; } else { patch.start2--; patch.length2 = parseInt(m[4], 10); } textPointer++; while (textPointer < text2.length) { var sign = text2[textPointer].charAt(0); try { var line = decodeURI(text2[textPointer].substring(1)); } catch (ex) { throw new Error("Illegal escape in patch_fromText: " + line); } if (sign == "-") { patch.diffs.push(new diff_match_patch4.Diff(DIFF_DELETE5, line)); } else if (sign == "+") { patch.diffs.push(new diff_match_patch4.Diff(DIFF_INSERT5, line)); } else if (sign == " ") { patch.diffs.push(new diff_match_patch4.Diff(DIFF_EQUAL4, line)); } else if (sign == "@") { break; } else if (sign === "") { } else { throw new Error('Invalid patch mode "' + sign + '" in: ' + line); } textPointer++; } } return patches; }; diff_match_patch4.patch_obj = function() { this.diffs = []; this.start1 = null; this.start2 = null; this.length1 = 0; this.length2 = 0; }; diff_match_patch4.patch_obj.prototype.toString = function() { var coords1, coords2; if (this.length1 === 0) { coords1 = this.start1 + ",0"; } else if (this.length1 == 1) { coords1 = this.start1 + 1; } else { coords1 = this.start1 + 1 + "," + this.length1; } if (this.length2 === 0) { coords2 = this.start2 + ",0"; } else if (this.length2 == 1) { coords2 = this.start2 + 1; } else { coords2 = this.start2 + 1 + "," + this.length2; } var text2 = ["@@ -" + coords1 + " +" + coords2 + " @@\n"]; var op; for (var x = 0; x < this.diffs.length; x++) { switch (this.diffs[x][0]) { case DIFF_INSERT5: op = "+"; break; case DIFF_DELETE5: op = "-"; break; case DIFF_EQUAL4: op = " "; break; } text2[x + 1] = op + encodeURI(this.diffs[x][1]) + "\n"; } return text2.join("").replace(/%20/g, " "); }; module2.exports = diff_match_patch4; module2.exports["diff_match_patch"] = diff_match_patch4; module2.exports["DIFF_DELETE"] = DIFF_DELETE5; module2.exports["DIFF_INSERT"] = DIFF_INSERT5; module2.exports["DIFF_EQUAL"] = DIFF_EQUAL4; } }); // (disabled):node_modules/immediate/lib/nextTick var require_nextTick = __commonJS({ "(disabled):node_modules/immediate/lib/nextTick"() { } }); // node_modules/immediate/lib/queueMicrotask.js var require_queueMicrotask = __commonJS({ "node_modules/immediate/lib/queueMicrotask.js"(exports) { "use strict"; exports.test = function() { return typeof window.queueMicrotask === "function"; }; exports.install = function(func) { return function() { window.queueMicrotask(func); }; }; } }); // node_modules/immediate/lib/mutation.js var require_mutation = __commonJS({ "node_modules/immediate/lib/mutation.js"(exports) { "use strict"; var Mutation = window.MutationObserver || window.WebKitMutationObserver; exports.test = function() { return Mutation; }; exports.install = function(handle) { var called = 0; var observer = new Mutation(handle); var element2 = window.document.createTextNode(""); observer.observe(element2, { characterData: true }); return function() { element2.data = called = ++called % 2; }; }; } }); // node_modules/immediate/lib/messageChannel.js var require_messageChannel = __commonJS({ "node_modules/immediate/lib/messageChannel.js"(exports) { "use strict"; exports.test = function() { if (window.setImmediate) { return false; } return typeof window.MessageChannel !== "undefined"; }; exports.install = function(func) { var channel = new window.MessageChannel(); channel.port1.onmessage = func; return function() { channel.port2.postMessage(0); }; }; } }); // node_modules/immediate/lib/stateChange.js var require_stateChange = __commonJS({ "node_modules/immediate/lib/stateChange.js"(exports) { "use strict"; exports.test = function() { return "document" in window && "onreadystatechange" in window.document.createElement("script"); }; exports.install = function(handle) { return function() { var scriptEl = window.document.createElement("script"); scriptEl.onreadystatechange = function() { handle(); scriptEl.onreadystatechange = null; scriptEl.parentNode.removeChild(scriptEl); scriptEl = null; }; window.document.documentElement.appendChild(scriptEl); return handle; }; }; } }); // node_modules/immediate/lib/timeout.js var require_timeout = __commonJS({ "node_modules/immediate/lib/timeout.js"(exports) { "use strict"; exports.test = function() { return true; }; exports.install = function(t2) { return function() { setTimeout(t2, 0); }; }; } }); // node_modules/immediate/lib/index.js var require_lib = __commonJS({ "node_modules/immediate/lib/index.js"(exports, module2) { "use strict"; var types = [ require_nextTick(), require_queueMicrotask(), require_mutation(), require_messageChannel(), require_stateChange(), require_timeout() ]; var draining; var currentQueue; var queueIndex = -1; var queue2 = []; var scheduled = false; function cleanUpNextTick() { if (!draining || !currentQueue) { return; } draining = false; if (currentQueue.length) { queue2 = currentQueue.concat(queue2); } else { queueIndex = -1; } if (queue2.length) { nextTick(); } } function nextTick() { if (draining) { return; } scheduled = false; draining = true; var len2 = queue2.length; var timeout = setTimeout(cleanUpNextTick); while (len2) { currentQueue = queue2; queue2 = []; while (currentQueue && ++queueIndex < len2) { currentQueue[queueIndex].run(); } queueIndex = -1; len2 = queue2.length; } currentQueue = null; queueIndex = -1; draining = false; clearTimeout(timeout); } var scheduleDrain; var i = -1; var len = types.length; while (++i < len) { if (types[i] && types[i].test && types[i].test()) { scheduleDrain = types[i].install(nextTick); break; } } function Item(fun, array) { this.fun = fun; this.array = array; } Item.prototype.run = function() { var fun = this.fun; var array = this.array; switch (array.length) { case 0: return fun(); case 1: return fun(array[0]); case 2: return fun(array[0], array[1]); case 3: return fun(array[0], array[1], array[2]); default: return fun.apply(null, array); } }; module2.exports = immediate2; function immediate2(task) { var args = new Array(arguments.length - 1); if (arguments.length > 1) { for (var i2 = 1; i2 < arguments.length; i2++) { args[i2 - 1] = arguments[i2]; } } queue2.push(new Item(task, args)); if (!scheduled && !draining) { scheduled = true; scheduleDrain(); } } } }); // node_modules/events/events.js var require_events = __commonJS({ "node_modules/events/events.js"(exports, module2) { "use strict"; var R = typeof Reflect === "object" ? Reflect : null; var ReflectApply = R && typeof R.apply === "function" ? R.apply : function ReflectApply2(target, receiver, args) { return Function.prototype.apply.call(target, receiver, args); }; var ReflectOwnKeys; if (R && typeof R.ownKeys === "function") { ReflectOwnKeys = R.ownKeys; } else if (Object.getOwnPropertySymbols) { ReflectOwnKeys = function ReflectOwnKeys2(target) { return Object.getOwnPropertyNames(target).concat(Object.getOwnPropertySymbols(target)); }; } else { ReflectOwnKeys = function ReflectOwnKeys2(target) { return Object.getOwnPropertyNames(target); }; } function ProcessEmitWarning(warning) { if (console && console.warn) console.warn(warning); } var NumberIsNaN = Number.isNaN || function NumberIsNaN2(value) { return value !== value; }; function EventEmitter2() { EventEmitter2.init.call(this); } module2.exports = EventEmitter2; module2.exports.once = once2; EventEmitter2.EventEmitter = EventEmitter2; EventEmitter2.prototype._events = void 0; EventEmitter2.prototype._eventsCount = 0; EventEmitter2.prototype._maxListeners = void 0; var defaultMaxListeners = 10; function checkListener(listener) { if (typeof listener !== "function") { throw new TypeError('The "listener" argument must be of type Function. Received type ' + typeof listener); } } Object.defineProperty(EventEmitter2, "defaultMaxListeners", { enumerable: true, get: function() { return defaultMaxListeners; }, set: function(arg) { if (typeof arg !== "number" || arg < 0 || NumberIsNaN(arg)) { throw new RangeError('The value of "defaultMaxListeners" is out of range. It must be a non-negative number. Received ' + arg + "."); } defaultMaxListeners = arg; } }); EventEmitter2.init = function() { if (this._events === void 0 || this._events === Object.getPrototypeOf(this)._events) { this._events = /* @__PURE__ */ Object.create(null); this._eventsCount = 0; } this._maxListeners = this._maxListeners || void 0; }; EventEmitter2.prototype.setMaxListeners = function setMaxListeners(n2) { if (typeof n2 !== "number" || n2 < 0 || NumberIsNaN(n2)) { throw new RangeError('The value of "n" is out of range. It must be a non-negative number. Received ' + n2 + "."); } this._maxListeners = n2; return this; }; function _getMaxListeners(that) { if (that._maxListeners === void 0) return EventEmitter2.defaultMaxListeners; return that._maxListeners; } EventEmitter2.prototype.getMaxListeners = function getMaxListeners() { return _getMaxListeners(this); }; EventEmitter2.prototype.emit = function emit(type) { var args = []; for (var i = 1; i < arguments.length; i++) args.push(arguments[i]); var doError = type === "error"; var events = this._events; if (events !== void 0) doError = doError && events.error === void 0; else if (!doError) return false; if (doError) { var er; if (args.length > 0) er = args[0]; if (er instanceof Error) { throw er; } var err = new Error("Unhandled error." + (er ? " (" + er.message + ")" : "")); err.context = er; throw err; } var handler = events[type]; if (handler === void 0) return false; if (typeof handler === "function") { ReflectApply(handler, this, args); } else { var len = handler.length; var listeners = arrayClone(handler, len); for (var i = 0; i < len; ++i) ReflectApply(listeners[i], this, args); } return true; }; function _addListener(target, type, listener, prepend) { var m; var events; var existing; checkListener(listener); events = target._events; if (events === void 0) { events = target._events = /* @__PURE__ */ Object.create(null); target._eventsCount = 0; } else { if (events.newListener !== void 0) { target.emit( "newListener", type, listener.listener ? listener.listener : listener ); events = target._events; } existing = events[type]; } if (existing === void 0) { existing = events[type] = listener; ++target._eventsCount; } else { if (typeof existing === "function") { existing = events[type] = prepend ? [listener, existing] : [existing, listener]; } else if (prepend) { existing.unshift(listener); } else { existing.push(listener); } m = _getMaxListeners(target); if (m > 0 && existing.length > m && !existing.warned) { existing.warned = true; var w = new Error("Possible EventEmitter memory leak detected. " + existing.length + " " + String(type) + " listeners added. Use emitter.setMaxListeners() to increase limit"); w.name = "MaxListenersExceededWarning"; w.emitter = target; w.type = type; w.count = existing.length; ProcessEmitWarning(w); } } return target; } EventEmitter2.prototype.addListener = function addListener(type, listener) { return _addListener(this, type, listener, false); }; EventEmitter2.prototype.on = EventEmitter2.prototype.addListener; EventEmitter2.prototype.prependListener = function prependListener(type, listener) { return _addListener(this, type, listener, true); }; function onceWrapper() { if (!this.fired) { this.target.removeListener(this.type, this.wrapFn); this.fired = true; if (arguments.length === 0) return this.listener.call(this.target); return this.listener.apply(this.target, arguments); } } function _onceWrap(target, type, listener) { var state = { fired: false, wrapFn: void 0, target, type, listener }; var wrapped = onceWrapper.bind(state); wrapped.listener = listener; state.wrapFn = wrapped; return wrapped; } EventEmitter2.prototype.once = function once3(type, listener) { checkListener(listener); this.on(type, _onceWrap(this, type, listener)); return this; }; EventEmitter2.prototype.prependOnceListener = function prependOnceListener(type, listener) { checkListener(listener); this.prependListener(type, _onceWrap(this, type, listener)); return this; }; EventEmitter2.prototype.removeListener = function removeListener(type, listener) { var list, events, position, i, originalListener; checkListener(listener); events = this._events; if (events === void 0) return this; list = events[type]; if (list === void 0) return this; if (list === listener || list.listener === listener) { if (--this._eventsCount === 0) this._events = /* @__PURE__ */ Object.create(null); else { delete events[type]; if (events.removeListener) this.emit("removeListener", type, list.listener || listener); } } else if (typeof list !== "function") { position = -1; for (i = list.length - 1; i >= 0; i--) { if (list[i] === listener || list[i].listener === listener) { originalListener = list[i].listener; position = i; break; } } if (position < 0) return this; if (position === 0) list.shift(); else { spliceOne(list, position); } if (list.length === 1) events[type] = list[0]; if (events.removeListener !== void 0) this.emit("removeListener", type, originalListener || listener); } return this; }; EventEmitter2.prototype.off = EventEmitter2.prototype.removeListener; EventEmitter2.prototype.removeAllListeners = function removeAllListeners(type) { var listeners, events, i; events = this._events; if (events === void 0) return this; if (events.removeListener === void 0) { if (arguments.length === 0) { this._events = /* @__PURE__ */ Object.create(null); this._eventsCount = 0; } else if (events[type] !== void 0) { if (--this._eventsCount === 0) this._events = /* @__PURE__ */ Object.create(null); else delete events[type]; } return this; } if (arguments.length === 0) { var keys2 = Object.keys(events); var key; for (i = 0; i < keys2.length; ++i) { key = keys2[i]; if (key === "removeListener") continue; this.removeAllListeners(key); } this.removeAllListeners("removeListener"); this._events = /* @__PURE__ */ Object.create(null); this._eventsCount = 0; return this; } listeners = events[type]; if (typeof listeners === "function") { this.removeListener(type, listeners); } else if (listeners !== void 0) { for (i = listeners.length - 1; i >= 0; i--) { this.removeListener(type, listeners[i]); } } return this; }; function _listeners(target, type, unwrap2) { var events = target._events; if (events === void 0) return []; var evlistener = events[type]; if (evlistener === void 0) return []; if (typeof evlistener === "function") return unwrap2 ? [evlistener.listener || evlistener] : [evlistener]; return unwrap2 ? unwrapListeners(evlistener) : arrayClone(evlistener, evlistener.length); } EventEmitter2.prototype.listeners = function listeners(type) { return _listeners(this, type, true); }; EventEmitter2.prototype.rawListeners = function rawListeners(type) { return _listeners(this, type, false); }; EventEmitter2.listenerCount = function(emitter, type) { if (typeof emitter.listenerCount === "function") { return emitter.listenerCount(type); } else { return listenerCount2.call(emitter, type); } }; EventEmitter2.prototype.listenerCount = listenerCount2; function listenerCount2(type) { var events = this._events; if (events !== void 0) { var evlistener = events[type]; if (typeof evlistener === "function") { return 1; } else if (evlistener !== void 0) { return evlistener.length; } } return 0; } EventEmitter2.prototype.eventNames = function eventNames() { return this._eventsCount > 0 ? ReflectOwnKeys(this._events) : []; }; function arrayClone(arr, n2) { var copy = new Array(n2); for (var i = 0; i < n2; ++i) copy[i] = arr[i]; return copy; } function spliceOne(list, index5) { for (; index5 + 1 < list.length; index5++) list[index5] = list[index5 + 1]; list.pop(); } function unwrapListeners(arr) { var ret = new Array(arr.length); for (var i = 0; i < ret.length; ++i) { ret[i] = arr[i].listener || arr[i]; } return ret; } function once2(emitter, name) { return new Promise(function(resolve, reject) { function errorListener(err) { emitter.removeListener(name, resolver); reject(err); } function resolver() { if (typeof emitter.removeListener === "function") { emitter.removeListener("error", errorListener); } resolve([].slice.call(arguments)); } ; eventTargetAgnosticAddListener(emitter, name, resolver, { once: true }); if (name !== "error") { addErrorHandlerIfEventEmitter(emitter, errorListener, { once: true }); } }); } function addErrorHandlerIfEventEmitter(emitter, handler, flags) { if (typeof emitter.on === "function") { eventTargetAgnosticAddListener(emitter, "error", handler, flags); } } function eventTargetAgnosticAddListener(emitter, name, listener, flags) { if (typeof emitter.on === "function") { if (flags.once) { emitter.once(name, listener); } else { emitter.on(name, listener); } } else if (typeof emitter.addEventListener === "function") { emitter.addEventListener(name, function wrapListener(arg) { if (flags.once) { emitter.removeEventListener(name, wrapListener); } listener(arg); }); } else { throw new TypeError('The "emitter" argument must be of type EventEmitter. Received type ' + typeof emitter); } } } }); // node_modules/spark-md5/spark-md5.js var require_spark_md5 = __commonJS({ "node_modules/spark-md5/spark-md5.js"(exports, module2) { (function(factory) { if (typeof exports === "object") { module2.exports = factory(); } else if (typeof define === "function" && define.amd) { define(factory); } else { var glob; try { glob = window; } catch (e2) { glob = self; } glob.SparkMD5 = factory(); } })(function(undefined2) { "use strict"; var add32 = function(a2, b) { return a2 + b & 4294967295; }, hex_chr = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f"]; function cmn(q, a2, b, x, s, t2) { a2 = add32(add32(a2, q), add32(x, t2)); return add32(a2 << s | a2 >>> 32 - s, b); } function md5cycle(x, k) { var a2 = x[0], b = x[1], c = x[2], d = x[3]; a2 += (b & c | ~b & d) + k[0] - 680876936 | 0; a2 = (a2 << 7 | a2 >>> 25) + b | 0; d += (a2 & b | ~a2 & c) + k[1] - 389564586 | 0; d = (d << 12 | d >>> 20) + a2 | 0; c += (d & a2 | ~d & b) + k[2] + 606105819 | 0; c = (c << 17 | c >>> 15) + d | 0; b += (c & d | ~c & a2) + k[3] - 1044525330 | 0; b = (b << 22 | b >>> 10) + c | 0; a2 += (b & c | ~b & d) + k[4] - 176418897 | 0; a2 = (a2 << 7 | a2 >>> 25) + b | 0; d += (a2 & b | ~a2 & c) + k[5] + 1200080426 | 0; d = (d << 12 | d >>> 20) + a2 | 0; c += (d & a2 | ~d & b) + k[6] - 1473231341 | 0; c = (c << 17 | c >>> 15) + d | 0; b += (c & d | ~c & a2) + k[7] - 45705983 | 0; b = (b << 22 | b >>> 10) + c | 0; a2 += (b & c | ~b & d) + k[8] + 1770035416 | 0; a2 = (a2 << 7 | a2 >>> 25) + b | 0; d += (a2 & b | ~a2 & c) + k[9] - 1958414417 | 0; d = (d << 12 | d >>> 20) + a2 | 0; c += (d & a2 | ~d & b) + k[10] - 42063 | 0; c = (c << 17 | c >>> 15) + d | 0; b += (c & d | ~c & a2) + k[11] - 1990404162 | 0; b = (b << 22 | b >>> 10) + c | 0; a2 += (b & c | ~b & d) + k[12] + 1804603682 | 0; a2 = (a2 << 7 | a2 >>> 25) + b | 0; d += (a2 & b | ~a2 & c) + k[13] - 40341101 | 0; d = (d << 12 | d >>> 20) + a2 | 0; c += (d & a2 | ~d & b) + k[14] - 1502002290 | 0; c = (c << 17 | c >>> 15) + d | 0; b += (c & d | ~c & a2) + k[15] + 1236535329 | 0; b = (b << 22 | b >>> 10) + c | 0; a2 += (b & d | c & ~d) + k[1] - 165796510 | 0; a2 = (a2 << 5 | a2 >>> 27) + b | 0; d += (a2 & c | b & ~c) + k[6] - 1069501632 | 0; d = (d << 9 | d >>> 23) + a2 | 0; c += (d & b | a2 & ~b) + k[11] + 643717713 | 0; c = (c << 14 | c >>> 18) + d | 0; b += (c & a2 | d & ~a2) + k[0] - 373897302 | 0; b = (b << 20 | b >>> 12) + c | 0; a2 += (b & d | c & ~d) + k[5] - 701558691 | 0; a2 = (a2 << 5 | a2 >>> 27) + b | 0; d += (a2 & c | b & ~c) + k[10] + 38016083 | 0; d = (d << 9 | d >>> 23) + a2 | 0; c += (d & b | a2 & ~b) + k[15] - 660478335 | 0; c = (c << 14 | c >>> 18) + d | 0; b += (c & a2 | d & ~a2) + k[4] - 405537848 | 0; b = (b << 20 | b >>> 12) + c | 0; a2 += (b & d | c & ~d) + k[9] + 568446438 | 0; a2 = (a2 << 5 | a2 >>> 27) + b | 0; d += (a2 & c | b & ~c) + k[14] - 1019803690 | 0; d = (d << 9 | d >>> 23) + a2 | 0; c += (d & b | a2 & ~b) + k[3] - 187363961 | 0; c = (c << 14 | c >>> 18) + d | 0; b += (c & a2 | d & ~a2) + k[8] + 1163531501 | 0; b = (b << 20 | b >>> 12) + c | 0; a2 += (b & d | c & ~d) + k[13] - 1444681467 | 0; a2 = (a2 << 5 | a2 >>> 27) + b | 0; d += (a2 & c | b & ~c) + k[2] - 51403784 | 0; d = (d << 9 | d >>> 23) + a2 | 0; c += (d & b | a2 & ~b) + k[7] + 1735328473 | 0; c = (c << 14 | c >>> 18) + d | 0; b += (c & a2 | d & ~a2) + k[12] - 1926607734 | 0; b = (b << 20 | b >>> 12) + c | 0; a2 += (b ^ c ^ d) + k[5] - 378558 | 0; a2 = (a2 << 4 | a2 >>> 28) + b | 0; d += (a2 ^ b ^ c) + k[8] - 2022574463 | 0; d = (d << 11 | d >>> 21) + a2 | 0; c += (d ^ a2 ^ b) + k[11] + 1839030562 | 0; c = (c << 16 | c >>> 16) + d | 0; b += (c ^ d ^ a2) + k[14] - 35309556 | 0; b = (b << 23 | b >>> 9) + c | 0; a2 += (b ^ c ^ d) + k[1] - 1530992060 | 0; a2 = (a2 << 4 | a2 >>> 28) + b | 0; d += (a2 ^ b ^ c) + k[4] + 1272893353 | 0; d = (d << 11 | d >>> 21) + a2 | 0; c += (d ^ a2 ^ b) + k[7] - 155497632 | 0; c = (c << 16 | c >>> 16) + d | 0; b += (c ^ d ^ a2) + k[10] - 1094730640 | 0; b = (b << 23 | b >>> 9) + c | 0; a2 += (b ^ c ^ d) + k[13] + 681279174 | 0; a2 = (a2 << 4 | a2 >>> 28) + b | 0; d += (a2 ^ b ^ c) + k[0] - 358537222 | 0; d = (d << 11 | d >>> 21) + a2 | 0; c += (d ^ a2 ^ b) + k[3] - 722521979 | 0; c = (c << 16 | c >>> 16) + d | 0; b += (c ^ d ^ a2) + k[6] + 76029189 | 0; b = (b << 23 | b >>> 9) + c | 0; a2 += (b ^ c ^ d) + k[9] - 640364487 | 0; a2 = (a2 << 4 | a2 >>> 28) + b | 0; d += (a2 ^ b ^ c) + k[12] - 421815835 | 0; d = (d << 11 | d >>> 21) + a2 | 0; c += (d ^ a2 ^ b) + k[15] + 530742520 | 0; c = (c << 16 | c >>> 16) + d | 0; b += (c ^ d ^ a2) + k[2] - 995338651 | 0; b = (b << 23 | b >>> 9) + c | 0; a2 += (c ^ (b | ~d)) + k[0] - 198630844 | 0; a2 = (a2 << 6 | a2 >>> 26) + b | 0; d += (b ^ (a2 | ~c)) + k[7] + 1126891415 | 0; d = (d << 10 | d >>> 22) + a2 | 0; c += (a2 ^ (d | ~b)) + k[14] - 1416354905 | 0; c = (c << 15 | c >>> 17) + d | 0; b += (d ^ (c | ~a2)) + k[5] - 57434055 | 0; b = (b << 21 | b >>> 11) + c | 0; a2 += (c ^ (b | ~d)) + k[12] + 1700485571 | 0; a2 = (a2 << 6 | a2 >>> 26) + b | 0; d += (b ^ (a2 | ~c)) + k[3] - 1894986606 | 0; d = (d << 10 | d >>> 22) + a2 | 0; c += (a2 ^ (d | ~b)) + k[10] - 1051523 | 0; c = (c << 15 | c >>> 17) + d | 0; b += (d ^ (c | ~a2)) + k[1] - 2054922799 | 0; b = (b << 21 | b >>> 11) + c | 0; a2 += (c ^ (b | ~d)) + k[8] + 1873313359 | 0; a2 = (a2 << 6 | a2 >>> 26) + b | 0; d += (b ^ (a2 | ~c)) + k[15] - 30611744 | 0; d = (d << 10 | d >>> 22) + a2 | 0; c += (a2 ^ (d | ~b)) + k[6] - 1560198380 | 0; c = (c << 15 | c >>> 17) + d | 0; b += (d ^ (c | ~a2)) + k[13] + 1309151649 | 0; b = (b << 21 | b >>> 11) + c | 0; a2 += (c ^ (b | ~d)) + k[4] - 145523070 | 0; a2 = (a2 << 6 | a2 >>> 26) + b | 0; d += (b ^ (a2 | ~c)) + k[11] - 1120210379 | 0; d = (d << 10 | d >>> 22) + a2 | 0; c += (a2 ^ (d | ~b)) + k[2] + 718787259 | 0; c = (c << 15 | c >>> 17) + d | 0; b += (d ^ (c | ~a2)) + k[9] - 343485551 | 0; b = (b << 21 | b >>> 11) + c | 0; x[0] = a2 + x[0] | 0; x[1] = b + x[1] | 0; x[2] = c + x[2] | 0; x[3] = d + x[3] | 0; } function md5blk(s) { var md5blks = [], i; for (i = 0; i < 64; i += 4) { md5blks[i >> 2] = s.charCodeAt(i) + (s.charCodeAt(i + 1) << 8) + (s.charCodeAt(i + 2) << 16) + (s.charCodeAt(i + 3) << 24); } return md5blks; } function md5blk_array(a2) { var md5blks = [], i; for (i = 0; i < 64; i += 4) { md5blks[i >> 2] = a2[i] + (a2[i + 1] << 8) + (a2[i + 2] << 16) + (a2[i + 3] << 24); } return md5blks; } function md51(s) { var n2 = s.length, state = [1732584193, -271733879, -1732584194, 271733878], i, length, tail, tmp, lo, hi; for (i = 64; i <= n2; i += 64) { md5cycle(state, md5blk(s.substring(i - 64, i))); } s = s.substring(i - 64); length = s.length; tail = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; for (i = 0; i < length; i += 1) { tail[i >> 2] |= s.charCodeAt(i) << (i % 4 << 3); } tail[i >> 2] |= 128 << (i % 4 << 3); if (i > 55) { md5cycle(state, tail); for (i = 0; i < 16; i += 1) { tail[i] = 0; } } tmp = n2 * 8; tmp = tmp.toString(16).match(/(.*?)(.{0,8})$/); lo = parseInt(tmp[2], 16); hi = parseInt(tmp[1], 16) || 0; tail[14] = lo; tail[15] = hi; md5cycle(state, tail); return state; } function md51_array(a2) { var n2 = a2.length, state = [1732584193, -271733879, -1732584194, 271733878], i, length, tail, tmp, lo, hi; for (i = 64; i <= n2; i += 64) { md5cycle(state, md5blk_array(a2.subarray(i - 64, i))); } a2 = i - 64 < n2 ? a2.subarray(i - 64) : new Uint8Array(0); length = a2.length; tail = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; for (i = 0; i < length; i += 1) { tail[i >> 2] |= a2[i] << (i % 4 << 3); } tail[i >> 2] |= 128 << (i % 4 << 3); if (i > 55) { md5cycle(state, tail); for (i = 0; i < 16; i += 1) { tail[i] = 0; } } tmp = n2 * 8; tmp = tmp.toString(16).match(/(.*?)(.{0,8})$/); lo = parseInt(tmp[2], 16); hi = parseInt(tmp[1], 16) || 0; tail[14] = lo; tail[15] = hi; md5cycle(state, tail); return state; } function rhex(n2) { var s = "", j; for (j = 0; j < 4; j += 1) { s += hex_chr[n2 >> j * 8 + 4 & 15] + hex_chr[n2 >> j * 8 & 15]; } return s; } function hex(x) { var i; for (i = 0; i < x.length; i += 1) { x[i] = rhex(x[i]); } return x.join(""); } if (hex(md51("hello")) !== "5d41402abc4b2a76b9719d911017c592") { add32 = function(x, y) { var lsw = (x & 65535) + (y & 65535), msw = (x >> 16) + (y >> 16) + (lsw >> 16); return msw << 16 | lsw & 65535; }; } if (typeof ArrayBuffer !== "undefined" && !ArrayBuffer.prototype.slice) { (function() { function clamp(val, length) { val = val | 0 || 0; if (val < 0) { return Math.max(val + length, 0); } return Math.min(val, length); } ArrayBuffer.prototype.slice = function(from, to) { var length = this.byteLength, begin = clamp(from, length), end = length, num, target, targetArray, sourceArray; if (to !== undefined2) { end = clamp(to, length); } if (begin > end) { return new ArrayBuffer(0); } num = end - begin; target = new ArrayBuffer(num); targetArray = new Uint8Array(target); sourceArray = new Uint8Array(this, begin, num); targetArray.set(sourceArray); return target; }; })(); } function toUtf8(str) { if (/[\u0080-\uFFFF]/.test(str)) { str = unescape(encodeURIComponent(str)); } return str; } function utf8Str2ArrayBuffer(str, returnUInt8Array) { var length = str.length, buff = new ArrayBuffer(length), arr = new Uint8Array(buff), i; for (i = 0; i < length; i += 1) { arr[i] = str.charCodeAt(i); } return returnUInt8Array ? arr : buff; } function arrayBuffer2Utf8Str(buff) { return String.fromCharCode.apply(null, new Uint8Array(buff)); } function concatenateArrayBuffers(first, second, returnUInt8Array) { var result = new Uint8Array(first.byteLength + second.byteLength); result.set(new Uint8Array(first)); result.set(new Uint8Array(second), first.byteLength); return returnUInt8Array ? result : result.buffer; } function hexToBinaryString(hex2) { var bytes = [], length = hex2.length, x; for (x = 0; x < length - 1; x += 2) { bytes.push(parseInt(hex2.substr(x, 2), 16)); } return String.fromCharCode.apply(String, bytes); } function SparkMD5() { this.reset(); } SparkMD5.prototype.append = function(str) { this.appendBinary(toUtf8(str)); return this; }; SparkMD5.prototype.appendBinary = function(contents) { this._buff += contents; this._length += contents.length; var length = this._buff.length, i; for (i = 64; i <= length; i += 64) { md5cycle(this._hash, md5blk(this._buff.substring(i - 64, i))); } this._buff = this._buff.substring(i - 64); return this; }; SparkMD5.prototype.end = function(raw) { var buff = this._buff, length = buff.length, i, tail = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], ret; for (i = 0; i < length; i += 1) { tail[i >> 2] |= buff.charCodeAt(i) << (i % 4 << 3); } this._finish(tail, length); ret = hex(this._hash); if (raw) { ret = hexToBinaryString(ret); } this.reset(); return ret; }; SparkMD5.prototype.reset = function() { this._buff = ""; this._length = 0; this._hash = [1732584193, -271733879, -1732584194, 271733878]; return this; }; SparkMD5.prototype.getState = function() { return { buff: this._buff, length: this._length, hash: this._hash.slice() }; }; SparkMD5.prototype.setState = function(state) { this._buff = state.buff; this._length = state.length; this._hash = state.hash; return this; }; SparkMD5.prototype.destroy = function() { delete this._hash; delete this._buff; delete this._length; }; SparkMD5.prototype._finish = function(tail, length) { var i = length, tmp, lo, hi; tail[i >> 2] |= 128 << (i % 4 << 3); if (i > 55) { md5cycle(this._hash, tail); for (i = 0; i < 16; i += 1) { tail[i] = 0; } } tmp = this._length * 8; tmp = tmp.toString(16).match(/(.*?)(.{0,8})$/); lo = parseInt(tmp[2], 16); hi = parseInt(tmp[1], 16) || 0; tail[14] = lo; tail[15] = hi; md5cycle(this._hash, tail); }; SparkMD5.hash = function(str, raw) { return SparkMD5.hashBinary(toUtf8(str), raw); }; SparkMD5.hashBinary = function(content, raw) { var hash = md51(content), ret = hex(hash); return raw ? hexToBinaryString(ret) : ret; }; SparkMD5.ArrayBuffer = function() { this.reset(); }; SparkMD5.ArrayBuffer.prototype.append = function(arr) { var buff = concatenateArrayBuffers(this._buff.buffer, arr, true), length = buff.length, i; this._length += arr.byteLength; for (i = 64; i <= length; i += 64) { md5cycle(this._hash, md5blk_array(buff.subarray(i - 64, i))); } this._buff = i - 64 < length ? new Uint8Array(buff.buffer.slice(i - 64)) : new Uint8Array(0); return this; }; SparkMD5.ArrayBuffer.prototype.end = function(raw) { var buff = this._buff, length = buff.length, tail = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], i, ret; for (i = 0; i < length; i += 1) { tail[i >> 2] |= buff[i] << (i % 4 << 3); } this._finish(tail, length); ret = hex(this._hash); if (raw) { ret = hexToBinaryString(ret); } this.reset(); return ret; }; SparkMD5.ArrayBuffer.prototype.reset = function() { this._buff = new Uint8Array(0); this._length = 0; this._hash = [1732584193, -271733879, -1732584194, 271733878]; return this; }; SparkMD5.ArrayBuffer.prototype.getState = function() { var state = SparkMD5.prototype.getState.call(this); state.buff = arrayBuffer2Utf8Str(state.buff); return state; }; SparkMD5.ArrayBuffer.prototype.setState = function(state) { state.buff = utf8Str2ArrayBuffer(state.buff, true); return SparkMD5.prototype.setState.call(this, state); }; SparkMD5.ArrayBuffer.prototype.destroy = SparkMD5.prototype.destroy; SparkMD5.ArrayBuffer.prototype._finish = SparkMD5.prototype._finish; SparkMD5.ArrayBuffer.hash = function(arr, raw) { var hash = md51_array(new Uint8Array(arr)), ret = hex(hash); return raw ? hexToBinaryString(ret) : ret; }; return SparkMD5; }); } }); // node_modules/vuvuzela/index.js var require_vuvuzela = __commonJS({ "node_modules/vuvuzela/index.js"(exports) { "use strict"; exports.stringify = function stringify3(input) { var queue2 = []; queue2.push({ obj: input }); var res2 = ""; var next, obj, prefix, val, i, arrayPrefix, keys2, k, key, value, objPrefix; while (next = queue2.pop()) { obj = next.obj; prefix = next.prefix || ""; val = next.val || ""; res2 += prefix; if (val) { res2 += val; } else if (typeof obj !== "object") { res2 += typeof obj === "undefined" ? null : JSON.stringify(obj); } else if (obj === null) { res2 += "null"; } else if (Array.isArray(obj)) { queue2.push({ val: "]" }); for (i = obj.length - 1; i >= 0; i--) { arrayPrefix = i === 0 ? "" : ","; queue2.push({ obj: obj[i], prefix: arrayPrefix }); } queue2.push({ val: "[" }); } else { keys2 = []; for (k in obj) { if (obj.hasOwnProperty(k)) { keys2.push(k); } } queue2.push({ val: "}" }); for (i = keys2.length - 1; i >= 0; i--) { key = keys2[i]; value = obj[key]; objPrefix = i > 0 ? "," : ""; objPrefix += JSON.stringify(key) + ":"; queue2.push({ obj: value, prefix: objPrefix }); } queue2.push({ val: "{" }); } } return res2; }; function pop2(obj, stack, metaStack) { var lastMetaElement = metaStack[metaStack.length - 1]; if (obj === lastMetaElement.element) { metaStack.pop(); lastMetaElement = metaStack[metaStack.length - 1]; } var element2 = lastMetaElement.element; var lastElementIndex = lastMetaElement.index; if (Array.isArray(element2)) { element2.push(obj); } else if (lastElementIndex === stack.length - 2) { var key = stack.pop(); element2[key] = obj; } else { stack.push(obj); } } exports.parse = function(str) { var stack = []; var metaStack = []; var i = 0; var collationIndex2, parsedNum, numChar; var parsedString, lastCh, numConsecutiveSlashes, ch; var arrayElement, objElement; while (true) { collationIndex2 = str[i++]; if (collationIndex2 === "}" || collationIndex2 === "]" || typeof collationIndex2 === "undefined") { if (stack.length === 1) { return stack.pop(); } else { pop2(stack.pop(), stack, metaStack); continue; } } switch (collationIndex2) { case " ": case " ": case "\n": case ":": case ",": break; case "n": i += 3; pop2(null, stack, metaStack); break; case "t": i += 3; pop2(true, stack, metaStack); break; case "f": i += 4; pop2(false, stack, metaStack); break; case "0": case "1": case "2": case "3": case "4": case "5": case "6": case "7": case "8": case "9": case "-": parsedNum = ""; i--; while (true) { numChar = str[i++]; if (/[\d\.\-e\+]/.test(numChar)) { parsedNum += numChar; } else { i--; break; } } pop2(parseFloat(parsedNum), stack, metaStack); break; case '"': parsedString = ""; lastCh = void 0; numConsecutiveSlashes = 0; while (true) { ch = str[i++]; if (ch !== '"' || lastCh === "\\" && numConsecutiveSlashes % 2 === 1) { parsedString += ch; lastCh = ch; if (lastCh === "\\") { numConsecutiveSlashes++; } else { numConsecutiveSlashes = 0; } } else { break; } } pop2(JSON.parse('"' + parsedString + '"'), stack, metaStack); break; case "[": arrayElement = { element: [], index: stack.length }; stack.push(arrayElement.element); metaStack.push(arrayElement); break; case "{": objElement = { element: {}, index: stack.length }; stack.push(objElement.element); metaStack.push(objElement); break; default: throw new Error( "unexpectedly reached end of input: " + collationIndex2 ); } } }; } }); // node_modules/pouchdb-wrappers/index.js var require_pouchdb_wrappers = __commonJS({ "node_modules/pouchdb-wrappers/index.js"(exports, module2) { "use strict"; function nodify(promise, callback) { promise.then((...args) => { callback(null, ...args); }).catch((err) => { callback(err); }); } function installWrappers(base, handlers = {}) { if (!base._originals || !base._handlers) { base._originals = {}; base._handlers = {}; } for (const [method, handler] of Object.entries(handlers)) { if (!(method in base)) { throw new Error(`Method '${method}' does not exist on given base, so it cannot be wrapped.`); } if (!(method in base._originals)) { base._originals[method] = base[method]; } if (method in base._handlers) { base._handlers[method].unshift(handler); } else { base._handlers[method] = [handler]; base[method] = replacementMethod(base, method); } } } function replacementMethod(base, method) { return function(...args) { function doMethod() { let callback = null; const minArgs = method === "query" ? 1 : 0; if (args.length > minArgs && typeof args[args.length - 1] === "function") { callback = args.pop(); } let prev = base._originals[method].bind(base); for (const handler of base._handlers[method]) { prev = handler.bind(base, prev); } const result = prev(...args); if (result.then && callback) { nodify(result, callback); } return result; } if (method !== "changes" && base.taskqueue && !base.taskqueue.isReady) { const dbReady = new Promise((resolve, reject) => { base.taskqueue.addTask((error) => { if (error) { reject(error); } else { resolve(); } }); }); return dbReady.then(doMethod); } else { return doMethod(); } }; } function uninstallWrappers(base, handlers) { if (!base._originals || !base._handlers) { throw new Error("No wrapper methods installed, so no methods can be uninstalled."); } for (const [method, handler] of Object.entries(handlers)) { const errorMessage = `Wrapper method for '${method}' not installed: ${handler.toString()}`; if (!(method in base._handlers)) { throw new Error(errorMessage); } const i = base._handlers[method].indexOf(handler); if (i === -1) { throw new Error(errorMessage); } else { base._handlers[method].splice(i, 1); } } } var toExport = { install: installWrappers, uninstall: uninstallWrappers }; try { module2.exports = toExport; } catch (e2) { } try { window.PouchDBWrappers = toExport; } catch (e2) { } } }); // node_modules/transform-pouch/index.js var require_transform_pouch = __commonJS({ "node_modules/transform-pouch/index.js"(exports, module2) { "use strict"; var wrappers = require_pouchdb_wrappers(); function isntInternalKey(key) { return key[0] !== "_"; } function isUntransformable(doc) { if (typeof doc._id === "string" && /^_local/.test(doc._id)) { return true; } if (doc._deleted) { return Object.keys(doc).filter(isntInternalKey).length === 0; } return false; } module2.exports = { transform: transform2, filter: transform2 }; function transform2(config) { const db = this; const incoming = function(doc) { if (!isUntransformable(doc) && config.incoming) { return config.incoming(doc); } return doc; }; const outgoing = function(doc) { if (!isUntransformable(doc) && config.outgoing) { return config.outgoing(doc); } return doc; }; const handlers = { async get(orig, ...args) { const response = await orig(...args); if (Array.isArray(response)) { await Promise.all(response.map(async (row) => { if (row.ok) { row.ok = await outgoing(row.ok); } })); return response; } else { return outgoing(response); } }, async bulkDocs(orig, docs, ...args) { if (docs.docs) { docs.docs = await Promise.all(docs.docs.map(incoming)); } else { docs = await Promise.all(docs.map(incoming)); } return orig(docs, ...args); }, async allDocs(orig, ...args) { const response = await orig(...args); await Promise.all(response.rows.map(async (row) => { if (row.doc) { row.doc = await outgoing(row.doc); } })); return response; }, async bulkGet(orig, ...args) { const mapDoc = async (doc) => { if (doc.ok) { return { ok: await outgoing(doc.ok) }; } else { return doc; } }; const mapResult = async (result) => { const { id, docs } = result; if (id && docs && Array.isArray(docs)) { return { id, docs: await Promise.all(docs.map(mapDoc)) }; } else { return result; } }; let { results, ...res2 } = await orig(...args); results = await Promise.all(results.map(mapResult)); return { results, ...res2 }; }, changes(orig, ...args) { async function modifyChange(change) { if (change.doc) { change.doc = await outgoing(change.doc); return change; } return change; } async function modifyChanges(res2) { if (res2.results) { res2.results = await Promise.all(res2.results.map(modifyChange)); return res2; } return res2; } const changes3 = orig(...args); const { on: origOn, then: origThen } = changes3; return Object.assign(changes3, { on(event, listener) { const origListener = listener; if (event === "change") { listener = async (change) => { origListener(await modifyChange(change)); }; } else if (event === "complete") { listener = async (res2) => { origListener(await modifyChanges(res2)); }; } return origOn.call(changes3, event, listener); }, then(resolve, reject) { return origThen.call(changes3, modifyChanges).then(resolve, reject); } }); } }; if (db.type() === "http") { handlers.put = async function(orig, doc, ...args) { doc = await incoming(doc); return orig(doc, ...args); }; handlers.query = async function(orig, ...args) { const response = await orig(...args); await Promise.all(response.rows.map(async (row) => { if (row.doc) { row.doc = await outgoing(row.doc); } })); return response; }; } wrappers.install(db, handlers); } if (typeof window !== "undefined" && window.PouchDB) { window.PouchDB.plugin(exports); } } }); // src/main.ts var main_exports = {}; __export(main_exports, { default: () => ObsidianLiveSyncPlugin }); module.exports = __toCommonJS(main_exports); var import_diff_match_patch4 = __toESM(require_diff_match_patch(), 1); // src/deps.ts var import_obsidian = require("obsidian"); var import_obsidian2 = require("obsidian"); var normalizePath = import_obsidian2.normalizePath; // src/lib/src/types.ts var symbolFilePath = Symbol(); var symbolFilePathWithPrefix = Symbol(); var symbolId = Symbol(); var MAX_DOC_SIZE_BIN = 102400; var VER = 10; var LEAF_WAIT_TIMEOUT = 9e4; var LOG_LEVEL = { DEBUG: -1, VERBOSE: 1, INFO: 10, NOTICE: 100, URGENT: 1e3 }; var VERSIONINFO_DOCID = "obsydian_livesync_version"; var MILSTONE_DOCID = "_local/obsydian_livesync_milestone"; var NODEINFO_DOCID = "_local/obsydian_livesync_nodeinfo"; var DEFAULT_SETTINGS = { couchDB_URI: "", couchDB_USER: "", couchDB_PASSWORD: "", couchDB_DBNAME: "", liveSync: false, syncOnSave: false, syncOnStart: false, savingDelay: 200, lessInformationInLog: false, gcDelay: 300, versionUpFlash: "", minimumChunkSize: 20, longLineThreshold: 250, showVerboseLog: false, suspendFileWatching: false, trashInsteadDelete: true, periodicReplication: false, periodicReplicationInterval: 60, syncOnFileOpen: false, encrypt: false, passphrase: "", usePathObfuscation: false, doNotDeleteFolder: false, resolveConflictsByNewerFile: false, batchSave: false, deviceAndVaultName: "", usePluginSettings: false, showOwnPlugins: false, showStatusOnEditor: false, usePluginSync: false, autoSweepPlugins: false, autoSweepPluginsPeriodic: false, notifyPluginOrSettingUpdated: false, checkIntegrityOnSave: false, batch_size: 50, batches_limit: 40, useHistory: false, disableRequestURI: false, skipOlderFilesOnSync: true, checkConflictOnlyOnOpen: false, syncInternalFiles: false, syncInternalFilesBeforeReplication: false, syncInternalFilesIgnorePatterns: "\\/node_modules\\/, \\/\\.git\\/, \\/obsidian-livesync\\/", syncInternalFilesInterval: 60, additionalSuffixOfDatabaseName: "", ignoreVersionCheck: false, lastReadUpdates: 0, deleteMetadataOfDeletedFiles: false, syncIgnoreRegEx: "", syncOnlyRegEx: "", customChunkSize: 0, readChunksOnline: true, watchInternalFileChanges: true, automaticallyDeleteMetadataOfDeletedFiles: 0, disableMarkdownAutoMerge: false, writeDocumentsIfConflicted: false, useDynamicIterationCount: false, syncAfterMerge: false, configPassphraseStore: "", encryptedPassphrase: "", encryptedCouchDBConnection: "", permitEmptyPassphrase: false, useIndexedDBAdapter: false, useTimeouts: false, writeLogToTheFile: false, hashCacheMaxCount: 300, hashCacheMaxAmount: 50, concurrencyOfReadChunksOnline: 100, minimumIntervalOfReadChunksOnline: 333 }; var PREFIXMD_LOGFILE = "LIVESYNC_LOG_"; var FLAGMD_REDFLAG = "redflag.md"; var FLAGMD_REDFLAG2 = "redflag2.md"; var FLAGMD_REDFLAG3 = "redflag3.md"; var SYNCINFO_ID = "syncinfo"; var SALT_OF_PASSPHRASE = "rHGMPtr6oWw7VSa3W3wpa8fT8U"; var PREFIX_OBFUSCATED = "f:"; var PREFIX_ENCRYPTED_CHUNK = "h:+"; // src/types.ts var PERIODIC_PLUGIN_SWEEP = 60; var CHeader = "h:"; var PSCHeader = "ps:"; var PSCHeaderEnd = "ps;"; var ICHeader = "i:"; var ICHeaderEnd = "i;"; var ICHeaderLength = ICHeader.length; var FileWatchEventQueueMax = 10; var configURIBase = "obsidian://setuplivesync?settings="; // src/lib/src/store.ts var ReadOnlyObservableStore = class { }; var ObservableStore = class extends ReadOnlyObservableStore { constructor(value) { super(); this.observers = []; this.interceptors = []; this.value = value; } set(value) { if (this.value != value) { let v = value; if (this.interceptors.length > 0) { for (const f3 of this.interceptors) { v = f3(v); } } this.value = v; this.invalidate(); } } apply(func) { this.value = func(this.value); this.invalidate(); } peek() { return this.value; } invalidate() { const value = this.value; if (value === void 0) return; const watchers = this.observers; for (const f3 of watchers) { f3(value); } } intercept(interceptor) { this.interceptors.push(interceptor); return () => this.removeInterceptor(interceptor); } removeInterceptor(interceptor) { this.interceptors = this.interceptors.filter((e2) => e2 != interceptor); } observe(observer) { this.observers.push(observer); return () => this.unobserve(observer); } unobserve(observer) { this.observers = this.observers.filter((e2) => e2 != observer); } }; var StreamStore = class extends ObservableStore { constructor(init3) { super(init3 != null ? init3 : []); this.itemInterceptors = []; this.subscribers = []; } push(value) { var _a; let v = value; for (const f3 of this.itemInterceptors) { v = f3(v); } for (const f3 of this.subscribers) { f3(v); } this.set([...(_a = this.value) != null ? _a : [], v]); } pop() { var _a; const v = [...(_a = this.value) != null ? _a : []]; const val = v.pop(); this.set(v); return val; } unshift(value) { var _a; let v = value; for (const f3 of this.itemInterceptors) { v = f3(v); } for (const f3 of this.subscribers) { f3(v); } this.set([v, ...(_a = this.value) != null ? _a : []]); } shift() { var _a; const [val, ...rest] = [...(_a = this.value) != null ? _a : []]; this.set(rest); return val; } subscribe(subscriber) { this.subscribers.push(subscriber); return () => this.unsubscribe(subscriber); } unsubscribe(subscriber) { this.subscribers = this.subscribers.filter((e2) => e2 != subscriber); } interceptEach(interceptor) { this.itemInterceptors.push(interceptor); return () => this.removeEachInterceptor(interceptor); } removeEachInterceptor(interceptor) { this.itemInterceptors = this.itemInterceptors.filter((e2) => e2 != interceptor); } }; var globalStore = /* @__PURE__ */ new Map(); var globalStream = /* @__PURE__ */ new Map(); function getGlobalStore(name, init3) { if (!globalStore.has(name)) { globalStore.set(name, new ObservableStore(init3)); } return globalStore.get(name); } function getGlobalStreamStore(name, init3) { if (!globalStream.has(name)) { globalStream.set(name, new StreamStore(init3)); } return globalStream.get(name); } function observeStores(storeA, storeB) { const value = { ...storeA.peek(), ...storeB.peek() }; const store = new ObservableStore(value); storeA.observe((value2) => store.apply((e2) => ({ ...e2, ...value2 }))); storeB.observe((value2) => store.apply((e2) => ({ ...e2, ...value2 }))); return store; } // src/lib/src/stores.ts var lockStore = getGlobalStore("locks", { pending: [], running: [], count: 0 }); var waitingData = getGlobalStore("processingLast", 0); var logStore = getGlobalStreamStore("logs", []); var logMessageStore = getGlobalStore("logMessage", []); // src/lib/src/logger.ts function Logger(message, level, key) { const entry = { message, level, key }; logStore.push(entry); } logStore.intercept((e2) => e2.slice(Math.min(e2.length - 200, 0))); // src/lib/src/LRUCache.ts var LRUCache = class { constructor(maxCache, maxCacheLength, forwardOnly = false) { this.cache = /* @__PURE__ */ new Map([]); this.revCache = /* @__PURE__ */ new Map([]); this.maxCache = 200; this.maxCachedLength = 5e7; this.cachedLength = 0; this.enableReversed = true; this.maxCache = maxCache || 200; this.maxCachedLength = (maxCacheLength || 1) * 1e6; this.enableReversed = !forwardOnly; Logger(`Cache initialized ${this.maxCache} / ${this.maxCachedLength}`, LOG_LEVEL.VERBOSE); } has(key) { return this.cache.has(key); } get(key) { const v = this.cache.get(key); if (v) { this.cache.delete(key); this.cache.set(key, v); if (this.enableReversed) { this.revCache.delete(v); this.revCache.set(v, key); } } return v; } revGet(value) { const key = this.revCache.get(value); if (value) { this.cache.delete(key); this.revCache.delete(value); this.cache.set(key, value); this.revCache.set(value, key); } return key; } set(key, value) { this.cache.set(key, value); if (this.enableReversed) this.revCache.set(value, key); this.cachedLength += `${value}`.length; if (this.cache.size > this.maxCache || this.cachedLength > this.maxCachedLength) { for (const [key2, value2] of this.cache) { this.cache.delete(key2); if (this.enableReversed) this.revCache.delete(value2); this.cachedLength -= `${value2}`.length; if (this.cache.size <= this.maxCache && this.cachedLength <= this.maxCachedLength) break; } } else { } } }; // src/lib/src/strbin.ts var revMap = {}; var numMap = {}; for (let i = 0; i < 256; i++) { revMap[`00${i.toString(16)}`.slice(-2)] = i; numMap[i] = `00${i.toString(16)}`.slice(-2); } function hexStringToUint8Array(src) { const len = src.length / 2; const ret = new Uint8Array(len); for (let i = 0; i < len; i++) { ret[i] = revMap[src[i * 2] + src[i * 2 + 1]]; } return ret; } function uint8ArrayToHexString(src) { return [...src].map((e2) => numMap[e2]).join(""); } function btoa_node(src) { return Buffer.from(src, "binary").toString("base64"); } function atob_node(src) { return Buffer.from(src, "base64").toString("binary"); } var btoa2 = typeof window !== "undefined" ? window.btoa : btoa_node; var atob2 = typeof window !== "undefined" ? window.atob : atob_node; var QUANTUM = 32768; var writeString = (string) => { const buffer = new Uint8Array(string.length * 4); const length = string.length; let index5 = 0; let chr = 0; let idx = 0; while (idx < length) { chr = string.charCodeAt(idx++); if (chr < 128) { buffer[index5++] = chr; } else if (chr < 2048) { buffer[index5++] = 192 | chr >>> 6; buffer[index5++] = 128 | chr & 63; } else if (chr < 55296 || chr > 57343) { buffer[index5++] = 224 | chr >>> 12; buffer[index5++] = 128 | chr >>> 6 & 63; buffer[index5++] = 128 | chr & 63; } else { chr = (chr - 55296 << 10 | string.charCodeAt(idx++) - 56320) + 65536; buffer[index5++] = 240 | chr >>> 18; buffer[index5++] = 128 | chr >>> 12 & 63; buffer[index5++] = 128 | chr >>> 6 & 63; buffer[index5++] = 128 | chr & 63; } } return buffer.slice(0, index5); }; var readString = (buffer) => { const length = buffer.length; let index5 = 0; const end = length; let string = ""; while (index5 < end) { const chunk = []; const cEnd = Math.min(index5 + QUANTUM, end); while (index5 < cEnd) { const chr = buffer[index5++]; if (chr < 128) { chunk.push(chr); } else if ((chr & 224) === 192) { chunk.push((chr & 31) << 6 | buffer[index5++] & 63); } else if ((chr & 240) === 224) { chunk.push((chr & 15) << 12 | (buffer[index5++] & 63) << 6 | buffer[index5++] & 63); } else if ((chr & 248) === 240) { let code = (chr & 7) << 18 | (buffer[index5++] & 63) << 12 | (buffer[index5++] & 63) << 6 | buffer[index5++] & 63; if (code < 65536) { chunk.push(code); } else { code -= 65536; chunk.push((code >>> 10) + 55296, (code & 1023) + 56320); } } } string += String.fromCharCode(...chunk); } return string; }; function binaryToBinaryString(src) { const len = src.length; if (len < QUANTUM) return String.fromCharCode(...src); let ret = ""; for (let i = 0; i < len; i += QUANTUM) { ret += String.fromCharCode( ...src.slice(i, i + QUANTUM) ); } return ret; } var encodeChunkSize = 3 * 5e7; function arrayBufferToBase64internalBrowser(buffer) { return new Promise((res2, rej) => { const blob = new Blob([buffer], { type: "application/octet-binary" }); const reader = new FileReader(); reader.onload = function(evt) { var _a, _b; const dataURI = ((_b = (_a = evt.target) == null ? void 0 : _a.result) == null ? void 0 : _b.toString()) || ""; if (buffer.byteLength != 0 && (dataURI == "" || dataURI == "data:")) return rej(new TypeError("Could not parse the encoded string")); const result = dataURI.substring(dataURI.indexOf(",") + 1); res2(result); }; reader.readAsDataURL(blob); }); } function arrayBufferToBase64internalNode(buffer) { const ret = Buffer.from(buffer.buffer).toString("base64"); return ret; } var arrayBufferToBase64internal = typeof window !== "undefined" ? arrayBufferToBase64internalBrowser : arrayBufferToBase64internalNode; async function arrayBufferToBase64(buffer) { const bufLen = buffer.byteLength; const pieces = []; let idx = 0; do { const offset = idx * encodeChunkSize; const pBuf = new DataView(buffer, offset, Math.min(encodeChunkSize, buffer.byteLength - offset)); pieces.push(await arrayBufferToBase64internal(pBuf)); idx++; } while (idx * encodeChunkSize < bufLen); return pieces; } function base64ToString(base64) { try { if (typeof base64 != "string") return base64.map((e2) => base64ToString(e2)).join(""); const binary_string = atob2(base64); const len = binary_string.length; const bytes = new Uint8Array(len); for (let i = 0; i < len; i++) { bytes[i] = binary_string.charCodeAt(i); } return readString(bytes); } catch (ex) { if (typeof base64 != "string") return base64.join(""); return base64; } } function base64ToArrayBuffer(base64) { if (typeof base64 == "string") return base64ToArrayBufferInternal(base64); const bufItems = base64.map((e2) => base64ToArrayBufferInternal(e2)); const len = bufItems.reduce((p, c) => p + c.byteLength, 0); const joinedArray = new Uint8Array(len); let offset = 0; bufItems.forEach((e2) => { joinedArray.set(new Uint8Array(e2), offset); offset += e2.byteLength; }); return joinedArray; } var base64ToArrayBufferInternal = typeof window !== "undefined" ? base64ToArrayBufferInternalBrowser : base64ToArrayBufferInternalNode; function base64ToArrayBufferInternalNode(base64) { try { return Buffer.from(base64, "base64").buffer; } catch (ex) { return writeString(base64).buffer; } } function base64ToArrayBufferInternalBrowser(base64) { try { const binary_string = atob2(base64); const len = binary_string.length; const bytes = new Uint8Array(len); for (let i = 0; i < len; i++) { bytes[i] = binary_string.charCodeAt(i); } return bytes.buffer; } catch (ex) { const len = base64.length; const bytes = new Uint8Array(len); for (let i = 0; i < len; i++) { bytes[i] = base64.charCodeAt(i); } return bytes.buffer; } } function* pickPiece(leftData, minimumChunkSize) { let buffer = ""; L1: do { const curLine = leftData.shift(); if (typeof curLine === "undefined") { yield buffer; break L1; } if (curLine.startsWith("```") || curLine.startsWith(" ```") || curLine.startsWith(" ```") || curLine.startsWith(" ```")) { yield buffer; buffer = curLine + (leftData.length != 0 ? "\n" : ""); L2: do { const curPx = leftData.shift(); if (typeof curPx === "undefined") { break L2; } buffer += curPx + (leftData.length != 0 ? "\n" : ""); } while (leftData.length > 0 && !(leftData[0].startsWith("```") || leftData[0].startsWith(" ```") || leftData[0].startsWith(" ```") || leftData[0].startsWith(" ```"))); const isLooksLikeBASE64 = buffer.endsWith("="); const maybeUneditable = buffer.length > 2048; const endOfCodeBlock = leftData.shift(); if (typeof endOfCodeBlock !== "undefined") { buffer += endOfCodeBlock; buffer += leftData.length != 0 ? "\n" : ""; } if (!isLooksLikeBASE64 && !maybeUneditable) { const splitExpr = /(.*?[;,:<])/g; const sx = buffer.split(splitExpr).filter((e2) => e2 != ""); for (const v of sx) { yield v; } } else { yield buffer; } buffer = ""; } else { buffer += curLine + (leftData.length != 0 ? "\n" : ""); if (buffer.length >= minimumChunkSize || leftData.length == 0 || leftData[0] == "#" || buffer[0] == "#") { yield buffer; buffer = ""; } } } while (leftData.length > 0); } function splitPieces2(dataSrc, pieceSize, plainSplit, minimumChunkSize, longLineThreshold) { return function* pieces() { const dataList = typeof dataSrc == "string" ? [dataSrc] : dataSrc; for (const data of dataList) { if (plainSplit) { const leftData = data.split("\n"); const f3 = pickPiece(leftData, minimumChunkSize); for (const piece of f3) { let buffer = piece; do { let ps = pieceSize; if (buffer.charCodeAt(ps - 1) != buffer.codePointAt(ps - 1)) { ps++; } yield buffer.substring(0, ps); buffer = buffer.substring(ps); } while (buffer != ""); } } else { let leftData = data; do { const piece = leftData.substring(0, pieceSize); leftData = leftData.substring(pieceSize); yield piece; } while (leftData != ""); } } }; } function versionNumberString2Number(version2) { return version2.split(".").reverse().map((e2, i) => e2 / 1 * 1e3 ** i).reduce((prev, current) => prev + current, 0); } var escapeStringToHTML = (str) => { if (!str) return ""; return str.replace(/[<>&"'`]/g, (match2) => { const escape = { "<": "<", ">": ">", "&": "&", '"': """, "'": "'", "`": "`" }; return escape[match2]; }); }; // src/lib/src/mods.ts var import_crypto = require("crypto"); var webcrypto; if (typeof window !== "undefined" && window.crypto) { webcrypto = window.crypto; } else { const crypto2 = import_crypto.webcrypto; webcrypto = crypto2; } // src/lib/src/e2ee_v2.ts var KeyBuffs = /* @__PURE__ */ new Map(); var decKeyBuffs = /* @__PURE__ */ new Map(); var KEY_RECYCLE_COUNT = 100; var semiStaticFieldBuffer; var nonceBuffer = new Uint32Array(1); async function getKeyForEncrypt(passphrase, autoCalculateIterations) { const buffKey = `${passphrase}-${autoCalculateIterations}`; const f3 = KeyBuffs.get(buffKey); if (f3) { f3.count--; if (f3.count > 0) { return [f3.key, f3.salt]; } f3.count--; } const passphraseLen = 15 - passphrase.length; const iteration = autoCalculateIterations ? (passphraseLen > 0 ? passphraseLen : 0) * 1e3 + 121 - passphraseLen : 1e5; const passphraseBin = new TextEncoder().encode(passphrase); const digest = await webcrypto.subtle.digest({ name: "SHA-256" }, passphraseBin); const keyMaterial = await webcrypto.subtle.importKey("raw", digest, { name: "PBKDF2" }, false, ["deriveKey"]); const salt = webcrypto.getRandomValues(new Uint8Array(16)); const key = await webcrypto.subtle.deriveKey( { name: "PBKDF2", salt, iterations: iteration, hash: "SHA-256" }, keyMaterial, { name: "AES-GCM", length: 256 }, false, ["encrypt"] ); KeyBuffs.set(buffKey, { key, salt, count: KEY_RECYCLE_COUNT }); return [key, salt]; } var keyGCCount = KEY_RECYCLE_COUNT * 5; var decKeyIdx = 0; var decKeyMin = 0; async function getKeyForDecryption(passphrase, salt, autoCalculateIterations) { keyGCCount--; if (keyGCCount < 0) { keyGCCount = KEY_RECYCLE_COUNT; const threshold = (decKeyIdx - decKeyMin) / 2; for (const [key2, buff] of decKeyBuffs) { if (buff.count < threshold) { decKeyBuffs.delete(key2); } decKeyMin = decKeyIdx; } } decKeyIdx++; const bufKey = passphrase + uint8ArrayToHexString(salt) + autoCalculateIterations; const f3 = decKeyBuffs.get(bufKey); if (f3) { f3.count = decKeyIdx; return [f3.key, f3.salt]; } const passphraseLen = 15 - passphrase.length; const iteration = autoCalculateIterations ? (passphraseLen > 0 ? passphraseLen : 0) * 1e3 + 121 - passphraseLen : 1e5; const passphraseBin = new TextEncoder().encode(passphrase); const digest = await webcrypto.subtle.digest({ name: "SHA-256" }, passphraseBin); const keyMaterial = await webcrypto.subtle.importKey("raw", digest, { name: "PBKDF2" }, false, ["deriveKey"]); const key = await webcrypto.subtle.deriveKey( { name: "PBKDF2", salt, iterations: iteration, hash: "SHA-256" }, keyMaterial, { name: "AES-GCM", length: 256 }, false, ["decrypt"] ); decKeyBuffs.set(bufKey, { key, salt, count: 0 }); return [key, salt]; } function getSemiStaticField(reset) { if (semiStaticFieldBuffer != null && !reset) { return semiStaticFieldBuffer; } semiStaticFieldBuffer = webcrypto.getRandomValues(new Uint8Array(12)); return semiStaticFieldBuffer; } function getNonce() { nonceBuffer[0]++; if (nonceBuffer[0] > 1e4) { getSemiStaticField(true); } return nonceBuffer; } async function encrypt(input, passphrase, autoCalculateIterations) { const [key, salt] = await getKeyForEncrypt(passphrase, autoCalculateIterations); const fixedPart = getSemiStaticField(); const invocationPart = getNonce(); const iv = new Uint8Array([...fixedPart, ...new Uint8Array(invocationPart.buffer)]); const plainStringified = JSON.stringify(input); const plainStringBuffer = writeString(plainStringified); const encryptedDataArrayBuffer = await webcrypto.subtle.encrypt({ name: "AES-GCM", iv }, key, plainStringBuffer); const encryptedData2 = btoa2(binaryToBinaryString(new Uint8Array(encryptedDataArrayBuffer))); const ret = `["${encryptedData2}","${uint8ArrayToHexString(iv)}","${uint8ArrayToHexString(salt)}"]`; return ret; } async function decrypt(encryptedResult, passphrase, autoCalculateIterations) { try { if (!encryptedResult.startsWith("[") || !encryptedResult.endsWith("]")) { throw new Error("Encrypted data corrupted!"); } const w = encryptedResult.substring(1, encryptedResult.length - 1).split(",").map((e2) => e2[0] == '"' ? e2.substring(1, e2.length - 1) : e2); const [encryptedData, ivString, salt] = w; const [key] = await getKeyForDecryption(passphrase, hexStringToUint8Array(salt), autoCalculateIterations); const iv = hexStringToUint8Array(ivString); const encryptedDataBin = atob2(encryptedData); const len = encryptedDataBin.length; const encryptedDataArrayBuffer = new Uint8Array(len); for (let i = 0; i < len; i++) { encryptedDataArrayBuffer[i] = encryptedDataBin.charCodeAt(i); } const plainStringBuffer = await webcrypto.subtle.decrypt({ name: "AES-GCM", iv }, key, encryptedDataArrayBuffer); const plainStringified = readString(new Uint8Array(plainStringBuffer)); const plain = JSON.parse(plainStringified); return plain; } catch (ex) { Logger("Couldn't decode! You should wrong the passphrases", LOG_LEVEL.VERBOSE); Logger(ex, LOG_LEVEL.VERBOSE); throw ex; } } async function tryDecrypt(encryptedResult, passphrase, autoCalculateIterations) { if (!passphrase) return false; try { return await decrypt(encryptedResult, passphrase, autoCalculateIterations); } catch (ex) { return false; } } async function testCrypt() { const src = "supercalifragilisticexpialidocious"; const encoded = await encrypt(src, "passwordTest", false); const decrypted = await decrypt(encoded, "passwordTest", false); if (src != decrypted) { Logger("WARNING! Your device would not support encryption.", LOG_LEVEL.VERBOSE); return false; } else { Logger("CRYPT LOGIC OK", LOG_LEVEL.VERBOSE); return true; } } // src/lib/src/path.ts function isValidFilenameInWidows(filename) { const regex = /[\u0000-\u001f]|[\\":?<>|*#]/g; if (regex.test(filename)) return false; const win = /(\\|\/)(COM\d|LPT\d|CON|PRN|AUX|NUL|CLOCK$)($|\.)/gi; if (win.test(filename)) return false; return true; } function isValidFilenameInDarwin(filename) { const regex = /[\u0000-\u001f]|[:]/g; return !regex.test(filename); } function isValidFilenameInLinux(filename) { const regex = /[\u0000-\u001f]/g; return !regex.test(filename); } function isValidFilenameInAndroid(filename) { const regex = /[\u0000-\u001f]|[\\":?<>|*#]/g; return !regex.test(filename); } function isFilePath(path) { if (path.indexOf(":") === -1) return true; return false; } function stripAllPrefixes(prefixedPath) { if (isFilePath(prefixedPath)) return prefixedPath; const [, body] = expandFilePathPrefix(prefixedPath); return stripAllPrefixes(body); } function addPrefix(path, prefix) { if (prefix && path.startsWith(prefix)) return path; return `${prefix != null ? prefix : ""}${path}`; } function expandFilePathPrefix(path) { let [prefix, body] = path.split(":", 2); if (!body) { body = prefix; prefix = ""; } else { prefix = prefix + ":"; } return [prefix, body]; } function expandDocumentIDPrefix(id) { let [prefix, body] = id.split(":", 2); if (!body) { body = prefix; prefix = ""; } else { prefix = prefix + ":"; } return [prefix, body]; } var hashString = memorizeFuncWithLRUCache(async (key) => { const buff = writeString(key); let digest = await webcrypto.subtle.digest("SHA-256", buff); const len = key.length; for (let i = 0; i < len; i++) { digest = await webcrypto.subtle.digest("SHA-256", buff); } return uint8ArrayToHexString(new Uint8Array(digest)); }); async function path2id_base(filename, obfuscatePassphrase) { if (filename.startsWith(PREFIX_OBFUSCATED)) return filename; let x = filename; if (x.startsWith("_")) x = "/" + x; if (!obfuscatePassphrase) return x; const [prefix, body] = expandFilePathPrefix(x); if (body.startsWith(PREFIX_OBFUSCATED)) return x; const hashedPassphrase = await hashString(obfuscatePassphrase); const out = await hashString(`${hashedPassphrase}:${filename}`); return prefix + PREFIX_OBFUSCATED + out; } function id2path_base(id, entry) { if (entry && (entry == null ? void 0 : entry.path)) { return id2path_base(entry.path); } if (id.startsWith(PREFIX_OBFUSCATED)) throw new Error("Entry has been obfuscated!"); const [prefix, body] = expandDocumentIDPrefix(id); if (body.startsWith(PREFIX_OBFUSCATED)) throw new Error("Entry has been obfuscated!"); if (body.startsWith("/")) { return body.substring(1); } return prefix + body; } function getPath(entry) { return id2path_base(entry._id, entry); } function stripPrefix(prefixedPath) { const [prefix, body] = prefixedPath.split(":", 2); if (!body) { return prefix; } return body; } function shouldBeIgnored(filename) { if (filename == FLAGMD_REDFLAG) { return true; } if (filename == FLAGMD_REDFLAG2) { return true; } if (filename == FLAGMD_REDFLAG3) { return true; } if (filename.startsWith(PREFIXMD_LOGFILE)) { return true; } return false; } function isPlainText(filename) { if (filename.endsWith(".md")) return true; if (filename.endsWith(".txt")) return true; if (filename.endsWith(".svg")) return true; if (filename.endsWith(".html")) return true; if (filename.endsWith(".csv")) return true; if (filename.endsWith(".css")) return true; if (filename.endsWith(".js")) return true; if (filename.endsWith(".xml")) return true; if (filename.endsWith(".canvas")) return true; return false; } function shouldSplitAsPlainText(filename) { if (filename.endsWith(".md")) return true; if (filename.endsWith(".txt")) return true; if (filename.endsWith(".canvas")) return true; return false; } // src/lib/src/utils_couchdb.ts var isValidRemoteCouchDBURI = (uri) => { if (uri.startsWith("https://")) return true; if (uri.startsWith("http://")) return true; return false; }; function isCloudantURI(uri) { if (uri.indexOf(".cloudantnosqldb.") !== -1 || uri.indexOf(".cloudant.com") !== -1) return true; return false; } var checkRemoteVersion = async (db, migrate, barrier = VER) => { try { const versionInfo = await db.get(VERSIONINFO_DOCID); if (versionInfo.type != "versioninfo") { return false; } const version2 = versionInfo.version; if (version2 < barrier) { const versionUpResult = await migrate(version2, barrier); if (versionUpResult) { await bumpRemoteVersion(db); return true; } } if (version2 == barrier) return true; return false; } catch (ex) { if (isErrorOfMissingDoc(ex)) { if (await bumpRemoteVersion(db)) { return true; } return false; } throw ex; } }; var bumpRemoteVersion = async (db, barrier = VER) => { const vi = { _id: VERSIONINFO_DOCID, version: barrier, type: "versioninfo" }; const versionInfo = await resolveWithIgnoreKnownError(db.get(VERSIONINFO_DOCID), vi); if (versionInfo.type != "versioninfo") { return false; } vi._rev = versionInfo._rev; await db.put(vi); return true; }; var checkSyncInfo = async (db) => { try { const syncinfo = await db.get(SYNCINFO_ID); console.log(syncinfo); return true; } catch (ex) { if (isErrorOfMissingDoc(ex)) { const randomStrSrc = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; const temp = [...Array(30)].map((e2) => Math.floor(Math.random() * randomStrSrc.length)).map((e2) => randomStrSrc[e2]).join(""); const newSyncInfo = { _id: SYNCINFO_ID, type: "syncinfo", data: temp }; if (await db.put(newSyncInfo)) { return true; } return false; } else { console.dir(ex); return false; } } }; async function putDesignDocuments(db) { const design = { "_id": "_design/replicate", "_rev": void 0, "ver": 2, "filters": { "default": function(doc, req) { return !("remote" in doc && doc.remote); }.toString(), "push": function(doc, req) { return true; }.toString(), "pull": function(doc, req) { return !(doc.type && doc.type == "leaf"); }.toString() } }; try { const w = await db.get(design._id); if (w.ver < design.ver) { design._rev = w._rev; await db.put(design); return true; } } catch (ex) { if (isErrorOfMissingDoc(ex)) { delete design._rev; await db.put(design); return true; } else { Logger("Could not make design documents", LOG_LEVEL.INFO); } } return false; } var enableEncryption = (db, passphrase, useDynamicIterationCount, migrationDecrypt) => { const decrypted = /* @__PURE__ */ new Map(); db.transform({ incoming: async (doc) => { const saveDoc = { ...doc }; if (isEncryptedChunkEntry(saveDoc) || isSyncInfoEntry(saveDoc)) { try { saveDoc.data = await encrypt(saveDoc.data, passphrase, useDynamicIterationCount); } catch (ex) { Logger("Encryption failed.", LOG_LEVEL.NOTICE); Logger(ex); throw ex; } } if (isObfuscatedEntry(saveDoc)) { try { saveDoc.path = await encrypt(getPath(saveDoc), passphrase, useDynamicIterationCount); } catch (ex) { Logger("Encryption failed.", LOG_LEVEL.NOTICE); Logger(ex); throw ex; } } return saveDoc; }, outgoing: async (doc) => { const loadDoc = { ...doc }; const _isChunkOrSyncInfo = isEncryptedChunkEntry(loadDoc) || isSyncInfoEntry(loadDoc); const _isObfuscatedEntry = isObfuscatedEntry(loadDoc); if (_isChunkOrSyncInfo || _isObfuscatedEntry) { if (migrationDecrypt && decrypted.has(loadDoc._id)) { return loadDoc; } try { if (_isChunkOrSyncInfo) { loadDoc.data = await decrypt(loadDoc.data, passphrase, useDynamicIterationCount); } if (_isObfuscatedEntry) { loadDoc.path = await decrypt(getPath(loadDoc), passphrase, useDynamicIterationCount); } if (migrationDecrypt) { decrypted.set(loadDoc._id, true); } } catch (ex) { if (useDynamicIterationCount) { try { if (_isChunkOrSyncInfo) { loadDoc.data = await decrypt(loadDoc.data, passphrase, false); } if (_isObfuscatedEntry) { loadDoc.path = await decrypt(getPath(loadDoc), passphrase, useDynamicIterationCount); } if (migrationDecrypt) { decrypted.set(loadDoc._id, true); } } catch (ex2) { if (migrationDecrypt && ex2.name == "SyntaxError") { return loadDoc; } Logger("Decryption failed.", LOG_LEVEL.NOTICE); Logger(ex2); throw ex2; } } else { Logger("Decryption failed.", LOG_LEVEL.NOTICE); Logger(ex); throw ex; } } } return loadDoc; } }); }; function isErrorOfMissingDoc(ex) { return (ex && (ex == null ? void 0 : ex.status)) == 404; } // src/lib/src/utils.ts function resolveWithIgnoreKnownError(p, def) { return new Promise((res2, rej) => { p.then(res2).catch((ex) => isErrorOfMissingDoc(ex) ? res2(def) : rej(ex)); }); } var delay = (ms) => { return new Promise((res2) => { setTimeout(() => { res2(); }, ms); }); }; function getDocData(doc) { return typeof doc == "string" ? doc : doc.join(""); } function getDocDataAsArray(doc) { return typeof doc == "string" ? [doc] : doc; } var chunkCheckLen = 1e6; function stringYielder(src) { return function* gen() { let buf = ""; for (const piece of src) { buf += piece; while (buf.length > chunkCheckLen) { const p = buf.slice(0, chunkCheckLen); buf = buf.substring(chunkCheckLen); yield p; } } if (buf != "") yield buf; return; }(); } function isDocContentSame(docA, docB) { const docAArray = getDocDataAsArray(docA); const docBArray = getDocDataAsArray(docB); const chunkA = stringYielder(docAArray); const chunkB = stringYielder(docBArray); let genA; let genB; do { genA = chunkA.next(); genB = chunkB.next(); if (genA.value != genB.value) { return false; } if (genA.done != genB.done) { return false; } } while (!genA.done); if (!genB.done) return false; return true; } function isObfuscatedEntry(doc) { if (doc._id.startsWith(PREFIX_OBFUSCATED)) { return true; } return false; } function isEncryptedChunkEntry(doc) { if (doc._id.startsWith(PREFIX_ENCRYPTED_CHUNK)) { return true; } return false; } function isSyncInfoEntry(doc) { if (doc._id == SYNCINFO_ID) { return true; } return false; } function memorizeFuncWithLRUCache(func) { const cache = new LRUCache(100, 1e5, true); return (key) => { const isExists = cache.has(key); if (isExists) return cache.get(key); const value = func(key); cache.set(key, value); return value; }; } // node_modules/pouchdb-collections/lib/index.es.js function mangle(key) { return "$" + key; } function unmangle(key) { return key.substring(1); } function Map$1() { this._store = {}; } Map$1.prototype.get = function(key) { var mangled = mangle(key); return this._store[mangled]; }; Map$1.prototype.set = function(key, value) { var mangled = mangle(key); this._store[mangled] = value; return true; }; Map$1.prototype.has = function(key) { var mangled = mangle(key); return mangled in this._store; }; Map$1.prototype.keys = function() { return Object.keys(this._store).map((k) => unmangle(k)); }; Map$1.prototype.delete = function(key) { var mangled = mangle(key); var res2 = mangled in this._store; delete this._store[mangled]; return res2; }; Map$1.prototype.forEach = function(cb) { var keys2 = Object.keys(this._store); for (var i = 0, len = keys2.length; i < len; i++) { var key = keys2[i]; var value = this._store[key]; key = unmangle(key); cb(value, key); } }; Object.defineProperty(Map$1.prototype, "size", { get: function() { return Object.keys(this._store).length; } }); function Set$1(array) { this._store = new Map$1(); if (array && Array.isArray(array)) { for (var i = 0, len = array.length; i < len; i++) { this.add(array[i]); } } } Set$1.prototype.add = function(key) { return this._store.set(key, true); }; Set$1.prototype.has = function(key) { return this._store.has(key); }; Set$1.prototype.forEach = function(cb) { this._store.forEach(function(value, key) { cb(key); }); }; Object.defineProperty(Set$1.prototype, "size", { get: function() { return this._store.size; } }); function supportsMapAndSet() { if (typeof Symbol === "undefined" || typeof Map === "undefined" || typeof Set === "undefined") { return false; } var prop = Object.getOwnPropertyDescriptor(Map, Symbol.species); return prop && "get" in prop && Map[Symbol.species] === Map; } var ExportedSet; var ExportedMap; { if (supportsMapAndSet()) { ExportedSet = Set; ExportedMap = Map; } else { ExportedSet = Set$1; ExportedMap = Map$1; } } // node_modules/pouchdb-utils/lib/index-browser.es.js var import_immediate = __toESM(require_lib()); // node_modules/pouchdb-errors/lib/index.es.js var PouchError = class extends Error { constructor(status, error, reason) { super(); this.status = status; this.name = error; this.message = reason; this.error = true; } toString() { return JSON.stringify({ status: this.status, name: this.name, message: this.message, reason: this.reason }); } }; var UNAUTHORIZED = new PouchError(401, "unauthorized", "Name or password is incorrect."); var MISSING_BULK_DOCS = new PouchError(400, "bad_request", "Missing JSON list of 'docs'"); var MISSING_DOC = new PouchError(404, "not_found", "missing"); var REV_CONFLICT = new PouchError(409, "conflict", "Document update conflict"); var INVALID_ID = new PouchError(400, "bad_request", "_id field must contain a string"); var MISSING_ID = new PouchError(412, "missing_id", "_id is required for puts"); var RESERVED_ID = new PouchError(400, "bad_request", "Only reserved document ids may start with underscore."); var NOT_OPEN = new PouchError(412, "precondition_failed", "Database not open"); var UNKNOWN_ERROR = new PouchError(500, "unknown_error", "Database encountered an unknown error"); var BAD_ARG = new PouchError(500, "badarg", "Some query argument is invalid"); var INVALID_REQUEST = new PouchError(400, "invalid_request", "Request was invalid"); var QUERY_PARSE_ERROR = new PouchError(400, "query_parse_error", "Some query parameter is invalid"); var DOC_VALIDATION = new PouchError(500, "doc_validation", "Bad special document member"); var BAD_REQUEST = new PouchError(400, "bad_request", "Something wrong with the request"); var NOT_AN_OBJECT = new PouchError(400, "bad_request", "Document must be a JSON object"); var DB_MISSING = new PouchError(404, "not_found", "Database not found"); var IDB_ERROR = new PouchError(500, "indexed_db_went_bad", "unknown"); var WSQ_ERROR = new PouchError(500, "web_sql_went_bad", "unknown"); var LDB_ERROR = new PouchError(500, "levelDB_went_went_bad", "unknown"); var FORBIDDEN = new PouchError(403, "forbidden", "Forbidden by design doc validate_doc_update function"); var INVALID_REV = new PouchError(400, "bad_request", "Invalid rev format"); var FILE_EXISTS = new PouchError(412, "file_exists", "The database could not be created, the file already exists."); var MISSING_STUB = new PouchError(412, "missing_stub", "A pre-existing attachment stub wasn't found"); var INVALID_URL = new PouchError(413, "invalid_url", "Provided URL is invalid"); function createError(error, reason) { function CustomPouchError(reason2) { var names = Object.getOwnPropertyNames(error); for (var i = 0, len = names.length; i < len; i++) { if (typeof error[names[i]] !== "function") { this[names[i]] = error[names[i]]; } } if (this.stack === void 0) { this.stack = new Error().stack; } if (reason2 !== void 0) { this.reason = reason2; } } CustomPouchError.prototype = PouchError.prototype; return new CustomPouchError(reason); } function generateErrorFromResponse(err) { if (typeof err !== "object") { var data = err; err = UNKNOWN_ERROR; err.data = data; } if ("error" in err && err.error === "conflict") { err.name = "conflict"; err.status = 409; } if (!("name" in err)) { err.name = err.error || "unknown"; } if (!("status" in err)) { err.status = 500; } if (!("message" in err)) { err.message = err.message || err.reason; } if (!("stack" in err)) { err.stack = new Error().stack; } return err; } // node_modules/pouchdb-utils/lib/index-browser.es.js var import_events = __toESM(require_events()); // node_modules/uuid/dist/esm-browser/rng.js var getRandomValues; var rnds8 = new Uint8Array(16); function rng() { if (!getRandomValues) { getRandomValues = typeof crypto !== "undefined" && crypto.getRandomValues && crypto.getRandomValues.bind(crypto) || typeof msCrypto !== "undefined" && typeof msCrypto.getRandomValues === "function" && msCrypto.getRandomValues.bind(msCrypto); if (!getRandomValues) { throw new Error("crypto.getRandomValues() not supported. See https://github.com/uuidjs/uuid#getrandomvalues-not-supported"); } } return getRandomValues(rnds8); } // node_modules/uuid/dist/esm-browser/regex.js var regex_default = /^(?:[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}|00000000-0000-0000-0000-000000000000)$/i; // node_modules/uuid/dist/esm-browser/validate.js function validate(uuid2) { return typeof uuid2 === "string" && regex_default.test(uuid2); } var validate_default = validate; // node_modules/uuid/dist/esm-browser/stringify.js var byteToHex = []; for (i = 0; i < 256; ++i) { byteToHex.push((i + 256).toString(16).substr(1)); } var i; function stringify(arr) { var offset = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : 0; var uuid2 = (byteToHex[arr[offset + 0]] + byteToHex[arr[offset + 1]] + byteToHex[arr[offset + 2]] + byteToHex[arr[offset + 3]] + "-" + byteToHex[arr[offset + 4]] + byteToHex[arr[offset + 5]] + "-" + byteToHex[arr[offset + 6]] + byteToHex[arr[offset + 7]] + "-" + byteToHex[arr[offset + 8]] + byteToHex[arr[offset + 9]] + "-" + byteToHex[arr[offset + 10]] + byteToHex[arr[offset + 11]] + byteToHex[arr[offset + 12]] + byteToHex[arr[offset + 13]] + byteToHex[arr[offset + 14]] + byteToHex[arr[offset + 15]]).toLowerCase(); if (!validate_default(uuid2)) { throw TypeError("Stringified UUID is invalid"); } return uuid2; } var stringify_default = stringify; // node_modules/uuid/dist/esm-browser/v4.js function v4(options, buf, offset) { options = options || {}; var rnds = options.random || (options.rng || rng)(); rnds[6] = rnds[6] & 15 | 64; rnds[8] = rnds[8] & 63 | 128; if (buf) { offset = offset || 0; for (var i = 0; i < 16; ++i) { buf[offset + i] = rnds[i]; } return buf; } return stringify_default(rnds); } var v4_default = v4; // node_modules/pouchdb-binary-utils/lib/index-browser.es.js var thisAtob = function(str) { return atob(str); }; var thisBtoa = function(str) { return btoa(str); }; function createBlob(parts, properties) { parts = parts || []; properties = properties || {}; try { return new Blob(parts, properties); } catch (e2) { if (e2.name !== "TypeError") { throw e2; } var Builder = typeof BlobBuilder !== "undefined" ? BlobBuilder : typeof MSBlobBuilder !== "undefined" ? MSBlobBuilder : typeof MozBlobBuilder !== "undefined" ? MozBlobBuilder : WebKitBlobBuilder; var builder = new Builder(); for (var i = 0; i < parts.length; i += 1) { builder.append(parts[i]); } return builder.getBlob(properties.type); } } function binaryStringToArrayBuffer(bin) { var length = bin.length; var buf = new ArrayBuffer(length); var arr = new Uint8Array(buf); for (var i = 0; i < length; i++) { arr[i] = bin.charCodeAt(i); } return buf; } function binStringToBluffer(binString, type) { return createBlob([binaryStringToArrayBuffer(binString)], { type }); } function b64ToBluffer(b64, type) { return binStringToBluffer(thisAtob(b64), type); } function arrayBufferToBinaryString(buffer) { var binary = ""; var bytes = new Uint8Array(buffer); var length = bytes.byteLength; for (var i = 0; i < length; i++) { binary += String.fromCharCode(bytes[i]); } return binary; } function readAsBinaryString(blob, callback) { var reader = new FileReader(); var hasBinaryString = typeof reader.readAsBinaryString === "function"; reader.onloadend = function(e2) { var result = e2.target.result || ""; if (hasBinaryString) { return callback(result); } callback(arrayBufferToBinaryString(result)); }; if (hasBinaryString) { reader.readAsBinaryString(blob); } else { reader.readAsArrayBuffer(blob); } } function blobToBinaryString(blobOrBuffer, callback) { readAsBinaryString(blobOrBuffer, function(bin) { callback(bin); }); } function blobToBase64(blobOrBuffer, callback) { blobToBinaryString(blobOrBuffer, function(base64) { callback(thisBtoa(base64)); }); } function readAsArrayBuffer(blob, callback) { var reader = new FileReader(); reader.onloadend = function(e2) { var result = e2.target.result || new ArrayBuffer(0); callback(result); }; reader.readAsArrayBuffer(blob); } // node_modules/pouchdb-md5/lib/index-browser.es.js var import_spark_md5 = __toESM(require_spark_md5()); var setImmediateShim = self.setImmediate || self.setTimeout; var MD5_CHUNK_SIZE = 32768; function rawToBase64(raw) { return thisBtoa(raw); } function sliceBlob(blob, start, end) { if (blob.webkitSlice) { return blob.webkitSlice(start, end); } return blob.slice(start, end); } function appendBlob(buffer, blob, start, end, callback) { if (start > 0 || end < blob.size) { blob = sliceBlob(blob, start, end); } readAsArrayBuffer(blob, function(arrayBuffer) { buffer.append(arrayBuffer); callback(); }); } function appendString(buffer, string, start, end, callback) { if (start > 0 || end < string.length) { string = string.substring(start, end); } buffer.appendBinary(string); callback(); } function binaryMd5(data, callback) { var inputIsString = typeof data === "string"; var len = inputIsString ? data.length : data.size; var chunkSize = Math.min(MD5_CHUNK_SIZE, len); var chunks = Math.ceil(len / chunkSize); var currentChunk = 0; var buffer = inputIsString ? new import_spark_md5.default() : new import_spark_md5.default.ArrayBuffer(); var append2 = inputIsString ? appendString : appendBlob; function next() { setImmediateShim(loadNextChunk); } function done() { var raw = buffer.end(true); var base64 = rawToBase64(raw); callback(base64); buffer.destroy(); } function loadNextChunk() { var start = currentChunk * chunkSize; var end = start + chunkSize; currentChunk++; if (currentChunk < chunks) { append2(buffer, data, start, end, next); } else { append2(buffer, data, start, end, done); } } loadNextChunk(); } function stringMd5(string) { return import_spark_md5.default.hash(string); } // node_modules/pouchdb-utils/lib/index-browser.es.js function isBinaryObject(object) { return typeof ArrayBuffer !== "undefined" && object instanceof ArrayBuffer || typeof Blob !== "undefined" && object instanceof Blob; } function cloneArrayBuffer(buff) { if (typeof buff.slice === "function") { return buff.slice(0); } var target = new ArrayBuffer(buff.byteLength); var targetArray = new Uint8Array(target); var sourceArray = new Uint8Array(buff); targetArray.set(sourceArray); return target; } function cloneBinaryObject(object) { if (object instanceof ArrayBuffer) { return cloneArrayBuffer(object); } var size = object.size; var type = object.type; if (typeof object.slice === "function") { return object.slice(0, size, type); } return object.webkitSlice(0, size, type); } var funcToString = Function.prototype.toString; var objectCtorString = funcToString.call(Object); function isPlainObject(value) { var proto = Object.getPrototypeOf(value); if (proto === null) { return true; } var Ctor = proto.constructor; return typeof Ctor == "function" && Ctor instanceof Ctor && funcToString.call(Ctor) == objectCtorString; } function clone(object) { var newObject; var i; var len; if (!object || typeof object !== "object") { return object; } if (Array.isArray(object)) { newObject = []; for (i = 0, len = object.length; i < len; i++) { newObject[i] = clone(object[i]); } return newObject; } if (object instanceof Date && isFinite(object)) { return object.toISOString(); } if (isBinaryObject(object)) { return cloneBinaryObject(object); } if (!isPlainObject(object)) { return object; } newObject = {}; for (i in object) { if (Object.prototype.hasOwnProperty.call(object, i)) { var value = clone(object[i]); if (typeof value !== "undefined") { newObject[i] = value; } } } return newObject; } function once(fun) { var called = false; return function(...args) { if (called) { throw new Error("once called more than once"); } else { called = true; fun.apply(this, args); } }; } function toPromise(func) { return function(...args) { args = clone(args); var self2 = this; var usedCB = typeof args[args.length - 1] === "function" ? args.pop() : false; var promise = new Promise(function(fulfill, reject) { var resp; try { var callback = once(function(err, mesg) { if (err) { reject(err); } else { fulfill(mesg); } }); args.push(callback); resp = func.apply(self2, args); if (resp && typeof resp.then === "function") { fulfill(resp); } } catch (e2) { reject(e2); } }); if (usedCB) { promise.then(function(result) { usedCB(null, result); }, usedCB); } return promise; }; } function logApiCall(self2, name, args) { if (self2.constructor.listeners("debug").length) { var logArgs = ["api", self2.name, name]; for (var i = 0; i < args.length - 1; i++) { logArgs.push(args[i]); } self2.constructor.emit("debug", logArgs); var origCallback = args[args.length - 1]; args[args.length - 1] = function(err, res2) { var responseArgs = ["api", self2.name, name]; responseArgs = responseArgs.concat( err ? ["error", err] : ["success", res2] ); self2.constructor.emit("debug", responseArgs); origCallback(err, res2); }; } } function adapterFun(name, callback) { return toPromise(function(...args) { if (this._closed) { return Promise.reject(new Error("database is closed")); } if (this._destroyed) { return Promise.reject(new Error("database is destroyed")); } var self2 = this; logApiCall(self2, name, args); if (!this.taskqueue.isReady) { return new Promise(function(fulfill, reject) { self2.taskqueue.addTask(function(failed) { if (failed) { reject(failed); } else { fulfill(self2[name].apply(self2, args)); } }); }); } return callback.apply(this, args); }); } function pick(obj, arr) { var res2 = {}; for (var i = 0, len = arr.length; i < len; i++) { var prop = arr[i]; if (prop in obj) { res2[prop] = obj[prop]; } } return res2; } var MAX_NUM_CONCURRENT_REQUESTS = 6; function identityFunction(x) { return x; } function formatResultForOpenRevsGet(result) { return [{ ok: result }]; } function bulkGet(db, opts, callback) { var requests = opts.docs; var requestsById = new ExportedMap(); requests.forEach(function(request) { if (requestsById.has(request.id)) { requestsById.get(request.id).push(request); } else { requestsById.set(request.id, [request]); } }); var numDocs = requestsById.size; var numDone = 0; var perDocResults = new Array(numDocs); function collapseResultsAndFinish() { var results = []; perDocResults.forEach(function(res2) { res2.docs.forEach(function(info2) { results.push({ id: res2.id, docs: [info2] }); }); }); callback(null, { results }); } function checkDone() { if (++numDone === numDocs) { collapseResultsAndFinish(); } } function gotResult(docIndex, id, docs) { perDocResults[docIndex] = { id, docs }; checkDone(); } var allRequests = []; requestsById.forEach(function(value, key) { allRequests.push(key); }); var i = 0; function nextBatch() { if (i >= allRequests.length) { return; } var upTo = Math.min(i + MAX_NUM_CONCURRENT_REQUESTS, allRequests.length); var batch = allRequests.slice(i, upTo); processBatch(batch, i); i += batch.length; } function processBatch(batch, offset) { batch.forEach(function(docId, j) { var docIdx = offset + j; var docRequests = requestsById.get(docId); var docOpts = pick(docRequests[0], ["atts_since", "attachments"]); docOpts.open_revs = docRequests.map(function(request) { return request.rev; }); docOpts.open_revs = docOpts.open_revs.filter(identityFunction); var formatResult = identityFunction; if (docOpts.open_revs.length === 0) { delete docOpts.open_revs; formatResult = formatResultForOpenRevsGet; } ["revs", "attachments", "binary", "ajax", "latest"].forEach(function(param) { if (param in opts) { docOpts[param] = opts[param]; } }); db.get(docId, docOpts, function(err, res2) { var result; if (err) { result = [{ error: err }]; } else { result = formatResult(res2); } gotResult(docIdx, docId, result); nextBatch(); }); }); } nextBatch(); } var hasLocal; try { localStorage.setItem("_pouch_check_localstorage", 1); hasLocal = !!localStorage.getItem("_pouch_check_localstorage"); } catch (e2) { hasLocal = false; } function hasLocalStorage() { return hasLocal; } var Changes = class extends import_events.default { constructor() { super(); this._listeners = {}; if (hasLocalStorage()) { addEventListener("storage", (e2) => { this.emit(e2.key); }); } } addListener(dbName, id, db, opts) { if (this._listeners[id]) { return; } var inprogress = false; var self2 = this; function eventFunction() { if (!self2._listeners[id]) { return; } if (inprogress) { inprogress = "waiting"; return; } inprogress = true; var changesOpts = pick(opts, [ "style", "include_docs", "attachments", "conflicts", "filter", "doc_ids", "view", "since", "query_params", "binary", "return_docs" ]); function onError() { inprogress = false; } db.changes(changesOpts).on("change", function(c) { if (c.seq > opts.since && !opts.cancelled) { opts.since = c.seq; opts.onChange(c); } }).on("complete", function() { if (inprogress === "waiting") { (0, import_immediate.default)(eventFunction); } inprogress = false; }).on("error", onError); } this._listeners[id] = eventFunction; this.on(dbName, eventFunction); } removeListener(dbName, id) { if (!(id in this._listeners)) { return; } super.removeListener(dbName, this._listeners[id]); delete this._listeners[id]; } notifyLocalWindows(dbName) { if (hasLocalStorage()) { localStorage[dbName] = localStorage[dbName] === "a" ? "b" : "a"; } } notify(dbName) { this.emit(dbName); this.notifyLocalWindows(dbName); } }; function guardedConsole(method) { if (typeof console !== "undefined" && typeof console[method] === "function") { var args = Array.prototype.slice.call(arguments, 1); console[method].apply(console, args); } } function randomNumber(min, max2) { var maxTimeout = 6e5; min = parseInt(min, 10) || 0; max2 = parseInt(max2, 10); if (max2 !== max2 || max2 <= min) { max2 = (min || 1) << 1; } else { max2 = max2 + 1; } if (max2 > maxTimeout) { min = maxTimeout >> 1; max2 = maxTimeout; } var ratio = Math.random(); var range = max2 - min; return ~~(range * ratio + min); } function defaultBackOff(min) { var max2 = 0; if (!min) { max2 = 2e3; } return randomNumber(min, max2); } function explainError(status, str) { guardedConsole("info", "The above " + status + " is totally normal. " + str); } var assign$1; { if (typeof Object.assign === "function") { assign$1 = Object.assign; } else { assign$1 = function(target) { var to = Object(target); for (var index5 = 1; index5 < arguments.length; index5++) { var nextSource = arguments[index5]; if (nextSource != null) { for (var nextKey in nextSource) { if (Object.prototype.hasOwnProperty.call(nextSource, nextKey)) { to[nextKey] = nextSource[nextKey]; } } } } return to; }; } } var assign$2 = assign$1; function tryFilter(filter2, doc, req) { try { return !filter2(doc, req); } catch (err) { var msg = "Filter function threw: " + err.toString(); return createError(BAD_REQUEST, msg); } } function filterChange(opts) { var req = {}; var hasFilter = opts.filter && typeof opts.filter === "function"; req.query = opts.query_params; return function filter2(change) { if (!change.doc) { change.doc = {}; } var filterReturn = hasFilter && tryFilter(opts.filter, change.doc, req); if (typeof filterReturn === "object") { return filterReturn; } if (filterReturn) { return false; } if (!opts.include_docs) { delete change.doc; } else if (!opts.attachments) { for (var att in change.doc._attachments) { if (Object.prototype.hasOwnProperty.call(change.doc._attachments, att)) { change.doc._attachments[att].stub = true; } } } return true; }; } function flatten(arrs) { var res2 = []; for (var i = 0, len = arrs.length; i < len; i++) { res2 = res2.concat(arrs[i]); } return res2; } function f() { } var hasName = f.name; var res; if (hasName) { res = function(fun) { return fun.name; }; } else { res = function(fun) { var match2 = fun.toString().match(/^\s*function\s*(?:(\S+)\s*)?\(/); if (match2 && match2[1]) { return match2[1]; } else { return ""; } }; } function invalidIdError(id) { var err; if (!id) { err = createError(MISSING_ID); } else if (typeof id !== "string") { err = createError(INVALID_ID); } else if (/^_/.test(id) && !/^_(design|local)/.test(id)) { err = createError(RESERVED_ID); } if (err) { throw err; } } function isRemote(db) { if (typeof db._remote === "boolean") { return db._remote; } if (typeof db.type === "function") { guardedConsole( "warn", "db.type() is deprecated and will be removed in a future version of PouchDB" ); return db.type() === "http"; } return false; } function listenerCount(ee, type) { return "listenerCount" in ee ? ee.listenerCount(type) : import_events.default.listenerCount(ee, type); } function parseDesignDocFunctionName(s) { if (!s) { return null; } var parts = s.split("/"); if (parts.length === 2) { return parts; } if (parts.length === 1) { return [s, s]; } return null; } function normalizeDesignDocFunctionName(s) { var normalized = parseDesignDocFunctionName(s); return normalized ? normalized.join("/") : null; } var keys = [ "source", "protocol", "authority", "userInfo", "user", "password", "host", "port", "relative", "path", "directory", "file", "query", "anchor" ]; var qName = "queryKey"; var qParser = /(?:^|&)([^&=]*)=?([^&]*)/g; var parser = /^(?:(?![^:@]+:[^:@\/]*@)([^:\/?#.]+):)?(?:\/\/)?((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/; function parseUri(str) { var m = parser.exec(str); var uri = {}; var i = 14; while (i--) { var key = keys[i]; var value = m[i] || ""; var encoded = ["user", "password"].indexOf(key) !== -1; uri[key] = encoded ? decodeURIComponent(value) : value; } uri[qName] = {}; uri[keys[12]].replace(qParser, function($0, $1, $2) { if ($1) { uri[qName][$1] = $2; } }); return uri; } function scopeEval(source, scope) { var keys2 = []; var values = []; for (var key in scope) { if (Object.prototype.hasOwnProperty.call(scope, key)) { keys2.push(key); values.push(scope[key]); } } keys2.push(source); return Function.apply(null, keys2).apply(null, values); } function upsert(db, docId, diffFun) { return db.get(docId).catch(function(err) { if (err.status !== 404) { throw err; } return {}; }).then(function(doc) { var docRev = doc._rev; var newDoc = diffFun(doc); if (!newDoc) { return { updated: false, rev: docRev }; } newDoc._id = docId; newDoc._rev = docRev; return tryAndPut(db, newDoc, diffFun); }); } function tryAndPut(db, doc, diffFun) { return db.put(doc).then(function(res2) { return { updated: true, rev: res2.rev }; }, function(err) { if (err.status !== 409) { throw err; } return upsert(db, doc._id, diffFun); }); } function rev(doc, deterministic_revs) { if (!deterministic_revs) { return v4_default().replace(/-/g, "").toLowerCase(); } var mutateableDoc = assign$2({}, doc); delete mutateableDoc._rev_tree; return stringMd5(JSON.stringify(mutateableDoc)); } var uuid = v4_default; // node_modules/pouchdb-merge/lib/index.es.js function winningRev(metadata) { var winningId; var winningPos; var winningDeleted; var toVisit = metadata.rev_tree.slice(); var node; while (node = toVisit.pop()) { var tree = node.ids; var branches = tree[2]; var pos = node.pos; if (branches.length) { for (var i = 0, len = branches.length; i < len; i++) { toVisit.push({ pos: pos + 1, ids: branches[i] }); } continue; } var deleted = !!tree[1].deleted; var id = tree[0]; if (!winningId || (winningDeleted !== deleted ? winningDeleted : winningPos !== pos ? winningPos < pos : winningId < id)) { winningId = id; winningPos = pos; winningDeleted = deleted; } } return winningPos + "-" + winningId; } function traverseRevTree(revs, callback) { var toVisit = revs.slice(); var node; while (node = toVisit.pop()) { var pos = node.pos; var tree = node.ids; var branches = tree[2]; var newCtx = callback(branches.length === 0, pos, tree[0], node.ctx, tree[1]); for (var i = 0, len = branches.length; i < len; i++) { toVisit.push({ pos: pos + 1, ids: branches[i], ctx: newCtx }); } } } function sortByPos(a2, b) { return a2.pos - b.pos; } function collectLeaves(revs) { var leaves = []; traverseRevTree(revs, function(isLeaf, pos, id, acc, opts) { if (isLeaf) { leaves.push({ rev: pos + "-" + id, pos, opts }); } }); leaves.sort(sortByPos).reverse(); for (var i = 0, len = leaves.length; i < len; i++) { delete leaves[i].pos; } return leaves; } function collectConflicts(metadata) { var win = winningRev(metadata); var leaves = collectLeaves(metadata.rev_tree); var conflicts = []; for (var i = 0, len = leaves.length; i < len; i++) { var leaf = leaves[i]; if (leaf.rev !== win && !leaf.opts.deleted) { conflicts.push(leaf.rev); } } return conflicts; } function compactTree(metadata) { var revs = []; traverseRevTree(metadata.rev_tree, function(isLeaf, pos, revHash, ctx, opts) { if (opts.status === "available" && !isLeaf) { revs.push(pos + "-" + revHash); opts.status = "missing"; } }); return revs; } function findPathToLeaf(revs, targetRev) { let path = []; const toVisit = revs.slice(); let node; while (node = toVisit.pop()) { const { pos, ids: tree } = node; const rev2 = `${pos}-${tree[0]}`; const branches = tree[2]; path.push(rev2); if (rev2 === targetRev) { if (branches.length !== 0) { throw new Error("The requested revision is not a leaf"); } return path.reverse(); } if (branches.length === 0 || branches.length > 1) { path = []; } for (let i = 0, len = branches.length; i < len; i++) { toVisit.push({ pos: pos + 1, ids: branches[i] }); } } if (path.length === 0) { throw new Error("The requested revision does not exist"); } return path.reverse(); } function rootToLeaf(revs) { var paths = []; var toVisit = revs.slice(); var node; while (node = toVisit.pop()) { var pos = node.pos; var tree = node.ids; var id = tree[0]; var opts = tree[1]; var branches = tree[2]; var isLeaf = branches.length === 0; var history = node.history ? node.history.slice() : []; history.push({ id, opts }); if (isLeaf) { paths.push({ pos: pos + 1 - history.length, ids: history }); } for (var i = 0, len = branches.length; i < len; i++) { toVisit.push({ pos: pos + 1, ids: branches[i], history }); } } return paths.reverse(); } function sortByPos$1(a2, b) { return a2.pos - b.pos; } function binarySearch(arr, item, comparator) { var low = 0; var high = arr.length; var mid; while (low < high) { mid = low + high >>> 1; if (comparator(arr[mid], item) < 0) { low = mid + 1; } else { high = mid; } } return low; } function insertSorted(arr, item, comparator) { var idx = binarySearch(arr, item, comparator); arr.splice(idx, 0, item); } function pathToTree(path, numStemmed) { var root; var leaf; for (var i = numStemmed, len = path.length; i < len; i++) { var node = path[i]; var currentLeaf = [node.id, node.opts, []]; if (leaf) { leaf[2].push(currentLeaf); leaf = currentLeaf; } else { root = leaf = currentLeaf; } } return root; } function compareTree(a2, b) { return a2[0] < b[0] ? -1 : 1; } function mergeTree(in_tree1, in_tree2) { var queue2 = [{ tree1: in_tree1, tree2: in_tree2 }]; var conflicts = false; while (queue2.length > 0) { var item = queue2.pop(); var tree1 = item.tree1; var tree2 = item.tree2; if (tree1[1].status || tree2[1].status) { tree1[1].status = tree1[1].status === "available" || tree2[1].status === "available" ? "available" : "missing"; } for (var i = 0; i < tree2[2].length; i++) { if (!tree1[2][0]) { conflicts = "new_leaf"; tree1[2][0] = tree2[2][i]; continue; } var merged = false; for (var j = 0; j < tree1[2].length; j++) { if (tree1[2][j][0] === tree2[2][i][0]) { queue2.push({ tree1: tree1[2][j], tree2: tree2[2][i] }); merged = true; } } if (!merged) { conflicts = "new_branch"; insertSorted(tree1[2], tree2[2][i], compareTree); } } } return { conflicts, tree: in_tree1 }; } function doMerge(tree, path, dontExpand) { var restree = []; var conflicts = false; var merged = false; var res2; if (!tree.length) { return { tree: [path], conflicts: "new_leaf" }; } for (var i = 0, len = tree.length; i < len; i++) { var branch = tree[i]; if (branch.pos === path.pos && branch.ids[0] === path.ids[0]) { res2 = mergeTree(branch.ids, path.ids); restree.push({ pos: branch.pos, ids: res2.tree }); conflicts = conflicts || res2.conflicts; merged = true; } else if (dontExpand !== true) { var t1 = branch.pos < path.pos ? branch : path; var t2 = branch.pos < path.pos ? path : branch; var diff = t2.pos - t1.pos; var candidateParents = []; var trees = []; trees.push({ ids: t1.ids, diff, parent: null, parentIdx: null }); while (trees.length > 0) { var item = trees.pop(); if (item.diff === 0) { if (item.ids[0] === t2.ids[0]) { candidateParents.push(item); } continue; } var elements = item.ids[2]; for (var j = 0, elementsLen = elements.length; j < elementsLen; j++) { trees.push({ ids: elements[j], diff: item.diff - 1, parent: item.ids, parentIdx: j }); } } var el = candidateParents[0]; if (!el) { restree.push(branch); } else { res2 = mergeTree(el.ids, t2.ids); el.parent[2][el.parentIdx] = res2.tree; restree.push({ pos: t1.pos, ids: t1.ids }); conflicts = conflicts || res2.conflicts; merged = true; } } else { restree.push(branch); } } if (!merged) { restree.push(path); } restree.sort(sortByPos$1); return { tree: restree, conflicts: conflicts || "internal_node" }; } function stem(tree, depth) { var paths = rootToLeaf(tree); var stemmedRevs; var result; for (var i = 0, len = paths.length; i < len; i++) { var path = paths[i]; var stemmed = path.ids; var node; if (stemmed.length > depth) { if (!stemmedRevs) { stemmedRevs = {}; } var numStemmed = stemmed.length - depth; node = { pos: path.pos + numStemmed, ids: pathToTree(stemmed, numStemmed) }; for (var s = 0; s < numStemmed; s++) { var rev2 = path.pos + s + "-" + stemmed[s].id; stemmedRevs[rev2] = true; } } else { node = { pos: path.pos, ids: pathToTree(stemmed, 0) }; } if (result) { result = doMerge(result, node, true).tree; } else { result = [node]; } } if (stemmedRevs) { traverseRevTree(result, function(isLeaf, pos, revHash) { delete stemmedRevs[pos + "-" + revHash]; }); } return { tree: result, revs: stemmedRevs ? Object.keys(stemmedRevs) : [] }; } function merge(tree, path, depth) { var newTree = doMerge(tree, path); var stemmed = stem(newTree.tree, depth); return { tree: stemmed.tree, stemmedRevs: stemmed.revs, conflicts: newTree.conflicts }; } function removeLeafFromRevTree(tree, leafRev) { return tree.flatMap((path) => { path = removeLeafFromPath(path, leafRev); return path ? [path] : []; }); } function removeLeafFromPath(path, leafRev) { const tree = clone(path); const toVisit = [tree]; let node; while (node = toVisit.pop()) { const { pos, ids: [id, , branches], parent } = node; const isLeaf = branches.length === 0; const hash = `${pos}-${id}`; if (isLeaf && hash === leafRev) { if (!parent) { return null; } parent.ids[2] = parent.ids[2].filter(function(branchNode) { return branchNode[0] !== id; }); return tree; } for (let i = 0, len = branches.length; i < len; i++) { toVisit.push({ pos: pos + 1, ids: branches[i], parent: node }); } } return tree; } function revExists(revs, rev2) { var toVisit = revs.slice(); var splitRev = rev2.split("-"); var targetPos = parseInt(splitRev[0], 10); var targetId = splitRev[1]; var node; while (node = toVisit.pop()) { if (node.pos === targetPos && node.ids[0] === targetId) { return true; } var branches = node.ids[2]; for (var i = 0, len = branches.length; i < len; i++) { toVisit.push({ pos: node.pos + 1, ids: branches[i] }); } } return false; } function getTrees(node) { return node.ids; } function isDeleted(metadata, rev2) { if (!rev2) { rev2 = winningRev(metadata); } var id = rev2.substring(rev2.indexOf("-") + 1); var toVisit = metadata.rev_tree.map(getTrees); var tree; while (tree = toVisit.pop()) { if (tree[0] === id) { return !!tree[1].deleted; } toVisit = toVisit.concat(tree[2]); } } function isLocalId(id) { return /^_local/.test(id); } function latest(rev2, metadata) { var toVisit = metadata.rev_tree.slice(); var node; while (node = toVisit.pop()) { var pos = node.pos; var tree = node.ids; var id = tree[0]; var opts = tree[1]; var branches = tree[2]; var isLeaf = branches.length === 0; var history = node.history ? node.history.slice() : []; history.push({ id, pos, opts }); if (isLeaf) { for (var i = 0, len = history.length; i < len; i++) { var historyNode = history[i]; var historyRev = historyNode.pos + "-" + historyNode.id; if (historyRev === rev2) { return pos + "-" + id; } } } for (var j = 0, l = branches.length; j < l; j++) { toVisit.push({ pos: pos + 1, ids: branches[j], history }); } } throw new Error("Unable to resolve latest revision for id " + metadata.id + ", rev " + rev2); } // node_modules/pouchdb-core/lib/index.es.js var import_events2 = __toESM(require_events()); // node_modules/pouchdb-fetch/lib/index-browser.es.js var a = typeof AbortController !== "undefined" ? AbortController : function() { return { abort: function() { } }; }; var f2 = fetch; var h = Headers; // node_modules/pouchdb-collate/lib/index.es.js function pad(str, padWith, upToLength) { var padding = ""; var targetLength = upToLength - str.length; while (padding.length < targetLength) { padding += padWith; } return padding; } function padLeft(str, padWith, upToLength) { var padding = pad(str, padWith, upToLength); return padding + str; } var MIN_MAGNITUDE = -324; var MAGNITUDE_DIGITS = 3; var SEP = ""; function collate(a2, b) { if (a2 === b) { return 0; } a2 = normalizeKey(a2); b = normalizeKey(b); var ai = collationIndex(a2); var bi = collationIndex(b); if (ai - bi !== 0) { return ai - bi; } switch (typeof a2) { case "number": return a2 - b; case "boolean": return a2 < b ? -1 : 1; case "string": return stringCollate(a2, b); } return Array.isArray(a2) ? arrayCollate(a2, b) : objectCollate(a2, b); } function normalizeKey(key) { switch (typeof key) { case "undefined": return null; case "number": if (key === Infinity || key === -Infinity || isNaN(key)) { return null; } return key; case "object": var origKey = key; if (Array.isArray(key)) { var len = key.length; key = new Array(len); for (var i = 0; i < len; i++) { key[i] = normalizeKey(origKey[i]); } } else if (key instanceof Date) { return key.toJSON(); } else if (key !== null) { key = {}; for (var k in origKey) { if (Object.prototype.hasOwnProperty.call(origKey, k)) { var val = origKey[k]; if (typeof val !== "undefined") { key[k] = normalizeKey(val); } } } } } return key; } function indexify(key) { if (key !== null) { switch (typeof key) { case "boolean": return key ? 1 : 0; case "number": return numToIndexableString(key); case "string": return key.replace(/\u0002/g, "").replace(/\u0001/g, "").replace(/\u0000/g, ""); case "object": var isArray2 = Array.isArray(key); var arr = isArray2 ? key : Object.keys(key); var i = -1; var len = arr.length; var result = ""; if (isArray2) { while (++i < len) { result += toIndexableString(arr[i]); } } else { while (++i < len) { var objKey = arr[i]; result += toIndexableString(objKey) + toIndexableString(key[objKey]); } } return result; } } return ""; } function toIndexableString(key) { var zero = "\0"; key = normalizeKey(key); return collationIndex(key) + SEP + indexify(key) + zero; } function parseNumber(str, i) { var originalIdx = i; var num; var zero = str[i] === "1"; if (zero) { num = 0; i++; } else { var neg = str[i] === "0"; i++; var numAsString = ""; var magAsString = str.substring(i, i + MAGNITUDE_DIGITS); var magnitude = parseInt(magAsString, 10) + MIN_MAGNITUDE; if (neg) { magnitude = -magnitude; } i += MAGNITUDE_DIGITS; while (true) { var ch = str[i]; if (ch === "\0") { break; } else { numAsString += ch; } i++; } numAsString = numAsString.split("."); if (numAsString.length === 1) { num = parseInt(numAsString, 10); } else { num = parseFloat(numAsString[0] + "." + numAsString[1]); } if (neg) { num = num - 10; } if (magnitude !== 0) { num = parseFloat(num + "e" + magnitude); } } return { num, length: i - originalIdx }; } function pop(stack, metaStack) { var obj = stack.pop(); if (metaStack.length) { var lastMetaElement = metaStack[metaStack.length - 1]; if (obj === lastMetaElement.element) { metaStack.pop(); lastMetaElement = metaStack[metaStack.length - 1]; } var element2 = lastMetaElement.element; var lastElementIndex = lastMetaElement.index; if (Array.isArray(element2)) { element2.push(obj); } else if (lastElementIndex === stack.length - 2) { var key = stack.pop(); element2[key] = obj; } else { stack.push(obj); } } } function parseIndexableString(str) { var stack = []; var metaStack = []; var i = 0; while (true) { var collationIndex2 = str[i++]; if (collationIndex2 === "\0") { if (stack.length === 1) { return stack.pop(); } else { pop(stack, metaStack); continue; } } switch (collationIndex2) { case "1": stack.push(null); break; case "2": stack.push(str[i] === "1"); i++; break; case "3": var parsedNum = parseNumber(str, i); stack.push(parsedNum.num); i += parsedNum.length; break; case "4": var parsedStr = ""; while (true) { var ch = str[i]; if (ch === "\0") { break; } parsedStr += ch; i++; } parsedStr = parsedStr.replace(/\u0001\u0001/g, "\0").replace(/\u0001\u0002/g, "").replace(/\u0002\u0002/g, ""); stack.push(parsedStr); break; case "5": var arrayElement = { element: [], index: stack.length }; stack.push(arrayElement.element); metaStack.push(arrayElement); break; case "6": var objElement = { element: {}, index: stack.length }; stack.push(objElement.element); metaStack.push(objElement); break; default: throw new Error( "bad collationIndex or unexpectedly reached end of input: " + collationIndex2 ); } } } function arrayCollate(a2, b) { var len = Math.min(a2.length, b.length); for (var i = 0; i < len; i++) { var sort = collate(a2[i], b[i]); if (sort !== 0) { return sort; } } return a2.length === b.length ? 0 : a2.length > b.length ? 1 : -1; } function stringCollate(a2, b) { return a2 === b ? 0 : a2 > b ? 1 : -1; } function objectCollate(a2, b) { var ak = Object.keys(a2), bk = Object.keys(b); var len = Math.min(ak.length, bk.length); for (var i = 0; i < len; i++) { var sort = collate(ak[i], bk[i]); if (sort !== 0) { return sort; } sort = collate(a2[ak[i]], b[bk[i]]); if (sort !== 0) { return sort; } } return ak.length === bk.length ? 0 : ak.length > bk.length ? 1 : -1; } function collationIndex(x) { var id = ["boolean", "number", "string", "object"]; var idx = id.indexOf(typeof x); if (~idx) { if (x === null) { return 1; } if (Array.isArray(x)) { return 5; } return idx < 3 ? idx + 2 : idx + 3; } if (Array.isArray(x)) { return 5; } } function numToIndexableString(num) { if (num === 0) { return "1"; } var expFormat = num.toExponential().split(/e\+?/); var magnitude = parseInt(expFormat[1], 10); var neg = num < 0; var result = neg ? "0" : "2"; var magForComparison = (neg ? -magnitude : magnitude) - MIN_MAGNITUDE; var magString = padLeft(magForComparison.toString(), "0", MAGNITUDE_DIGITS); result += SEP + magString; var factor = Math.abs(parseFloat(expFormat[0])); if (neg) { factor = 10 - factor; } var factorStr = factor.toFixed(20); factorStr = factorStr.replace(/\.?0+$/, ""); result += SEP + factorStr; return result; } // node_modules/pouchdb-selector-core/lib/index.es.js function getFieldFromDoc(doc, parsedField) { var value = doc; for (var i = 0, len = parsedField.length; i < len; i++) { var key = parsedField[i]; value = value[key]; if (!value) { break; } } return value; } function setFieldInDoc(doc, parsedField, value) { for (var i = 0, len = parsedField.length; i < len - 1; i++) { var elem = parsedField[i]; doc = doc[elem] = doc[elem] || {}; } doc[parsedField[len - 1]] = value; } function compare(left, right) { return left < right ? -1 : left > right ? 1 : 0; } function parseField(fieldName) { var fields = []; var current = ""; for (var i = 0, len = fieldName.length; i < len; i++) { var ch = fieldName[i]; if (i > 0 && fieldName[i - 1] === "\\" && (ch === "$" || ch === ".")) { current = current.substring(0, current.length - 1) + ch; } else if (ch === ".") { fields.push(current); current = ""; } else { current += ch; } } fields.push(current); return fields; } var combinationFields = ["$or", "$nor", "$not"]; function isCombinationalField(field) { return combinationFields.indexOf(field) > -1; } function getKey(obj) { return Object.keys(obj)[0]; } function getValue(obj) { return obj[getKey(obj)]; } function mergeAndedSelectors(selectors) { var res2 = {}; var first = { $or: true, $nor: true }; selectors.forEach(function(selector) { Object.keys(selector).forEach(function(field) { var matcher = selector[field]; if (typeof matcher !== "object") { matcher = { $eq: matcher }; } if (isCombinationalField(field)) { if (matcher instanceof Array) { if (first[field]) { first[field] = false; res2[field] = matcher; return; } var entries = []; res2[field].forEach(function(existing) { Object.keys(matcher).forEach(function(key) { var m = matcher[key]; var longest = Math.max(Object.keys(existing).length, Object.keys(m).length); var merged = mergeAndedSelectors([existing, m]); if (Object.keys(merged).length <= longest) { return; } entries.push(merged); }); }); res2[field] = entries; } else { res2[field] = mergeAndedSelectors([matcher]); } } else { var fieldMatchers = res2[field] = res2[field] || {}; Object.keys(matcher).forEach(function(operator) { var value = matcher[operator]; if (operator === "$gt" || operator === "$gte") { return mergeGtGte(operator, value, fieldMatchers); } else if (operator === "$lt" || operator === "$lte") { return mergeLtLte(operator, value, fieldMatchers); } else if (operator === "$ne") { return mergeNe(value, fieldMatchers); } else if (operator === "$eq") { return mergeEq(value, fieldMatchers); } else if (operator === "$regex") { return mergeRegex(value, fieldMatchers); } fieldMatchers[operator] = value; }); } }); }); return res2; } function mergeGtGte(operator, value, fieldMatchers) { if (typeof fieldMatchers.$eq !== "undefined") { return; } if (typeof fieldMatchers.$gte !== "undefined") { if (operator === "$gte") { if (value > fieldMatchers.$gte) { fieldMatchers.$gte = value; } } else { if (value >= fieldMatchers.$gte) { delete fieldMatchers.$gte; fieldMatchers.$gt = value; } } } else if (typeof fieldMatchers.$gt !== "undefined") { if (operator === "$gte") { if (value > fieldMatchers.$gt) { delete fieldMatchers.$gt; fieldMatchers.$gte = value; } } else { if (value > fieldMatchers.$gt) { fieldMatchers.$gt = value; } } } else { fieldMatchers[operator] = value; } } function mergeLtLte(operator, value, fieldMatchers) { if (typeof fieldMatchers.$eq !== "undefined") { return; } if (typeof fieldMatchers.$lte !== "undefined") { if (operator === "$lte") { if (value < fieldMatchers.$lte) { fieldMatchers.$lte = value; } } else { if (value <= fieldMatchers.$lte) { delete fieldMatchers.$lte; fieldMatchers.$lt = value; } } } else if (typeof fieldMatchers.$lt !== "undefined") { if (operator === "$lte") { if (value < fieldMatchers.$lt) { delete fieldMatchers.$lt; fieldMatchers.$lte = value; } } else { if (value < fieldMatchers.$lt) { fieldMatchers.$lt = value; } } } else { fieldMatchers[operator] = value; } } function mergeNe(value, fieldMatchers) { if ("$ne" in fieldMatchers) { fieldMatchers.$ne.push(value); } else { fieldMatchers.$ne = [value]; } } function mergeEq(value, fieldMatchers) { delete fieldMatchers.$gt; delete fieldMatchers.$gte; delete fieldMatchers.$lt; delete fieldMatchers.$lte; delete fieldMatchers.$ne; fieldMatchers.$eq = value; } function mergeRegex(value, fieldMatchers) { if ("$regex" in fieldMatchers) { fieldMatchers.$regex.push(value); } else { fieldMatchers.$regex = [value]; } } function mergeAndedSelectorsNested(obj) { for (var prop in obj) { if (Array.isArray(obj)) { for (var i in obj) { if (obj[i]["$and"]) { obj[i] = mergeAndedSelectors(obj[i]["$and"]); } } } var value = obj[prop]; if (typeof value === "object") { mergeAndedSelectorsNested(value); } } return obj; } function isAndInSelector(obj, isAnd) { for (var prop in obj) { if (prop === "$and") { isAnd = true; } var value = obj[prop]; if (typeof value === "object") { isAnd = isAndInSelector(value, isAnd); } } return isAnd; } function massageSelector(input) { var result = clone(input); if (isAndInSelector(result, false)) { result = mergeAndedSelectorsNested(result); if ("$and" in result) { result = mergeAndedSelectors(result["$and"]); } } ["$or", "$nor"].forEach(function(orOrNor) { if (orOrNor in result) { result[orOrNor].forEach(function(subSelector) { var fields2 = Object.keys(subSelector); for (var i2 = 0; i2 < fields2.length; i2++) { var field2 = fields2[i2]; var matcher2 = subSelector[field2]; if (typeof matcher2 !== "object" || matcher2 === null) { subSelector[field2] = { $eq: matcher2 }; } } }); } }); if ("$not" in result) { result["$not"] = mergeAndedSelectors([result["$not"]]); } var fields = Object.keys(result); for (var i = 0; i < fields.length; i++) { var field = fields[i]; var matcher = result[field]; if (typeof matcher !== "object" || matcher === null) { matcher = { $eq: matcher }; } result[field] = matcher; } normalizeArrayOperators(result); return result; } function normalizeArrayOperators(selector) { Object.keys(selector).forEach(function(field) { var matcher = selector[field]; if (Array.isArray(matcher)) { matcher.forEach(function(matcherItem) { if (matcherItem && typeof matcherItem === "object") { normalizeArrayOperators(matcherItem); } }); } else if (field === "$ne") { selector.$ne = [matcher]; } else if (field === "$regex") { selector.$regex = [matcher]; } else if (matcher && typeof matcher === "object") { normalizeArrayOperators(matcher); } }); } function createFieldSorter(sort) { function getFieldValuesAsArray(doc) { return sort.map(function(sorting) { var fieldName = getKey(sorting); var parsedField = parseField(fieldName); var docFieldValue = getFieldFromDoc(doc, parsedField); return docFieldValue; }); } return function(aRow, bRow) { var aFieldValues = getFieldValuesAsArray(aRow.doc); var bFieldValues = getFieldValuesAsArray(bRow.doc); var collation = collate(aFieldValues, bFieldValues); if (collation !== 0) { return collation; } return compare(aRow.doc._id, bRow.doc._id); }; } function filterInMemoryFields(rows, requestDef, inMemoryFields) { rows = rows.filter(function(row) { return rowFilter(row.doc, requestDef.selector, inMemoryFields); }); if (requestDef.sort) { var fieldSorter = createFieldSorter(requestDef.sort); rows = rows.sort(fieldSorter); if (typeof requestDef.sort[0] !== "string" && getValue(requestDef.sort[0]) === "desc") { rows = rows.reverse(); } } if ("limit" in requestDef || "skip" in requestDef) { var skip = requestDef.skip || 0; var limit = ("limit" in requestDef ? requestDef.limit : rows.length) + skip; rows = rows.slice(skip, limit); } return rows; } function rowFilter(doc, selector, inMemoryFields) { return inMemoryFields.every(function(field) { var matcher = selector[field]; var parsedField = parseField(field); var docFieldValue = getFieldFromDoc(doc, parsedField); if (isCombinationalField(field)) { return matchCominationalSelector(field, matcher, doc); } return matchSelector(matcher, doc, parsedField, docFieldValue); }); } function matchSelector(matcher, doc, parsedField, docFieldValue) { if (!matcher) { return true; } if (typeof matcher === "object") { return Object.keys(matcher).every(function(maybeUserOperator) { var userValue = matcher[maybeUserOperator]; if (maybeUserOperator.indexOf("$") === 0) { return match(maybeUserOperator, doc, userValue, parsedField, docFieldValue); } else { var subParsedField = parseField(maybeUserOperator); if (docFieldValue === void 0 && typeof userValue !== "object" && subParsedField.length > 0) { return false; } var subDocFieldValue = getFieldFromDoc(docFieldValue, subParsedField); if (typeof userValue === "object") { return matchSelector(userValue, doc, parsedField, subDocFieldValue); } return match("$eq", doc, userValue, subParsedField, subDocFieldValue); } }); } return matcher === docFieldValue; } function matchCominationalSelector(field, matcher, doc) { if (field === "$or") { return matcher.some(function(orMatchers) { return rowFilter(doc, orMatchers, Object.keys(orMatchers)); }); } if (field === "$not") { return !rowFilter(doc, matcher, Object.keys(matcher)); } return !matcher.find(function(orMatchers) { return rowFilter(doc, orMatchers, Object.keys(orMatchers)); }); } function match(userOperator, doc, userValue, parsedField, docFieldValue) { if (!matchers[userOperator]) { throw new Error('unknown operator "' + userOperator + '" - should be one of $eq, $lte, $lt, $gt, $gte, $exists, $ne, $in, $nin, $size, $mod, $regex, $elemMatch, $type, $allMatch or $all'); } return matchers[userOperator](doc, userValue, parsedField, docFieldValue); } function fieldExists(docFieldValue) { return typeof docFieldValue !== "undefined" && docFieldValue !== null; } function fieldIsNotUndefined(docFieldValue) { return typeof docFieldValue !== "undefined"; } function modField(docFieldValue, userValue) { if (typeof docFieldValue !== "number" || parseInt(docFieldValue, 10) !== docFieldValue) { return false; } var divisor = userValue[0]; var mod = userValue[1]; return docFieldValue % divisor === mod; } function arrayContainsValue(docFieldValue, userValue) { return userValue.some(function(val) { if (docFieldValue instanceof Array) { return docFieldValue.some(function(docFieldValueItem) { return collate(val, docFieldValueItem) === 0; }); } return collate(val, docFieldValue) === 0; }); } function arrayContainsAllValues(docFieldValue, userValue) { return userValue.every(function(val) { return docFieldValue.some(function(docFieldValueItem) { return collate(val, docFieldValueItem) === 0; }); }); } function arraySize(docFieldValue, userValue) { return docFieldValue.length === userValue; } function regexMatch(docFieldValue, userValue) { var re = new RegExp(userValue); return re.test(docFieldValue); } function typeMatch(docFieldValue, userValue) { switch (userValue) { case "null": return docFieldValue === null; case "boolean": return typeof docFieldValue === "boolean"; case "number": return typeof docFieldValue === "number"; case "string": return typeof docFieldValue === "string"; case "array": return docFieldValue instanceof Array; case "object": return {}.toString.call(docFieldValue) === "[object Object]"; } } var matchers = { "$elemMatch": function(doc, userValue, parsedField, docFieldValue) { if (!Array.isArray(docFieldValue)) { return false; } if (docFieldValue.length === 0) { return false; } if (typeof docFieldValue[0] === "object" && docFieldValue[0] !== null) { return docFieldValue.some(function(val) { return rowFilter(val, userValue, Object.keys(userValue)); }); } return docFieldValue.some(function(val) { return matchSelector(userValue, doc, parsedField, val); }); }, "$allMatch": function(doc, userValue, parsedField, docFieldValue) { if (!Array.isArray(docFieldValue)) { return false; } if (docFieldValue.length === 0) { return false; } if (typeof docFieldValue[0] === "object" && docFieldValue[0] !== null) { return docFieldValue.every(function(val) { return rowFilter(val, userValue, Object.keys(userValue)); }); } return docFieldValue.every(function(val) { return matchSelector(userValue, doc, parsedField, val); }); }, "$eq": function(doc, userValue, parsedField, docFieldValue) { return fieldIsNotUndefined(docFieldValue) && collate(docFieldValue, userValue) === 0; }, "$gte": function(doc, userValue, parsedField, docFieldValue) { return fieldIsNotUndefined(docFieldValue) && collate(docFieldValue, userValue) >= 0; }, "$gt": function(doc, userValue, parsedField, docFieldValue) { return fieldIsNotUndefined(docFieldValue) && collate(docFieldValue, userValue) > 0; }, "$lte": function(doc, userValue, parsedField, docFieldValue) { return fieldIsNotUndefined(docFieldValue) && collate(docFieldValue, userValue) <= 0; }, "$lt": function(doc, userValue, parsedField, docFieldValue) { return fieldIsNotUndefined(docFieldValue) && collate(docFieldValue, userValue) < 0; }, "$exists": function(doc, userValue, parsedField, docFieldValue) { if (userValue) { return fieldIsNotUndefined(docFieldValue); } return !fieldIsNotUndefined(docFieldValue); }, "$mod": function(doc, userValue, parsedField, docFieldValue) { return fieldExists(docFieldValue) && modField(docFieldValue, userValue); }, "$ne": function(doc, userValue, parsedField, docFieldValue) { return userValue.every(function(neValue) { return collate(docFieldValue, neValue) !== 0; }); }, "$in": function(doc, userValue, parsedField, docFieldValue) { return fieldExists(docFieldValue) && arrayContainsValue(docFieldValue, userValue); }, "$nin": function(doc, userValue, parsedField, docFieldValue) { return fieldExists(docFieldValue) && !arrayContainsValue(docFieldValue, userValue); }, "$size": function(doc, userValue, parsedField, docFieldValue) { return fieldExists(docFieldValue) && Array.isArray(docFieldValue) && arraySize(docFieldValue, userValue); }, "$all": function(doc, userValue, parsedField, docFieldValue) { return Array.isArray(docFieldValue) && arrayContainsAllValues(docFieldValue, userValue); }, "$regex": function(doc, userValue, parsedField, docFieldValue) { return fieldExists(docFieldValue) && typeof docFieldValue == "string" && userValue.every(function(regexValue) { return regexMatch(docFieldValue, regexValue); }); }, "$type": function(doc, userValue, parsedField, docFieldValue) { return typeMatch(docFieldValue, userValue); } }; function matchesSelector(doc, selector) { if (typeof selector !== "object") { throw new Error("Selector error: expected a JSON object"); } selector = massageSelector(selector); var row = { "doc": doc }; var rowsMatched = filterInMemoryFields([row], { "selector": selector }, Object.keys(selector)); return rowsMatched && rowsMatched.length === 1; } // node_modules/pouchdb-changes-filter/lib/index-browser.es.js function evalFilter(input) { return scopeEval('"use strict";\nreturn ' + input + ";", {}); } function evalView(input) { var code = [ "return function(doc) {", ' "use strict";', " var emitted = false;", " var emit = function (a, b) {", " emitted = true;", " };", " var view = " + input + ";", " view(doc);", " if (emitted) {", " return true;", " }", "};" ].join("\n"); return scopeEval(code, {}); } function validate2(opts, callback) { if (opts.selector) { if (opts.filter && opts.filter !== "_selector") { var filterName = typeof opts.filter === "string" ? opts.filter : "function"; return callback(new Error('selector invalid for filter "' + filterName + '"')); } } callback(); } function normalize(opts) { if (opts.view && !opts.filter) { opts.filter = "_view"; } if (opts.selector && !opts.filter) { opts.filter = "_selector"; } if (opts.filter && typeof opts.filter === "string") { if (opts.filter === "_view") { opts.view = normalizeDesignDocFunctionName(opts.view); } else { opts.filter = normalizeDesignDocFunctionName(opts.filter); } } } function shouldFilter(changesHandler, opts) { return opts.filter && typeof opts.filter === "string" && !opts.doc_ids && !isRemote(changesHandler.db); } function filter(changesHandler, opts) { var callback = opts.complete; if (opts.filter === "_view") { if (!opts.view || typeof opts.view !== "string") { var err = createError( BAD_REQUEST, "`view` filter parameter not found or invalid." ); return callback(err); } var viewName = parseDesignDocFunctionName(opts.view); changesHandler.db.get("_design/" + viewName[0], function(err2, ddoc) { if (changesHandler.isCancelled) { return callback(null, { status: "cancelled" }); } if (err2) { return callback(generateErrorFromResponse(err2)); } var mapFun = ddoc && ddoc.views && ddoc.views[viewName[1]] && ddoc.views[viewName[1]].map; if (!mapFun) { return callback(createError( MISSING_DOC, ddoc.views ? "missing json key: " + viewName[1] : "missing json key: views" )); } opts.filter = evalView(mapFun); changesHandler.doChanges(opts); }); } else if (opts.selector) { opts.filter = function(doc) { return matchesSelector(doc, opts.selector); }; changesHandler.doChanges(opts); } else { var filterName = parseDesignDocFunctionName(opts.filter); changesHandler.db.get("_design/" + filterName[0], function(err2, ddoc) { if (changesHandler.isCancelled) { return callback(null, { status: "cancelled" }); } if (err2) { return callback(generateErrorFromResponse(err2)); } var filterFun = ddoc && ddoc.filters && ddoc.filters[filterName[1]]; if (!filterFun) { return callback(createError( MISSING_DOC, ddoc && ddoc.filters ? "missing json key: " + filterName[1] : "missing json key: filters" )); } opts.filter = evalFilter(filterFun); changesHandler.doChanges(opts); }); } } function applyChangesFilterPlugin(PouchDB2) { PouchDB2._changesFilterPlugin = { validate: validate2, normalize, shouldFilter, filter }; } var index_browser_es_default = applyChangesFilterPlugin; // node_modules/pouchdb-core/lib/index.es.js function tryCatchInChangeListener(self2, change, pending, lastSeq) { try { self2.emit("change", change, pending, lastSeq); } catch (e2) { guardedConsole("error", 'Error in .on("change", function):', e2); } } function processChange(doc, metadata, opts) { var changeList = [{ rev: doc._rev }]; if (opts.style === "all_docs") { changeList = collectLeaves(metadata.rev_tree).map(function(x) { return { rev: x.rev }; }); } var change = { id: metadata.id, changes: changeList, doc }; if (isDeleted(metadata, doc._rev)) { change.deleted = true; } if (opts.conflicts) { change.doc._conflicts = collectConflicts(metadata); if (!change.doc._conflicts.length) { delete change.doc._conflicts; } } return change; } var Changes2 = class extends import_events2.default { constructor(db, opts, callback) { super(); this.db = db; opts = opts ? clone(opts) : {}; var complete = opts.complete = once((err, resp) => { if (err) { if (listenerCount(this, "error") > 0) { this.emit("error", err); } } else { this.emit("complete", resp); } this.removeAllListeners(); db.removeListener("destroyed", onDestroy2); }); if (callback) { this.on("complete", function(resp) { callback(null, resp); }); this.on("error", callback); } const onDestroy2 = () => { this.cancel(); }; db.once("destroyed", onDestroy2); opts.onChange = (change, pending, lastSeq) => { if (this.isCancelled) { return; } tryCatchInChangeListener(this, change, pending, lastSeq); }; var promise = new Promise(function(fulfill, reject) { opts.complete = function(err, res2) { if (err) { reject(err); } else { fulfill(res2); } }; }); this.once("cancel", function() { db.removeListener("destroyed", onDestroy2); opts.complete(null, { status: "cancelled" }); }); this.then = promise.then.bind(promise); this["catch"] = promise["catch"].bind(promise); this.then(function(result) { complete(null, result); }, complete); if (!db.taskqueue.isReady) { db.taskqueue.addTask((failed) => { if (failed) { opts.complete(failed); } else if (this.isCancelled) { this.emit("cancel"); } else { this.validateChanges(opts); } }); } else { this.validateChanges(opts); } } cancel() { this.isCancelled = true; if (this.db.taskqueue.isReady) { this.emit("cancel"); } } validateChanges(opts) { var callback = opts.complete; if (PouchDB._changesFilterPlugin) { PouchDB._changesFilterPlugin.validate(opts, (err) => { if (err) { return callback(err); } this.doChanges(opts); }); } else { this.doChanges(opts); } } doChanges(opts) { var callback = opts.complete; opts = clone(opts); if ("live" in opts && !("continuous" in opts)) { opts.continuous = opts.live; } opts.processChange = processChange; if (opts.since === "latest") { opts.since = "now"; } if (!opts.since) { opts.since = 0; } if (opts.since === "now") { this.db.info().then((info2) => { if (this.isCancelled) { callback(null, { status: "cancelled" }); return; } opts.since = info2.update_seq; this.doChanges(opts); }, callback); return; } if (PouchDB._changesFilterPlugin) { PouchDB._changesFilterPlugin.normalize(opts); if (PouchDB._changesFilterPlugin.shouldFilter(this, opts)) { return PouchDB._changesFilterPlugin.filter(this, opts); } } else { ["doc_ids", "filter", "selector", "view"].forEach(function(key) { if (key in opts) { guardedConsole( "warn", 'The "' + key + '" option was passed in to changes/replicate, but pouchdb-changes-filter plugin is not installed, so it was ignored. Please install the plugin to enable filtering.' ); } }); } if (!("descending" in opts)) { opts.descending = false; } opts.limit = opts.limit === 0 ? 1 : opts.limit; opts.complete = callback; var newPromise = this.db._changes(opts); if (newPromise && typeof newPromise.cancel === "function") { const cancel = this.cancel; this.cancel = (...args) => { newPromise.cancel(); cancel.apply(this, args); }; } } }; function compare2(left, right) { return left < right ? -1 : left > right ? 1 : 0; } function yankError(callback, docId) { return function(err, results) { if (err || results[0] && results[0].error) { err = err || results[0]; err.docId = docId; callback(err); } else { callback(null, results.length ? results[0] : results); } }; } function cleanDocs(docs) { for (var i = 0; i < docs.length; i++) { var doc = docs[i]; if (doc._deleted) { delete doc._attachments; } else if (doc._attachments) { var atts = Object.keys(doc._attachments); for (var j = 0; j < atts.length; j++) { var att = atts[j]; doc._attachments[att] = pick( doc._attachments[att], ["data", "digest", "content_type", "length", "revpos", "stub"] ); } } } } function compareByIdThenRev(a2, b) { var idCompare = compare2(a2._id, b._id); if (idCompare !== 0) { return idCompare; } var aStart = a2._revisions ? a2._revisions.start : 0; var bStart = b._revisions ? b._revisions.start : 0; return compare2(aStart, bStart); } function computeHeight(revs) { var height = {}; var edges = []; traverseRevTree(revs, function(isLeaf, pos, id, prnt) { var rev$$1 = pos + "-" + id; if (isLeaf) { height[rev$$1] = 0; } if (prnt !== void 0) { edges.push({ from: prnt, to: rev$$1 }); } return rev$$1; }); edges.reverse(); edges.forEach(function(edge) { if (height[edge.from] === void 0) { height[edge.from] = 1 + height[edge.to]; } else { height[edge.from] = Math.min(height[edge.from], 1 + height[edge.to]); } }); return height; } function allDocsKeysParse(opts) { var keys2 = "limit" in opts ? opts.keys.slice(opts.skip, opts.limit + opts.skip) : opts.skip > 0 ? opts.keys.slice(opts.skip) : opts.keys; opts.keys = keys2; opts.skip = 0; delete opts.limit; if (opts.descending) { keys2.reverse(); opts.descending = false; } } function doNextCompaction(self2) { var task = self2._compactionQueue[0]; var opts = task.opts; var callback = task.callback; self2.get("_local/compaction").catch(function() { return false; }).then(function(doc) { if (doc && doc.last_seq) { opts.last_seq = doc.last_seq; } self2._compact(opts, function(err, res2) { if (err) { callback(err); } else { callback(null, res2); } (0, import_immediate.default)(function() { self2._compactionQueue.shift(); if (self2._compactionQueue.length) { doNextCompaction(self2); } }); }); }); } function appendPurgeSeq(db, docId, rev$$1) { return db.get("_local/purges").then(function(doc) { const purgeSeq = doc.purgeSeq + 1; doc.purges.push({ docId, rev: rev$$1, purgeSeq }); if (doc.purges.length > self.purged_infos_limit) { doc.purges.splice(0, doc.purges.length - self.purged_infos_limit); } doc.purgeSeq = purgeSeq; return doc; }).catch(function(err) { if (err.status !== 404) { throw err; } return { _id: "_local/purges", purges: [{ docId, rev: rev$$1, purgeSeq: 0 }], purgeSeq: 0 }; }).then(function(doc) { return db.put(doc); }); } function attachmentNameError(name) { if (name.charAt(0) === "_") { return name + " is not a valid attachment name, attachment names cannot start with '_'"; } return false; } var AbstractPouchDB = class extends import_events2.default { _setup() { this.post = adapterFun("post", function(doc, opts, callback) { if (typeof opts === "function") { callback = opts; opts = {}; } if (typeof doc !== "object" || Array.isArray(doc)) { return callback(createError(NOT_AN_OBJECT)); } this.bulkDocs({ docs: [doc] }, opts, yankError(callback, doc._id)); }).bind(this); this.put = adapterFun("put", function(doc, opts, cb) { if (typeof opts === "function") { cb = opts; opts = {}; } if (typeof doc !== "object" || Array.isArray(doc)) { return cb(createError(NOT_AN_OBJECT)); } invalidIdError(doc._id); if (isLocalId(doc._id) && typeof this._putLocal === "function") { if (doc._deleted) { return this._removeLocal(doc, cb); } else { return this._putLocal(doc, cb); } } const putDoc = (next) => { if (typeof this._put === "function" && opts.new_edits !== false) { this._put(doc, opts, next); } else { this.bulkDocs({ docs: [doc] }, opts, yankError(next, doc._id)); } }; if (opts.force && doc._rev) { transformForceOptionToNewEditsOption(); putDoc(function(err) { var result = err ? null : { ok: true, id: doc._id, rev: doc._rev }; cb(err, result); }); } else { putDoc(cb); } function transformForceOptionToNewEditsOption() { var parts = doc._rev.split("-"); var oldRevId = parts[1]; var oldRevNum = parseInt(parts[0], 10); var newRevNum = oldRevNum + 1; var newRevId = rev(); doc._revisions = { start: newRevNum, ids: [newRevId, oldRevId] }; doc._rev = newRevNum + "-" + newRevId; opts.new_edits = false; } }).bind(this); this.putAttachment = adapterFun("putAttachment", function(docId, attachmentId, rev$$1, blob, type) { var api = this; if (typeof type === "function") { type = blob; blob = rev$$1; rev$$1 = null; } if (typeof type === "undefined") { type = blob; blob = rev$$1; rev$$1 = null; } if (!type) { guardedConsole("warn", "Attachment", attachmentId, "on document", docId, "is missing content_type"); } function createAttachment(doc) { var prevrevpos = "_rev" in doc ? parseInt(doc._rev, 10) : 0; doc._attachments = doc._attachments || {}; doc._attachments[attachmentId] = { content_type: type, data: blob, revpos: ++prevrevpos }; return api.put(doc); } return api.get(docId).then(function(doc) { if (doc._rev !== rev$$1) { throw createError(REV_CONFLICT); } return createAttachment(doc); }, function(err) { if (err.reason === MISSING_DOC.message) { return createAttachment({ _id: docId }); } else { throw err; } }); }).bind(this); this.removeAttachment = adapterFun("removeAttachment", function(docId, attachmentId, rev$$1, callback) { this.get(docId, (err, obj) => { if (err) { callback(err); return; } if (obj._rev !== rev$$1) { callback(createError(REV_CONFLICT)); return; } if (!obj._attachments) { return callback(); } delete obj._attachments[attachmentId]; if (Object.keys(obj._attachments).length === 0) { delete obj._attachments; } this.put(obj, callback); }); }).bind(this); this.remove = adapterFun("remove", function(docOrId, optsOrRev, opts, callback) { var doc; if (typeof optsOrRev === "string") { doc = { _id: docOrId, _rev: optsOrRev }; if (typeof opts === "function") { callback = opts; opts = {}; } } else { doc = docOrId; if (typeof optsOrRev === "function") { callback = optsOrRev; opts = {}; } else { callback = opts; opts = optsOrRev; } } opts = opts || {}; opts.was_delete = true; var newDoc = { _id: doc._id, _rev: doc._rev || opts.rev }; newDoc._deleted = true; if (isLocalId(newDoc._id) && typeof this._removeLocal === "function") { return this._removeLocal(doc, callback); } this.bulkDocs({ docs: [newDoc] }, opts, yankError(callback, newDoc._id)); }).bind(this); this.revsDiff = adapterFun("revsDiff", function(req, opts, callback) { if (typeof opts === "function") { callback = opts; opts = {}; } var ids = Object.keys(req); if (!ids.length) { return callback(null, {}); } var count = 0; var missing = new ExportedMap(); function addToMissing(id, revId) { if (!missing.has(id)) { missing.set(id, { missing: [] }); } missing.get(id).missing.push(revId); } function processDoc(id, rev_tree) { var missingForId = req[id].slice(0); traverseRevTree(rev_tree, function(isLeaf, pos, revHash, ctx, opts2) { var rev$$1 = pos + "-" + revHash; var idx = missingForId.indexOf(rev$$1); if (idx === -1) { return; } missingForId.splice(idx, 1); if (opts2.status !== "available") { addToMissing(id, rev$$1); } }); missingForId.forEach(function(rev$$1) { addToMissing(id, rev$$1); }); } ids.map(function(id) { this._getRevisionTree(id, function(err, rev_tree) { if (err && err.status === 404 && err.message === "missing") { missing.set(id, { missing: req[id] }); } else if (err) { return callback(err); } else { processDoc(id, rev_tree); } if (++count === ids.length) { var missingObj = {}; missing.forEach(function(value, key) { missingObj[key] = value; }); return callback(null, missingObj); } }); }, this); }).bind(this); this.bulkGet = adapterFun("bulkGet", function(opts, callback) { bulkGet(this, opts, callback); }).bind(this); this.compactDocument = adapterFun("compactDocument", function(docId, maxHeight, callback) { this._getRevisionTree(docId, (err, revTree) => { if (err) { return callback(err); } var height = computeHeight(revTree); var candidates = []; var revs = []; Object.keys(height).forEach(function(rev$$1) { if (height[rev$$1] > maxHeight) { candidates.push(rev$$1); } }); traverseRevTree(revTree, function(isLeaf, pos, revHash, ctx, opts) { var rev$$1 = pos + "-" + revHash; if (opts.status === "available" && candidates.indexOf(rev$$1) !== -1) { revs.push(rev$$1); } }); this._doCompaction(docId, revs, callback); }); }).bind(this); this.compact = adapterFun("compact", function(opts, callback) { if (typeof opts === "function") { callback = opts; opts = {}; } opts = opts || {}; this._compactionQueue = this._compactionQueue || []; this._compactionQueue.push({ opts, callback }); if (this._compactionQueue.length === 1) { doNextCompaction(this); } }).bind(this); this.get = adapterFun("get", function(id, opts, cb) { if (typeof opts === "function") { cb = opts; opts = {}; } if (typeof id !== "string") { return cb(createError(INVALID_ID)); } if (isLocalId(id) && typeof this._getLocal === "function") { return this._getLocal(id, cb); } var leaves = []; const finishOpenRevs = () => { var result = []; var count = leaves.length; if (!count) { return cb(null, result); } leaves.forEach((leaf) => { this.get(id, { rev: leaf, revs: opts.revs, latest: opts.latest, attachments: opts.attachments, binary: opts.binary }, function(err, doc) { if (!err) { var existing; for (var i2 = 0, l2 = result.length; i2 < l2; i2++) { if (result[i2].ok && result[i2].ok._rev === doc._rev) { existing = true; break; } } if (!existing) { result.push({ ok: doc }); } } else { result.push({ missing: leaf }); } count--; if (!count) { cb(null, result); } }); }); }; if (opts.open_revs) { if (opts.open_revs === "all") { this._getRevisionTree(id, function(err, rev_tree) { if (err) { return cb(err); } leaves = collectLeaves(rev_tree).map(function(leaf) { return leaf.rev; }); finishOpenRevs(); }); } else { if (Array.isArray(opts.open_revs)) { leaves = opts.open_revs; for (var i = 0; i < leaves.length; i++) { var l = leaves[i]; if (!(typeof l === "string" && /^\d+-/.test(l))) { return cb(createError(INVALID_REV)); } } finishOpenRevs(); } else { return cb(createError(UNKNOWN_ERROR, "function_clause")); } } return; } return this._get(id, opts, (err, result) => { if (err) { err.docId = id; return cb(err); } var doc = result.doc; var metadata = result.metadata; var ctx = result.ctx; if (opts.conflicts) { var conflicts = collectConflicts(metadata); if (conflicts.length) { doc._conflicts = conflicts; } } if (isDeleted(metadata, doc._rev)) { doc._deleted = true; } if (opts.revs || opts.revs_info) { var splittedRev = doc._rev.split("-"); var revNo = parseInt(splittedRev[0], 10); var revHash = splittedRev[1]; var paths = rootToLeaf(metadata.rev_tree); var path = null; for (var i2 = 0; i2 < paths.length; i2++) { var currentPath = paths[i2]; var hashIndex = currentPath.ids.map(function(x) { return x.id; }).indexOf(revHash); var hashFoundAtRevPos = hashIndex === revNo - 1; if (hashFoundAtRevPos || !path && hashIndex !== -1) { path = currentPath; } } if (!path) { err = new Error("invalid rev tree"); err.docId = id; return cb(err); } var indexOfRev = path.ids.map(function(x) { return x.id; }).indexOf(doc._rev.split("-")[1]) + 1; var howMany = path.ids.length - indexOfRev; path.ids.splice(indexOfRev, howMany); path.ids.reverse(); if (opts.revs) { doc._revisions = { start: path.pos + path.ids.length - 1, ids: path.ids.map(function(rev$$1) { return rev$$1.id; }) }; } if (opts.revs_info) { var pos = path.pos + path.ids.length; doc._revs_info = path.ids.map(function(rev$$1) { pos--; return { rev: pos + "-" + rev$$1.id, status: rev$$1.opts.status }; }); } } if (opts.attachments && doc._attachments) { var attachments = doc._attachments; var count = Object.keys(attachments).length; if (count === 0) { return cb(null, doc); } Object.keys(attachments).forEach((key2) => { this._getAttachment(doc._id, key2, attachments[key2], { rev: doc._rev, binary: opts.binary, ctx }, function(err2, data) { var att = doc._attachments[key2]; att.data = data; delete att.stub; delete att.length; if (!--count) { cb(null, doc); } }); }); } else { if (doc._attachments) { for (var key in doc._attachments) { if (Object.prototype.hasOwnProperty.call(doc._attachments, key)) { doc._attachments[key].stub = true; } } } cb(null, doc); } }); }).bind(this); this.getAttachment = adapterFun("getAttachment", function(docId, attachmentId, opts, callback) { if (opts instanceof Function) { callback = opts; opts = {}; } this._get(docId, opts, (err, res2) => { if (err) { return callback(err); } if (res2.doc._attachments && res2.doc._attachments[attachmentId]) { opts.ctx = res2.ctx; opts.binary = true; this._getAttachment( docId, attachmentId, res2.doc._attachments[attachmentId], opts, callback ); } else { return callback(createError(MISSING_DOC)); } }); }).bind(this); this.allDocs = adapterFun("allDocs", function(opts, callback) { if (typeof opts === "function") { callback = opts; opts = {}; } opts.skip = typeof opts.skip !== "undefined" ? opts.skip : 0; if (opts.start_key) { opts.startkey = opts.start_key; } if (opts.end_key) { opts.endkey = opts.end_key; } if ("keys" in opts) { if (!Array.isArray(opts.keys)) { return callback(new TypeError("options.keys must be an array")); } var incompatibleOpt = ["startkey", "endkey", "key"].filter(function(incompatibleOpt2) { return incompatibleOpt2 in opts; })[0]; if (incompatibleOpt) { callback(createError( QUERY_PARSE_ERROR, "Query parameter `" + incompatibleOpt + "` is not compatible with multi-get" )); return; } if (!isRemote(this)) { allDocsKeysParse(opts); if (opts.keys.length === 0) { return this._allDocs({ limit: 0 }, callback); } } } return this._allDocs(opts, callback); }).bind(this); this.close = adapterFun("close", function(callback) { this._closed = true; this.emit("closed"); return this._close(callback); }).bind(this); this.info = adapterFun("info", function(callback) { this._info((err, info2) => { if (err) { return callback(err); } info2.db_name = info2.db_name || this.name; info2.auto_compaction = !!(this.auto_compaction && !isRemote(this)); info2.adapter = this.adapter; callback(null, info2); }); }).bind(this); this.id = adapterFun("id", function(callback) { return this._id(callback); }).bind(this); this.bulkDocs = adapterFun("bulkDocs", function(req, opts, callback) { if (typeof opts === "function") { callback = opts; opts = {}; } opts = opts || {}; if (Array.isArray(req)) { req = { docs: req }; } if (!req || !req.docs || !Array.isArray(req.docs)) { return callback(createError(MISSING_BULK_DOCS)); } for (var i = 0; i < req.docs.length; ++i) { if (typeof req.docs[i] !== "object" || Array.isArray(req.docs[i])) { return callback(createError(NOT_AN_OBJECT)); } } var attachmentError; req.docs.forEach(function(doc) { if (doc._attachments) { Object.keys(doc._attachments).forEach(function(name) { attachmentError = attachmentError || attachmentNameError(name); if (!doc._attachments[name].content_type) { guardedConsole("warn", "Attachment", name, "on document", doc._id, "is missing content_type"); } }); } }); if (attachmentError) { return callback(createError(BAD_REQUEST, attachmentError)); } if (!("new_edits" in opts)) { if ("new_edits" in req) { opts.new_edits = req.new_edits; } else { opts.new_edits = true; } } var adapter = this; if (!opts.new_edits && !isRemote(adapter)) { req.docs.sort(compareByIdThenRev); } cleanDocs(req.docs); var ids = req.docs.map(function(doc) { return doc._id; }); this._bulkDocs(req, opts, function(err, res2) { if (err) { return callback(err); } if (!opts.new_edits) { res2 = res2.filter(function(x) { return x.error; }); } if (!isRemote(adapter)) { for (var i2 = 0, l = res2.length; i2 < l; i2++) { res2[i2].id = res2[i2].id || ids[i2]; } } callback(null, res2); }); }).bind(this); this.registerDependentDatabase = adapterFun("registerDependentDatabase", function(dependentDb, callback) { var dbOptions = clone(this.__opts); if (this.__opts.view_adapter) { dbOptions.adapter = this.__opts.view_adapter; } var depDB = new this.constructor(dependentDb, dbOptions); function diffFun(doc) { doc.dependentDbs = doc.dependentDbs || {}; if (doc.dependentDbs[dependentDb]) { return false; } doc.dependentDbs[dependentDb] = true; return doc; } upsert(this, "_local/_pouch_dependentDbs", diffFun).then(function() { callback(null, { db: depDB }); }).catch(callback); }).bind(this); this.destroy = adapterFun("destroy", function(opts, callback) { if (typeof opts === "function") { callback = opts; opts = {}; } var usePrefix = "use_prefix" in this ? this.use_prefix : true; const destroyDb = () => { this._destroy(opts, (err, resp) => { if (err) { return callback(err); } this._destroyed = true; this.emit("destroyed"); callback(null, resp || { "ok": true }); }); }; if (isRemote(this)) { return destroyDb(); } this.get("_local/_pouch_dependentDbs", (err, localDoc) => { if (err) { if (err.status !== 404) { return callback(err); } else { return destroyDb(); } } var dependentDbs = localDoc.dependentDbs; var PouchDB2 = this.constructor; var deletedMap = Object.keys(dependentDbs).map((name) => { var trueName = usePrefix ? name.replace(new RegExp("^" + PouchDB2.prefix), "") : name; return new PouchDB2(trueName, this.__opts).destroy(); }); Promise.all(deletedMap).then(destroyDb, callback); }); }).bind(this); } _compact(opts, callback) { var changesOpts = { return_docs: false, last_seq: opts.last_seq || 0 }; var promises = []; var taskId; var compactedDocs = 0; const onChange = (row) => { this.activeTasks.update(taskId, { completed_items: ++compactedDocs }); promises.push(this.compactDocument(row.id, 0)); }; const onError = (err) => { this.activeTasks.remove(taskId, err); callback(err); }; const onComplete = (resp) => { var lastSeq = resp.last_seq; Promise.all(promises).then(() => { return upsert(this, "_local/compaction", (doc) => { if (!doc.last_seq || doc.last_seq < lastSeq) { doc.last_seq = lastSeq; return doc; } return false; }); }).then(() => { this.activeTasks.remove(taskId); callback(null, { ok: true }); }).catch(onError); }; this.info().then((info2) => { taskId = this.activeTasks.add({ name: "database_compaction", total_items: info2.update_seq - changesOpts.last_seq }); this.changes(changesOpts).on("change", onChange).on("complete", onComplete).on("error", onError); }); } changes(opts, callback) { if (typeof opts === "function") { callback = opts; opts = {}; } opts = opts || {}; opts.return_docs = "return_docs" in opts ? opts.return_docs : !opts.live; return new Changes2(this, opts, callback); } type() { return typeof this._type === "function" ? this._type() : this.adapter; } }; AbstractPouchDB.prototype.purge = adapterFun("_purge", function(docId, rev$$1, callback) { if (typeof this._purge === "undefined") { return callback(createError(UNKNOWN_ERROR, "Purge is not implemented in the " + this.adapter + " adapter.")); } var self2 = this; self2._getRevisionTree(docId, (error, revs) => { if (error) { return callback(error); } if (!revs) { return callback(createError(MISSING_DOC)); } let path; try { path = findPathToLeaf(revs, rev$$1); } catch (error2) { return callback(error2.message || error2); } self2._purge(docId, path, (error2, result) => { if (error2) { return callback(error2); } else { appendPurgeSeq(self2, docId, rev$$1).then(function() { return callback(null, result); }); } }); }); }); var TaskQueue = class { constructor() { this.isReady = false; this.failed = false; this.queue = []; } execute() { var fun; if (this.failed) { while (fun = this.queue.shift()) { fun(this.failed); } } else { while (fun = this.queue.shift()) { fun(); } } } fail(err) { this.failed = err; this.execute(); } ready(db) { this.isReady = true; this.db = db; this.execute(); } addTask(fun) { this.queue.push(fun); if (this.failed) { this.execute(); } } }; function parseAdapter(name, opts) { var match2 = name.match(/([a-z-]*):\/\/(.*)/); if (match2) { return { name: /https?/.test(match2[1]) ? match2[1] + "://" + match2[2] : match2[2], adapter: match2[1] }; } var adapters = PouchDB.adapters; var preferredAdapters = PouchDB.preferredAdapters; var prefix = PouchDB.prefix; var adapterName = opts.adapter; if (!adapterName) { for (var i = 0; i < preferredAdapters.length; ++i) { adapterName = preferredAdapters[i]; if (adapterName === "idb" && "websql" in adapters && hasLocalStorage() && localStorage["_pouch__websqldb_" + prefix + name]) { guardedConsole("log", 'PouchDB is downgrading "' + name + '" to WebSQL to avoid data loss, because it was already opened with WebSQL.'); continue; } break; } } var adapter = adapters[adapterName]; var usePrefix = adapter && "use_prefix" in adapter ? adapter.use_prefix : true; return { name: usePrefix ? prefix + name : name, adapter: adapterName }; } function inherits(A, B) { A.prototype = Object.create(B.prototype, { constructor: { value: A } }); } function createClass(parent, init3) { let klass = function(...args) { if (!(this instanceof klass)) { return new klass(...args); } init3.apply(this, args); }; inherits(klass, parent); return klass; } function prepareForDestruction(self2) { function onDestroyed(from_constructor) { self2.removeListener("closed", onClosed); if (!from_constructor) { self2.constructor.emit("destroyed", self2.name); } } function onClosed() { self2.removeListener("destroyed", onDestroyed); self2.constructor.emit("unref", self2); } self2.once("destroyed", onDestroyed); self2.once("closed", onClosed); self2.constructor.emit("ref", self2); } var PouchInternal = class extends AbstractPouchDB { constructor(name, opts) { super(); this._setup(name, opts); } _setup(name, opts) { super._setup(); opts = opts || {}; if (name && typeof name === "object") { opts = name; name = opts.name; delete opts.name; } if (opts.deterministic_revs === void 0) { opts.deterministic_revs = true; } this.__opts = opts = clone(opts); this.auto_compaction = opts.auto_compaction; this.purged_infos_limit = opts.purged_infos_limit || 1e3; this.prefix = PouchDB.prefix; if (typeof name !== "string") { throw new Error("Missing/invalid DB name"); } var prefixedName = (opts.prefix || "") + name; var backend = parseAdapter(prefixedName, opts); opts.name = backend.name; opts.adapter = opts.adapter || backend.adapter; this.name = name; this._adapter = opts.adapter; PouchDB.emit("debug", ["adapter", "Picked adapter: ", opts.adapter]); if (!PouchDB.adapters[opts.adapter] || !PouchDB.adapters[opts.adapter].valid()) { throw new Error("Invalid Adapter: " + opts.adapter); } if (opts.view_adapter) { if (!PouchDB.adapters[opts.view_adapter] || !PouchDB.adapters[opts.view_adapter].valid()) { throw new Error("Invalid View Adapter: " + opts.view_adapter); } } this.taskqueue = new TaskQueue(); this.adapter = opts.adapter; PouchDB.adapters[opts.adapter].call(this, opts, (err) => { if (err) { return this.taskqueue.fail(err); } prepareForDestruction(this); this.emit("created", this); PouchDB.emit("created", this.name); this.taskqueue.ready(this); }); } }; var PouchDB = createClass(PouchInternal, function(name, opts) { PouchInternal.prototype._setup.call(this, name, opts); }); var ActiveTasks = class { constructor() { this.tasks = {}; } list() { return Object.values(this.tasks); } add(task) { const id = v4_default(); this.tasks[id] = { id, name: task.name, total_items: task.total_items, created_at: new Date().toJSON() }; return id; } get(id) { return this.tasks[id]; } remove(id, reason) { delete this.tasks[id]; return this.tasks; } update(id, updatedTask) { const task = this.tasks[id]; if (typeof task !== "undefined") { const mergedTask = { id: task.id, name: task.name, created_at: task.created_at, total_items: updatedTask.total_items || task.total_items, completed_items: updatedTask.completed_items || task.completed_items, updated_at: new Date().toJSON() }; this.tasks[id] = mergedTask; } return this.tasks; } }; PouchDB.adapters = {}; PouchDB.preferredAdapters = []; PouchDB.prefix = "_pouch_"; var eventEmitter = new import_events2.default(); function setUpEventEmitter(Pouch) { Object.keys(import_events2.default.prototype).forEach(function(key) { if (typeof import_events2.default.prototype[key] === "function") { Pouch[key] = eventEmitter[key].bind(eventEmitter); } }); var destructListeners = Pouch._destructionListeners = new ExportedMap(); Pouch.on("ref", function onConstructorRef(db) { if (!destructListeners.has(db.name)) { destructListeners.set(db.name, []); } destructListeners.get(db.name).push(db); }); Pouch.on("unref", function onConstructorUnref(db) { if (!destructListeners.has(db.name)) { return; } var dbList = destructListeners.get(db.name); var pos = dbList.indexOf(db); if (pos < 0) { return; } dbList.splice(pos, 1); if (dbList.length > 1) { destructListeners.set(db.name, dbList); } else { destructListeners.delete(db.name); } }); Pouch.on("destroyed", function onConstructorDestroyed(name) { if (!destructListeners.has(name)) { return; } var dbList = destructListeners.get(name); destructListeners.delete(name); dbList.forEach(function(db) { db.emit("destroyed", true); }); }); } setUpEventEmitter(PouchDB); PouchDB.adapter = function(id, obj, addToPreferredAdapters) { if (obj.valid()) { PouchDB.adapters[id] = obj; if (addToPreferredAdapters) { PouchDB.preferredAdapters.push(id); } } }; PouchDB.plugin = function(obj) { if (typeof obj === "function") { obj(PouchDB); } else if (typeof obj !== "object" || Object.keys(obj).length === 0) { throw new Error('Invalid plugin: got "' + obj + '", expected an object or a function'); } else { Object.keys(obj).forEach(function(id) { PouchDB.prototype[id] = obj[id]; }); } if (this.__defaults) { PouchDB.__defaults = assign$2({}, this.__defaults); } return PouchDB; }; PouchDB.defaults = function(defaultOpts) { let PouchWithDefaults = createClass(PouchDB, function(name, opts) { opts = opts || {}; if (name && typeof name === "object") { opts = name; name = opts.name; delete opts.name; } opts = assign$2({}, PouchWithDefaults.__defaults, opts); PouchDB.call(this, name, opts); }); PouchWithDefaults.preferredAdapters = PouchDB.preferredAdapters.slice(); Object.keys(PouchDB).forEach(function(key) { if (!(key in PouchWithDefaults)) { PouchWithDefaults[key] = PouchDB[key]; } }); PouchWithDefaults.__defaults = assign$2({}, this.__defaults, defaultOpts); return PouchWithDefaults; }; PouchDB.fetch = function(url, opts) { return f2(url, opts); }; PouchDB.prototype.activeTasks = PouchDB.activeTasks = new ActiveTasks(); var version = "8.0.1"; PouchDB.plugin(index_browser_es_default); PouchDB.version = version; var index_es_default = PouchDB; // node_modules/pouchdb-adapter-utils/lib/index.es.js function toObject(array) { return array.reduce(function(obj, item) { obj[item] = true; return obj; }, {}); } var reservedWords = toObject([ "_id", "_rev", "_access", "_attachments", "_deleted", "_revisions", "_revs_info", "_conflicts", "_deleted_conflicts", "_local_seq", "_rev_tree", "_replication_id", "_replication_state", "_replication_state_time", "_replication_state_reason", "_replication_stats", "_removed" ]); var dataWords = toObject([ "_access", "_attachments", "_replication_id", "_replication_state", "_replication_state_time", "_replication_state_reason", "_replication_stats" ]); function parseRevisionInfo(rev$$1) { if (!/^\d+-/.test(rev$$1)) { return createError(INVALID_REV); } var idx = rev$$1.indexOf("-"); var left = rev$$1.substring(0, idx); var right = rev$$1.substring(idx + 1); return { prefix: parseInt(left, 10), id: right }; } function makeRevTreeFromRevisions(revisions, opts) { var pos = revisions.start - revisions.ids.length + 1; var revisionIds = revisions.ids; var ids = [revisionIds[0], opts, []]; for (var i = 1, len = revisionIds.length; i < len; i++) { ids = [revisionIds[i], { status: "missing" }, [ids]]; } return [{ pos, ids }]; } function parseDoc(doc, newEdits, dbOpts) { if (!dbOpts) { dbOpts = { deterministic_revs: true }; } var nRevNum; var newRevId; var revInfo; var opts = { status: "available" }; if (doc._deleted) { opts.deleted = true; } if (newEdits) { if (!doc._id) { doc._id = uuid(); } newRevId = rev(doc, dbOpts.deterministic_revs); if (doc._rev) { revInfo = parseRevisionInfo(doc._rev); if (revInfo.error) { return revInfo; } doc._rev_tree = [{ pos: revInfo.prefix, ids: [revInfo.id, { status: "missing" }, [[newRevId, opts, []]]] }]; nRevNum = revInfo.prefix + 1; } else { doc._rev_tree = [{ pos: 1, ids: [newRevId, opts, []] }]; nRevNum = 1; } } else { if (doc._revisions) { doc._rev_tree = makeRevTreeFromRevisions(doc._revisions, opts); nRevNum = doc._revisions.start; newRevId = doc._revisions.ids[0]; } if (!doc._rev_tree) { revInfo = parseRevisionInfo(doc._rev); if (revInfo.error) { return revInfo; } nRevNum = revInfo.prefix; newRevId = revInfo.id; doc._rev_tree = [{ pos: nRevNum, ids: [newRevId, opts, []] }]; } } invalidIdError(doc._id); doc._rev = nRevNum + "-" + newRevId; var result = { metadata: {}, data: {} }; for (var key in doc) { if (Object.prototype.hasOwnProperty.call(doc, key)) { var specialKey = key[0] === "_"; if (specialKey && !reservedWords[key]) { var error = createError(DOC_VALIDATION, key); error.message = DOC_VALIDATION.message + ": " + key; throw error; } else if (specialKey && !dataWords[key]) { result.metadata[key.slice(1)] = doc[key]; } else { result.data[key] = doc[key]; } } } return result; } function parseBase64(data) { try { return thisAtob(data); } catch (e2) { var err = createError( BAD_ARG, "Attachment is not a valid base64 string" ); return { error: err }; } } function preprocessString(att, blobType, callback) { var asBinary = parseBase64(att.data); if (asBinary.error) { return callback(asBinary.error); } att.length = asBinary.length; if (blobType === "blob") { att.data = binStringToBluffer(asBinary, att.content_type); } else if (blobType === "base64") { att.data = thisBtoa(asBinary); } else { att.data = asBinary; } binaryMd5(asBinary, function(result) { att.digest = "md5-" + result; callback(); }); } function preprocessBlob(att, blobType, callback) { binaryMd5(att.data, function(md5) { att.digest = "md5-" + md5; att.length = att.data.size || att.data.length || 0; if (blobType === "binary") { blobToBinaryString(att.data, function(binString) { att.data = binString; callback(); }); } else if (blobType === "base64") { blobToBase64(att.data, function(b64) { att.data = b64; callback(); }); } else { callback(); } }); } function preprocessAttachment(att, blobType, callback) { if (att.stub) { return callback(); } if (typeof att.data === "string") { preprocessString(att, blobType, callback); } else { preprocessBlob(att, blobType, callback); } } function preprocessAttachments(docInfos, blobType, callback) { if (!docInfos.length) { return callback(); } var docv = 0; var overallErr; docInfos.forEach(function(docInfo) { var attachments = docInfo.data && docInfo.data._attachments ? Object.keys(docInfo.data._attachments) : []; var recv = 0; if (!attachments.length) { return done(); } function processedAttachment(err) { overallErr = err; recv++; if (recv === attachments.length) { done(); } } for (var key in docInfo.data._attachments) { if (Object.prototype.hasOwnProperty.call(docInfo.data._attachments, key)) { preprocessAttachment( docInfo.data._attachments[key], blobType, processedAttachment ); } } }); function done() { docv++; if (docInfos.length === docv) { if (overallErr) { callback(overallErr); } else { callback(); } } } } function updateDoc(revLimit, prev, docInfo, results, i, cb, writeDoc, newEdits) { if (revExists(prev.rev_tree, docInfo.metadata.rev) && !newEdits) { results[i] = docInfo; return cb(); } var previousWinningRev = prev.winningRev || winningRev(prev); var previouslyDeleted = "deleted" in prev ? prev.deleted : isDeleted(prev, previousWinningRev); var deleted = "deleted" in docInfo.metadata ? docInfo.metadata.deleted : isDeleted(docInfo.metadata); var isRoot = /^1-/.test(docInfo.metadata.rev); if (previouslyDeleted && !deleted && newEdits && isRoot) { var newDoc = docInfo.data; newDoc._rev = previousWinningRev; newDoc._id = docInfo.metadata.id; docInfo = parseDoc(newDoc, newEdits); } var merged = merge(prev.rev_tree, docInfo.metadata.rev_tree[0], revLimit); var inConflict = newEdits && (previouslyDeleted && deleted && merged.conflicts !== "new_leaf" || !previouslyDeleted && merged.conflicts !== "new_leaf" || previouslyDeleted && !deleted && merged.conflicts === "new_branch"); if (inConflict) { var err = createError(REV_CONFLICT); results[i] = err; return cb(); } var newRev = docInfo.metadata.rev; docInfo.metadata.rev_tree = merged.tree; docInfo.stemmedRevs = merged.stemmedRevs || []; if (prev.rev_map) { docInfo.metadata.rev_map = prev.rev_map; } var winningRev$$1 = winningRev(docInfo.metadata); var winningRevIsDeleted = isDeleted(docInfo.metadata, winningRev$$1); var delta = previouslyDeleted === winningRevIsDeleted ? 0 : previouslyDeleted < winningRevIsDeleted ? -1 : 1; var newRevIsDeleted; if (newRev === winningRev$$1) { newRevIsDeleted = winningRevIsDeleted; } else { newRevIsDeleted = isDeleted(docInfo.metadata, newRev); } writeDoc( docInfo, winningRev$$1, winningRevIsDeleted, newRevIsDeleted, true, delta, i, cb ); } function rootIsMissing(docInfo) { return docInfo.metadata.rev_tree[0].ids[1].status === "missing"; } function processDocs(revLimit, docInfos, api, fetchedDocs, tx, results, writeDoc, opts, overallCallback) { revLimit = revLimit || 1e3; function insertDoc(docInfo, resultsIdx, callback) { var winningRev$$1 = winningRev(docInfo.metadata); var deleted = isDeleted(docInfo.metadata, winningRev$$1); if ("was_delete" in opts && deleted) { results[resultsIdx] = createError(MISSING_DOC, "deleted"); return callback(); } var inConflict = newEdits && rootIsMissing(docInfo); if (inConflict) { var err = createError(REV_CONFLICT); results[resultsIdx] = err; return callback(); } var delta = deleted ? 0 : 1; writeDoc( docInfo, winningRev$$1, deleted, deleted, false, delta, resultsIdx, callback ); } var newEdits = opts.new_edits; var idsToDocs = new ExportedMap(); var docsDone = 0; var docsToDo = docInfos.length; function checkAllDocsDone() { if (++docsDone === docsToDo && overallCallback) { overallCallback(); } } docInfos.forEach(function(currentDoc, resultsIdx) { if (currentDoc._id && isLocalId(currentDoc._id)) { var fun = currentDoc._deleted ? "_removeLocal" : "_putLocal"; api[fun](currentDoc, { ctx: tx }, function(err, res2) { results[resultsIdx] = err || res2; checkAllDocsDone(); }); return; } var id = currentDoc.metadata.id; if (idsToDocs.has(id)) { docsToDo--; idsToDocs.get(id).push([currentDoc, resultsIdx]); } else { idsToDocs.set(id, [[currentDoc, resultsIdx]]); } }); idsToDocs.forEach(function(docs, id) { var numDone = 0; function docWritten() { if (++numDone < docs.length) { nextDoc(); } else { checkAllDocsDone(); } } function nextDoc() { var value = docs[numDone]; var currentDoc = value[0]; var resultsIdx = value[1]; if (fetchedDocs.has(id)) { updateDoc( revLimit, fetchedDocs.get(id), currentDoc, results, resultsIdx, docWritten, writeDoc, newEdits ); } else { var merged = merge([], currentDoc.metadata.rev_tree[0], revLimit); currentDoc.metadata.rev_tree = merged.tree; currentDoc.stemmedRevs = merged.stemmedRevs || []; insertDoc(currentDoc, resultsIdx, docWritten); } } nextDoc(); }); } // node_modules/pouchdb-json/lib/index.es.js var import_vuvuzela = __toESM(require_vuvuzela()); function safeJsonParse(str) { try { return JSON.parse(str); } catch (e2) { return import_vuvuzela.default.parse(str); } } function safeJsonStringify(json) { try { return JSON.stringify(json); } catch (e2) { return import_vuvuzela.default.stringify(json); } } // node_modules/pouchdb-adapter-idb/lib/index.es.js var ADAPTER_VERSION = 5; var DOC_STORE = "document-store"; var BY_SEQ_STORE = "by-sequence"; var ATTACH_STORE = "attach-store"; var ATTACH_AND_SEQ_STORE = "attach-seq-store"; var META_STORE = "meta-store"; var LOCAL_STORE = "local-store"; var DETECT_BLOB_SUPPORT_STORE = "detect-blob-support"; function idbError(callback) { return function(evt) { var message = "unknown_error"; if (evt.target && evt.target.error) { message = evt.target.error.name || evt.target.error.message; } callback(createError(IDB_ERROR, message, evt.type)); }; } function encodeMetadata(metadata, winningRev$$1, deleted) { return { data: safeJsonStringify(metadata), winningRev: winningRev$$1, deletedOrLocal: deleted ? "1" : "0", seq: metadata.seq, id: metadata.id }; } function decodeMetadata(storedObject) { if (!storedObject) { return null; } var metadata = safeJsonParse(storedObject.data); metadata.winningRev = storedObject.winningRev; metadata.deleted = storedObject.deletedOrLocal === "1"; metadata.seq = storedObject.seq; return metadata; } function decodeDoc(doc) { if (!doc) { return doc; } var idx = doc._doc_id_rev.lastIndexOf(":"); doc._id = doc._doc_id_rev.substring(0, idx - 1); doc._rev = doc._doc_id_rev.substring(idx + 1); delete doc._doc_id_rev; return doc; } function readBlobData(body, type, asBlob, callback) { if (asBlob) { if (!body) { callback(createBlob([""], { type })); } else if (typeof body !== "string") { callback(body); } else { callback(b64ToBluffer(body, type)); } } else { if (!body) { callback(""); } else if (typeof body !== "string") { readAsBinaryString(body, function(binary) { callback(thisBtoa(binary)); }); } else { callback(body); } } } function fetchAttachmentsIfNecessary(doc, opts, txn, cb) { var attachments = Object.keys(doc._attachments || {}); if (!attachments.length) { return cb && cb(); } var numDone = 0; function checkDone() { if (++numDone === attachments.length && cb) { cb(); } } function fetchAttachment(doc2, att) { var attObj = doc2._attachments[att]; var digest = attObj.digest; var req = txn.objectStore(ATTACH_STORE).get(digest); req.onsuccess = function(e2) { attObj.body = e2.target.result.body; checkDone(); }; } attachments.forEach(function(att) { if (opts.attachments && opts.include_docs) { fetchAttachment(doc, att); } else { doc._attachments[att].stub = true; checkDone(); } }); } function postProcessAttachments(results, asBlob) { return Promise.all(results.map(function(row) { if (row.doc && row.doc._attachments) { var attNames = Object.keys(row.doc._attachments); return Promise.all(attNames.map(function(att) { var attObj = row.doc._attachments[att]; if (!("body" in attObj)) { return; } var body = attObj.body; var type = attObj.content_type; return new Promise(function(resolve) { readBlobData(body, type, asBlob, function(data) { row.doc._attachments[att] = assign$2( pick(attObj, ["digest", "content_type"]), { data } ); resolve(); }); }); })); } })); } function compactRevs(revs, docId, txn) { var possiblyOrphanedDigests = []; var seqStore = txn.objectStore(BY_SEQ_STORE); var attStore = txn.objectStore(ATTACH_STORE); var attAndSeqStore = txn.objectStore(ATTACH_AND_SEQ_STORE); var count = revs.length; function checkDone() { count--; if (!count) { deleteOrphanedAttachments(); } } function deleteOrphanedAttachments() { if (!possiblyOrphanedDigests.length) { return; } possiblyOrphanedDigests.forEach(function(digest) { var countReq = attAndSeqStore.index("digestSeq").count( IDBKeyRange.bound( digest + "::", digest + "::\uFFFF", false, false ) ); countReq.onsuccess = function(e2) { var count2 = e2.target.result; if (!count2) { attStore.delete(digest); } }; }); } revs.forEach(function(rev2) { var index5 = seqStore.index("_doc_id_rev"); var key = docId + "::" + rev2; index5.getKey(key).onsuccess = function(e2) { var seq = e2.target.result; if (typeof seq !== "number") { return checkDone(); } seqStore.delete(seq); var cursor = attAndSeqStore.index("seq").openCursor(IDBKeyRange.only(seq)); cursor.onsuccess = function(event) { var cursor2 = event.target.result; if (cursor2) { var digest = cursor2.value.digestSeq.split("::")[0]; possiblyOrphanedDigests.push(digest); attAndSeqStore.delete(cursor2.primaryKey); cursor2.continue(); } else { checkDone(); } }; }; }); } function openTransactionSafely(idb, stores, mode) { try { return { txn: idb.transaction(stores, mode) }; } catch (err) { return { error: err }; } } var changesHandler$1 = new Changes(); function idbBulkDocs(dbOpts, req, opts, api, idb, callback) { var docInfos = req.docs; var txn; var docStore; var bySeqStore; var attachStore; var attachAndSeqStore; var metaStore; var docInfoError; var metaDoc; for (var i = 0, len = docInfos.length; i < len; i++) { var doc = docInfos[i]; if (doc._id && isLocalId(doc._id)) { continue; } doc = docInfos[i] = parseDoc(doc, opts.new_edits, dbOpts); if (doc.error && !docInfoError) { docInfoError = doc; } } if (docInfoError) { return callback(docInfoError); } var allDocsProcessed = false; var docCountDelta = 0; var results = new Array(docInfos.length); var fetchedDocs = new ExportedMap(); var preconditionErrored = false; var blobType = api._meta.blobSupport ? "blob" : "base64"; preprocessAttachments(docInfos, blobType, function(err) { if (err) { return callback(err); } startTransaction(); }); function startTransaction() { var stores = [ DOC_STORE, BY_SEQ_STORE, ATTACH_STORE, LOCAL_STORE, ATTACH_AND_SEQ_STORE, META_STORE ]; var txnResult = openTransactionSafely(idb, stores, "readwrite"); if (txnResult.error) { return callback(txnResult.error); } txn = txnResult.txn; txn.onabort = idbError(callback); txn.ontimeout = idbError(callback); txn.oncomplete = complete; docStore = txn.objectStore(DOC_STORE); bySeqStore = txn.objectStore(BY_SEQ_STORE); attachStore = txn.objectStore(ATTACH_STORE); attachAndSeqStore = txn.objectStore(ATTACH_AND_SEQ_STORE); metaStore = txn.objectStore(META_STORE); metaStore.get(META_STORE).onsuccess = function(e2) { metaDoc = e2.target.result; updateDocCountIfReady(); }; verifyAttachments(function(err) { if (err) { preconditionErrored = true; return callback(err); } fetchExistingDocs(); }); } function onAllDocsProcessed() { allDocsProcessed = true; updateDocCountIfReady(); } function idbProcessDocs() { processDocs( dbOpts.revs_limit, docInfos, api, fetchedDocs, txn, results, writeDoc, opts, onAllDocsProcessed ); } function updateDocCountIfReady() { if (!metaDoc || !allDocsProcessed) { return; } metaDoc.docCount += docCountDelta; metaStore.put(metaDoc); } function fetchExistingDocs() { if (!docInfos.length) { return; } var numFetched = 0; function checkDone() { if (++numFetched === docInfos.length) { idbProcessDocs(); } } function readMetadata(event) { var metadata = decodeMetadata(event.target.result); if (metadata) { fetchedDocs.set(metadata.id, metadata); } checkDone(); } for (var i2 = 0, len2 = docInfos.length; i2 < len2; i2++) { var docInfo = docInfos[i2]; if (docInfo._id && isLocalId(docInfo._id)) { checkDone(); continue; } var req2 = docStore.get(docInfo.metadata.id); req2.onsuccess = readMetadata; } } function complete() { if (preconditionErrored) { return; } changesHandler$1.notify(api._meta.name); callback(null, results); } function verifyAttachment(digest, callback2) { var req2 = attachStore.get(digest); req2.onsuccess = function(e2) { if (!e2.target.result) { var err = createError( MISSING_STUB, "unknown stub attachment with digest " + digest ); err.status = 412; callback2(err); } else { callback2(); } }; } function verifyAttachments(finish) { var digests = []; docInfos.forEach(function(docInfo) { if (docInfo.data && docInfo.data._attachments) { Object.keys(docInfo.data._attachments).forEach(function(filename) { var att = docInfo.data._attachments[filename]; if (att.stub) { digests.push(att.digest); } }); } }); if (!digests.length) { return finish(); } var numDone = 0; var err; function checkDone() { if (++numDone === digests.length) { finish(err); } } digests.forEach(function(digest) { verifyAttachment(digest, function(attErr) { if (attErr && !err) { err = attErr; } checkDone(); }); }); } function writeDoc(docInfo, winningRev$$1, winningRevIsDeleted, newRevIsDeleted, isUpdate, delta, resultsIdx, callback2) { docInfo.metadata.winningRev = winningRev$$1; docInfo.metadata.deleted = winningRevIsDeleted; var doc2 = docInfo.data; doc2._id = docInfo.metadata.id; doc2._rev = docInfo.metadata.rev; if (newRevIsDeleted) { doc2._deleted = true; } var hasAttachments = doc2._attachments && Object.keys(doc2._attachments).length; if (hasAttachments) { return writeAttachments( docInfo, winningRev$$1, winningRevIsDeleted, isUpdate, resultsIdx, callback2 ); } docCountDelta += delta; updateDocCountIfReady(); finishDoc( docInfo, winningRev$$1, winningRevIsDeleted, isUpdate, resultsIdx, callback2 ); } function finishDoc(docInfo, winningRev$$1, winningRevIsDeleted, isUpdate, resultsIdx, callback2) { var doc2 = docInfo.data; var metadata = docInfo.metadata; doc2._doc_id_rev = metadata.id + "::" + metadata.rev; delete doc2._id; delete doc2._rev; function afterPutDoc(e2) { var revsToDelete = docInfo.stemmedRevs || []; if (isUpdate && api.auto_compaction) { revsToDelete = revsToDelete.concat(compactTree(docInfo.metadata)); } if (revsToDelete && revsToDelete.length) { compactRevs(revsToDelete, docInfo.metadata.id, txn); } metadata.seq = e2.target.result; var metadataToStore = encodeMetadata( metadata, winningRev$$1, winningRevIsDeleted ); var metaDataReq = docStore.put(metadataToStore); metaDataReq.onsuccess = afterPutMetadata; } function afterPutDocError(e2) { e2.preventDefault(); e2.stopPropagation(); var index5 = bySeqStore.index("_doc_id_rev"); var getKeyReq = index5.getKey(doc2._doc_id_rev); getKeyReq.onsuccess = function(e3) { var putReq2 = bySeqStore.put(doc2, e3.target.result); putReq2.onsuccess = afterPutDoc; }; } function afterPutMetadata() { results[resultsIdx] = { ok: true, id: metadata.id, rev: metadata.rev }; fetchedDocs.set(docInfo.metadata.id, docInfo.metadata); insertAttachmentMappings(docInfo, metadata.seq, callback2); } var putReq = bySeqStore.put(doc2); putReq.onsuccess = afterPutDoc; putReq.onerror = afterPutDocError; } function writeAttachments(docInfo, winningRev$$1, winningRevIsDeleted, isUpdate, resultsIdx, callback2) { var doc2 = docInfo.data; var numDone = 0; var attachments = Object.keys(doc2._attachments); function collectResults() { if (numDone === attachments.length) { finishDoc( docInfo, winningRev$$1, winningRevIsDeleted, isUpdate, resultsIdx, callback2 ); } } function attachmentSaved() { numDone++; collectResults(); } attachments.forEach(function(key) { var att = docInfo.data._attachments[key]; if (!att.stub) { var data = att.data; delete att.data; att.revpos = parseInt(winningRev$$1, 10); var digest = att.digest; saveAttachment(digest, data, attachmentSaved); } else { numDone++; collectResults(); } }); } function insertAttachmentMappings(docInfo, seq, callback2) { var attsAdded = 0; var attsToAdd = Object.keys(docInfo.data._attachments || {}); if (!attsToAdd.length) { return callback2(); } function checkDone() { if (++attsAdded === attsToAdd.length) { callback2(); } } function add(att) { var digest = docInfo.data._attachments[att].digest; var req2 = attachAndSeqStore.put({ seq, digestSeq: digest + "::" + seq }); req2.onsuccess = checkDone; req2.onerror = function(e2) { e2.preventDefault(); e2.stopPropagation(); checkDone(); }; } for (var i2 = 0; i2 < attsToAdd.length; i2++) { add(attsToAdd[i2]); } } function saveAttachment(digest, data, callback2) { var getKeyReq = attachStore.count(digest); getKeyReq.onsuccess = function(e2) { var count = e2.target.result; if (count) { return callback2(); } var newAtt = { digest, body: data }; var putReq = attachStore.put(newAtt); putReq.onsuccess = callback2; }; } } function runBatchedCursor(objectStore, keyRange, descending, batchSize, onBatch) { if (batchSize === -1) { batchSize = 1e3; } var useGetAll = typeof objectStore.getAll === "function" && typeof objectStore.getAllKeys === "function" && batchSize > 1 && !descending; var keysBatch; var valuesBatch; var pseudoCursor; function onGetAll(e2) { valuesBatch = e2.target.result; if (keysBatch) { onBatch(keysBatch, valuesBatch, pseudoCursor); } } function onGetAllKeys(e2) { keysBatch = e2.target.result; if (valuesBatch) { onBatch(keysBatch, valuesBatch, pseudoCursor); } } function continuePseudoCursor() { if (!keysBatch.length) { return onBatch(); } var lastKey = keysBatch[keysBatch.length - 1]; var newKeyRange; if (keyRange && keyRange.upper) { try { newKeyRange = IDBKeyRange.bound( lastKey, keyRange.upper, true, keyRange.upperOpen ); } catch (e2) { if (e2.name === "DataError" && e2.code === 0) { return onBatch(); } } } else { newKeyRange = IDBKeyRange.lowerBound(lastKey, true); } keyRange = newKeyRange; keysBatch = null; valuesBatch = null; objectStore.getAll(keyRange, batchSize).onsuccess = onGetAll; objectStore.getAllKeys(keyRange, batchSize).onsuccess = onGetAllKeys; } function onCursor(e2) { var cursor = e2.target.result; if (!cursor) { return onBatch(); } onBatch([cursor.key], [cursor.value], cursor); } if (useGetAll) { pseudoCursor = { "continue": continuePseudoCursor }; objectStore.getAll(keyRange, batchSize).onsuccess = onGetAll; objectStore.getAllKeys(keyRange, batchSize).onsuccess = onGetAllKeys; } else if (descending) { objectStore.openCursor(keyRange, "prev").onsuccess = onCursor; } else { objectStore.openCursor(keyRange).onsuccess = onCursor; } } function getAll(objectStore, keyRange, onSuccess) { if (typeof objectStore.getAll === "function") { objectStore.getAll(keyRange).onsuccess = onSuccess; return; } var values = []; function onCursor(e2) { var cursor = e2.target.result; if (cursor) { values.push(cursor.value); cursor.continue(); } else { onSuccess({ target: { result: values } }); } } objectStore.openCursor(keyRange).onsuccess = onCursor; } function allDocsKeys(keys2, docStore, onBatch) { var valuesBatch = new Array(keys2.length); var count = 0; keys2.forEach(function(key, index5) { docStore.get(key).onsuccess = function(event) { if (event.target.result) { valuesBatch[index5] = event.target.result; } else { valuesBatch[index5] = { key, error: "not_found" }; } count++; if (count === keys2.length) { onBatch(keys2, valuesBatch, {}); } }; }); } function createKeyRange(start, end, inclusiveEnd, key, descending) { try { if (start && end) { if (descending) { return IDBKeyRange.bound(end, start, !inclusiveEnd, false); } else { return IDBKeyRange.bound(start, end, false, !inclusiveEnd); } } else if (start) { if (descending) { return IDBKeyRange.upperBound(start); } else { return IDBKeyRange.lowerBound(start); } } else if (end) { if (descending) { return IDBKeyRange.lowerBound(end, !inclusiveEnd); } else { return IDBKeyRange.upperBound(end, !inclusiveEnd); } } else if (key) { return IDBKeyRange.only(key); } } catch (e2) { return { error: e2 }; } return null; } function idbAllDocs(opts, idb, callback) { var start = "startkey" in opts ? opts.startkey : false; var end = "endkey" in opts ? opts.endkey : false; var key = "key" in opts ? opts.key : false; var keys2 = "keys" in opts ? opts.keys : false; var skip = opts.skip || 0; var limit = typeof opts.limit === "number" ? opts.limit : -1; var inclusiveEnd = opts.inclusive_end !== false; var keyRange; var keyRangeError; if (!keys2) { keyRange = createKeyRange(start, end, inclusiveEnd, key, opts.descending); keyRangeError = keyRange && keyRange.error; if (keyRangeError && !(keyRangeError.name === "DataError" && keyRangeError.code === 0)) { return callback(createError( IDB_ERROR, keyRangeError.name, keyRangeError.message )); } } var stores = [DOC_STORE, BY_SEQ_STORE, META_STORE]; if (opts.attachments) { stores.push(ATTACH_STORE); } var txnResult = openTransactionSafely(idb, stores, "readonly"); if (txnResult.error) { return callback(txnResult.error); } var txn = txnResult.txn; txn.oncomplete = onTxnComplete; txn.onabort = idbError(callback); var docStore = txn.objectStore(DOC_STORE); var seqStore = txn.objectStore(BY_SEQ_STORE); var metaStore = txn.objectStore(META_STORE); var docIdRevIndex = seqStore.index("_doc_id_rev"); var results = []; var docCount; var updateSeq; metaStore.get(META_STORE).onsuccess = function(e2) { docCount = e2.target.result.docCount; }; if (opts.update_seq) { getMaxUpdateSeq(seqStore, function(e2) { if (e2.target.result && e2.target.result.length > 0) { updateSeq = e2.target.result[0]; } }); } function getMaxUpdateSeq(objectStore, onSuccess) { function onCursor(e2) { var cursor = e2.target.result; var maxKey = void 0; if (cursor && cursor.key) { maxKey = cursor.key; } return onSuccess({ target: { result: [maxKey] } }); } objectStore.openCursor(null, "prev").onsuccess = onCursor; } function fetchDocAsynchronously(metadata, row, winningRev$$1) { var key2 = metadata.id + "::" + winningRev$$1; docIdRevIndex.get(key2).onsuccess = function onGetDoc(e2) { row.doc = decodeDoc(e2.target.result) || {}; if (opts.conflicts) { var conflicts = collectConflicts(metadata); if (conflicts.length) { row.doc._conflicts = conflicts; } } fetchAttachmentsIfNecessary(row.doc, opts, txn); }; } function allDocsInner(winningRev$$1, metadata) { var row = { id: metadata.id, key: metadata.id, value: { rev: winningRev$$1 } }; var deleted = metadata.deleted; if (deleted) { if (keys2) { results.push(row); row.value.deleted = true; row.doc = null; } } else if (skip-- <= 0) { results.push(row); if (opts.include_docs) { fetchDocAsynchronously(metadata, row, winningRev$$1); } } } function processBatch(batchValues) { for (var i = 0, len = batchValues.length; i < len; i++) { if (results.length === limit) { break; } var batchValue = batchValues[i]; if (batchValue.error && keys2) { results.push(batchValue); continue; } var metadata = decodeMetadata(batchValue); var winningRev$$1 = metadata.winningRev; allDocsInner(winningRev$$1, metadata); } } function onBatch(batchKeys, batchValues, cursor) { if (!cursor) { return; } processBatch(batchValues); if (results.length < limit) { cursor.continue(); } } function onGetAll(e2) { var values = e2.target.result; if (opts.descending) { values = values.reverse(); } processBatch(values); } function onResultsReady() { var returnVal = { total_rows: docCount, offset: opts.skip, rows: results }; if (opts.update_seq && updateSeq !== void 0) { returnVal.update_seq = updateSeq; } callback(null, returnVal); } function onTxnComplete() { if (opts.attachments) { postProcessAttachments(results, opts.binary).then(onResultsReady); } else { onResultsReady(); } } if (keyRangeError || limit === 0) { return; } if (keys2) { return allDocsKeys(opts.keys, docStore, onBatch); } if (limit === -1) { return getAll(docStore, keyRange, onGetAll); } runBatchedCursor(docStore, keyRange, opts.descending, limit + skip, onBatch); } function checkBlobSupport(txn) { return new Promise(function(resolve) { var blob$$1 = createBlob([""]); var req = txn.objectStore(DETECT_BLOB_SUPPORT_STORE).put(blob$$1, "key"); req.onsuccess = function() { var matchedChrome = navigator.userAgent.match(/Chrome\/(\d+)/); var matchedEdge = navigator.userAgent.match(/Edge\//); resolve(matchedEdge || !matchedChrome || parseInt(matchedChrome[1], 10) >= 43); }; req.onerror = txn.onabort = function(e2) { e2.preventDefault(); e2.stopPropagation(); resolve(false); }; }).catch(function() { return false; }); } function countDocs(txn, cb) { var index5 = txn.objectStore(DOC_STORE).index("deletedOrLocal"); index5.count(IDBKeyRange.only("0")).onsuccess = function(e2) { cb(e2.target.result); }; } var running = false; var queue = []; function tryCode(fun, err, res2, PouchDB2) { try { fun(err, res2); } catch (err2) { PouchDB2.emit("error", err2); } } function applyNext() { if (running || !queue.length) { return; } running = true; queue.shift()(); } function enqueueTask(action, callback, PouchDB2) { queue.push(function runAction() { action(function runCallback(err, res2) { tryCode(callback, err, res2, PouchDB2); running = false; (0, import_immediate.default)(function runNext() { applyNext(PouchDB2); }); }); }); applyNext(); } function changes(opts, api, dbName, idb) { opts = clone(opts); if (opts.continuous) { var id = dbName + ":" + uuid(); changesHandler$1.addListener(dbName, id, api, opts); changesHandler$1.notify(dbName); return { cancel: function() { changesHandler$1.removeListener(dbName, id); } }; } var docIds = opts.doc_ids && new ExportedSet(opts.doc_ids); opts.since = opts.since || 0; var lastSeq = opts.since; var limit = "limit" in opts ? opts.limit : -1; if (limit === 0) { limit = 1; } var results = []; var numResults = 0; var filter2 = filterChange(opts); var docIdsToMetadata = new ExportedMap(); var txn; var bySeqStore; var docStore; var docIdRevIndex; function onBatch(batchKeys, batchValues, cursor) { if (!cursor || !batchKeys.length) { return; } var winningDocs = new Array(batchKeys.length); var metadatas = new Array(batchKeys.length); function processMetadataAndWinningDoc(metadata, winningDoc) { var change = opts.processChange(winningDoc, metadata, opts); lastSeq = change.seq = metadata.seq; var filtered = filter2(change); if (typeof filtered === "object") { return Promise.reject(filtered); } if (!filtered) { return Promise.resolve(); } numResults++; if (opts.return_docs) { results.push(change); } if (opts.attachments && opts.include_docs) { return new Promise(function(resolve) { fetchAttachmentsIfNecessary(winningDoc, opts, txn, function() { postProcessAttachments([change], opts.binary).then(function() { resolve(change); }); }); }); } else { return Promise.resolve(change); } } function onBatchDone() { var promises = []; for (var i = 0, len = winningDocs.length; i < len; i++) { if (numResults === limit) { break; } var winningDoc = winningDocs[i]; if (!winningDoc) { continue; } var metadata = metadatas[i]; promises.push(processMetadataAndWinningDoc(metadata, winningDoc)); } Promise.all(promises).then(function(changes3) { for (var i2 = 0, len2 = changes3.length; i2 < len2; i2++) { if (changes3[i2]) { opts.onChange(changes3[i2]); } } }).catch(opts.complete); if (numResults !== limit) { cursor.continue(); } } var numDone = 0; batchValues.forEach(function(value, i) { var doc = decodeDoc(value); var seq = batchKeys[i]; fetchWinningDocAndMetadata(doc, seq, function(metadata, winningDoc) { metadatas[i] = metadata; winningDocs[i] = winningDoc; if (++numDone === batchKeys.length) { onBatchDone(); } }); }); } function onGetMetadata(doc, seq, metadata, cb) { if (metadata.seq !== seq) { return cb(); } if (metadata.winningRev === doc._rev) { return cb(metadata, doc); } var docIdRev = doc._id + "::" + metadata.winningRev; var req = docIdRevIndex.get(docIdRev); req.onsuccess = function(e2) { cb(metadata, decodeDoc(e2.target.result)); }; } function fetchWinningDocAndMetadata(doc, seq, cb) { if (docIds && !docIds.has(doc._id)) { return cb(); } var metadata = docIdsToMetadata.get(doc._id); if (metadata) { return onGetMetadata(doc, seq, metadata, cb); } docStore.get(doc._id).onsuccess = function(e2) { metadata = decodeMetadata(e2.target.result); docIdsToMetadata.set(doc._id, metadata); onGetMetadata(doc, seq, metadata, cb); }; } function finish() { opts.complete(null, { results, last_seq: lastSeq }); } function onTxnComplete() { if (!opts.continuous && opts.attachments) { postProcessAttachments(results).then(finish); } else { finish(); } } var objectStores = [DOC_STORE, BY_SEQ_STORE]; if (opts.attachments) { objectStores.push(ATTACH_STORE); } var txnResult = openTransactionSafely(idb, objectStores, "readonly"); if (txnResult.error) { return opts.complete(txnResult.error); } txn = txnResult.txn; txn.onabort = idbError(opts.complete); txn.oncomplete = onTxnComplete; bySeqStore = txn.objectStore(BY_SEQ_STORE); docStore = txn.objectStore(DOC_STORE); docIdRevIndex = bySeqStore.index("_doc_id_rev"); var keyRange = opts.since && !opts.descending ? IDBKeyRange.lowerBound(opts.since, true) : null; runBatchedCursor(bySeqStore, keyRange, opts.descending, limit, onBatch); } var cachedDBs = new ExportedMap(); var blobSupportPromise; var openReqList = new ExportedMap(); function IdbPouch(opts, callback) { var api = this; enqueueTask(function(thisCallback) { init(api, opts, thisCallback); }, callback, api.constructor); } function init(api, opts, callback) { var dbName = opts.name; var idb = null; var idbGlobalFailureError = null; api._meta = null; function enrichCallbackError(callback2) { return function(error, result) { if (error && error instanceof Error && !error.reason) { if (idbGlobalFailureError) { error.reason = idbGlobalFailureError; } } callback2(error, result); }; } function createSchema(db) { var docStore = db.createObjectStore(DOC_STORE, { keyPath: "id" }); db.createObjectStore(BY_SEQ_STORE, { autoIncrement: true }).createIndex("_doc_id_rev", "_doc_id_rev", { unique: true }); db.createObjectStore(ATTACH_STORE, { keyPath: "digest" }); db.createObjectStore(META_STORE, { keyPath: "id", autoIncrement: false }); db.createObjectStore(DETECT_BLOB_SUPPORT_STORE); docStore.createIndex("deletedOrLocal", "deletedOrLocal", { unique: false }); db.createObjectStore(LOCAL_STORE, { keyPath: "_id" }); var attAndSeqStore = db.createObjectStore( ATTACH_AND_SEQ_STORE, { autoIncrement: true } ); attAndSeqStore.createIndex("seq", "seq"); attAndSeqStore.createIndex("digestSeq", "digestSeq", { unique: true }); } function addDeletedOrLocalIndex(txn, callback2) { var docStore = txn.objectStore(DOC_STORE); docStore.createIndex("deletedOrLocal", "deletedOrLocal", { unique: false }); docStore.openCursor().onsuccess = function(event) { var cursor = event.target.result; if (cursor) { var metadata = cursor.value; var deleted = isDeleted(metadata); metadata.deletedOrLocal = deleted ? "1" : "0"; docStore.put(metadata); cursor.continue(); } else { callback2(); } }; } function createLocalStoreSchema(db) { db.createObjectStore(LOCAL_STORE, { keyPath: "_id" }).createIndex("_doc_id_rev", "_doc_id_rev", { unique: true }); } function migrateLocalStore(txn, cb) { var localStore = txn.objectStore(LOCAL_STORE); var docStore = txn.objectStore(DOC_STORE); var seqStore = txn.objectStore(BY_SEQ_STORE); var cursor = docStore.openCursor(); cursor.onsuccess = function(event) { var cursor2 = event.target.result; if (cursor2) { var metadata = cursor2.value; var docId = metadata.id; var local = isLocalId(docId); var rev2 = winningRev(metadata); if (local) { var docIdRev = docId + "::" + rev2; var start = docId + "::"; var end = docId + "::~"; var index5 = seqStore.index("_doc_id_rev"); var range = IDBKeyRange.bound(start, end, false, false); var seqCursor = index5.openCursor(range); seqCursor.onsuccess = function(e2) { seqCursor = e2.target.result; if (!seqCursor) { docStore.delete(cursor2.primaryKey); cursor2.continue(); } else { var data = seqCursor.value; if (data._doc_id_rev === docIdRev) { localStore.put(data); } seqStore.delete(seqCursor.primaryKey); seqCursor.continue(); } }; } else { cursor2.continue(); } } else if (cb) { cb(); } }; } function addAttachAndSeqStore(db) { var attAndSeqStore = db.createObjectStore( ATTACH_AND_SEQ_STORE, { autoIncrement: true } ); attAndSeqStore.createIndex("seq", "seq"); attAndSeqStore.createIndex("digestSeq", "digestSeq", { unique: true }); } function migrateAttsAndSeqs(txn, callback2) { var seqStore = txn.objectStore(BY_SEQ_STORE); var attStore = txn.objectStore(ATTACH_STORE); var attAndSeqStore = txn.objectStore(ATTACH_AND_SEQ_STORE); var req2 = attStore.count(); req2.onsuccess = function(e2) { var count = e2.target.result; if (!count) { return callback2(); } seqStore.openCursor().onsuccess = function(e3) { var cursor = e3.target.result; if (!cursor) { return callback2(); } var doc = cursor.value; var seq = cursor.primaryKey; var atts = Object.keys(doc._attachments || {}); var digestMap = {}; for (var j = 0; j < atts.length; j++) { var att = doc._attachments[atts[j]]; digestMap[att.digest] = true; } var digests = Object.keys(digestMap); for (j = 0; j < digests.length; j++) { var digest = digests[j]; attAndSeqStore.put({ seq, digestSeq: digest + "::" + seq }); } cursor.continue(); }; }; } function migrateMetadata(txn) { function decodeMetadataCompat(storedObject) { if (!storedObject.data) { storedObject.deleted = storedObject.deletedOrLocal === "1"; return storedObject; } return decodeMetadata(storedObject); } var bySeqStore = txn.objectStore(BY_SEQ_STORE); var docStore = txn.objectStore(DOC_STORE); var cursor = docStore.openCursor(); cursor.onsuccess = function(e2) { var cursor2 = e2.target.result; if (!cursor2) { return; } var metadata = decodeMetadataCompat(cursor2.value); metadata.winningRev = metadata.winningRev || winningRev(metadata); function fetchMetadataSeq() { var start = metadata.id + "::"; var end = metadata.id + "::\uFFFF"; var req2 = bySeqStore.index("_doc_id_rev").openCursor( IDBKeyRange.bound(start, end) ); var metadataSeq = 0; req2.onsuccess = function(e3) { var cursor3 = e3.target.result; if (!cursor3) { metadata.seq = metadataSeq; return onGetMetadataSeq(); } var seq = cursor3.primaryKey; if (seq > metadataSeq) { metadataSeq = seq; } cursor3.continue(); }; } function onGetMetadataSeq() { var metadataToStore = encodeMetadata( metadata, metadata.winningRev, metadata.deleted ); var req2 = docStore.put(metadataToStore); req2.onsuccess = function() { cursor2.continue(); }; } if (metadata.seq) { return onGetMetadataSeq(); } fetchMetadataSeq(); }; } api._remote = false; api.type = function() { return "idb"; }; api._id = toPromise(function(callback2) { callback2(null, api._meta.instanceId); }); api._bulkDocs = function idb_bulkDocs(req2, reqOpts, callback2) { idbBulkDocs(opts, req2, reqOpts, api, idb, enrichCallbackError(callback2)); }; api._get = function idb_get(id, opts2, callback2) { var doc; var metadata; var err; var txn = opts2.ctx; if (!txn) { var txnResult = openTransactionSafely( idb, [DOC_STORE, BY_SEQ_STORE, ATTACH_STORE], "readonly" ); if (txnResult.error) { return callback2(txnResult.error); } txn = txnResult.txn; } function finish() { callback2(err, { doc, metadata, ctx: txn }); } txn.objectStore(DOC_STORE).get(id).onsuccess = function(e2) { metadata = decodeMetadata(e2.target.result); if (!metadata) { err = createError(MISSING_DOC, "missing"); return finish(); } var rev2; if (!opts2.rev) { rev2 = metadata.winningRev; var deleted = isDeleted(metadata); if (deleted) { err = createError(MISSING_DOC, "deleted"); return finish(); } } else { rev2 = opts2.latest ? latest(opts2.rev, metadata) : opts2.rev; } var objectStore = txn.objectStore(BY_SEQ_STORE); var key = metadata.id + "::" + rev2; objectStore.index("_doc_id_rev").get(key).onsuccess = function(e3) { doc = e3.target.result; if (doc) { doc = decodeDoc(doc); } if (!doc) { err = createError(MISSING_DOC, "missing"); return finish(); } finish(); }; }; }; api._getAttachment = function(docId, attachId, attachment, opts2, callback2) { var txn; if (opts2.ctx) { txn = opts2.ctx; } else { var txnResult = openTransactionSafely( idb, [DOC_STORE, BY_SEQ_STORE, ATTACH_STORE], "readonly" ); if (txnResult.error) { return callback2(txnResult.error); } txn = txnResult.txn; } var digest = attachment.digest; var type = attachment.content_type; txn.objectStore(ATTACH_STORE).get(digest).onsuccess = function(e2) { var body = e2.target.result.body; readBlobData(body, type, opts2.binary, function(blobData) { callback2(null, blobData); }); }; }; api._info = function idb_info(callback2) { var updateSeq; var docCount; var txnResult = openTransactionSafely(idb, [META_STORE, BY_SEQ_STORE], "readonly"); if (txnResult.error) { return callback2(txnResult.error); } var txn = txnResult.txn; txn.objectStore(META_STORE).get(META_STORE).onsuccess = function(e2) { docCount = e2.target.result.docCount; }; txn.objectStore(BY_SEQ_STORE).openCursor(null, "prev").onsuccess = function(e2) { var cursor = e2.target.result; updateSeq = cursor ? cursor.key : 0; }; txn.oncomplete = function() { callback2(null, { doc_count: docCount, update_seq: updateSeq, idb_attachment_format: api._meta.blobSupport ? "binary" : "base64" }); }; }; api._allDocs = function idb_allDocs(opts2, callback2) { idbAllDocs(opts2, idb, enrichCallbackError(callback2)); }; api._changes = function idbChanges2(opts2) { return changes(opts2, api, dbName, idb); }; api._close = function(callback2) { idb.close(); cachedDBs.delete(dbName); callback2(); }; api._getRevisionTree = function(docId, callback2) { var txnResult = openTransactionSafely(idb, [DOC_STORE], "readonly"); if (txnResult.error) { return callback2(txnResult.error); } var txn = txnResult.txn; var req2 = txn.objectStore(DOC_STORE).get(docId); req2.onsuccess = function(event) { var doc = decodeMetadata(event.target.result); if (!doc) { callback2(createError(MISSING_DOC)); } else { callback2(null, doc.rev_tree); } }; }; api._doCompaction = function(docId, revs, callback2) { var stores = [ DOC_STORE, BY_SEQ_STORE, ATTACH_STORE, ATTACH_AND_SEQ_STORE ]; var txnResult = openTransactionSafely(idb, stores, "readwrite"); if (txnResult.error) { return callback2(txnResult.error); } var txn = txnResult.txn; var docStore = txn.objectStore(DOC_STORE); docStore.get(docId).onsuccess = function(event) { var metadata = decodeMetadata(event.target.result); traverseRevTree(metadata.rev_tree, function(isLeaf, pos, revHash, ctx, opts2) { var rev2 = pos + "-" + revHash; if (revs.indexOf(rev2) !== -1) { opts2.status = "missing"; } }); compactRevs(revs, docId, txn); var winningRev$$1 = metadata.winningRev; var deleted = metadata.deleted; txn.objectStore(DOC_STORE).put( encodeMetadata(metadata, winningRev$$1, deleted) ); }; txn.onabort = idbError(callback2); txn.oncomplete = function() { callback2(); }; }; api._getLocal = function(id, callback2) { var txnResult = openTransactionSafely(idb, [LOCAL_STORE], "readonly"); if (txnResult.error) { return callback2(txnResult.error); } var tx = txnResult.txn; var req2 = tx.objectStore(LOCAL_STORE).get(id); req2.onerror = idbError(callback2); req2.onsuccess = function(e2) { var doc = e2.target.result; if (!doc) { callback2(createError(MISSING_DOC)); } else { delete doc["_doc_id_rev"]; callback2(null, doc); } }; }; api._putLocal = function(doc, opts2, callback2) { if (typeof opts2 === "function") { callback2 = opts2; opts2 = {}; } delete doc._revisions; var oldRev = doc._rev; var id = doc._id; if (!oldRev) { doc._rev = "0-1"; } else { doc._rev = "0-" + (parseInt(oldRev.split("-")[1], 10) + 1); } var tx = opts2.ctx; var ret; if (!tx) { var txnResult = openTransactionSafely(idb, [LOCAL_STORE], "readwrite"); if (txnResult.error) { return callback2(txnResult.error); } tx = txnResult.txn; tx.onerror = idbError(callback2); tx.oncomplete = function() { if (ret) { callback2(null, ret); } }; } var oStore = tx.objectStore(LOCAL_STORE); var req2; if (oldRev) { req2 = oStore.get(id); req2.onsuccess = function(e2) { var oldDoc = e2.target.result; if (!oldDoc || oldDoc._rev !== oldRev) { callback2(createError(REV_CONFLICT)); } else { var req3 = oStore.put(doc); req3.onsuccess = function() { ret = { ok: true, id: doc._id, rev: doc._rev }; if (opts2.ctx) { callback2(null, ret); } }; } }; } else { req2 = oStore.add(doc); req2.onerror = function(e2) { callback2(createError(REV_CONFLICT)); e2.preventDefault(); e2.stopPropagation(); }; req2.onsuccess = function() { ret = { ok: true, id: doc._id, rev: doc._rev }; if (opts2.ctx) { callback2(null, ret); } }; } }; api._removeLocal = function(doc, opts2, callback2) { if (typeof opts2 === "function") { callback2 = opts2; opts2 = {}; } var tx = opts2.ctx; if (!tx) { var txnResult = openTransactionSafely(idb, [LOCAL_STORE], "readwrite"); if (txnResult.error) { return callback2(txnResult.error); } tx = txnResult.txn; tx.oncomplete = function() { if (ret) { callback2(null, ret); } }; } var ret; var id = doc._id; var oStore = tx.objectStore(LOCAL_STORE); var req2 = oStore.get(id); req2.onerror = idbError(callback2); req2.onsuccess = function(e2) { var oldDoc = e2.target.result; if (!oldDoc || oldDoc._rev !== doc._rev) { callback2(createError(MISSING_DOC)); } else { oStore.delete(id); ret = { ok: true, id, rev: "0-0" }; if (opts2.ctx) { callback2(null, ret); } } }; }; api._destroy = function(opts2, callback2) { changesHandler$1.removeAllListeners(dbName); var openReq = openReqList.get(dbName); if (openReq && openReq.result) { openReq.result.close(); cachedDBs.delete(dbName); } var req2 = indexedDB.deleteDatabase(dbName); req2.onsuccess = function() { openReqList.delete(dbName); if (hasLocalStorage() && dbName in localStorage) { delete localStorage[dbName]; } callback2(null, { "ok": true }); }; req2.onerror = idbError(callback2); }; var cached = cachedDBs.get(dbName); if (cached) { idb = cached.idb; api._meta = cached.global; return (0, import_immediate.default)(function() { callback(null, api); }); } var req = indexedDB.open(dbName, ADAPTER_VERSION); openReqList.set(dbName, req); req.onupgradeneeded = function(e2) { var db = e2.target.result; if (e2.oldVersion < 1) { return createSchema(db); } var txn = e2.currentTarget.transaction; if (e2.oldVersion < 3) { createLocalStoreSchema(db); } if (e2.oldVersion < 4) { addAttachAndSeqStore(db); } var migrations = [ addDeletedOrLocalIndex, migrateLocalStore, migrateAttsAndSeqs, migrateMetadata ]; var i = e2.oldVersion; function next() { var migration = migrations[i - 1]; i++; if (migration) { migration(txn, next); } } next(); }; req.onsuccess = function(e2) { idb = e2.target.result; idb.onversionchange = function() { idb.close(); cachedDBs.delete(dbName); }; idb.onabort = function(e3) { guardedConsole("error", "Database has a global failure", e3.target.error); idbGlobalFailureError = e3.target.error; idb.close(); cachedDBs.delete(dbName); }; var txn = idb.transaction([ META_STORE, DETECT_BLOB_SUPPORT_STORE, DOC_STORE ], "readwrite"); var storedMetaDoc = false; var metaDoc; var docCount; var blobSupport; var instanceId; function completeSetup() { if (typeof blobSupport === "undefined" || !storedMetaDoc) { return; } api._meta = { name: dbName, instanceId, blobSupport }; cachedDBs.set(dbName, { idb, global: api._meta }); callback(null, api); } function storeMetaDocIfReady() { if (typeof docCount === "undefined" || typeof metaDoc === "undefined") { return; } var instanceKey = dbName + "_id"; if (instanceKey in metaDoc) { instanceId = metaDoc[instanceKey]; } else { metaDoc[instanceKey] = instanceId = uuid(); } metaDoc.docCount = docCount; txn.objectStore(META_STORE).put(metaDoc); } txn.objectStore(META_STORE).get(META_STORE).onsuccess = function(e3) { metaDoc = e3.target.result || { id: META_STORE }; storeMetaDocIfReady(); }; countDocs(txn, function(count) { docCount = count; storeMetaDocIfReady(); }); if (!blobSupportPromise) { blobSupportPromise = checkBlobSupport(txn); } blobSupportPromise.then(function(val) { blobSupport = val; completeSetup(); }); txn.oncomplete = function() { storedMetaDoc = true; completeSetup(); }; txn.onabort = idbError(callback); }; req.onerror = function(e2) { var msg = e2.target.error && e2.target.error.message; if (!msg) { msg = "Failed to open indexedDB, are you in private browsing mode?"; } else if (msg.indexOf("stored database is a higher version") !== -1) { msg = new Error('This DB was created with the newer "indexeddb" adapter, but you are trying to open it with the older "idb" adapter'); } guardedConsole("error", msg); callback(createError(IDB_ERROR, msg)); }; } IdbPouch.valid = function() { try { return typeof indexedDB !== "undefined" && typeof IDBKeyRange !== "undefined"; } catch (e2) { return false; } }; function index(PouchDB2) { PouchDB2.adapter("idb", IdbPouch, true); } var index_es_default2 = index; // node_modules/pouchdb-adapter-indexeddb/lib/index.es.js var IDB_NULL = Number.MIN_SAFE_INTEGER; var IDB_FALSE = Number.MIN_SAFE_INTEGER + 1; var IDB_TRUE = Number.MIN_SAFE_INTEGER + 2; var TEST_KEY_INVALID = /^[^a-zA-Z_$]|[^a-zA-Z0-9_$]+/; var TEST_PATH_INVALID = /\\.|(^|\.)[^a-zA-Z_$]|[^a-zA-Z0-9_$.]+/; function needsSanitise(name, isPath) { if (isPath) { return TEST_PATH_INVALID.test(name); } else { return TEST_KEY_INVALID.test(name); } } var KEY_INVALID = new RegExp(TEST_KEY_INVALID.source, "g"); var PATH_INVALID = new RegExp(TEST_PATH_INVALID.source, "g"); var SLASH = "\\".charCodeAt(0); var IS_DOT = ".".charCodeAt(0); function sanitise(name, isPath) { var correctCharacters = function(match2) { var good = ""; for (var i = 0; i < match2.length; i++) { var code = match2.charCodeAt(i); if (code === IS_DOT && isPath && i === 0) { good += "."; } else if (code === SLASH && isPath) { continue; } else { good += "_c" + code + "_"; } } return good; }; if (isPath) { return name.replace(PATH_INVALID, correctCharacters); } else { return name.replace(KEY_INVALID, correctCharacters); } } function needsRewrite(data) { for (var key of Object.keys(data)) { if (needsSanitise(key)) { return true; } else if (data[key] === null || typeof data[key] === "boolean") { return true; } else if (typeof data[key] === "object") { return needsRewrite(data[key]); } } } function rewrite(data) { if (!needsRewrite(data)) { return false; } var isArray2 = Array.isArray(data); var clone2 = isArray2 ? [] : {}; Object.keys(data).forEach(function(key) { var safeKey = isArray2 ? key : sanitise(key); if (data[key] === null) { clone2[safeKey] = IDB_NULL; } else if (typeof data[key] === "boolean") { clone2[safeKey] = data[key] ? IDB_TRUE : IDB_FALSE; } else if (typeof data[key] === "object") { clone2[safeKey] = rewrite(data[key]); } else { clone2[safeKey] = data[key]; } }); return clone2; } var DOC_STORE2 = "docs"; var META_STORE2 = "meta"; function idbError2(callback) { return function(evt) { var message = "unknown_error"; if (evt.target && evt.target.error) { message = evt.target.error.name || evt.target.error.message; } callback(createError(IDB_ERROR, message, evt.type)); }; } function processAttachment(name, src, doc, isBinary) { delete doc._attachments[name].stub; if (isBinary) { doc._attachments[name].data = src.attachments[doc._attachments[name].digest].data; return Promise.resolve(); } return new Promise(function(resolve) { var data = src.attachments[doc._attachments[name].digest].data; readAsBinaryString(data, function(binString) { doc._attachments[name].data = thisBtoa(binString); delete doc._attachments[name].length; resolve(); }); }); } function rawIndexFields(ddoc, viewName) { var fields = ddoc.views[viewName].options && ddoc.views[viewName].options.def && ddoc.views[viewName].options.def.fields || []; return fields.map(function(field) { if (typeof field === "string") { return field; } else { return Object.keys(field)[0]; } }); } function isPartialFilterView(ddoc, viewName) { return viewName in ddoc.views && ddoc.views[viewName].options && ddoc.views[viewName].options.def && ddoc.views[viewName].options.def.partial_filter_selector; } function naturalIndexName(fields) { return "_find_idx/" + fields.join("/"); } function correctIndexFields(fields) { return ["deleted"].concat( fields.map(function(field) { if (["_id", "_rev", "_deleted", "_attachments"].includes(field)) { return field.substr(1); } else { return "data." + sanitise(field, true); } }) ); } var POUCHDB_IDB_VERSION = 1; var versionMultiplier = Math.pow(10, 13); function createIdbVersion() { return versionMultiplier * POUCHDB_IDB_VERSION + new Date().getTime(); } function getPouchDbVersion(version2) { return Math.floor(version2 / versionMultiplier); } function maintainNativeIndexes(openReq, reject) { var docStore = openReq.transaction.objectStore(DOC_STORE2); var ddocsReq = docStore.getAll(IDBKeyRange.bound("_design/", "_design/\uFFFF")); ddocsReq.onsuccess = function(e2) { var results = e2.target.result; var existingIndexNames = Array.from(docStore.indexNames); var expectedIndexes = results.filter(function(row) { return row.deleted === 0 && row.revs[row.rev].data.views; }).map(function(row) { return row.revs[row.rev].data; }).reduce(function(indexes, ddoc) { return Object.keys(ddoc.views).reduce(function(acc, viewName) { var fields = rawIndexFields(ddoc, viewName); if (fields && fields.length > 0) { acc[naturalIndexName(fields)] = correctIndexFields(fields); } return acc; }, indexes); }, {}); var expectedIndexNames = Object.keys(expectedIndexes); var systemIndexNames = ["seq"]; existingIndexNames.forEach(function(index5) { if (systemIndexNames.indexOf(index5) === -1 && expectedIndexNames.indexOf(index5) === -1) { docStore.deleteIndex(index5); } }); var newIndexNames = expectedIndexNames.filter(function(ei) { return existingIndexNames.indexOf(ei) === -1; }); try { newIndexNames.forEach(function(indexName) { docStore.createIndex(indexName, expectedIndexes[indexName]); }); } catch (err) { reject(err); } }; } function upgradePouchDbSchema(db, pouchdbVersion) { if (pouchdbVersion < 1) { var docStore = db.createObjectStore(DOC_STORE2, { keyPath: "id" }); docStore.createIndex("seq", "seq", { unique: true }); db.createObjectStore(META_STORE2, { keyPath: "id" }); } } function openDatabase(openDatabases2, api, opts, resolve, reject) { var openReq = opts.versionchanged ? indexedDB.open(opts.name) : indexedDB.open(opts.name, createIdbVersion()); openReq.onupgradeneeded = function(e2) { if (e2.oldVersion > 0 && e2.oldVersion < versionMultiplier) { throw new Error('Incorrect adapter: you should specify the "idb" adapter to open this DB'); } else if (e2.oldVersion === 0 && e2.newVersion < versionMultiplier) { indexedDB.deleteDatabase(opts.name); throw new Error("Database was deleted while open"); } var db = e2.target.result; var pouchdbVersion = getPouchDbVersion(e2.oldVersion); upgradePouchDbSchema(db, pouchdbVersion); maintainNativeIndexes(openReq, reject); }; openReq.onblocked = function(e2) { console.error("onblocked, this should never happen", e2); }; openReq.onsuccess = function(e2) { var idb = e2.target.result; idb.onabort = function(e3) { console.error("Database has a global failure", e3.target.error); delete openDatabases2[opts.name]; idb.close(); }; idb.onversionchange = function() { console.log("Database was made stale, closing handle"); openDatabases2[opts.name].versionchanged = true; idb.close(); }; idb.onclose = function() { console.log("Database was made stale, closing handle"); if (opts.name in openDatabases2) { openDatabases2[opts.name].versionchanged = true; } }; var metadata = { id: META_STORE2 }; var txn = idb.transaction([META_STORE2], "readwrite"); txn.oncomplete = function() { resolve({ idb, metadata }); }; var metaStore = txn.objectStore(META_STORE2); metaStore.get(META_STORE2).onsuccess = function(e3) { metadata = e3.target.result || metadata; var changed = false; if (!("doc_count" in metadata)) { changed = true; metadata.doc_count = 0; } if (!("seq" in metadata)) { changed = true; metadata.seq = 0; } if (!("db_uuid" in metadata)) { changed = true; metadata.db_uuid = uuid(); } if (changed) { metaStore.put(metadata); } }; }; openReq.onerror = function(e2) { reject(e2.target.error); }; } function setup(openDatabases2, api, opts) { if (!openDatabases2[opts.name] || openDatabases2[opts.name].versionchanged) { opts.versionchanged = openDatabases2[opts.name] && openDatabases2[opts.name].versionchanged; openDatabases2[opts.name] = new Promise(function(resolve, reject) { openDatabase(openDatabases2, api, opts, resolve, reject); }); } return openDatabases2[opts.name]; } function info(metadata, callback) { callback(null, { doc_count: metadata.doc_count, update_seq: metadata.seq }); } function get(txn, id, opts, callback) { if (txn.error) { return callback(txn.error); } txn.txn.objectStore(DOC_STORE2).get(id).onsuccess = function(e2) { var doc = e2.target.result; var rev2; if (!opts.rev) { rev2 = doc && doc.rev; } else { rev2 = opts.latest ? latest(opts.rev, doc) : opts.rev; } if (!doc || doc.deleted && !opts.rev || !(rev2 in doc.revs)) { callback(createError(MISSING_DOC, "missing")); return; } var result = doc.revs[rev2].data; result._id = doc.id; result._rev = rev2; callback(null, { doc: result, metadata: doc, ctx: txn }); }; } function parseAttachment(attachment, opts, cb) { if (opts.binary) { return cb(null, attachment); } else { readAsBinaryString(attachment, function(binString) { cb(null, thisBtoa(binString)); }); } } function getAttachment(txn, docId, attachId, _, opts, cb) { if (txn.error) { return cb(txn.error); } var attachment; txn.txn.objectStore(DOC_STORE2).get(docId).onsuccess = function(e2) { var doc = e2.target.result; var rev2 = doc.revs[opts.rev || doc.rev].data; var digest = rev2._attachments[attachId].digest; attachment = doc.attachments[digest].data; }; txn.txn.oncomplete = function() { parseAttachment(attachment, opts, cb); }; txn.txn.onabort = cb; } function bulkDocs(api, req, opts, metadata, dbOpts, idbChanges2, callback) { var txn; var error; var results = []; var docs = []; var lastWriteIndex; var revsLimit = dbOpts.revs_limit || 1e3; var rewriteEnabled = dbOpts.name.indexOf("-mrview-") === -1; const autoCompaction = dbOpts.auto_compaction; function docsRevsLimit(doc) { return /^_local/.test(doc.id) ? 1 : revsLimit; } function rootIsMissing2(doc) { return doc.rev_tree[0].ids[1].status === "missing"; } function parseBase642(data) { try { return atob(data); } catch (e2) { return { error: createError(BAD_ARG, "Attachment is not a valid base64 string") }; } } function fetchExistingDocs(txn2, docs2) { var fetched = 0; var oldDocs = {}; function readDone(e2) { if (e2.target.result) { oldDocs[e2.target.result.id] = e2.target.result; } if (++fetched === docs2.length) { processDocs2(txn2, docs2, oldDocs); } } docs2.forEach(function(doc) { txn2.objectStore(DOC_STORE2).get(doc.id).onsuccess = readDone; }); } function revHasAttachment(doc, rev2, digest) { return doc.revs[rev2] && doc.revs[rev2].data._attachments && Object.values(doc.revs[rev2].data._attachments).find(function(att) { return att.digest === digest; }); } function processDocs2(txn2, docs2, oldDocs) { docs2.forEach(function(doc, i2) { var newDoc; if ("was_delete" in opts && !Object.prototype.hasOwnProperty.call(oldDocs, doc.id)) { newDoc = createError(MISSING_DOC, "deleted"); } else if (opts.new_edits && !Object.prototype.hasOwnProperty.call(oldDocs, doc.id) && rootIsMissing2(doc)) { newDoc = createError(REV_CONFLICT); } else if (Object.prototype.hasOwnProperty.call(oldDocs, doc.id)) { newDoc = update2(txn2, doc, oldDocs[doc.id]); if (newDoc == false) { return; } } else { var merged = merge([], doc.rev_tree[0], docsRevsLimit(doc)); doc.rev_tree = merged.tree; doc.stemmedRevs = merged.stemmedRevs; newDoc = doc; newDoc.isNewDoc = true; newDoc.wasDeleted = doc.revs[doc.rev].deleted ? 1 : 0; } if (newDoc.error) { results[i2] = newDoc; } else { oldDocs[newDoc.id] = newDoc; lastWriteIndex = i2; write(txn2, newDoc, i2); } }); } function convertDocFormat(doc) { var newDoc = { id: doc.metadata.id, rev: doc.metadata.rev, rev_tree: doc.metadata.rev_tree, revs: doc.metadata.revs || {} }; newDoc.revs[newDoc.rev] = { data: doc.data, deleted: doc.metadata.deleted }; return newDoc; } function update2(txn2, doc, oldDoc) { if (doc.rev in oldDoc.revs && !opts.new_edits) { return false; } var isRoot = /^1-/.test(doc.rev); if (oldDoc.deleted && !doc.deleted && opts.new_edits && isRoot) { var tmp = doc.revs[doc.rev].data; tmp._rev = oldDoc.rev; tmp._id = oldDoc.id; doc = convertDocFormat(parseDoc(tmp, opts.new_edits, dbOpts)); } var merged = merge(oldDoc.rev_tree, doc.rev_tree[0], docsRevsLimit(doc)); doc.stemmedRevs = merged.stemmedRevs; doc.rev_tree = merged.tree; var revs = oldDoc.revs; revs[doc.rev] = doc.revs[doc.rev]; doc.revs = revs; doc.attachments = oldDoc.attachments; var inConflict = opts.new_edits && (oldDoc.deleted && doc.deleted || !oldDoc.deleted && merged.conflicts !== "new_leaf" || oldDoc.deleted && !doc.deleted && merged.conflicts === "new_branch" || oldDoc.rev === doc.rev); if (inConflict) { return createError(REV_CONFLICT); } doc.wasDeleted = oldDoc.deleted; return doc; } function write(txn2, doc, i2) { var winningRev$$1 = winningRev(doc); var writtenRev = doc.rev; var isLocal = /^_local/.test(doc.id); var theDoc = doc.revs[winningRev$$1].data; const isNewDoc = doc.isNewDoc; if (rewriteEnabled) { var result2 = rewrite(theDoc); if (result2) { doc.data = result2; delete doc.data._attachments; } else { doc.data = theDoc; } } else { doc.data = theDoc; } doc.rev = winningRev$$1; doc.deleted = doc.revs[winningRev$$1].deleted ? 1 : 0; if (!isLocal) { doc.seq = ++metadata.seq; var delta = 0; if (doc.isNewDoc) { delta = doc.deleted ? 0 : 1; } else if (doc.wasDeleted !== doc.deleted) { delta = doc.deleted ? -1 : 1; } metadata.doc_count += delta; } delete doc.isNewDoc; delete doc.wasDeleted; let revsToDelete = doc.stemmedRevs || []; if (autoCompaction && !isNewDoc) { const result3 = compactTree(doc); if (result3.length) { revsToDelete = revsToDelete.concat(result3); } } if (revsToDelete.length) { revsToDelete.forEach(function(rev2) { delete doc.revs[rev2]; }); } delete doc.stemmedRevs; if (!("attachments" in doc)) { doc.attachments = {}; } if (theDoc._attachments) { for (var k in theDoc._attachments) { var attachment = theDoc._attachments[k]; if (attachment.stub) { if (!(attachment.digest in doc.attachments)) { error = createError(MISSING_STUB); txn2.abort(); return; } if (revHasAttachment(doc, writtenRev, attachment.digest)) { doc.attachments[attachment.digest].revs[writtenRev] = true; } } else { doc.attachments[attachment.digest] = attachment; doc.attachments[attachment.digest].revs = {}; doc.attachments[attachment.digest].revs[writtenRev] = true; theDoc._attachments[k] = { stub: true, digest: attachment.digest, content_type: attachment.content_type, length: attachment.length, revpos: parseInt(writtenRev, 10) }; } } } if (isLocal && doc.deleted) { txn2.objectStore(DOC_STORE2).delete(doc.id).onsuccess = function() { results[i2] = { ok: true, id: doc.id, rev: "0-0" }; }; updateSeq(i2); return; } txn2.objectStore(DOC_STORE2).put(doc).onsuccess = function() { results[i2] = { ok: true, id: doc.id, rev: writtenRev }; updateSeq(i2); }; } function updateSeq(i2) { if (i2 === lastWriteIndex) { txn.objectStore(META_STORE2).put(metadata); } } function preProcessAttachment(attachment) { if (attachment.stub) { return Promise.resolve(attachment); } var binData; if (typeof attachment.data === "string") { binData = parseBase642(attachment.data); if (binData.error) { return Promise.reject(binData.error); } attachment.data = binStringToBluffer(binData, attachment.content_type); } else { binData = attachment.data; } return new Promise(function(resolve) { binaryMd5(binData, function(result2) { attachment.digest = "md5-" + result2; attachment.length = binData.size || binData.length || 0; resolve(attachment); }); }); } function preProcessAttachments() { var promises = docs.map(function(doc) { var data = doc.revs[doc.rev].data; if (!data._attachments) { return Promise.resolve(data); } var attachments = Object.keys(data._attachments).map(function(k) { data._attachments[k].name = k; return preProcessAttachment(data._attachments[k]); }); return Promise.all(attachments).then(function(newAttachments) { var processed = {}; newAttachments.forEach(function(attachment) { processed[attachment.name] = attachment; delete attachment.name; }); data._attachments = processed; return data; }); }); return Promise.all(promises); } for (var i = 0, len = req.docs.length; i < len; i++) { var result; try { result = parseDoc(req.docs[i], opts.new_edits, dbOpts); } catch (err) { result = err; } if (result.error) { return callback(result); } docs.push(convertDocFormat(result)); } preProcessAttachments().then(function() { api._openTransactionSafely([DOC_STORE2, META_STORE2], "readwrite", function(err, _txn) { if (err) { return callback(err); } txn = _txn; txn.onabort = function() { callback(error || createError(UNKNOWN_ERROR, "transaction was aborted")); }; txn.ontimeout = idbError2(callback); txn.oncomplete = function() { idbChanges2.notify(dbOpts.name); callback(null, results); }; fetchExistingDocs(txn, docs); }); }).catch(function(err) { callback(err); }); } function allDocsKeys2(keys2, docStore, allDocsInner) { var valuesBatch = new Array(keys2.length); var count = 0; keys2.forEach(function(key, index5) { docStore.get(key).onsuccess = function(event) { if (event.target.result) { valuesBatch[index5] = event.target.result; } else { valuesBatch[index5] = { key, error: "not_found" }; } count++; if (count === keys2.length) { valuesBatch.forEach(function(doc) { allDocsInner(doc); }); } }; }); } function createKeyRange2(start, end, inclusiveEnd, key, descending) { try { if (start && end) { if (descending) { return IDBKeyRange.bound(end, start, !inclusiveEnd, false); } else { return IDBKeyRange.bound(start, end, false, !inclusiveEnd); } } else if (start) { if (descending) { return IDBKeyRange.upperBound(start); } else { return IDBKeyRange.lowerBound(start); } } else if (end) { if (descending) { return IDBKeyRange.lowerBound(end, !inclusiveEnd); } else { return IDBKeyRange.upperBound(end, !inclusiveEnd); } } else if (key) { return IDBKeyRange.only(key); } } catch (e2) { return { error: e2 }; } return null; } function handleKeyRangeError(opts, metadata, err, callback) { if (err.name === "DataError" && err.code === 0) { var returnVal = { total_rows: metadata.doc_count, offset: opts.skip, rows: [] }; if (opts.update_seq) { returnVal.update_seq = metadata.seq; } return callback(null, returnVal); } callback(createError(IDB_ERROR, err.name, err.message)); } function allDocs(txn, metadata, opts, callback) { if (txn.error) { return callback(txn.error); } if (opts.limit === 0) { var returnVal = { total_rows: metadata.doc_count, offset: opts.skip, rows: [] }; if (opts.update_seq) { returnVal.update_seq = metadata.seq; } return callback(null, returnVal); } var results = []; var processing = []; var start = "startkey" in opts ? opts.startkey : false; var end = "endkey" in opts ? opts.endkey : false; var key = "key" in opts ? opts.key : false; var keys2 = "keys" in opts ? opts.keys : false; var skip = opts.skip || 0; var limit = typeof opts.limit === "number" ? opts.limit : -1; var inclusiveEnd = opts.inclusive_end !== false; var descending = "descending" in opts && opts.descending ? "prev" : null; var keyRange; if (!keys2) { keyRange = createKeyRange2(start, end, inclusiveEnd, key, descending); if (keyRange && keyRange.error) { return handleKeyRangeError(opts, metadata, keyRange.error, callback); } } var docStore = txn.txn.objectStore(DOC_STORE2); txn.txn.oncomplete = onTxnComplete; if (keys2) { return allDocsKeys2(opts.keys, docStore, allDocsInner); } function include_doc(row, doc) { var docData = doc.revs[doc.rev].data; row.doc = docData; row.doc._id = doc.id; row.doc._rev = doc.rev; if (opts.conflicts) { var conflicts = collectConflicts(doc); if (conflicts.length) { row.doc._conflicts = conflicts; } } if (opts.attachments && docData._attachments) { for (var name in docData._attachments) { processing.push(processAttachment(name, doc, row.doc, opts.binary)); } } } function allDocsInner(doc) { if (doc.error && keys2) { results.push(doc); return true; } var row = { id: doc.id, key: doc.id, value: { rev: doc.rev } }; var deleted = doc.deleted; if (deleted) { if (keys2) { results.push(row); row.value.deleted = true; row.doc = null; } } else if (skip-- <= 0) { results.push(row); if (opts.include_docs) { include_doc(row, doc); } if (--limit === 0) { return false; } } return true; } function onTxnComplete() { Promise.all(processing).then(function() { var returnVal2 = { total_rows: metadata.doc_count, offset: 0, rows: results }; if (opts.update_seq) { returnVal2.update_seq = metadata.seq; } callback(null, returnVal2); }); } var cursor = descending ? docStore.openCursor(keyRange, descending) : docStore.openCursor(keyRange); cursor.onsuccess = function(e2) { var doc = e2.target.result && e2.target.result.value; if (!doc) { return; } if (/^_local/.test(doc.id)) { return e2.target.result.continue(); } var continueCursor = allDocsInner(doc); if (continueCursor) { e2.target.result.continue(); } }; } function changes2(txn, idbChanges2, api, dbOpts, opts) { if (txn.error) { return opts.complete(txn.error); } if (opts.continuous) { var id = dbOpts.name + ":" + uuid(); idbChanges2.addListener(dbOpts.name, id, api, opts); idbChanges2.notify(dbOpts.name); return { cancel: function() { idbChanges2.removeListener(dbOpts.name, id); } }; } var limit = "limit" in opts ? opts.limit : -1; if (limit === 0) { limit = 1; } var store = txn.txn.objectStore(DOC_STORE2).index("seq"); var filter2 = filterChange(opts); var received = 0; var lastSeq = opts.since || 0; var results = []; var processing = []; function onReqSuccess(e2) { if (!e2.target.result) { return; } var cursor = e2.target.result; var doc = cursor.value; doc.data = doc.revs[doc.rev].data; doc.data._id = doc.id; doc.data._rev = doc.rev; if (doc.deleted) { doc.data._deleted = true; } if (opts.doc_ids && opts.doc_ids.indexOf(doc.id) === -1) { return cursor.continue(); } var change = opts.processChange(doc.data, doc, opts); change.seq = doc.seq; lastSeq = doc.seq; var filtered = filter2(change); if (typeof filtered === "object") { return opts.complete(filtered); } if (filtered) { received++; if (opts.return_docs) { results.push(change); } if (opts.include_docs && opts.attachments && doc.data._attachments) { var promises = []; for (var name in doc.data._attachments) { var p = processAttachment(name, doc, change.doc, opts.binary); promises.push(p); processing.push(p); } Promise.all(promises).then(function() { opts.onChange(change); }); } else { opts.onChange(change); } } if (received !== limit) { cursor.continue(); } } function onTxnComplete() { Promise.all(processing).then(function() { opts.complete(null, { results, last_seq: lastSeq }); }); } var req; if (opts.descending) { req = store.openCursor(null, "prev"); } else { req = store.openCursor(IDBKeyRange.lowerBound(opts.since, true)); } txn.txn.oncomplete = onTxnComplete; req.onsuccess = onReqSuccess; } function getRevisionTree(txn, id, callback) { if (txn.error) { return callback(txn.error); } var req = txn.txn.objectStore(DOC_STORE2).get(id); req.onsuccess = function(e2) { if (!e2.target.result) { callback(createError(MISSING_DOC)); } else { callback(null, e2.target.result.rev_tree); } }; } function doCompaction(txn, id, revs, callback) { if (txn.error) { return callback(txn.error); } var docStore = txn.txn.objectStore(DOC_STORE2); docStore.get(id).onsuccess = function(e2) { var doc = e2.target.result; traverseRevTree(doc.rev_tree, function(isLeaf, pos, revHash, ctx, opts) { var rev2 = pos + "-" + revHash; if (revs.indexOf(rev2) !== -1) { opts.status = "missing"; } }); var attachments = []; revs.forEach(function(rev2) { if (rev2 in doc.revs) { if (doc.revs[rev2].data._attachments) { for (var k in doc.revs[rev2].data._attachments) { attachments.push(doc.revs[rev2].data._attachments[k].digest); } } delete doc.revs[rev2]; } }); attachments.forEach(function(digest) { revs.forEach(function(rev2) { delete doc.attachments[digest].revs[rev2]; }); if (!Object.keys(doc.attachments[digest].revs).length) { delete doc.attachments[digest]; } }); docStore.put(doc); }; txn.txn.oncomplete = function() { callback(); }; } function destroy(dbOpts, openDatabases2, idbChanges2, callback) { idbChanges2.removeAllListeners(dbOpts.name); function doDestroy() { var req = indexedDB.deleteDatabase(dbOpts.name); req.onsuccess = function() { delete openDatabases2[dbOpts.name]; callback(null, { ok: true }); }; } if (dbOpts.name in openDatabases2) { openDatabases2[dbOpts.name].then(function(res2) { res2.idb.close(); doDestroy(); }); } else { doDestroy(); } } var COUCH_COLLATE_LO = null; var COUCH_COLLATE_HI = "\uFFFF"; var IDB_COLLATE_LO = Number.NEGATIVE_INFINITY; var IDB_COLLATE_HI = [[[[[[[[[[[[]]]]]]]]]]]]; function externaliseRecord(idbDoc) { var doc = idbDoc.revs[idbDoc.rev].data; doc._id = idbDoc.id; doc._rev = idbDoc.rev; if (idbDoc.deleted) { doc._deleted = true; } return doc; } function generateKeyRange(opts) { function defined(obj, k) { return obj[k] !== void 0; } function convert(key, exact) { var filterDeleted = [0].concat(key); return filterDeleted.map(function(k) { if (k === null && exact) { return IDB_NULL; } else if (k === true) { return IDB_TRUE; } else if (k === false) { return IDB_FALSE; } if (!exact) { if (k === COUCH_COLLATE_LO) { return IDB_COLLATE_LO; } else if (Object.prototype.hasOwnProperty.call(k, COUCH_COLLATE_HI)) { return IDB_COLLATE_HI; } } return k; }); } if (!defined(opts, "inclusive_end")) { opts.inclusive_end = true; } if (!defined(opts, "inclusive_start")) { opts.inclusive_start = true; } if (opts.descending) { var realEndkey = opts.startkey, realInclusiveEnd = opts.inclusive_start; opts.startkey = opts.endkey; opts.endkey = realEndkey; opts.inclusive_start = opts.inclusive_end; opts.inclusive_end = realInclusiveEnd; } try { if (defined(opts, "key")) { return IDBKeyRange.only(convert(opts.key, true)); } if (defined(opts, "startkey") && !defined(opts, "endkey")) { return IDBKeyRange.bound( convert(opts.startkey), [1], !opts.inclusive_start, true ); } if (!defined(opts, "startkey") && defined(opts, "endkey")) { return IDBKeyRange.upperBound(convert(opts.endkey), !opts.inclusive_end); } if (defined(opts, "startkey") && defined(opts, "endkey")) { return IDBKeyRange.bound( convert(opts.startkey), convert(opts.endkey), !opts.inclusive_start, !opts.inclusive_end ); } return IDBKeyRange.only([0]); } catch (err) { console.error("Could not generate keyRange", err, opts); throw Error("Could not generate key range with " + JSON.stringify(opts)); } } function getIndexHandle(pdb, fields, reject) { var indexName = naturalIndexName(fields); return new Promise(function(resolve) { pdb._openTransactionSafely([DOC_STORE2], "readonly", function(err, txn) { if (err) { return idbError2(reject)(err); } txn.onabort = idbError2(reject); txn.ontimeout = idbError2(reject); var existingIndexNames = Array.from(txn.objectStore(DOC_STORE2).indexNames); if (existingIndexNames.indexOf(indexName) === -1) { pdb._freshen().then(function() { return getIndexHandle(pdb, fields, reject); }).then(resolve); } else { resolve(txn.objectStore(DOC_STORE2).index(indexName)); } }); }); } function query(idb, signature, opts, fallback) { var pdb = this; var parts = signature.split("/"); return new Promise(function(resolve, reject) { pdb.get("_design/" + parts[0]).then(function(ddoc) { if (isPartialFilterView(ddoc, parts[1])) { return fallback(signature, opts).then(resolve, reject); } var fields = rawIndexFields(ddoc, parts[1]); if (!fields) { throw new Error("ddoc " + ddoc._id + " with view " + parts[1] + " does not have map.options.def.fields defined."); } var skip = opts.skip; var limit = Number.isInteger(opts.limit) && opts.limit; return getIndexHandle(pdb, fields, reject).then(function(indexHandle) { var keyRange = generateKeyRange(opts); var req = indexHandle.openCursor(keyRange, opts.descending ? "prev" : "next"); var rows = []; req.onerror = idbError2(reject); req.onsuccess = function(e2) { var cursor = e2.target.result; if (!cursor || limit === 0) { return resolve({ rows }); } if (skip) { cursor.advance(skip); skip = false; return; } if (limit) { limit = limit - 1; } rows.push({ doc: externaliseRecord(cursor.value) }); cursor.continue(); }; }); }).catch(reject); }); } function viewCleanup(idb, fallback) { return fallback(); } function purgeAttachments(doc, revs) { if (!doc.attachments) { return {}; } for (let key in doc.attachments) { const attachment = doc.attachments[key]; for (let rev2 of revs) { if (attachment.revs[rev2]) { delete attachment.revs[rev2]; } } if (Object.keys(attachment.revs).length === 0) { delete doc.attachments[key]; } } return doc.attachments; } function purge(txn, docId, revs, callback) { if (txn.error) { return callback(txn.error); } const docStore = txn.txn.objectStore(DOC_STORE2); const deletedRevs = []; let documentWasRemovedCompletely = false; docStore.get(docId).onsuccess = (e2) => { const doc = e2.target.result; for (const rev2 of revs) { doc.rev_tree = removeLeafFromRevTree(doc.rev_tree, rev2); delete doc.revs[rev2]; deletedRevs.push(rev2); } if (doc.rev_tree.length === 0) { docStore.delete(doc.id); documentWasRemovedCompletely = true; return; } doc.rev = winningRev(doc); doc.data = doc.revs[doc.rev].data; doc.attachments = purgeAttachments(doc, revs); docStore.put(doc); }; txn.txn.oncomplete = function() { callback(null, { ok: true, deletedRevs, documentWasRemovedCompletely }); }; } var ADAPTER_NAME = "indexeddb"; var idbChanges = new Changes(); var openDatabases = {}; function IdbPouch2(dbOpts, callback) { if (dbOpts.view_adapter) { console.log("Please note that the indexeddb adapter manages _find indexes itself, therefore it is not using your specified view_adapter"); } var api = this; var metadata = {}; var $ = function(fun) { return function() { var args = Array.prototype.slice.call(arguments); setup(openDatabases, api, dbOpts).then(function(res2) { metadata = res2.metadata; args.unshift(res2.idb); fun.apply(api, args); }).catch(function(err) { var last = args.pop(); if (typeof last === "function") { last(err); } else { console.error(err); } }); }; }; var $p = function(fun) { return function() { var args = Array.prototype.slice.call(arguments); return setup(openDatabases, api, dbOpts).then(function(res2) { metadata = res2.metadata; args.unshift(res2.idb); return fun.apply(api, args); }); }; }; var $t = function(fun, stores, mode) { stores = stores || [DOC_STORE2]; mode = mode || "readonly"; return function() { var args = Array.prototype.slice.call(arguments); var txn = {}; setup(openDatabases, api, dbOpts).then(function(res2) { metadata = res2.metadata; txn.txn = res2.idb.transaction(stores, mode); }).catch(function(err) { console.error("Failed to establish transaction safely"); console.error(err); txn.error = err; }).then(function() { args.unshift(txn); fun.apply(api, args); }); }; }; api._openTransactionSafely = function(stores, mode, callback2) { $t(function(txn, callback3) { callback3(txn.error, txn.txn); }, stores, mode)(callback2); }; api._remote = false; api.type = function() { return ADAPTER_NAME; }; api._id = $(function(_, cb) { cb(null, metadata.db_uuid); }); api._info = $(function(_, cb) { return info(metadata, cb); }); api._get = $t(get); api._bulkDocs = $(function(_, req, opts, callback2) { bulkDocs(api, req, opts, metadata, dbOpts, idbChanges, callback2); }); api._allDocs = $t(function(txn, opts, cb) { allDocs(txn, metadata, opts, cb); }); api._getAttachment = $t(getAttachment); api._changes = $t(function(txn, opts) { changes2(txn, idbChanges, api, dbOpts, opts); }); api._getRevisionTree = $t(getRevisionTree); api._doCompaction = $t(doCompaction, [DOC_STORE2], "readwrite"); api._customFindAbstractMapper = { query: $p(query), viewCleanup: $p(viewCleanup) }; api._destroy = function(opts, callback2) { return destroy(dbOpts, openDatabases, idbChanges, callback2); }; api._close = $(function(db, cb) { delete openDatabases[dbOpts.name]; db.close(); cb(); }); api._freshen = function() { return new Promise(function(resolve) { api._close(function() { $(resolve)(); }); }); }; api._purge = $t(purge, [DOC_STORE2], "readwrite"); setTimeout(function() { callback(null, api); }); } IdbPouch2.valid = function() { return true; }; function index2(PouchDB2) { PouchDB2.adapter(ADAPTER_NAME, IdbPouch2, true); } var index_es_default3 = index2; // node_modules/pouchdb-adapter-http/lib/index.es.js function pool(promiseFactories, limit) { return new Promise(function(resolve, reject) { var running2 = 0; var current = 0; var done = 0; var len = promiseFactories.length; var err; function runNext() { running2++; promiseFactories[current++]().then(onSuccess, onError); } function doNext() { if (++done === len) { if (err) { reject(err); } else { resolve(); } } else { runNextBatch(); } } function onSuccess() { running2--; doNext(); } function onError(thisErr) { running2--; err = err || thisErr; doNext(); } function runNextBatch() { while (running2 < limit && current < len) { runNext(); } } runNextBatch(); }); } var CHANGES_BATCH_SIZE = 25; var MAX_SIMULTANEOUS_REVS = 50; var CHANGES_TIMEOUT_BUFFER = 5e3; var DEFAULT_HEARTBEAT = 1e4; var supportsBulkGetMap = {}; function readAttachmentsAsBlobOrBuffer(row) { let doc = row.doc || row.ok; let atts = doc && doc._attachments; if (!atts) { return; } Object.keys(atts).forEach(function(filename) { let att = atts[filename]; att.data = b64ToBluffer(att.data, att.content_type); }); } function encodeDocId(id) { if (/^_design/.test(id)) { return "_design/" + encodeURIComponent(id.slice(8)); } if (/^_local/.test(id)) { return "_local/" + encodeURIComponent(id.slice(7)); } return encodeURIComponent(id); } function preprocessAttachments2(doc) { if (!doc._attachments || !Object.keys(doc._attachments)) { return Promise.resolve(); } return Promise.all(Object.keys(doc._attachments).map(function(key) { let attachment = doc._attachments[key]; if (attachment.data && typeof attachment.data !== "string") { return new Promise(function(resolve) { blobToBase64(attachment.data, resolve); }).then(function(b64) { attachment.data = b64; }); } })); } function hasUrlPrefix(opts) { if (!opts.prefix) { return false; } let protocol = parseUri(opts.prefix).protocol; return protocol === "http" || protocol === "https"; } function getHost(name, opts) { if (hasUrlPrefix(opts)) { let dbName = opts.name.substr(opts.prefix.length); let prefix = opts.prefix.replace(/\/?$/, "/"); name = prefix + encodeURIComponent(dbName); } let uri = parseUri(name); if (uri.user || uri.password) { uri.auth = { username: uri.user, password: uri.password }; } let parts = uri.path.replace(/(^\/|\/$)/g, "").split("/"); uri.db = parts.pop(); if (uri.db.indexOf("%") === -1) { uri.db = encodeURIComponent(uri.db); } uri.path = parts.join("/"); return uri; } function genDBUrl(opts, path) { return genUrl(opts, opts.db + "/" + path); } function genUrl(opts, path) { let pathDel = !opts.path ? "" : "/"; return opts.protocol + "://" + opts.host + (opts.port ? ":" + opts.port : "") + "/" + opts.path + pathDel + path; } function paramsToStr(params) { return "?" + Object.keys(params).map(function(k) { return k + "=" + encodeURIComponent(params[k]); }).join("&"); } function shouldCacheBust(opts) { let ua = typeof navigator !== "undefined" && navigator.userAgent ? navigator.userAgent.toLowerCase() : ""; let isIE = ua.indexOf("msie") !== -1; let isTrident = ua.indexOf("trident") !== -1; let isEdge = ua.indexOf("edge") !== -1; let isGET = !("method" in opts) || opts.method === "GET"; return (isIE || isTrident || isEdge) && isGET; } function HttpPouch(opts, callback) { let api = this; let host = getHost(opts.name, opts); let dbUrl = genDBUrl(host, ""); opts = clone(opts); const ourFetch = async function(url, options) { options = options || {}; options.headers = options.headers || new h(); options.credentials = "include"; if (opts.auth || host.auth) { let nAuth = opts.auth || host.auth; let str = nAuth.username + ":" + nAuth.password; let token = thisBtoa(unescape(encodeURIComponent(str))); options.headers.set("Authorization", "Basic " + token); } let headers = opts.headers || {}; Object.keys(headers).forEach(function(key) { options.headers.append(key, headers[key]); }); if (shouldCacheBust(options)) { url += (url.indexOf("?") === -1 ? "?" : "&") + "_nonce=" + Date.now(); } let fetchFun = opts.fetch || f2; return await fetchFun(url, options); }; function adapterFun$$1(name, fun) { return adapterFun(name, function(...args) { setup2().then(function() { return fun.apply(this, args); }).catch(function(e2) { let callback2 = args.pop(); callback2(e2); }); }).bind(api); } async function fetchJSON(url, options) { let result = {}; options = options || {}; options.headers = options.headers || new h(); if (!options.headers.get("Content-Type")) { options.headers.set("Content-Type", "application/json"); } if (!options.headers.get("Accept")) { options.headers.set("Accept", "application/json"); } const response = await ourFetch(url, options); result.ok = response.ok; result.status = response.status; const json = await response.json(); result.data = json; if (!result.ok) { result.data.status = result.status; let err = generateErrorFromResponse(result.data); throw err; } if (Array.isArray(result.data)) { result.data = result.data.map(function(v) { if (v.error || v.missing) { return generateErrorFromResponse(v); } else { return v; } }); } return result; } let setupPromise; async function setup2() { if (opts.skip_setup) { return Promise.resolve(); } if (setupPromise) { return setupPromise; } setupPromise = fetchJSON(dbUrl).catch(function(err) { if (err && err.status && err.status === 404) { explainError(404, "PouchDB is just detecting if the remote exists."); return fetchJSON(dbUrl, { method: "PUT" }); } else { return Promise.reject(err); } }).catch(function(err) { if (err && err.status && err.status === 412) { return true; } return Promise.reject(err); }); setupPromise.catch(function() { setupPromise = null; }); return setupPromise; } (0, import_immediate.default)(function() { callback(null, api); }); api._remote = true; api.type = function() { return "http"; }; api.id = adapterFun$$1("id", async function(callback2) { let result; try { const response = await ourFetch(genUrl(host, "")); result = await response.json(); } catch (err) { result = {}; } let uuid2 = result && result.uuid ? result.uuid + host.db : genDBUrl(host, ""); callback2(null, uuid2); }); api.compact = adapterFun$$1("compact", async function(opts2, callback2) { if (typeof opts2 === "function") { callback2 = opts2; opts2 = {}; } opts2 = clone(opts2); await fetchJSON(genDBUrl(host, "_compact"), { method: "POST" }); function ping() { api.info(function(err, res2) { if (res2 && !res2.compact_running) { callback2(null, { ok: true }); } else { setTimeout(ping, opts2.interval || 200); } }); } ping(); }); api.bulkGet = adapterFun("bulkGet", function(opts2, callback2) { let self2 = this; async function doBulkGet(cb) { let params = {}; if (opts2.revs) { params.revs = true; } if (opts2.attachments) { params.attachments = true; } if (opts2.latest) { params.latest = true; } try { const result = await fetchJSON(genDBUrl(host, "_bulk_get" + paramsToStr(params)), { method: "POST", body: JSON.stringify({ docs: opts2.docs }) }); if (opts2.attachments && opts2.binary) { result.data.results.forEach(function(res2) { res2.docs.forEach(readAttachmentsAsBlobOrBuffer); }); } cb(null, result.data); } catch (error) { cb(error); } } function doBulkGetShim() { let batchSize = MAX_SIMULTANEOUS_REVS; let numBatches = Math.ceil(opts2.docs.length / batchSize); let numDone = 0; let results = new Array(numBatches); function onResult(batchNum) { return function(err, res2) { results[batchNum] = res2.results; if (++numDone === numBatches) { callback2(null, { results: flatten(results) }); } }; } for (let i = 0; i < numBatches; i++) { let subOpts = pick(opts2, ["revs", "attachments", "binary", "latest"]); subOpts.docs = opts2.docs.slice( i * batchSize, Math.min(opts2.docs.length, (i + 1) * batchSize) ); bulkGet(self2, subOpts, onResult(i)); } } let dbUrl2 = genUrl(host, ""); let supportsBulkGet = supportsBulkGetMap[dbUrl2]; if (typeof supportsBulkGet !== "boolean") { doBulkGet(function(err, res2) { if (err) { supportsBulkGetMap[dbUrl2] = false; explainError( err.status, "PouchDB is just detecting if the remote supports the _bulk_get API." ); doBulkGetShim(); } else { supportsBulkGetMap[dbUrl2] = true; callback2(null, res2); } }); } else if (supportsBulkGet) { doBulkGet(callback2); } else { doBulkGetShim(); } }); api._info = async function(callback2) { try { await setup2(); const response = await ourFetch(genDBUrl(host, "")); const info2 = await response.json(); info2.host = genDBUrl(host, ""); callback2(null, info2); } catch (err) { callback2(err); } }; api.fetch = async function(path, options) { await setup2(); const url = path.substring(0, 1) === "/" ? genUrl(host, path.substring(1)) : genDBUrl(host, path); return ourFetch(url, options); }; api.get = adapterFun$$1("get", async function(id, opts2, callback2) { if (typeof opts2 === "function") { callback2 = opts2; opts2 = {}; } opts2 = clone(opts2); let params = {}; if (opts2.revs) { params.revs = true; } if (opts2.revs_info) { params.revs_info = true; } if (opts2.latest) { params.latest = true; } if (opts2.open_revs) { if (opts2.open_revs !== "all") { opts2.open_revs = JSON.stringify(opts2.open_revs); } params.open_revs = opts2.open_revs; } if (opts2.rev) { params.rev = opts2.rev; } if (opts2.conflicts) { params.conflicts = opts2.conflicts; } if (opts2.update_seq) { params.update_seq = opts2.update_seq; } id = encodeDocId(id); function fetchAttachments(doc) { let atts = doc._attachments; let filenames = atts && Object.keys(atts); if (!atts || !filenames.length) { return; } async function fetchData(filename) { const att = atts[filename]; const path = encodeDocId(doc._id) + "/" + encodeAttachmentId(filename) + "?rev=" + doc._rev; const response = await ourFetch(genDBUrl(host, path)); let blob; if ("buffer" in response) { blob = await response.buffer(); } else { blob = await response.blob(); } let data; if (opts2.binary) { let typeFieldDescriptor = Object.getOwnPropertyDescriptor(blob.__proto__, "type"); if (!typeFieldDescriptor || typeFieldDescriptor.set) { blob.type = att.content_type; } data = blob; } else { data = await new Promise(function(resolve) { blobToBase64(blob, resolve); }); } delete att.stub; delete att.length; att.data = data; } let promiseFactories = filenames.map(function(filename) { return function() { return fetchData(filename); }; }); return pool(promiseFactories, 5); } function fetchAllAttachments(docOrDocs) { if (Array.isArray(docOrDocs)) { return Promise.all(docOrDocs.map(function(doc) { if (doc.ok) { return fetchAttachments(doc.ok); } })); } return fetchAttachments(docOrDocs); } const url = genDBUrl(host, id + paramsToStr(params)); try { const res2 = await fetchJSON(url); if (opts2.attachments) { await fetchAllAttachments(res2.data); } callback2(null, res2.data); } catch (error) { error.docId = id; callback2(error); } }); api.remove = adapterFun$$1("remove", async function(docOrId, optsOrRev, opts2, cb) { let doc; if (typeof optsOrRev === "string") { doc = { _id: docOrId, _rev: optsOrRev }; if (typeof opts2 === "function") { cb = opts2; opts2 = {}; } } else { doc = docOrId; if (typeof optsOrRev === "function") { cb = optsOrRev; opts2 = {}; } else { cb = opts2; opts2 = optsOrRev; } } const rev2 = doc._rev || opts2.rev; const url = genDBUrl(host, encodeDocId(doc._id)) + "?rev=" + rev2; try { const result = await fetchJSON(url, { method: "DELETE" }); cb(null, result.data); } catch (error) { cb(error); } }); function encodeAttachmentId(attachmentId) { return attachmentId.split("/").map(encodeURIComponent).join("/"); } api.getAttachment = adapterFun$$1("getAttachment", async function(docId, attachmentId, opts2, callback2) { if (typeof opts2 === "function") { callback2 = opts2; opts2 = {}; } const params = opts2.rev ? "?rev=" + opts2.rev : ""; const url = genDBUrl(host, encodeDocId(docId)) + "/" + encodeAttachmentId(attachmentId) + params; let contentType; try { const response = await ourFetch(url, { method: "GET" }); if (!response.ok) { throw response; } contentType = response.headers.get("content-type"); let blob; if (typeof process !== "undefined" && !process.browser && typeof response.buffer === "function") { blob = await response.buffer(); } else { blob = await response.blob(); } if (typeof process !== "undefined" && !process.browser) { var typeFieldDescriptor = Object.getOwnPropertyDescriptor(blob.__proto__, "type"); if (!typeFieldDescriptor || typeFieldDescriptor.set) { blob.type = contentType; } } callback2(null, blob); } catch (err) { callback2(err); } }); api.removeAttachment = adapterFun$$1("removeAttachment", async function(docId, attachmentId, rev2, callback2) { const url = genDBUrl(host, encodeDocId(docId) + "/" + encodeAttachmentId(attachmentId)) + "?rev=" + rev2; try { const result = await fetchJSON(url, { method: "DELETE" }); callback2(null, result.data); } catch (error) { callback2(error); } }); api.putAttachment = adapterFun$$1("putAttachment", async function(docId, attachmentId, rev2, blob, type, callback2) { if (typeof type === "function") { callback2 = type; type = blob; blob = rev2; rev2 = null; } const id = encodeDocId(docId) + "/" + encodeAttachmentId(attachmentId); let url = genDBUrl(host, id); if (rev2) { url += "?rev=" + rev2; } if (typeof blob === "string") { let binary; try { binary = thisAtob(blob); } catch (err) { return callback2(createError( BAD_ARG, "Attachment is not a valid base64 string" )); } blob = binary ? binStringToBluffer(binary, type) : ""; } try { const result = await fetchJSON(url, { headers: new h({ "Content-Type": type }), method: "PUT", body: blob }); callback2(null, result.data); } catch (error) { callback2(error); } }); api._bulkDocs = async function(req, opts2, callback2) { req.new_edits = opts2.new_edits; try { await setup2(); await Promise.all(req.docs.map(preprocessAttachments2)); const result = await fetchJSON(genDBUrl(host, "_bulk_docs"), { method: "POST", body: JSON.stringify(req) }); callback2(null, result.data); } catch (error) { callback2(error); } }; api._put = async function(doc, opts2, callback2) { try { await setup2(); await preprocessAttachments2(doc); const result = await fetchJSON(genDBUrl(host, encodeDocId(doc._id)), { method: "PUT", body: JSON.stringify(doc) }); callback2(null, result.data); } catch (error) { error.docId = doc && doc._id; callback2(error); } }; api.allDocs = adapterFun$$1("allDocs", async function(opts2, callback2) { if (typeof opts2 === "function") { callback2 = opts2; opts2 = {}; } opts2 = clone(opts2); let params = {}; let body; let method = "GET"; if (opts2.conflicts) { params.conflicts = true; } if (opts2.update_seq) { params.update_seq = true; } if (opts2.descending) { params.descending = true; } if (opts2.include_docs) { params.include_docs = true; } if (opts2.attachments) { params.attachments = true; } if (opts2.key) { params.key = JSON.stringify(opts2.key); } if (opts2.start_key) { opts2.startkey = opts2.start_key; } if (opts2.startkey) { params.startkey = JSON.stringify(opts2.startkey); } if (opts2.end_key) { opts2.endkey = opts2.end_key; } if (opts2.endkey) { params.endkey = JSON.stringify(opts2.endkey); } if (typeof opts2.inclusive_end !== "undefined") { params.inclusive_end = !!opts2.inclusive_end; } if (typeof opts2.limit !== "undefined") { params.limit = opts2.limit; } if (typeof opts2.skip !== "undefined") { params.skip = opts2.skip; } let paramStr = paramsToStr(params); if (typeof opts2.keys !== "undefined") { method = "POST"; body = { keys: opts2.keys }; } try { const result = await fetchJSON(genDBUrl(host, "_all_docs" + paramStr), { method, body: JSON.stringify(body) }); if (opts2.include_docs && opts2.attachments && opts2.binary) { result.data.rows.forEach(readAttachmentsAsBlobOrBuffer); } callback2(null, result.data); } catch (error) { callback2(error); } }); api._changes = function(opts2) { let batchSize = "batch_size" in opts2 ? opts2.batch_size : CHANGES_BATCH_SIZE; opts2 = clone(opts2); if (opts2.continuous && !("heartbeat" in opts2)) { opts2.heartbeat = DEFAULT_HEARTBEAT; } let requestTimeout = "timeout" in opts2 ? opts2.timeout : 30 * 1e3; if ("timeout" in opts2 && opts2.timeout && requestTimeout - opts2.timeout < CHANGES_TIMEOUT_BUFFER) { requestTimeout = opts2.timeout + CHANGES_TIMEOUT_BUFFER; } if ("heartbeat" in opts2 && opts2.heartbeat && requestTimeout - opts2.heartbeat < CHANGES_TIMEOUT_BUFFER) { requestTimeout = opts2.heartbeat + CHANGES_TIMEOUT_BUFFER; } let params = {}; if ("timeout" in opts2 && opts2.timeout) { params.timeout = opts2.timeout; } let limit = typeof opts2.limit !== "undefined" ? opts2.limit : false; let leftToFetch = limit; if (opts2.style) { params.style = opts2.style; } if (opts2.include_docs || opts2.filter && typeof opts2.filter === "function") { params.include_docs = true; } if (opts2.attachments) { params.attachments = true; } if (opts2.continuous) { params.feed = "longpoll"; } if (opts2.seq_interval) { params.seq_interval = opts2.seq_interval; } if (opts2.conflicts) { params.conflicts = true; } if (opts2.descending) { params.descending = true; } if (opts2.update_seq) { params.update_seq = true; } if ("heartbeat" in opts2) { if (opts2.heartbeat) { params.heartbeat = opts2.heartbeat; } } if (opts2.filter && typeof opts2.filter === "string") { params.filter = opts2.filter; } if (opts2.view && typeof opts2.view === "string") { params.filter = "_view"; params.view = opts2.view; } if (opts2.query_params && typeof opts2.query_params === "object") { for (let param_name in opts2.query_params) { if (Object.prototype.hasOwnProperty.call(opts2.query_params, param_name)) { params[param_name] = opts2.query_params[param_name]; } } } let method = "GET"; let body; if (opts2.doc_ids) { params.filter = "_doc_ids"; method = "POST"; body = { doc_ids: opts2.doc_ids }; } else if (opts2.selector) { params.filter = "_selector"; method = "POST"; body = { selector: opts2.selector }; } let controller = new a(); let lastFetchedSeq; const fetchData = async function(since, callback2) { if (opts2.aborted) { return; } params.since = since; if (typeof params.since === "object") { params.since = JSON.stringify(params.since); } if (opts2.descending) { if (limit) { params.limit = leftToFetch; } } else { params.limit = !limit || leftToFetch > batchSize ? batchSize : leftToFetch; } let url = genDBUrl(host, "_changes" + paramsToStr(params)); let fetchOpts = { signal: controller.signal, method, body: JSON.stringify(body) }; lastFetchedSeq = since; if (opts2.aborted) { return; } try { await setup2(); const result = await fetchJSON(url, fetchOpts); callback2(null, result.data); } catch (error) { callback2(error); } }; let results = { results: [] }; const fetched = function(err, res2) { if (opts2.aborted) { return; } let raw_results_length = 0; if (res2 && res2.results) { raw_results_length = res2.results.length; results.last_seq = res2.last_seq; let pending = null; let lastSeq = null; if (typeof res2.pending === "number") { pending = res2.pending; } if (typeof results.last_seq === "string" || typeof results.last_seq === "number") { lastSeq = results.last_seq; } let req = {}; req.query = opts2.query_params; res2.results = res2.results.filter(function(c) { leftToFetch--; let ret = filterChange(opts2)(c); if (ret) { if (opts2.include_docs && opts2.attachments && opts2.binary) { readAttachmentsAsBlobOrBuffer(c); } if (opts2.return_docs) { results.results.push(c); } opts2.onChange(c, pending, lastSeq); } return ret; }); } else if (err) { opts2.aborted = true; opts2.complete(err); return; } if (res2 && res2.last_seq) { lastFetchedSeq = res2.last_seq; } let finished = limit && leftToFetch <= 0 || res2 && raw_results_length < batchSize || opts2.descending; if (opts2.continuous && !(limit && leftToFetch <= 0) || !finished) { (0, import_immediate.default)(function() { fetchData(lastFetchedSeq, fetched); }); } else { opts2.complete(null, results); } }; fetchData(opts2.since || 0, fetched); return { cancel: function() { opts2.aborted = true; controller.abort(); } }; }; api.revsDiff = adapterFun$$1("revsDiff", async function(req, opts2, callback2) { if (typeof opts2 === "function") { callback2 = opts2; opts2 = {}; } try { const result = await fetchJSON(genDBUrl(host, "_revs_diff"), { method: "POST", body: JSON.stringify(req) }); callback2(null, result.data); } catch (error) { callback2(error); } }); api._close = function(callback2) { callback2(); }; api._destroy = async function(options, callback2) { try { const json = await fetchJSON(genDBUrl(host, ""), { method: "DELETE" }); callback2(null, json); } catch (error) { if (error.status === 404) { callback2(null, { ok: true }); } else { callback2(error); } } }; } HttpPouch.valid = function() { return true; }; function index3(PouchDB2) { PouchDB2.adapter("http", HttpPouch, false); PouchDB2.adapter("https", HttpPouch, false); } var index_es_default4 = index3; // node_modules/pouchdb-mapreduce-utils/lib/index.es.js var QueryParseError = class extends Error { constructor(message) { super(); this.status = 400; this.name = "query_parse_error"; this.message = message; this.error = true; try { Error.captureStackTrace(this, QueryParseError); } catch (e2) { } } }; var NotFoundError = class extends Error { constructor(message) { super(); this.status = 404; this.name = "not_found"; this.message = message; this.error = true; try { Error.captureStackTrace(this, NotFoundError); } catch (e2) { } } }; var BuiltInError = class extends Error { constructor(message) { super(); this.status = 500; this.name = "invalid_value"; this.message = message; this.error = true; try { Error.captureStackTrace(this, BuiltInError); } catch (e2) { } } }; function promisedCallback(promise, callback) { if (callback) { promise.then(function(res2) { (0, import_immediate.default)(function() { callback(null, res2); }); }, function(reason) { (0, import_immediate.default)(function() { callback(reason); }); }); } return promise; } function callbackify(fun) { return function(...args) { var cb = args.pop(); var promise = fun.apply(this, args); if (typeof cb === "function") { promisedCallback(promise, cb); } return promise; }; } function fin(promise, finalPromiseFactory) { return promise.then(function(res2) { return finalPromiseFactory().then(function() { return res2; }); }, function(reason) { return finalPromiseFactory().then(function() { throw reason; }); }); } function sequentialize(queue2, promiseFactory) { return function() { var args = arguments; var that = this; return queue2.add(function() { return promiseFactory.apply(that, args); }); }; } function uniq(arr) { var theSet = new ExportedSet(arr); var result = new Array(theSet.size); var index5 = -1; theSet.forEach(function(value) { result[++index5] = value; }); return result; } function mapToKeysArray(map) { var result = new Array(map.size); var index5 = -1; map.forEach(function(value, key) { result[++index5] = key; }); return result; } // node_modules/pouchdb-abstract-mapreduce/lib/index.es.js var TaskQueue2 = class { constructor() { this.promise = new Promise(function(fulfill) { fulfill(); }); } add(promiseFactory) { this.promise = this.promise.catch(function() { }).then(function() { return promiseFactory(); }); return this.promise; } finish() { return this.promise; } }; function stringify2(input) { if (!input) { return "undefined"; } switch (typeof input) { case "function": return input.toString(); case "string": return input.toString(); default: return JSON.stringify(input); } } function createViewSignature(mapFun, reduceFun) { return stringify2(mapFun) + stringify2(reduceFun) + "undefined"; } async function createView(sourceDB, viewName, mapFun, reduceFun, temporary, localDocName2) { const viewSignature = createViewSignature(mapFun, reduceFun); let cachedViews; if (!temporary) { cachedViews = sourceDB._cachedViews = sourceDB._cachedViews || {}; if (cachedViews[viewSignature]) { return cachedViews[viewSignature]; } } const promiseForView = sourceDB.info().then(async function(info2) { const depDbName = info2.db_name + "-mrview-" + (temporary ? "temp" : stringMd5(viewSignature)); function diffFunction(doc) { doc.views = doc.views || {}; let fullViewName = viewName; if (fullViewName.indexOf("/") === -1) { fullViewName = viewName + "/" + viewName; } const depDbs = doc.views[fullViewName] = doc.views[fullViewName] || {}; if (depDbs[depDbName]) { return; } depDbs[depDbName] = true; return doc; } await upsert(sourceDB, "_local/" + localDocName2, diffFunction); const res2 = await sourceDB.registerDependentDatabase(depDbName); const db = res2.db; db.auto_compaction = true; const view = { name: depDbName, db, sourceDB, adapter: sourceDB.adapter, mapFun, reduceFun }; let lastSeqDoc; try { lastSeqDoc = await view.db.get("_local/lastSeq"); } catch (err) { if (err.status !== 404) { throw err; } } view.seq = lastSeqDoc ? lastSeqDoc.seq : 0; if (cachedViews) { view.db.once("destroyed", function() { delete cachedViews[viewSignature]; }); } return view; }); if (cachedViews) { cachedViews[viewSignature] = promiseForView; } return promiseForView; } var persistentQueues = {}; var tempViewQueue = new TaskQueue2(); var CHANGES_BATCH_SIZE2 = 50; function parseViewName(name) { return name.indexOf("/") === -1 ? [name, name] : name.split("/"); } function isGenOne(changes3) { return changes3.length === 1 && /^1-/.test(changes3[0].rev); } function emitError(db, e2, data) { try { db.emit("error", e2); } catch (err) { guardedConsole( "error", "The user's map/reduce function threw an uncaught error.\nYou can debug this error by doing:\nmyDatabase.on('error', function (err) { debugger; });\nPlease double-check your map/reduce function." ); guardedConsole("error", e2, data); } } function createAbstractMapReduce(localDocName2, mapper3, reducer3, ddocValidator3) { function tryMap(db, fun, doc) { try { fun(doc); } catch (e2) { emitError(db, e2, { fun, doc }); } } function tryReduce(db, fun, keys2, values, rereduce) { try { return { output: fun(keys2, values, rereduce) }; } catch (e2) { emitError(db, e2, { fun, keys: keys2, values, rereduce }); return { error: e2 }; } } function sortByKeyThenValue(x, y) { const keyCompare = collate(x.key, y.key); return keyCompare !== 0 ? keyCompare : collate(x.value, y.value); } function sliceResults(results, limit, skip) { skip = skip || 0; if (typeof limit === "number") { return results.slice(skip, limit + skip); } else if (skip > 0) { return results.slice(skip); } return results; } function rowToDocId(row) { const val = row.value; const docId = val && typeof val === "object" && val._id || row.id; return docId; } function readAttachmentsAsBlobOrBuffer2(res2) { res2.rows.forEach(function(row) { const atts = row.doc && row.doc._attachments; if (!atts) { return; } Object.keys(atts).forEach(function(filename) { const att = atts[filename]; atts[filename].data = b64ToBluffer(att.data, att.content_type); }); }); } function postprocessAttachments(opts) { return function(res2) { if (opts.include_docs && opts.attachments && opts.binary) { readAttachmentsAsBlobOrBuffer2(res2); } return res2; }; } function addHttpParam(paramName, opts, params, asJson) { let val = opts[paramName]; if (typeof val !== "undefined") { if (asJson) { val = encodeURIComponent(JSON.stringify(val)); } params.push(paramName + "=" + val); } } function coerceInteger(integerCandidate) { if (typeof integerCandidate !== "undefined") { const asNumber = Number(integerCandidate); if (!isNaN(asNumber) && asNumber === parseInt(integerCandidate, 10)) { return asNumber; } else { return integerCandidate; } } } function coerceOptions(opts) { opts.group_level = coerceInteger(opts.group_level); opts.limit = coerceInteger(opts.limit); opts.skip = coerceInteger(opts.skip); return opts; } function checkPositiveInteger(number) { if (number) { if (typeof number !== "number") { return new QueryParseError(`Invalid value for integer: "${number}"`); } if (number < 0) { return new QueryParseError(`Invalid value for positive integer: "${number}"`); } } } function checkQueryParseError(options, fun) { const startkeyName = options.descending ? "endkey" : "startkey"; const endkeyName = options.descending ? "startkey" : "endkey"; if (typeof options[startkeyName] !== "undefined" && typeof options[endkeyName] !== "undefined" && collate(options[startkeyName], options[endkeyName]) > 0) { throw new QueryParseError("No rows can match your key range, reverse your start_key and end_key or set {descending : true}"); } else if (fun.reduce && options.reduce !== false) { if (options.include_docs) { throw new QueryParseError("{include_docs:true} is invalid for reduce"); } else if (options.keys && options.keys.length > 1 && !options.group && !options.group_level) { throw new QueryParseError("Multi-key fetches for reduce views must use {group: true}"); } } ["group_level", "limit", "skip"].forEach(function(optionName) { const error = checkPositiveInteger(options[optionName]); if (error) { throw error; } }); } async function httpQuery(db, fun, opts) { let params = []; let body; let method = "GET"; let ok; addHttpParam("reduce", opts, params); addHttpParam("include_docs", opts, params); addHttpParam("attachments", opts, params); addHttpParam("limit", opts, params); addHttpParam("descending", opts, params); addHttpParam("group", opts, params); addHttpParam("group_level", opts, params); addHttpParam("skip", opts, params); addHttpParam("stale", opts, params); addHttpParam("conflicts", opts, params); addHttpParam("startkey", opts, params, true); addHttpParam("start_key", opts, params, true); addHttpParam("endkey", opts, params, true); addHttpParam("end_key", opts, params, true); addHttpParam("inclusive_end", opts, params); addHttpParam("key", opts, params, true); addHttpParam("update_seq", opts, params); params = params.join("&"); params = params === "" ? "" : "?" + params; if (typeof opts.keys !== "undefined") { const MAX_URL_LENGTH = 2e3; const keysAsString = `keys=${encodeURIComponent(JSON.stringify(opts.keys))}`; if (keysAsString.length + params.length + 1 <= MAX_URL_LENGTH) { params += (params[0] === "?" ? "&" : "?") + keysAsString; } else { method = "POST"; if (typeof fun === "string") { body = { keys: opts.keys }; } else { fun.keys = opts.keys; } } } if (typeof fun === "string") { const parts = parseViewName(fun); const response2 = await db.fetch("_design/" + parts[0] + "/_view/" + parts[1] + params, { headers: new h({ "Content-Type": "application/json" }), method, body: JSON.stringify(body) }); ok = response2.ok; const result2 = await response2.json(); if (!ok) { result2.status = response2.status; throw generateErrorFromResponse(result2); } result2.rows.forEach(function(row) { if (row.value && row.value.error && row.value.error === "builtin_reduce_error") { throw new Error(row.reason); } }); return new Promise(function(resolve) { resolve(result2); }).then(postprocessAttachments(opts)); } body = body || {}; Object.keys(fun).forEach(function(key) { if (Array.isArray(fun[key])) { body[key] = fun[key]; } else { body[key] = fun[key].toString(); } }); const response = await db.fetch("_temp_view" + params, { headers: new h({ "Content-Type": "application/json" }), method: "POST", body: JSON.stringify(body) }); ok = response.ok; const result = await response.json(); if (!ok) { result.status = response.status; throw generateErrorFromResponse(result); } return new Promise(function(resolve) { resolve(result); }).then(postprocessAttachments(opts)); } function customQuery(db, fun, opts) { return new Promise(function(resolve, reject) { db._query(fun, opts, function(err, res2) { if (err) { return reject(err); } resolve(res2); }); }); } function customViewCleanup(db) { return new Promise(function(resolve, reject) { db._viewCleanup(function(err, res2) { if (err) { return reject(err); } resolve(res2); }); }); } function defaultsTo(value) { return function(reason) { if (reason.status === 404) { return value; } else { throw reason; } }; } async function getDocsToPersist(docId, view, docIdsToChangesAndEmits) { const metaDocId = "_local/doc_" + docId; const defaultMetaDoc = { _id: metaDocId, keys: [] }; const docData = docIdsToChangesAndEmits.get(docId); const indexableKeysToKeyValues = docData[0]; const changes3 = docData[1]; function getMetaDoc() { if (isGenOne(changes3)) { return Promise.resolve(defaultMetaDoc); } return view.db.get(metaDocId).catch(defaultsTo(defaultMetaDoc)); } function getKeyValueDocs(metaDoc2) { if (!metaDoc2.keys.length) { return Promise.resolve({ rows: [] }); } return view.db.allDocs({ keys: metaDoc2.keys, include_docs: true }); } function processKeyValueDocs(metaDoc2, kvDocsRes) { const kvDocs = []; const oldKeys = new ExportedSet(); for (let i = 0, len = kvDocsRes.rows.length; i < len; i++) { const row = kvDocsRes.rows[i]; const doc = row.doc; if (!doc) { continue; } kvDocs.push(doc); oldKeys.add(doc._id); doc._deleted = !indexableKeysToKeyValues.has(doc._id); if (!doc._deleted) { const keyValue = indexableKeysToKeyValues.get(doc._id); if ("value" in keyValue) { doc.value = keyValue.value; } } } const newKeys = mapToKeysArray(indexableKeysToKeyValues); newKeys.forEach(function(key) { if (!oldKeys.has(key)) { const kvDoc = { _id: key }; const keyValue = indexableKeysToKeyValues.get(key); if ("value" in keyValue) { kvDoc.value = keyValue.value; } kvDocs.push(kvDoc); } }); metaDoc2.keys = uniq(newKeys.concat(metaDoc2.keys)); kvDocs.push(metaDoc2); return kvDocs; } const metaDoc = await getMetaDoc(); const keyValueDocs = await getKeyValueDocs(metaDoc); return processKeyValueDocs(metaDoc, keyValueDocs); } function updatePurgeSeq(view) { return view.sourceDB.get("_local/purges").then(function(res2) { const purgeSeq = res2.purgeSeq; return view.db.get("_local/purgeSeq").then(function(res3) { return res3._rev; }).catch(function(err) { if (err.status !== 404) { throw err; } return void 0; }).then(function(rev2) { return view.db.put({ _id: "_local/purgeSeq", _rev: rev2, purgeSeq }); }); }).catch(function(err) { if (err.status !== 404) { throw err; } }); } function saveKeyValues(view, docIdsToChangesAndEmits, seq) { var seqDocId = "_local/lastSeq"; return view.db.get(seqDocId).catch(defaultsTo({ _id: seqDocId, seq: 0 })).then(function(lastSeqDoc) { var docIds = mapToKeysArray(docIdsToChangesAndEmits); return Promise.all(docIds.map(function(docId) { return getDocsToPersist(docId, view, docIdsToChangesAndEmits); })).then(function(listOfDocsToPersist) { var docsToPersist = flatten(listOfDocsToPersist); lastSeqDoc.seq = seq; docsToPersist.push(lastSeqDoc); return view.db.bulkDocs({ docs: docsToPersist }); }).then(() => updatePurgeSeq(view)); }); } function getQueue(view) { const viewName = typeof view === "string" ? view : view.name; let queue2 = persistentQueues[viewName]; if (!queue2) { queue2 = persistentQueues[viewName] = new TaskQueue2(); } return queue2; } async function updateView(view, opts) { return sequentialize(getQueue(view), function() { return updateViewInQueue(view, opts); })(); } async function updateViewInQueue(view, opts) { let mapResults; let doc; let taskId; function emit(key, value) { const output = { id: doc._id, key: normalizeKey(key) }; if (typeof value !== "undefined" && value !== null) { output.value = normalizeKey(value); } mapResults.push(output); } const mapFun = mapper3(view.mapFun, emit); let currentSeq = view.seq || 0; function createTask() { return view.sourceDB.info().then(function(info2) { taskId = view.sourceDB.activeTasks.add({ name: "view_indexing", total_items: info2.update_seq - currentSeq }); }); } function processChange2(docIdsToChangesAndEmits, seq) { return function() { return saveKeyValues(view, docIdsToChangesAndEmits, seq); }; } let indexed_docs = 0; const progress = { view: view.name, indexed_docs }; view.sourceDB.emit("indexing", progress); const queue2 = new TaskQueue2(); async function processNextBatch() { const response = await view.sourceDB.changes({ return_docs: true, conflicts: true, include_docs: true, style: "all_docs", since: currentSeq, limit: opts.changes_batch_size }); const purges = await getRecentPurges(); return processBatch(response, purges); } function getRecentPurges() { return view.db.get("_local/purgeSeq").then(function(res2) { return res2.purgeSeq; }).catch(function(err) { if (err && err.status !== 404) { throw err; } return -1; }).then(function(purgeSeq) { return view.sourceDB.get("_local/purges").then(function(res2) { const recentPurges = res2.purges.filter(function(purge2, index5) { return index5 > purgeSeq; }).map((purge2) => purge2.docId); const uniquePurges = recentPurges.filter(function(docId, index5) { return recentPurges.indexOf(docId) === index5; }); return Promise.all(uniquePurges.map(function(docId) { return view.sourceDB.get(docId).then(function(doc2) { return { docId, doc: doc2 }; }).catch(function(err) { if (err.status !== 404) { throw err; } return { docId }; }); })); }).catch(function(err) { if (err && err.status !== 404) { throw err; } return []; }); }); } function processBatch(response, purges) { var results = response.results; if (!results.length && !purges.length) { return; } for (let purge2 of purges) { const index5 = results.findIndex(function(change) { return change.id === purge2.docId; }); if (index5 < 0) { const entry = { _id: purge2.docId, doc: { _id: purge2.docId, _deleted: 1 }, changes: [] }; if (purge2.doc) { entry.doc = purge2.doc; entry.changes.push({ rev: purge2.doc._rev }); } results.push(entry); } } var docIdsToChangesAndEmits = createDocIdsToChangesAndEmits(results); queue2.add(processChange2(docIdsToChangesAndEmits, currentSeq)); indexed_docs = indexed_docs + results.length; const progress2 = { view: view.name, last_seq: response.last_seq, results_count: results.length, indexed_docs }; view.sourceDB.emit("indexing", progress2); view.sourceDB.activeTasks.update(taskId, { completed_items: indexed_docs }); if (results.length < opts.changes_batch_size) { return; } return processNextBatch(); } function createDocIdsToChangesAndEmits(results) { const docIdsToChangesAndEmits = new ExportedMap(); for (let i = 0, len = results.length; i < len; i++) { const change = results[i]; if (change.doc._id[0] !== "_") { mapResults = []; doc = change.doc; if (!doc._deleted) { tryMap(view.sourceDB, mapFun, doc); } mapResults.sort(sortByKeyThenValue); const indexableKeysToKeyValues = createIndexableKeysToKeyValues(mapResults); docIdsToChangesAndEmits.set(change.doc._id, [ indexableKeysToKeyValues, change.changes ]); } currentSeq = change.seq; } return docIdsToChangesAndEmits; } function createIndexableKeysToKeyValues(mapResults2) { const indexableKeysToKeyValues = new ExportedMap(); let lastKey; for (let i = 0, len = mapResults2.length; i < len; i++) { const emittedKeyValue = mapResults2[i]; const complexKey = [emittedKeyValue.key, emittedKeyValue.id]; if (i > 0 && collate(emittedKeyValue.key, lastKey) === 0) { complexKey.push(i); } indexableKeysToKeyValues.set(toIndexableString(complexKey), emittedKeyValue); lastKey = emittedKeyValue.key; } return indexableKeysToKeyValues; } try { await createTask(); await processNextBatch(); await queue2.finish(); view.seq = currentSeq; view.sourceDB.activeTasks.remove(taskId); } catch (error) { view.sourceDB.activeTasks.remove(taskId, error); } } function reduceView(view, results, options) { if (options.group_level === 0) { delete options.group_level; } const shouldGroup = options.group || options.group_level; const reduceFun = reducer3(view.reduceFun); const groups = []; const lvl = isNaN(options.group_level) ? Number.POSITIVE_INFINITY : options.group_level; results.forEach(function(e2) { const last = groups[groups.length - 1]; let groupKey = shouldGroup ? e2.key : null; if (shouldGroup && Array.isArray(groupKey)) { groupKey = groupKey.slice(0, lvl); } if (last && collate(last.groupKey, groupKey) === 0) { last.keys.push([e2.key, e2.id]); last.values.push(e2.value); return; } groups.push({ keys: [[e2.key, e2.id]], values: [e2.value], groupKey }); }); results = []; for (let i = 0, len = groups.length; i < len; i++) { const e2 = groups[i]; const reduceTry = tryReduce(view.sourceDB, reduceFun, e2.keys, e2.values, false); if (reduceTry.error && reduceTry.error instanceof BuiltInError) { throw reduceTry.error; } results.push({ value: reduceTry.error ? null : reduceTry.output, key: e2.groupKey }); } return { rows: sliceResults(results, options.limit, options.skip) }; } function queryView(view, opts) { return sequentialize(getQueue(view), function() { return queryViewInQueue(view, opts); })(); } async function queryViewInQueue(view, opts) { let totalRows; const shouldReduce = view.reduceFun && opts.reduce !== false; const skip = opts.skip || 0; if (typeof opts.keys !== "undefined" && !opts.keys.length) { opts.limit = 0; delete opts.keys; } async function fetchFromView(viewOpts) { viewOpts.include_docs = true; const res2 = await view.db.allDocs(viewOpts); totalRows = res2.total_rows; return res2.rows.map(function(result) { if ("value" in result.doc && typeof result.doc.value === "object" && result.doc.value !== null) { const keys2 = Object.keys(result.doc.value).sort(); const expectedKeys = ["id", "key", "value"]; if (!(keys2 < expectedKeys || keys2 > expectedKeys)) { return result.doc.value; } } const parsedKeyAndDocId = parseIndexableString(result.doc._id); return { key: parsedKeyAndDocId[0], id: parsedKeyAndDocId[1], value: "value" in result.doc ? result.doc.value : null }; }); } async function onMapResultsReady(rows) { let finalResults; if (shouldReduce) { finalResults = reduceView(view, rows, opts); } else if (typeof opts.keys === "undefined") { finalResults = { total_rows: totalRows, offset: skip, rows }; } else { finalResults = { total_rows: totalRows, offset: skip, rows: sliceResults(rows, opts.limit, opts.skip) }; } if (opts.update_seq) { finalResults.update_seq = view.seq; } if (opts.include_docs) { const docIds = uniq(rows.map(rowToDocId)); const allDocsRes = await view.sourceDB.allDocs({ keys: docIds, include_docs: true, conflicts: opts.conflicts, attachments: opts.attachments, binary: opts.binary }); var docIdsToDocs = new ExportedMap(); allDocsRes.rows.forEach(function(row) { docIdsToDocs.set(row.id, row.doc); }); rows.forEach(function(row) { var docId = rowToDocId(row); var doc = docIdsToDocs.get(docId); if (doc) { row.doc = doc; } }); return finalResults; } else { return finalResults; } } if (typeof opts.keys !== "undefined") { const keys2 = opts.keys; const fetchPromises = keys2.map(function(key) { const viewOpts = { startkey: toIndexableString([key]), endkey: toIndexableString([key, {}]) }; if (opts.update_seq) { viewOpts.update_seq = true; } return fetchFromView(viewOpts); }); const result = await Promise.all(fetchPromises); const flattenedResult = flatten(result); return onMapResultsReady(flattenedResult); } else { const viewOpts = { descending: opts.descending }; if (opts.update_seq) { viewOpts.update_seq = true; } let startkey; let endkey; if ("start_key" in opts) { startkey = opts.start_key; } if ("startkey" in opts) { startkey = opts.startkey; } if ("end_key" in opts) { endkey = opts.end_key; } if ("endkey" in opts) { endkey = opts.endkey; } if (typeof startkey !== "undefined") { viewOpts.startkey = opts.descending ? toIndexableString([startkey, {}]) : toIndexableString([startkey]); } if (typeof endkey !== "undefined") { let inclusiveEnd = opts.inclusive_end !== false; if (opts.descending) { inclusiveEnd = !inclusiveEnd; } viewOpts.endkey = toIndexableString( inclusiveEnd ? [endkey, {}] : [endkey] ); } if (typeof opts.key !== "undefined") { const keyStart = toIndexableString([opts.key]); const keyEnd = toIndexableString([opts.key, {}]); if (viewOpts.descending) { viewOpts.endkey = keyStart; viewOpts.startkey = keyEnd; } else { viewOpts.startkey = keyStart; viewOpts.endkey = keyEnd; } } if (!shouldReduce) { if (typeof opts.limit === "number") { viewOpts.limit = opts.limit; } viewOpts.skip = skip; } const result = await fetchFromView(viewOpts); return onMapResultsReady(result); } } async function httpViewCleanup(db) { const response = await db.fetch("_view_cleanup", { headers: new h({ "Content-Type": "application/json" }), method: "POST" }); return response.json(); } async function localViewCleanup(db) { try { const metaDoc = await db.get("_local/" + localDocName2); const docsToViews = new ExportedMap(); Object.keys(metaDoc.views).forEach(function(fullViewName) { const parts = parseViewName(fullViewName); const designDocName = "_design/" + parts[0]; const viewName = parts[1]; let views = docsToViews.get(designDocName); if (!views) { views = new ExportedSet(); docsToViews.set(designDocName, views); } views.add(viewName); }); const opts = { keys: mapToKeysArray(docsToViews), include_docs: true }; const res2 = await db.allDocs(opts); const viewsToStatus = {}; res2.rows.forEach(function(row) { const ddocName = row.key.substring(8); docsToViews.get(row.key).forEach(function(viewName) { let fullViewName = ddocName + "/" + viewName; if (!metaDoc.views[fullViewName]) { fullViewName = viewName; } const viewDBNames = Object.keys(metaDoc.views[fullViewName]); const statusIsGood = row.doc && row.doc.views && row.doc.views[viewName]; viewDBNames.forEach(function(viewDBName) { viewsToStatus[viewDBName] = viewsToStatus[viewDBName] || statusIsGood; }); }); }); const dbsToDelete = Object.keys(viewsToStatus).filter(function(viewDBName) { return !viewsToStatus[viewDBName]; }); const destroyPromises = dbsToDelete.map(function(viewDBName) { return sequentialize(getQueue(viewDBName), function() { return new db.constructor(viewDBName, db.__opts).destroy(); })(); }); return Promise.all(destroyPromises).then(function() { return { ok: true }; }); } catch (err) { if (err.status === 404) { return { ok: true }; } else { throw err; } } } async function queryPromised(db, fun, opts) { if (typeof db._query === "function") { return customQuery(db, fun, opts); } if (isRemote(db)) { return httpQuery(db, fun, opts); } const updateViewOpts = { changes_batch_size: db.__opts.view_update_changes_batch_size || CHANGES_BATCH_SIZE2 }; if (typeof fun !== "string") { checkQueryParseError(opts, fun); tempViewQueue.add(async function() { const view = await createView( db, "temp_view/temp_view", fun.map, fun.reduce, true, localDocName2 ); return fin( updateView(view, updateViewOpts).then( function() { return queryView(view, opts); } ), function() { return view.db.destroy(); } ); }); return tempViewQueue.finish(); } else { const fullViewName = fun; const parts = parseViewName(fullViewName); const designDocName = parts[0]; const viewName = parts[1]; const doc = await db.get("_design/" + designDocName); fun = doc.views && doc.views[viewName]; if (!fun) { throw new NotFoundError(`ddoc ${doc._id} has no view named ${viewName}`); } ddocValidator3(doc, viewName); checkQueryParseError(opts, fun); const view = await createView( db, fullViewName, fun.map, fun.reduce, false, localDocName2 ); if (opts.stale === "ok" || opts.stale === "update_after") { if (opts.stale === "update_after") { (0, import_immediate.default)(function() { updateView(view, updateViewOpts); }); } return queryView(view, opts); } else { await updateView(view, updateViewOpts); return queryView(view, opts); } } } function abstractQuery(fun, opts, callback) { const db = this; if (typeof opts === "function") { callback = opts; opts = {}; } opts = opts ? coerceOptions(opts) : {}; if (typeof fun === "function") { fun = { map: fun }; } const promise = Promise.resolve().then(function() { return queryPromised(db, fun, opts); }); promisedCallback(promise, callback); return promise; } const abstractViewCleanup = callbackify(function() { const db = this; if (typeof db._viewCleanup === "function") { return customViewCleanup(db); } if (isRemote(db)) { return httpViewCleanup(db); } return localViewCleanup(db); }); return { query: abstractQuery, viewCleanup: abstractViewCleanup }; } var index_es_default5 = createAbstractMapReduce; // node_modules/pouchdb-mapreduce/lib/index-browser.es.js function createBuiltInError(name) { var message = "builtin " + name + " function requires map values to be numbers or number arrays"; return new BuiltInError(message); } function sum(values) { var result = 0; for (var i = 0, len = values.length; i < len; i++) { var num = values[i]; if (typeof num !== "number") { if (Array.isArray(num)) { result = typeof result === "number" ? [result] : result; for (var j = 0, jLen = num.length; j < jLen; j++) { var jNum = num[j]; if (typeof jNum !== "number") { throw createBuiltInError("_sum"); } else if (typeof result[j] === "undefined") { result.push(jNum); } else { result[j] += jNum; } } } else { throw createBuiltInError("_sum"); } } else if (typeof result === "number") { result += num; } else { result[0] += num; } } return result; } var log = guardedConsole.bind(null, "log"); var isArray = Array.isArray; var toJSON = JSON.parse; function evalFunctionWithEval(func, emit) { return scopeEval( "return (" + func.replace(/;\s*$/, "") + ");", { emit, sum, log, isArray, toJSON } ); } var builtInReduce = { _sum: function(keys2, values) { return sum(values); }, _count: function(keys2, values) { return values.length; }, _stats: function(keys2, values) { function sumsqr(values2) { var _sumsqr = 0; for (var i = 0, len = values2.length; i < len; i++) { var num = values2[i]; _sumsqr += num * num; } return _sumsqr; } return { sum: sum(values), min: Math.min.apply(null, values), max: Math.max.apply(null, values), count: values.length, sumsqr: sumsqr(values) }; } }; function getBuiltIn(reduceFunString) { if (/^_sum/.test(reduceFunString)) { return builtInReduce._sum; } else if (/^_count/.test(reduceFunString)) { return builtInReduce._count; } else if (/^_stats/.test(reduceFunString)) { return builtInReduce._stats; } else if (/^_/.test(reduceFunString)) { throw new Error(reduceFunString + " is not a supported reduce function."); } } function mapper(mapFun, emit) { if (typeof mapFun === "function" && mapFun.length === 2) { var origMap = mapFun; return function(doc) { return origMap(doc, emit); }; } else { return evalFunctionWithEval(mapFun.toString(), emit); } } function reducer(reduceFun) { var reduceFunString = reduceFun.toString(); var builtIn = getBuiltIn(reduceFunString); if (builtIn) { return builtIn; } else { return evalFunctionWithEval(reduceFunString); } } function ddocValidator(ddoc, viewName) { var fun = ddoc.views && ddoc.views[viewName]; if (typeof fun.map !== "string") { throw new NotFoundError("ddoc " + ddoc._id + " has no string view named " + viewName + ", instead found object of type: " + typeof fun.map); } } var localDocName = "mrviews"; var abstract = index_es_default5(localDocName, mapper, reducer, ddocValidator); function query2(fun, opts, callback) { return abstract.query.call(this, fun, opts, callback); } function viewCleanup2(callback) { return abstract.viewCleanup.call(this, callback); } var index4 = { query: query2, viewCleanup: viewCleanup2 }; var index_browser_es_default2 = index4; // node_modules/pouchdb-checkpointer/lib/index.es.js var CHECKPOINT_VERSION = 1; var REPLICATOR = "pouchdb"; var CHECKPOINT_HISTORY_SIZE = 5; var LOWEST_SEQ = 0; function updateCheckpoint(db, id, checkpoint, session, returnValue) { return db.get(id).catch(function(err) { if (err.status === 404) { if (db.adapter === "http" || db.adapter === "https") { explainError( 404, "PouchDB is just checking if a remote checkpoint exists." ); } return { session_id: session, _id: id, history: [], replicator: REPLICATOR, version: CHECKPOINT_VERSION }; } throw err; }).then(function(doc) { if (returnValue.cancelled) { return; } if (doc.last_seq === checkpoint) { return; } doc.history = (doc.history || []).filter(function(item) { return item.session_id !== session; }); doc.history.unshift({ last_seq: checkpoint, session_id: session }); doc.history = doc.history.slice(0, CHECKPOINT_HISTORY_SIZE); doc.version = CHECKPOINT_VERSION; doc.replicator = REPLICATOR; doc.session_id = session; doc.last_seq = checkpoint; return db.put(doc).catch(function(err) { if (err.status === 409) { return updateCheckpoint(db, id, checkpoint, session, returnValue); } throw err; }); }); } var CheckpointerInternal = class { constructor(src, target, id, returnValue, opts) { this.src = src; this.target = target; this.id = id; this.returnValue = returnValue; this.opts = opts || {}; } writeCheckpoint(checkpoint, session) { var self2 = this; return this.updateTarget(checkpoint, session).then(function() { return self2.updateSource(checkpoint, session); }); } updateTarget(checkpoint, session) { if (this.opts.writeTargetCheckpoint) { return updateCheckpoint( this.target, this.id, checkpoint, session, this.returnValue ); } else { return Promise.resolve(true); } } updateSource(checkpoint, session) { if (this.opts.writeSourceCheckpoint) { var self2 = this; return updateCheckpoint( this.src, this.id, checkpoint, session, this.returnValue ).catch(function(err) { if (isForbiddenError(err)) { self2.opts.writeSourceCheckpoint = false; return true; } throw err; }); } else { return Promise.resolve(true); } } getCheckpoint() { var self2 = this; if (self2.opts && self2.opts.writeSourceCheckpoint && !self2.opts.writeTargetCheckpoint) { return self2.src.get(self2.id).then(function(sourceDoc) { return sourceDoc.last_seq || LOWEST_SEQ; }).catch(function(err) { if (err.status !== 404) { throw err; } return LOWEST_SEQ; }); } return self2.target.get(self2.id).then(function(targetDoc) { if (self2.opts && self2.opts.writeTargetCheckpoint && !self2.opts.writeSourceCheckpoint) { return targetDoc.last_seq || LOWEST_SEQ; } return self2.src.get(self2.id).then(function(sourceDoc) { if (targetDoc.version !== sourceDoc.version) { return LOWEST_SEQ; } var version2; if (targetDoc.version) { version2 = targetDoc.version.toString(); } else { version2 = "undefined"; } if (version2 in comparisons) { return comparisons[version2](targetDoc, sourceDoc); } return LOWEST_SEQ; }, function(err) { if (err.status === 404 && targetDoc.last_seq) { return self2.src.put({ _id: self2.id, last_seq: LOWEST_SEQ }).then(function() { return LOWEST_SEQ; }, function(err2) { if (isForbiddenError(err2)) { self2.opts.writeSourceCheckpoint = false; return targetDoc.last_seq; } return LOWEST_SEQ; }); } throw err; }); }).catch(function(err) { if (err.status !== 404) { throw err; } return LOWEST_SEQ; }); } }; var comparisons = { "undefined": function(targetDoc, sourceDoc) { if (collate(targetDoc.last_seq, sourceDoc.last_seq) === 0) { return sourceDoc.last_seq; } return 0; }, "1": function(targetDoc, sourceDoc) { return compareReplicationLogs(sourceDoc, targetDoc).last_seq; } }; function compareReplicationLogs(srcDoc, tgtDoc) { if (srcDoc.session_id === tgtDoc.session_id) { return { last_seq: srcDoc.last_seq, history: srcDoc.history }; } return compareReplicationHistory(srcDoc.history, tgtDoc.history); } function compareReplicationHistory(sourceHistory, targetHistory) { var S = sourceHistory[0]; var sourceRest = sourceHistory.slice(1); var T = targetHistory[0]; var targetRest = targetHistory.slice(1); if (!S || targetHistory.length === 0) { return { last_seq: LOWEST_SEQ, history: [] }; } var sourceId = S.session_id; if (hasSessionId(sourceId, targetHistory)) { return { last_seq: S.last_seq, history: sourceHistory }; } var targetId = T.session_id; if (hasSessionId(targetId, sourceRest)) { return { last_seq: T.last_seq, history: targetRest }; } return compareReplicationHistory(sourceRest, targetRest); } function hasSessionId(sessionId, history) { var props = history[0]; var rest = history.slice(1); if (!sessionId || history.length === 0) { return false; } if (sessionId === props.session_id) { return true; } return hasSessionId(sessionId, rest); } function isForbiddenError(err) { return typeof err.status === "number" && Math.floor(err.status / 100) === 4; } function Checkpointer(src, target, id, returnValue, opts) { if (!(this instanceof CheckpointerInternal)) { return new CheckpointerInternal(src, target, id, returnValue, opts); } return Checkpointer; } var index_es_default6 = Checkpointer; // node_modules/pouchdb-generate-replication-id/lib/index.es.js function sortObjectPropertiesByKey(queryParams) { return Object.keys(queryParams).sort(collate).reduce(function(result, key) { result[key] = queryParams[key]; return result; }, {}); } function generateReplicationId(src, target, opts) { var docIds = opts.doc_ids ? opts.doc_ids.sort(collate) : ""; var filterFun = opts.filter ? opts.filter.toString() : ""; var queryParams = ""; var filterViewName = ""; var selector = ""; if (opts.selector) { selector = JSON.stringify(opts.selector); } if (opts.filter && opts.query_params) { queryParams = JSON.stringify(sortObjectPropertiesByKey(opts.query_params)); } if (opts.filter && opts.filter === "_view") { filterViewName = opts.view.toString(); } return Promise.all([src.id(), target.id()]).then(function(res2) { var queryData = res2[0] + res2[1] + filterFun + filterViewName + queryParams + docIds + selector; return new Promise(function(resolve) { binaryMd5(queryData, resolve); }); }).then(function(md5sum) { md5sum = md5sum.replace(/\//g, ".").replace(/\+/g, "_"); return "_local/" + md5sum; }); } var index_es_default7 = generateReplicationId; // node_modules/pouchdb-replication/lib/index.es.js var import_events3 = __toESM(require_events()); function fileHasChanged(localDoc, remoteDoc, filename) { return !localDoc._attachments || !localDoc._attachments[filename] || localDoc._attachments[filename].digest !== remoteDoc._attachments[filename].digest; } function getDocAttachments(db, doc) { var filenames = Object.keys(doc._attachments); return Promise.all(filenames.map(function(filename) { return db.getAttachment(doc._id, filename, { rev: doc._rev }); })); } function getDocAttachmentsFromTargetOrSource(target, src, doc) { var doCheckForLocalAttachments = isRemote(src) && !isRemote(target); var filenames = Object.keys(doc._attachments); if (!doCheckForLocalAttachments) { return getDocAttachments(src, doc); } return target.get(doc._id).then(function(localDoc) { return Promise.all(filenames.map(function(filename) { if (fileHasChanged(localDoc, doc, filename)) { return src.getAttachment(doc._id, filename); } return target.getAttachment(localDoc._id, filename); })); }).catch(function(error) { if (error.status !== 404) { throw error; } return getDocAttachments(src, doc); }); } function createBulkGetOpts(diffs) { var requests = []; Object.keys(diffs).forEach(function(id) { var missingRevs = diffs[id].missing; missingRevs.forEach(function(missingRev) { requests.push({ id, rev: missingRev }); }); }); return { docs: requests, revs: true, latest: true }; } function getDocs(src, target, diffs, state) { diffs = clone(diffs); var resultDocs = [], ok = true; function getAllDocs() { var bulkGetOpts = createBulkGetOpts(diffs); if (!bulkGetOpts.docs.length) { return; } return src.bulkGet(bulkGetOpts).then(function(bulkGetResponse) { if (state.cancelled) { throw new Error("cancelled"); } return Promise.all(bulkGetResponse.results.map(function(bulkGetInfo) { return Promise.all(bulkGetInfo.docs.map(function(doc) { var remoteDoc = doc.ok; if (doc.error) { ok = false; } if (!remoteDoc || !remoteDoc._attachments) { return remoteDoc; } return getDocAttachmentsFromTargetOrSource(target, src, remoteDoc).then(function(attachments) { var filenames = Object.keys(remoteDoc._attachments); attachments.forEach(function(attachment, i) { var att = remoteDoc._attachments[filenames[i]]; delete att.stub; delete att.length; att.data = attachment; }); return remoteDoc; }); })); })).then(function(results) { resultDocs = resultDocs.concat(flatten(results).filter(Boolean)); }); }); } function returnResult() { return { ok, docs: resultDocs }; } return Promise.resolve().then(getAllDocs).then(returnResult); } var STARTING_BACK_OFF = 0; function backOff(opts, returnValue, error, callback) { if (opts.retry === false) { returnValue.emit("error", error); returnValue.removeAllListeners(); return; } if (typeof opts.back_off_function !== "function") { opts.back_off_function = defaultBackOff; } returnValue.emit("requestError", error); if (returnValue.state === "active" || returnValue.state === "pending") { returnValue.emit("paused", error); returnValue.state = "stopped"; var backOffSet = function backoffTimeSet() { opts.current_back_off = STARTING_BACK_OFF; }; var removeBackOffSetter = function removeBackOffTimeSet() { returnValue.removeListener("active", backOffSet); }; returnValue.once("paused", removeBackOffSetter); returnValue.once("active", backOffSet); } opts.current_back_off = opts.current_back_off || STARTING_BACK_OFF; opts.current_back_off = opts.back_off_function(opts.current_back_off); setTimeout(callback, opts.current_back_off); } function replicate(src, target, opts, returnValue, result) { var batches = []; var currentBatch; var pendingBatch = { seq: 0, changes: [], docs: [] }; var writingCheckpoint = false; var changesCompleted = false; var replicationCompleted = false; var initial_last_seq = 0; var last_seq = 0; var continuous = opts.continuous || opts.live || false; var batch_size = opts.batch_size || 100; var batches_limit = opts.batches_limit || 10; var style = opts.style || "all_docs"; var changesPending = false; var doc_ids = opts.doc_ids; var selector = opts.selector; var repId; var checkpointer; var changedDocs = []; var session = uuid(); var taskId; result = result || { ok: true, start_time: new Date().toISOString(), docs_read: 0, docs_written: 0, doc_write_failures: 0, errors: [] }; var changesOpts = {}; returnValue.ready(src, target); function initCheckpointer() { if (checkpointer) { return Promise.resolve(); } return index_es_default7(src, target, opts).then(function(res2) { repId = res2; var checkpointOpts = {}; if (opts.checkpoint === false) { checkpointOpts = { writeSourceCheckpoint: false, writeTargetCheckpoint: false }; } else if (opts.checkpoint === "source") { checkpointOpts = { writeSourceCheckpoint: true, writeTargetCheckpoint: false }; } else if (opts.checkpoint === "target") { checkpointOpts = { writeSourceCheckpoint: false, writeTargetCheckpoint: true }; } else { checkpointOpts = { writeSourceCheckpoint: true, writeTargetCheckpoint: true }; } checkpointer = new index_es_default6(src, target, repId, returnValue, checkpointOpts); }); } function writeDocs() { changedDocs = []; if (currentBatch.docs.length === 0) { return; } var docs = currentBatch.docs; var bulkOpts = { timeout: opts.timeout }; return target.bulkDocs({ docs, new_edits: false }, bulkOpts).then(function(res2) { if (returnValue.cancelled) { completeReplication(); throw new Error("cancelled"); } var errorsById = /* @__PURE__ */ Object.create(null); res2.forEach(function(res3) { if (res3.error) { errorsById[res3.id] = res3; } }); var errorsNo = Object.keys(errorsById).length; result.doc_write_failures += errorsNo; result.docs_written += docs.length - errorsNo; docs.forEach(function(doc) { var error = errorsById[doc._id]; if (error) { result.errors.push(error); var errorName = (error.name || "").toLowerCase(); if (errorName === "unauthorized" || errorName === "forbidden") { returnValue.emit("denied", clone(error)); } else { throw error; } } else { changedDocs.push(doc); } }); }, function(err) { result.doc_write_failures += docs.length; throw err; }); } function finishBatch() { if (currentBatch.error) { throw new Error("There was a problem getting docs."); } result.last_seq = last_seq = currentBatch.seq; var outResult = clone(result); if (changedDocs.length) { outResult.docs = changedDocs; if (typeof currentBatch.pending === "number") { outResult.pending = currentBatch.pending; delete currentBatch.pending; } returnValue.emit("change", outResult); } writingCheckpoint = true; src.info().then(function(info2) { var task = src.activeTasks.get(taskId); if (!currentBatch || !task) { return; } var completed = task.completed_items || 0; var total_items = parseInt(info2.update_seq, 10) - parseInt(initial_last_seq, 10); src.activeTasks.update(taskId, { completed_items: completed + currentBatch.changes.length, total_items }); }); return checkpointer.writeCheckpoint( currentBatch.seq, session ).then(function() { returnValue.emit("checkpoint", { "checkpoint": currentBatch.seq }); writingCheckpoint = false; if (returnValue.cancelled) { completeReplication(); throw new Error("cancelled"); } currentBatch = void 0; getChanges(); }).catch(function(err) { onCheckpointError(err); throw err; }); } function getDiffs() { var diff = {}; currentBatch.changes.forEach(function(change) { returnValue.emit("checkpoint", { "revs_diff": change }); if (change.id === "_user/") { return; } diff[change.id] = change.changes.map(function(x) { return x.rev; }); }); return target.revsDiff(diff).then(function(diffs) { if (returnValue.cancelled) { completeReplication(); throw new Error("cancelled"); } currentBatch.diffs = diffs; }); } function getBatchDocs() { return getDocs(src, target, currentBatch.diffs, returnValue).then(function(got) { currentBatch.error = !got.ok; got.docs.forEach(function(doc) { delete currentBatch.diffs[doc._id]; result.docs_read++; currentBatch.docs.push(doc); }); }); } function startNextBatch() { if (returnValue.cancelled || currentBatch) { return; } if (batches.length === 0) { processPendingBatch(true); return; } currentBatch = batches.shift(); returnValue.emit("checkpoint", { "start_next_batch": currentBatch.seq }); getDiffs().then(getBatchDocs).then(writeDocs).then(finishBatch).then(startNextBatch).catch(function(err) { abortReplication("batch processing terminated with error", err); }); } function processPendingBatch(immediate2) { if (pendingBatch.changes.length === 0) { if (batches.length === 0 && !currentBatch) { if (continuous && changesOpts.live || changesCompleted) { returnValue.state = "pending"; returnValue.emit("paused"); } if (changesCompleted) { completeReplication(); } } return; } if (immediate2 || changesCompleted || pendingBatch.changes.length >= batch_size) { batches.push(pendingBatch); pendingBatch = { seq: 0, changes: [], docs: [] }; if (returnValue.state === "pending" || returnValue.state === "stopped") { returnValue.state = "active"; returnValue.emit("active"); } startNextBatch(); } } function abortReplication(reason, err) { if (replicationCompleted) { return; } if (!err.message) { err.message = reason; } result.ok = false; result.status = "aborting"; batches = []; pendingBatch = { seq: 0, changes: [], docs: [] }; completeReplication(err); } function completeReplication(fatalError) { if (replicationCompleted) { return; } if (returnValue.cancelled) { result.status = "cancelled"; if (writingCheckpoint) { return; } } result.status = result.status || "complete"; result.end_time = new Date().toISOString(); result.last_seq = last_seq; replicationCompleted = true; src.activeTasks.remove(taskId, fatalError); if (fatalError) { fatalError = createError(fatalError); fatalError.result = result; var errorName = (fatalError.name || "").toLowerCase(); if (errorName === "unauthorized" || errorName === "forbidden") { returnValue.emit("error", fatalError); returnValue.removeAllListeners(); } else { backOff(opts, returnValue, fatalError, function() { replicate(src, target, opts, returnValue); }); } } else { returnValue.emit("complete", result); returnValue.removeAllListeners(); } } function onChange(change, pending, lastSeq) { if (returnValue.cancelled) { return completeReplication(); } if (typeof pending === "number") { pendingBatch.pending = pending; } var filter2 = filterChange(opts)(change); if (!filter2) { var task = src.activeTasks.get(taskId); if (task) { var completed = task.completed_items || 0; src.activeTasks.update(taskId, { completed_items: ++completed }); } return; } pendingBatch.seq = change.seq || lastSeq; pendingBatch.changes.push(change); returnValue.emit("checkpoint", { "pending_batch": pendingBatch.seq }); (0, import_immediate.default)(function() { processPendingBatch(batches.length === 0 && changesOpts.live); }); } function onChangesComplete(changes3) { changesPending = false; if (returnValue.cancelled) { return completeReplication(); } if (changes3.results.length > 0) { changesOpts.since = changes3.results[changes3.results.length - 1].seq; getChanges(); processPendingBatch(true); } else { var complete = function() { if (continuous) { changesOpts.live = true; getChanges(); } else { changesCompleted = true; } processPendingBatch(true); }; if (!currentBatch && changes3.results.length === 0) { writingCheckpoint = true; checkpointer.writeCheckpoint( changes3.last_seq, session ).then(function() { writingCheckpoint = false; result.last_seq = last_seq = changes3.last_seq; if (returnValue.cancelled) { completeReplication(); throw new Error("cancelled"); } else { complete(); } }).catch(onCheckpointError); } else { complete(); } } } function onChangesError(err) { changesPending = false; if (returnValue.cancelled) { return completeReplication(); } abortReplication("changes rejected", err); } function getChanges() { if (!(!changesPending && !changesCompleted && batches.length < batches_limit)) { return; } changesPending = true; function abortChanges() { changes3.cancel(); } function removeListener() { returnValue.removeListener("cancel", abortChanges); } if (returnValue._changes) { returnValue.removeListener("cancel", returnValue._abortChanges); returnValue._changes.cancel(); } returnValue.once("cancel", abortChanges); var changes3 = src.changes(changesOpts).on("change", onChange); changes3.then(removeListener, removeListener); changes3.then(onChangesComplete).catch(onChangesError); if (opts.retry) { returnValue._changes = changes3; returnValue._abortChanges = abortChanges; } } function createTask(checkpoint) { return src.info().then(function(info2) { var total_items = typeof opts.since === "undefined" ? parseInt(info2.update_seq, 10) - parseInt(checkpoint, 10) : parseInt(info2.update_seq, 10); taskId = src.activeTasks.add({ name: `${continuous ? "continuous " : ""}replication from ${info2.db_name}`, total_items }); return checkpoint; }); } function startChanges() { initCheckpointer().then(function() { if (returnValue.cancelled) { completeReplication(); return; } return checkpointer.getCheckpoint().then(createTask).then(function(checkpoint) { last_seq = checkpoint; initial_last_seq = checkpoint; changesOpts = { since: last_seq, limit: batch_size, batch_size, style, doc_ids, selector, return_docs: true }; if (opts.filter) { if (typeof opts.filter !== "string") { changesOpts.include_docs = true; } else { changesOpts.filter = opts.filter; } } if ("heartbeat" in opts) { changesOpts.heartbeat = opts.heartbeat; } if ("timeout" in opts) { changesOpts.timeout = opts.timeout; } if (opts.query_params) { changesOpts.query_params = opts.query_params; } if (opts.view) { changesOpts.view = opts.view; } getChanges(); }); }).catch(function(err) { abortReplication("getCheckpoint rejected with ", err); }); } function onCheckpointError(err) { writingCheckpoint = false; abortReplication("writeCheckpoint completed with error", err); } if (returnValue.cancelled) { completeReplication(); return; } if (!returnValue._addedListeners) { returnValue.once("cancel", completeReplication); if (typeof opts.complete === "function") { returnValue.once("error", opts.complete); returnValue.once("complete", function(result2) { opts.complete(null, result2); }); } returnValue._addedListeners = true; } if (typeof opts.since === "undefined") { startChanges(); } else { initCheckpointer().then(function() { writingCheckpoint = true; return checkpointer.writeCheckpoint(opts.since, session); }).then(function() { writingCheckpoint = false; if (returnValue.cancelled) { completeReplication(); return; } last_seq = opts.since; startChanges(); }).catch(onCheckpointError); } } var Replication = class extends import_events3.default { constructor() { super(); this.cancelled = false; this.state = "pending"; const promise = new Promise((fulfill, reject) => { this.once("complete", fulfill); this.once("error", reject); }); this.then = function(resolve, reject) { return promise.then(resolve, reject); }; this.catch = function(reject) { return promise.catch(reject); }; this.catch(function() { }); } cancel() { this.cancelled = true; this.state = "cancelled"; this.emit("cancel"); } ready(src, target) { if (this._readyCalled) { return; } this._readyCalled = true; const onDestroy2 = () => { this.cancel(); }; src.once("destroyed", onDestroy2); target.once("destroyed", onDestroy2); function cleanup() { src.removeListener("destroyed", onDestroy2); target.removeListener("destroyed", onDestroy2); } this.once("complete", cleanup); this.once("error", cleanup); } }; function toPouch(db, opts) { var PouchConstructor = opts.PouchConstructor; if (typeof db === "string") { return new PouchConstructor(db, opts); } else { return db; } } function replicateWrapper(src, target, opts, callback) { if (typeof opts === "function") { callback = opts; opts = {}; } if (typeof opts === "undefined") { opts = {}; } if (opts.doc_ids && !Array.isArray(opts.doc_ids)) { throw createError( BAD_REQUEST, "`doc_ids` filter parameter is not a list." ); } opts.complete = callback; opts = clone(opts); opts.continuous = opts.continuous || opts.live; opts.retry = "retry" in opts ? opts.retry : false; opts.PouchConstructor = opts.PouchConstructor || this; var replicateRet = new Replication(opts); var srcPouch = toPouch(src, opts); var targetPouch = toPouch(target, opts); replicate(srcPouch, targetPouch, opts, replicateRet); return replicateRet; } function sync(src, target, opts, callback) { if (typeof opts === "function") { callback = opts; opts = {}; } if (typeof opts === "undefined") { opts = {}; } opts = clone(opts); opts.PouchConstructor = opts.PouchConstructor || this; src = toPouch(src, opts); target = toPouch(target, opts); return new Sync(src, target, opts, callback); } var Sync = class extends import_events3.default { constructor(src, target, opts, callback) { super(); this.canceled = false; const optsPush = opts.push ? assign$2({}, opts, opts.push) : opts; const optsPull = opts.pull ? assign$2({}, opts, opts.pull) : opts; this.push = replicateWrapper(src, target, optsPush); this.pull = replicateWrapper(target, src, optsPull); this.pushPaused = true; this.pullPaused = true; const pullChange = (change) => { this.emit("change", { direction: "pull", change }); }; const pushChange = (change) => { this.emit("change", { direction: "push", change }); }; const pushDenied = (doc) => { this.emit("denied", { direction: "push", doc }); }; const pullDenied = (doc) => { this.emit("denied", { direction: "pull", doc }); }; const pushPaused = () => { this.pushPaused = true; if (this.pullPaused) { this.emit("paused"); } }; const pullPaused = () => { this.pullPaused = true; if (this.pushPaused) { this.emit("paused"); } }; const pushActive = () => { this.pushPaused = false; if (this.pullPaused) { this.emit("active", { direction: "push" }); } }; const pullActive = () => { this.pullPaused = false; if (this.pushPaused) { this.emit("active", { direction: "pull" }); } }; let removed = {}; const removeAll = (type) => { return (event, func) => { const isChange = event === "change" && (func === pullChange || func === pushChange); const isDenied = event === "denied" && (func === pullDenied || func === pushDenied); const isPaused = event === "paused" && (func === pullPaused || func === pushPaused); const isActive = event === "active" && (func === pullActive || func === pushActive); if (isChange || isDenied || isPaused || isActive) { if (!(event in removed)) { removed[event] = {}; } removed[event][type] = true; if (Object.keys(removed[event]).length === 2) { this.removeAllListeners(event); } } }; }; if (opts.live) { this.push.on("complete", this.pull.cancel.bind(this.pull)); this.pull.on("complete", this.push.cancel.bind(this.push)); } function addOneListener(ee, event, listener) { if (ee.listeners(event).indexOf(listener) == -1) { ee.on(event, listener); } } this.on("newListener", function(event) { if (event === "change") { addOneListener(this.pull, "change", pullChange); addOneListener(this.push, "change", pushChange); } else if (event === "denied") { addOneListener(this.pull, "denied", pullDenied); addOneListener(this.push, "denied", pushDenied); } else if (event === "active") { addOneListener(this.pull, "active", pullActive); addOneListener(this.push, "active", pushActive); } else if (event === "paused") { addOneListener(this.pull, "paused", pullPaused); addOneListener(this.push, "paused", pushPaused); } }); this.on("removeListener", function(event) { if (event === "change") { this.pull.removeListener("change", pullChange); this.push.removeListener("change", pushChange); } else if (event === "denied") { this.pull.removeListener("denied", pullDenied); this.push.removeListener("denied", pushDenied); } else if (event === "active") { this.pull.removeListener("active", pullActive); this.push.removeListener("active", pushActive); } else if (event === "paused") { this.pull.removeListener("paused", pullPaused); this.push.removeListener("paused", pushPaused); } }); this.pull.on("removeListener", removeAll("pull")); this.push.on("removeListener", removeAll("push")); const promise = Promise.all([ this.push, this.pull ]).then((resp) => { const out = { push: resp[0], pull: resp[1] }; this.emit("complete", out); if (callback) { callback(null, out); } this.removeAllListeners(); return out; }, (err) => { this.cancel(); if (callback) { callback(err); } else { this.emit("error", err); } this.removeAllListeners(); if (callback) { throw err; } }); this.then = function(success, err) { return promise.then(success, err); }; this.catch = function(err) { return promise.catch(err); }; } cancel() { if (!this.canceled) { this.canceled = true; this.push.cancel(); this.pull.cancel(); } } }; function replication(PouchDB2) { PouchDB2.replicate = replicateWrapper; PouchDB2.sync = sync; Object.defineProperty(PouchDB2.prototype, "replicate", { get: function() { var self2 = this; if (typeof this.replicateMethods === "undefined") { this.replicateMethods = { from: function(other, opts, callback) { return self2.constructor.replicate(other, self2, opts, callback); }, to: function(other, opts, callback) { return self2.constructor.replicate(self2, other, opts, callback); } }; } return this.replicateMethods; } }); PouchDB2.prototype.sync = function(dbName, opts, callback) { return this.constructor.sync(this, dbName, opts, callback); }; } var index_es_default8 = replication; // node_modules/pouchdb-find/lib/index-browser.es.js function massageCreateIndexRequest(requestDef) { requestDef = clone(requestDef); if (!requestDef.index) { requestDef.index = {}; } ["type", "name", "ddoc"].forEach(function(key) { if (requestDef.index[key]) { requestDef[key] = requestDef.index[key]; delete requestDef.index[key]; } }); if (requestDef.fields) { requestDef.index.fields = requestDef.fields; delete requestDef.fields; } if (!requestDef.type) { requestDef.type = "json"; } return requestDef; } function checkFieldValueType(name, value, isHttp) { var message = ""; var received = value; var addReceived = true; if (["$in", "$nin", "$or", "$and", "$mod", "$nor", "$all"].indexOf(name) !== -1) { if (!Array.isArray(value)) { message = "Query operator " + name + " must be an array."; } } if (["$not", "$elemMatch", "$allMatch"].indexOf(name) !== -1) { if (!(!Array.isArray(value) && typeof value === "object" && value !== null)) { message = "Query operator " + name + " must be an object."; } } if (name === "$mod" && Array.isArray(value)) { if (value.length !== 2) { message = "Query operator $mod must be in the format [divisor, remainder], where divisor and remainder are both integers."; } else { var divisor = value[0]; var mod = value[1]; if (divisor === 0) { message = "Query operator $mod's divisor cannot be 0, cannot divide by zero."; addReceived = false; } if (typeof divisor !== "number" || parseInt(divisor, 10) !== divisor) { message = "Query operator $mod's divisor is not an integer."; received = divisor; } if (parseInt(mod, 10) !== mod) { message = "Query operator $mod's remainder is not an integer."; received = mod; } } } if (name === "$exists") { if (typeof value !== "boolean") { message = "Query operator $exists must be a boolean."; } } if (name === "$type") { var allowed = ["null", "boolean", "number", "string", "array", "object"]; var allowedStr = '"' + allowed.slice(0, allowed.length - 1).join('", "') + '", or "' + allowed[allowed.length - 1] + '"'; if (typeof value !== "string") { message = "Query operator $type must be a string. Supported values: " + allowedStr + "."; } else if (allowed.indexOf(value) == -1) { message = "Query operator $type must be a string. Supported values: " + allowedStr + "."; } } if (name === "$size") { if (parseInt(value, 10) !== value) { message = "Query operator $size must be a integer."; } } if (name === "$regex") { if (typeof value !== "string") { if (isHttp) { message = "Query operator $regex must be a string."; } else if (!(value instanceof RegExp)) { message = "Query operator $regex must be a string or an instance of a javascript regular expression."; } } } if (message) { if (addReceived) { var type = received === null ? " " : Array.isArray(received) ? " array" : " " + typeof received; var receivedStr = typeof received === "object" && received !== null ? JSON.stringify(received, null, " ") : received; message += " Received" + type + ": " + receivedStr; } throw new Error(message); } } var requireValidation = ["$all", "$allMatch", "$and", "$elemMatch", "$exists", "$in", "$mod", "$nin", "$nor", "$not", "$or", "$regex", "$size", "$type"]; var arrayTypeComparisonOperators = ["$in", "$nin", "$mod", "$all"]; var equalityOperators = ["$eq", "$gt", "$gte", "$lt", "$lte"]; function validateSelector(input, isHttp) { if (Array.isArray(input)) { for (var entry of input) { if (typeof entry === "object" && value !== null) { validateSelector(entry, isHttp); } } } else { var fields = Object.keys(input); for (var i = 0; i < fields.length; i++) { var key = fields[i]; var value = input[key]; if (requireValidation.indexOf(key) !== -1) { checkFieldValueType(key, value, isHttp); } if (equalityOperators.indexOf(key) !== -1) { continue; } if (arrayTypeComparisonOperators.indexOf(key) !== -1) { continue; } if (typeof value === "object" && value !== null) { validateSelector(value, isHttp); } } } } function dbFetch(db, path, opts, callback) { var status, ok; opts.headers = new h({ "Content-type": "application/json" }); db.fetch(path, opts).then(function(response) { status = response.status; ok = response.ok; return response.json(); }).then(function(json) { if (!ok) { json.status = status; var err = generateErrorFromResponse(json); callback(err); } else { callback(null, json); } }).catch(callback); } function createIndex(db, requestDef, callback) { requestDef = massageCreateIndexRequest(requestDef); dbFetch(db, "_index", { method: "POST", body: JSON.stringify(requestDef) }, callback); } function find(db, requestDef, callback) { validateSelector(requestDef.selector, true); dbFetch(db, "_find", { method: "POST", body: JSON.stringify(requestDef) }, callback); } function explain(db, requestDef, callback) { dbFetch(db, "_explain", { method: "POST", body: JSON.stringify(requestDef) }, callback); } function getIndexes(db, callback) { dbFetch(db, "_index", { method: "GET" }, callback); } function deleteIndex(db, indexDef, callback) { var ddoc = indexDef.ddoc; var type = indexDef.type || "json"; var name = indexDef.name; if (!ddoc) { return callback(new Error("you must provide an index's ddoc")); } if (!name) { return callback(new Error("you must provide an index's name")); } var url = "_index/" + [ddoc, type, name].map(encodeURIComponent).join("/"); dbFetch(db, url, { method: "DELETE" }, callback); } function callbackify2(fun) { return function(...args) { var cb = args.pop(); var promise = fun.apply(this, args); promisedCallback2(promise, cb); return promise; }; } function promisedCallback2(promise, callback) { promise.then(function(res2) { (0, import_immediate.default)(function() { callback(null, res2); }); }, function(reason) { (0, import_immediate.default)(function() { callback(reason); }); }); return promise; } var flatten2 = function(...args) { var res2 = []; for (var i = 0, len = args.length; i < len; i++) { var subArr = args[i]; if (Array.isArray(subArr)) { res2 = res2.concat(flatten2.apply(null, subArr)); } else { res2.push(subArr); } } return res2; }; function mergeObjects(arr) { var res2 = {}; for (var i = 0, len = arr.length; i < len; i++) { res2 = assign$2(res2, arr[i]); } return res2; } function pick2(obj, arr) { var res2 = {}; for (var i = 0, len = arr.length; i < len; i++) { var parsedField = parseField(arr[i]); var value = getFieldFromDoc(obj, parsedField); if (typeof value !== "undefined") { setFieldInDoc(res2, parsedField, value); } } return res2; } function oneArrayIsSubArrayOfOther(left, right) { for (var i = 0, len = Math.min(left.length, right.length); i < len; i++) { if (left[i] !== right[i]) { return false; } } return true; } function oneArrayIsStrictSubArrayOfOther(left, right) { if (left.length > right.length) { return false; } return oneArrayIsSubArrayOfOther(left, right); } function oneSetIsSubArrayOfOther(left, right) { left = left.slice(); for (var i = 0, len = right.length; i < len; i++) { var field = right[i]; if (!left.length) { break; } var leftIdx = left.indexOf(field); if (leftIdx === -1) { return false; } else { left.splice(leftIdx, 1); } } return true; } function arrayToObject(arr) { var res2 = {}; for (var i = 0, len = arr.length; i < len; i++) { res2[arr[i]] = true; } return res2; } function max(arr, fun) { var max2 = null; var maxScore = -1; for (var i = 0, len = arr.length; i < len; i++) { var element2 = arr[i]; var score = fun(element2); if (score > maxScore) { maxScore = score; max2 = element2; } } return max2; } function arrayEquals(arr1, arr2) { if (arr1.length !== arr2.length) { return false; } for (var i = 0, len = arr1.length; i < len; i++) { if (arr1[i] !== arr2[i]) { return false; } } return true; } function uniq2(arr) { var obj = {}; for (var i = 0; i < arr.length; i++) { obj["$" + arr[i]] = true; } return Object.keys(obj).map(function(key) { return key.substring(1); }); } function createDeepMultiMapper(fields, emit, selector) { return function(doc) { if (selector && !matchesSelector(doc, selector)) { return; } var toEmit = []; for (var i = 0, iLen = fields.length; i < iLen; i++) { var parsedField = parseField(fields[i]); var value = doc; for (var j = 0, jLen = parsedField.length; j < jLen; j++) { var key = parsedField[j]; value = value[key]; if (typeof value === "undefined") { return; } } toEmit.push(value); } emit(toEmit); }; } function createDeepSingleMapper(field, emit, selector) { var parsedField = parseField(field); return function(doc) { if (selector && !matchesSelector(doc, selector)) { return; } var value = doc; for (var i = 0, len = parsedField.length; i < len; i++) { var key = parsedField[i]; value = value[key]; if (typeof value === "undefined") { return; } } emit(value); }; } function createShallowSingleMapper(field, emit, selector) { return function(doc) { if (selector && !matchesSelector(doc, selector)) { return; } emit(doc[field]); }; } function createShallowMultiMapper(fields, emit, selector) { return function(doc) { if (selector && !matchesSelector(doc, selector)) { return; } var toEmit = []; for (var i = 0, len = fields.length; i < len; i++) { toEmit.push(doc[fields[i]]); } emit(toEmit); }; } function checkShallow(fields) { for (var i = 0, len = fields.length; i < len; i++) { var field = fields[i]; if (field.indexOf(".") !== -1) { return false; } } return true; } function createMapper(fields, emit, selector) { var isShallow = checkShallow(fields); var isSingle = fields.length === 1; if (isShallow) { if (isSingle) { return createShallowSingleMapper(fields[0], emit, selector); } else { return createShallowMultiMapper(fields, emit, selector); } } else { if (isSingle) { return createDeepSingleMapper(fields[0], emit, selector); } else { return createDeepMultiMapper(fields, emit, selector); } } } function mapper2(mapFunDef, emit) { const fields = Object.keys(mapFunDef.fields); const partialSelector = mapFunDef.partial_filter_selector; return createMapper(fields, emit, partialSelector); } function reducer2() { throw new Error("reduce not supported"); } function ddocValidator2(ddoc, viewName) { var view = ddoc.views[viewName]; if (!view.map || !view.map.fields) { throw new Error("ddoc " + ddoc._id + " with view " + viewName + " doesn't have map.fields defined. maybe it wasn't created by this plugin?"); } } var abstractMapper = index_es_default5( "indexes", mapper2, reducer2, ddocValidator2 ); function abstractMapper$1(db) { if (db._customFindAbstractMapper) { return { query: function addQueryFallback(signature, opts) { var fallback = abstractMapper.query.bind(this); return db._customFindAbstractMapper.query.call(this, signature, opts, fallback); }, viewCleanup: function addViewCleanupFallback() { var fallback = abstractMapper.viewCleanup.bind(this); return db._customFindAbstractMapper.viewCleanup.call(this, fallback); } }; } return abstractMapper; } function massageSort(sort) { if (!Array.isArray(sort)) { throw new Error("invalid sort json - should be an array"); } return sort.map(function(sorting) { if (typeof sorting === "string") { var obj = {}; obj[sorting] = "asc"; return obj; } else { return sorting; } }); } function massageUseIndex(useIndex) { var cleanedUseIndex = []; if (typeof useIndex === "string") { cleanedUseIndex.push(useIndex); } else { cleanedUseIndex = useIndex; } return cleanedUseIndex.map(function(name) { return name.replace("_design/", ""); }); } function massageIndexDef(indexDef) { indexDef.fields = indexDef.fields.map(function(field) { if (typeof field === "string") { var obj = {}; obj[field] = "asc"; return obj; } return field; }); if (indexDef.partial_filter_selector) { indexDef.partial_filter_selector = massageSelector( indexDef.partial_filter_selector ); } return indexDef; } function getKeyFromDoc(doc, index5) { var res2 = []; for (var i = 0; i < index5.def.fields.length; i++) { var field = getKey(index5.def.fields[i]); res2.push(getFieldFromDoc(doc, parseField(field))); } return res2; } function filterInclusiveStart(rows, targetValue, index5) { var indexFields = index5.def.fields; for (var i = 0, len = rows.length; i < len; i++) { var row = rows[i]; var docKey = getKeyFromDoc(row.doc, index5); if (indexFields.length === 1) { docKey = docKey[0]; } else { while (docKey.length > targetValue.length) { docKey.pop(); } } if (Math.abs(collate(docKey, targetValue)) > 0) { break; } } return i > 0 ? rows.slice(i) : rows; } function reverseOptions(opts) { var newOpts = clone(opts); delete newOpts.startkey; delete newOpts.endkey; delete newOpts.inclusive_start; delete newOpts.inclusive_end; if ("endkey" in opts) { newOpts.startkey = opts.endkey; } if ("startkey" in opts) { newOpts.endkey = opts.startkey; } if ("inclusive_start" in opts) { newOpts.inclusive_end = opts.inclusive_start; } if ("inclusive_end" in opts) { newOpts.inclusive_start = opts.inclusive_end; } return newOpts; } function validateIndex(index5) { var ascFields = index5.fields.filter(function(field) { return getValue(field) === "asc"; }); if (ascFields.length !== 0 && ascFields.length !== index5.fields.length) { throw new Error("unsupported mixed sorting"); } } function validateSort(requestDef, index5) { if (index5.defaultUsed && requestDef.sort) { var noneIdSorts = requestDef.sort.filter(function(sortItem) { return Object.keys(sortItem)[0] !== "_id"; }).map(function(sortItem) { return Object.keys(sortItem)[0]; }); if (noneIdSorts.length > 0) { throw new Error('Cannot sort on field(s) "' + noneIdSorts.join(",") + '" when using the default index'); } } if (index5.defaultUsed) { return; } } function validateFindRequest(requestDef) { if (typeof requestDef.selector !== "object") { throw new Error("you must provide a selector when you find()"); } } function getUserFields(selector, sort) { var selectorFields = Object.keys(selector); var sortFields = sort ? sort.map(getKey) : []; var userFields; if (selectorFields.length >= sortFields.length) { userFields = selectorFields; } else { userFields = sortFields; } if (sortFields.length === 0) { return { fields: userFields }; } userFields = userFields.sort(function(left, right) { var leftIdx = sortFields.indexOf(left); if (leftIdx === -1) { leftIdx = Number.MAX_VALUE; } var rightIdx = sortFields.indexOf(right); if (rightIdx === -1) { rightIdx = Number.MAX_VALUE; } return leftIdx < rightIdx ? -1 : leftIdx > rightIdx ? 1 : 0; }); return { fields: userFields, sortOrder: sort.map(getKey) }; } function createIndex$1(db, requestDef) { requestDef = massageCreateIndexRequest(requestDef); var originalIndexDef = clone(requestDef.index); requestDef.index = massageIndexDef(requestDef.index); validateIndex(requestDef.index); var md5; function getMd5() { return md5 || (md5 = stringMd5(JSON.stringify(requestDef))); } var viewName = requestDef.name || "idx-" + getMd5(); var ddocName = requestDef.ddoc || "idx-" + getMd5(); var ddocId = "_design/" + ddocName; var hasInvalidLanguage = false; var viewExists = false; function updateDdoc(doc) { if (doc._rev && doc.language !== "query") { hasInvalidLanguage = true; } doc.language = "query"; doc.views = doc.views || {}; viewExists = !!doc.views[viewName]; if (viewExists) { return false; } doc.views[viewName] = { map: { fields: mergeObjects(requestDef.index.fields), partial_filter_selector: requestDef.index.partial_filter_selector }, reduce: "_count", options: { def: originalIndexDef } }; return doc; } db.constructor.emit("debug", ["find", "creating index", ddocId]); return upsert(db, ddocId, updateDdoc).then(function() { if (hasInvalidLanguage) { throw new Error('invalid language for ddoc with id "' + ddocId + '" (should be "query")'); } }).then(function() { var signature = ddocName + "/" + viewName; return abstractMapper$1(db).query.call(db, signature, { limit: 0, reduce: false }).then(function() { return { id: ddocId, name: viewName, result: viewExists ? "exists" : "created" }; }); }); } function getIndexes$1(db) { return db.allDocs({ startkey: "_design/", endkey: "_design/\uFFFF", include_docs: true }).then(function(allDocsRes) { var res2 = { indexes: [{ ddoc: null, name: "_all_docs", type: "special", def: { fields: [{ _id: "asc" }] } }] }; res2.indexes = flatten2(res2.indexes, allDocsRes.rows.filter(function(row) { return row.doc.language === "query"; }).map(function(row) { var viewNames = row.doc.views !== void 0 ? Object.keys(row.doc.views) : []; return viewNames.map(function(viewName) { var view = row.doc.views[viewName]; return { ddoc: row.id, name: viewName, type: "json", def: massageIndexDef(view.options.def) }; }); })); res2.indexes.sort(function(left, right) { return compare(left.name, right.name); }); res2.total_rows = res2.indexes.length; return res2; }); } var COLLATE_LO = null; var COLLATE_HI = { "\uFFFF": {} }; var SHORT_CIRCUIT_QUERY = { queryOpts: { limit: 0, startkey: COLLATE_HI, endkey: COLLATE_LO }, inMemoryFields: [] }; function checkFieldInIndex(index5, field) { var indexFields = index5.def.fields.map(getKey); for (var i = 0, len = indexFields.length; i < len; i++) { var indexField = indexFields[i]; if (field === indexField) { return true; } } return false; } function userOperatorLosesPrecision(selector, field) { var matcher = selector[field]; var userOperator = getKey(matcher); return userOperator !== "$eq"; } function sortFieldsByIndex(userFields, index5) { var indexFields = index5.def.fields.map(getKey); return userFields.slice().sort(function(a2, b) { var aIdx = indexFields.indexOf(a2); var bIdx = indexFields.indexOf(b); if (aIdx === -1) { aIdx = Number.MAX_VALUE; } if (bIdx === -1) { bIdx = Number.MAX_VALUE; } return compare(aIdx, bIdx); }); } function getBasicInMemoryFields(index5, selector, userFields) { userFields = sortFieldsByIndex(userFields, index5); var needToFilterInMemory = false; for (var i = 0, len = userFields.length; i < len; i++) { var field = userFields[i]; if (needToFilterInMemory || !checkFieldInIndex(index5, field)) { return userFields.slice(i); } if (i < len - 1 && userOperatorLosesPrecision(selector, field)) { needToFilterInMemory = true; } } return []; } function getInMemoryFieldsFromNe(selector) { var fields = []; Object.keys(selector).forEach(function(field) { var matcher = selector[field]; Object.keys(matcher).forEach(function(operator) { if (operator === "$ne") { fields.push(field); } }); }); return fields; } function getInMemoryFields(coreInMemoryFields, index5, selector, userFields) { var result = flatten2( coreInMemoryFields, getBasicInMemoryFields(index5, selector, userFields), getInMemoryFieldsFromNe(selector) ); return sortFieldsByIndex(uniq2(result), index5); } function checkIndexFieldsMatch(indexFields, sortOrder, fields) { if (sortOrder) { var sortMatches = oneArrayIsStrictSubArrayOfOther(sortOrder, indexFields); var selectorMatches = oneArrayIsSubArrayOfOther(fields, indexFields); return sortMatches && selectorMatches; } return oneSetIsSubArrayOfOther(fields, indexFields); } var logicalMatchers = ["$eq", "$gt", "$gte", "$lt", "$lte"]; function isNonLogicalMatcher(matcher) { return logicalMatchers.indexOf(matcher) === -1; } function checkFieldsLogicallySound(indexFields, selector) { var firstField = indexFields[0]; var matcher = selector[firstField]; if (typeof matcher === "undefined") { return true; } var isInvalidNe = Object.keys(matcher).length === 1 && getKey(matcher) === "$ne"; return !isInvalidNe; } function checkIndexMatches(index5, sortOrder, fields, selector) { var indexFields = index5.def.fields.map(getKey); var fieldsMatch = checkIndexFieldsMatch(indexFields, sortOrder, fields); if (!fieldsMatch) { return false; } return checkFieldsLogicallySound(indexFields, selector); } function findMatchingIndexes(selector, userFields, sortOrder, indexes) { return indexes.filter(function(index5) { return checkIndexMatches(index5, sortOrder, userFields, selector); }); } function findBestMatchingIndex(selector, userFields, sortOrder, indexes, useIndex) { var matchingIndexes = findMatchingIndexes(selector, userFields, sortOrder, indexes); if (matchingIndexes.length === 0) { if (useIndex) { throw { error: "no_usable_index", message: "There is no index available for this selector." }; } var defaultIndex = indexes[0]; defaultIndex.defaultUsed = true; return defaultIndex; } if (matchingIndexes.length === 1 && !useIndex) { return matchingIndexes[0]; } var userFieldsMap = arrayToObject(userFields); function scoreIndex(index6) { var indexFields = index6.def.fields.map(getKey); var score = 0; for (var i = 0, len = indexFields.length; i < len; i++) { var indexField = indexFields[i]; if (userFieldsMap[indexField]) { score++; } } return score; } if (useIndex) { var useIndexDdoc = "_design/" + useIndex[0]; var useIndexName = useIndex.length === 2 ? useIndex[1] : false; var index5 = matchingIndexes.find(function(index6) { if (useIndexName && index6.ddoc === useIndexDdoc && useIndexName === index6.name) { return true; } if (index6.ddoc === useIndexDdoc) { return true; } return false; }); if (!index5) { throw { error: "unknown_error", message: "Could not find that index or could not use that index for the query" }; } return index5; } return max(matchingIndexes, scoreIndex); } function getSingleFieldQueryOptsFor(userOperator, userValue) { switch (userOperator) { case "$eq": return { key: userValue }; case "$lte": return { endkey: userValue }; case "$gte": return { startkey: userValue }; case "$lt": return { endkey: userValue, inclusive_end: false }; case "$gt": return { startkey: userValue, inclusive_start: false }; } return { startkey: COLLATE_LO }; } function getSingleFieldCoreQueryPlan(selector, index5) { var field = getKey(index5.def.fields[0]); var matcher = selector[field] || {}; var inMemoryFields = []; var userOperators = Object.keys(matcher); var combinedOpts; userOperators.forEach(function(userOperator) { if (isNonLogicalMatcher(userOperator)) { inMemoryFields.push(field); } var userValue = matcher[userOperator]; var newQueryOpts = getSingleFieldQueryOptsFor(userOperator, userValue); if (combinedOpts) { combinedOpts = mergeObjects([combinedOpts, newQueryOpts]); } else { combinedOpts = newQueryOpts; } }); return { queryOpts: combinedOpts, inMemoryFields }; } function getMultiFieldCoreQueryPlan(userOperator, userValue) { switch (userOperator) { case "$eq": return { startkey: userValue, endkey: userValue }; case "$lte": return { endkey: userValue }; case "$gte": return { startkey: userValue }; case "$lt": return { endkey: userValue, inclusive_end: false }; case "$gt": return { startkey: userValue, inclusive_start: false }; } } function getMultiFieldQueryOpts(selector, index5) { var indexFields = index5.def.fields.map(getKey); var inMemoryFields = []; var startkey = []; var endkey = []; var inclusiveStart; var inclusiveEnd; function finish(i2) { if (inclusiveStart !== false) { startkey.push(COLLATE_LO); } if (inclusiveEnd !== false) { endkey.push(COLLATE_HI); } inMemoryFields = indexFields.slice(i2); } for (var i = 0, len = indexFields.length; i < len; i++) { var indexField = indexFields[i]; var matcher = selector[indexField]; if (!matcher || !Object.keys(matcher).length) { finish(i); break; } else if (Object.keys(matcher).some(isNonLogicalMatcher)) { finish(i); break; } else if (i > 0) { var usingGtlt = "$gt" in matcher || "$gte" in matcher || "$lt" in matcher || "$lte" in matcher; var previousKeys = Object.keys(selector[indexFields[i - 1]]); var previousWasEq = arrayEquals(previousKeys, ["$eq"]); var previousWasSame = arrayEquals(previousKeys, Object.keys(matcher)); var gtltLostSpecificity = usingGtlt && !previousWasEq && !previousWasSame; if (gtltLostSpecificity) { finish(i); break; } } var userOperators = Object.keys(matcher); var combinedOpts = null; for (var j = 0; j < userOperators.length; j++) { var userOperator = userOperators[j]; var userValue = matcher[userOperator]; var newOpts = getMultiFieldCoreQueryPlan(userOperator, userValue); if (combinedOpts) { combinedOpts = mergeObjects([combinedOpts, newOpts]); } else { combinedOpts = newOpts; } } startkey.push("startkey" in combinedOpts ? combinedOpts.startkey : COLLATE_LO); endkey.push("endkey" in combinedOpts ? combinedOpts.endkey : COLLATE_HI); if ("inclusive_start" in combinedOpts) { inclusiveStart = combinedOpts.inclusive_start; } if ("inclusive_end" in combinedOpts) { inclusiveEnd = combinedOpts.inclusive_end; } } var res2 = { startkey, endkey }; if (typeof inclusiveStart !== "undefined") { res2.inclusive_start = inclusiveStart; } if (typeof inclusiveEnd !== "undefined") { res2.inclusive_end = inclusiveEnd; } return { queryOpts: res2, inMemoryFields }; } function shouldShortCircuit(selector) { const values = Object.keys(selector).map(function(key) { return selector[key]; }); return values.some(function(val) { return typeof val === "object" && Object.keys(val).length === 0; }); } function getDefaultQueryPlan(selector) { return { queryOpts: { startkey: null }, inMemoryFields: [Object.keys(selector)] }; } function getCoreQueryPlan(selector, index5) { if (index5.defaultUsed) { return getDefaultQueryPlan(selector, index5); } if (index5.def.fields.length === 1) { return getSingleFieldCoreQueryPlan(selector, index5); } return getMultiFieldQueryOpts(selector, index5); } function planQuery(request, indexes) { var selector = request.selector; var sort = request.sort; if (shouldShortCircuit(selector)) { return assign$2({}, SHORT_CIRCUIT_QUERY, { index: indexes[0] }); } var userFieldsRes = getUserFields(selector, sort); var userFields = userFieldsRes.fields; var sortOrder = userFieldsRes.sortOrder; var index5 = findBestMatchingIndex(selector, userFields, sortOrder, indexes, request.use_index); var coreQueryPlan = getCoreQueryPlan(selector, index5); var queryOpts = coreQueryPlan.queryOpts; var coreInMemoryFields = coreQueryPlan.inMemoryFields; var inMemoryFields = getInMemoryFields(coreInMemoryFields, index5, selector, userFields); var res2 = { queryOpts, index: index5, inMemoryFields }; return res2; } function indexToSignature(index5) { return index5.ddoc.substring(8) + "/" + index5.name; } function doAllDocs(db, originalOpts) { var opts = clone(originalOpts); if (opts.descending) { if ("endkey" in opts && typeof opts.endkey !== "string") { opts.endkey = ""; } if ("startkey" in opts && typeof opts.startkey !== "string") { opts.limit = 0; } } else { if ("startkey" in opts && typeof opts.startkey !== "string") { opts.startkey = ""; } if ("endkey" in opts && typeof opts.endkey !== "string") { opts.limit = 0; } } if ("key" in opts && typeof opts.key !== "string") { opts.limit = 0; } if (opts.limit > 0 && opts.indexes_count) { opts.original_limit = opts.limit; opts.limit += opts.indexes_count; } return db.allDocs(opts).then(function(res2) { res2.rows = res2.rows.filter(function(row) { return !/^_design\//.test(row.id); }); if (opts.original_limit) { opts.limit = opts.original_limit; } res2.rows = res2.rows.slice(0, opts.limit); return res2; }); } function find$1(db, requestDef, explain2) { if (requestDef.selector) { validateSelector(requestDef.selector, false); requestDef.selector = massageSelector(requestDef.selector); } if (requestDef.sort) { requestDef.sort = massageSort(requestDef.sort); } if (requestDef.use_index) { requestDef.use_index = massageUseIndex(requestDef.use_index); } validateFindRequest(requestDef); return getIndexes$1(db).then(function(getIndexesRes) { db.constructor.emit("debug", ["find", "planning query", requestDef]); var queryPlan = planQuery(requestDef, getIndexesRes.indexes); db.constructor.emit("debug", ["find", "query plan", queryPlan]); var indexToUse = queryPlan.index; validateSort(requestDef, indexToUse); var opts = assign$2({ include_docs: true, reduce: false, indexes_count: getIndexesRes.total_rows }, queryPlan.queryOpts); if ("startkey" in opts && "endkey" in opts && collate(opts.startkey, opts.endkey) > 0) { return { docs: [] }; } var isDescending = requestDef.sort && typeof requestDef.sort[0] !== "string" && getValue(requestDef.sort[0]) === "desc"; if (isDescending) { opts.descending = true; opts = reverseOptions(opts); } if (!queryPlan.inMemoryFields.length) { if ("limit" in requestDef) { opts.limit = requestDef.limit; } if ("skip" in requestDef) { opts.skip = requestDef.skip; } } if (explain2) { return Promise.resolve(queryPlan, opts); } return Promise.resolve().then(function() { if (indexToUse.name === "_all_docs") { return doAllDocs(db, opts); } else { var signature = indexToSignature(indexToUse); return abstractMapper$1(db).query.call(db, signature, opts); } }).then(function(res2) { if (opts.inclusive_start === false) { res2.rows = filterInclusiveStart(res2.rows, opts.startkey, indexToUse); } if (queryPlan.inMemoryFields.length) { res2.rows = filterInMemoryFields(res2.rows, requestDef, queryPlan.inMemoryFields); } var resp = { docs: res2.rows.map(function(row) { var doc = row.doc; if (requestDef.fields) { return pick2(doc, requestDef.fields); } return doc; }) }; if (indexToUse.defaultUsed) { resp.warning = "No matching index found, create an index to optimize query time."; } return resp; }); }); } function explain$1(db, requestDef) { return find$1(db, requestDef, true).then(function(queryPlan) { return { dbname: db.name, index: queryPlan.index, selector: requestDef.selector, range: { start_key: queryPlan.queryOpts.startkey, end_key: queryPlan.queryOpts.endkey }, opts: { use_index: requestDef.use_index || [], bookmark: "nil", limit: requestDef.limit, skip: requestDef.skip, sort: requestDef.sort || {}, fields: requestDef.fields, conflicts: false, r: [49] }, limit: requestDef.limit, skip: requestDef.skip || 0, fields: requestDef.fields }; }); } function deleteIndex$1(db, index5) { if (!index5.ddoc) { throw new Error("you must supply an index.ddoc when deleting"); } if (!index5.name) { throw new Error("you must supply an index.name when deleting"); } var docId = index5.ddoc; var viewName = index5.name; function deltaFun(doc) { if (Object.keys(doc.views).length === 1 && doc.views[viewName]) { return { _id: docId, _deleted: true }; } delete doc.views[viewName]; return doc; } return upsert(db, docId, deltaFun).then(function() { return abstractMapper$1(db).viewCleanup.apply(db); }).then(function() { return { ok: true }; }); } var createIndexAsCallback = callbackify2(createIndex$1); var findAsCallback = callbackify2(find$1); var explainAsCallback = callbackify2(explain$1); var getIndexesAsCallback = callbackify2(getIndexes$1); var deleteIndexAsCallback = callbackify2(deleteIndex$1); var plugin = {}; plugin.createIndex = toPromise(function(requestDef, callback) { if (typeof requestDef !== "object") { return callback(new Error("you must provide an index to create")); } var createIndex$$1 = isRemote(this) ? createIndex : createIndexAsCallback; createIndex$$1(this, requestDef, callback); }); plugin.find = toPromise(function(requestDef, callback) { if (typeof callback === "undefined") { callback = requestDef; requestDef = void 0; } if (typeof requestDef !== "object") { return callback(new Error("you must provide search parameters to find()")); } var find$$1 = isRemote(this) ? find : findAsCallback; find$$1(this, requestDef, callback); }); plugin.explain = toPromise(function(requestDef, callback) { if (typeof callback === "undefined") { callback = requestDef; requestDef = void 0; } if (typeof requestDef !== "object") { return callback(new Error("you must provide search parameters to explain()")); } var find$$1 = isRemote(this) ? explain : explainAsCallback; find$$1(this, requestDef, callback); }); plugin.getIndexes = toPromise(function(callback) { var getIndexes$$1 = isRemote(this) ? getIndexes : getIndexesAsCallback; getIndexes$$1(this, callback); }); plugin.deleteIndex = toPromise(function(indexDef, callback) { if (typeof indexDef !== "object") { return callback(new Error("you must provide an index to delete")); } var deleteIndex$$1 = isRemote(this) ? deleteIndex : deleteIndexAsCallback; deleteIndex$$1(this, indexDef, callback); }); var index_browser_es_default3 = plugin; // src/lib/src/pouchdb-browser.ts var import_transform_pouch = __toESM(require_transform_pouch(), 1); index_es_default.plugin(index_es_default2).plugin(index_es_default3).plugin(index_es_default4).plugin(index_browser_es_default2).plugin(index_es_default8).plugin(index_browser_es_default3).plugin(import_transform_pouch.default); // src/LogDisplayModal.ts var LogDisplayModal = class extends import_obsidian.Modal { constructor(app2, plugin2) { super(app2); this.plugin = plugin2; } onOpen() { const { contentEl } = this; contentEl.empty(); contentEl.createEl("h2", { text: "Sync Status" }); const div = contentEl.createDiv(""); div.addClass("op-scrollable"); div.addClass("op-pre"); this.logEl = div; this.unsubscribe = logMessageStore.observe((e2) => { let msg = ""; for (const v of e2) { msg += escapeStringToHTML(v) + "
"; } this.logEl.innerHTML = msg; }); logMessageStore.invalidate(); } onClose() { const { contentEl } = this; contentEl.empty(); if (this.unsubscribe) this.unsubscribe(); } }; // src/ConflictResolveModal.ts var import_diff_match_patch = __toESM(require_diff_match_patch(), 1); var ConflictResolveModal = class extends import_obsidian.Modal { constructor(app2, filename, diff, callback) { super(app2); this.result = diff; this.callback = callback; this.filename = filename; } onOpen() { const { contentEl } = this; contentEl.empty(); contentEl.createEl("h2", { text: "This document has conflicted changes." }); contentEl.createEl("span", { text: this.filename }); const div = contentEl.createDiv(""); div.addClass("op-scrollable"); let diff = ""; for (const v of this.result.diff) { const x1 = v[0]; const x2 = v[1]; if (x1 == import_diff_match_patch.DIFF_DELETE) { diff += "" + escapeStringToHTML(x2) + ""; } else if (x1 == import_diff_match_patch.DIFF_EQUAL) { diff += "" + escapeStringToHTML(x2) + ""; } else if (x1 == import_diff_match_patch.DIFF_INSERT) { diff += "" + escapeStringToHTML(x2) + ""; } } diff = diff.replace(/\n/g, "
"); div.innerHTML = diff; const div2 = contentEl.createDiv(""); const date1 = new Date(this.result.left.mtime).toLocaleString() + (this.result.left.deleted ? " (Deleted)" : ""); const date2 = new Date(this.result.right.mtime).toLocaleString() + (this.result.right.deleted ? " (Deleted)" : ""); div2.innerHTML = ` A:${date1}
B:${date2}
`; contentEl.createEl("button", { text: "Keep A" }, (e2) => { e2.addEventListener("click", async () => { await this.callback(this.result.right.rev); this.callback = null; this.close(); }); }); contentEl.createEl("button", { text: "Keep B" }, (e2) => { e2.addEventListener("click", async () => { await this.callback(this.result.left.rev); this.callback = null; this.close(); }); }); contentEl.createEl("button", { text: "Concat both" }, (e2) => { e2.addEventListener("click", async () => { await this.callback(""); this.callback = null; this.close(); }); }); contentEl.createEl("button", { text: "Not now" }, (e2) => { e2.addEventListener("click", () => { this.close(); }); }); } onClose() { const { contentEl } = this; contentEl.empty(); if (this.callback != null) { this.callback(null); } } }; // src/lib/src/semaphore.ts function makeUniqueString() { const randomStrSrc = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; const temp = [...Array(30)].map(() => Math.floor(Math.random() * randomStrSrc.length)).map((e2) => randomStrSrc[e2]).join(""); return `${Date.now()}-${temp}`; } function Semaphore(limit, onRelease) { const _limit = limit; let currentProcesses = 0; let queue2 = []; function execProcess() { queue2 = queue2.filter((e2) => e2.state != "DONE"); for (const queueItem2 of queue2) { if (queueItem2.state != "NONE") continue; if (queueItem2.quantity + currentProcesses > _limit) { break; } queueItem2.state = "RUNNING"; currentProcesses += queueItem2.quantity; if (queueItem2 == null ? void 0 : queueItem2.timer) { clearTimeout(queueItem2.timer); } queueItem2.notify(true); } } function release(key) { const finishedTask = queue2.find((e2) => e2.key == key); if (!finishedTask) { throw new Error("Missing locked semaphore!"); } if (finishedTask.state == "RUNNING") { currentProcesses -= finishedTask.quantity; } finishedTask.state = "DONE"; if (onRelease) onRelease(queue2.filter((e2) => e2.state != "DONE")); execProcess(); } return { _acquire(quantity, memo, timeout) { const key = makeUniqueString(); if (_limit < quantity) { throw Error("Too big quantity"); } let notify = (_) => { }; const semaphoreStopper = new Promise((res2) => { notify = (result) => { if (result) { res2(() => { release(key); }); } else { res2(false); } }; }); const notifier = { key, notify, semaphoreStopper, quantity, memo, state: "NONE" }; if (timeout) notifier.timer = setTimeout(() => { release(key); notify(false); }, timeout); queue2.push(notifier); execProcess(); return semaphoreStopper; }, acquire(quantity = 1, memo) { return this._acquire(quantity, memo != null ? memo : "", 0); }, tryAcquire(quantity = 1, timeout, memo) { return this._acquire(quantity, memo != null ? memo : "", timeout); }, peekQueues() { return queue2; } }; } // node_modules/svelte/internal/index.mjs function noop() { } function run(fn) { return fn(); } function blank_object() { return /* @__PURE__ */ Object.create(null); } function run_all(fns) { fns.forEach(run); } function is_function(thing) { return typeof thing === "function"; } function safe_not_equal(a2, b) { return a2 != a2 ? b == b : a2 !== b || (a2 && typeof a2 === "object" || typeof a2 === "function"); } function is_empty(obj) { return Object.keys(obj).length === 0; } function null_to_empty(value) { return value == null ? "" : value; } var is_hydrating = false; function start_hydrating() { is_hydrating = true; } function end_hydrating() { is_hydrating = false; } function append(target, node) { target.appendChild(node); } function append_styles(target, style_sheet_id, styles) { const append_styles_to = get_root_for_style(target); if (!append_styles_to.getElementById(style_sheet_id)) { const style = element("style"); style.id = style_sheet_id; style.textContent = styles; append_stylesheet(append_styles_to, style); } } function get_root_for_style(node) { if (!node) return document; const root = node.getRootNode ? node.getRootNode() : node.ownerDocument; if (root && root.host) { return root; } return node.ownerDocument; } function append_stylesheet(node, style) { append(node.head || node, style); return style.sheet; } function insert(target, node, anchor) { target.insertBefore(node, anchor || null); } function detach(node) { if (node.parentNode) { node.parentNode.removeChild(node); } } function destroy_each(iterations, detaching) { for (let i = 0; i < iterations.length; i += 1) { if (iterations[i]) iterations[i].d(detaching); } } function element(name) { return document.createElement(name); } function text(data) { return document.createTextNode(data); } function space() { return text(" "); } function empty() { return text(""); } function listen(node, event, handler, options) { node.addEventListener(event, handler, options); return () => node.removeEventListener(event, handler, options); } function attr(node, attribute, value) { if (value == null) node.removeAttribute(attribute); else if (node.getAttribute(attribute) !== value) node.setAttribute(attribute, value); } function children(element2) { return Array.from(element2.childNodes); } function set_data(text2, data) { data = "" + data; if (text2.wholeText !== data) text2.data = data; } function set_style(node, key, value, important) { if (value === null) { node.style.removeProperty(key); } else { node.style.setProperty(key, value, important ? "important" : ""); } } function toggle_class(element2, name, toggle) { element2.classList[toggle ? "add" : "remove"](name); } var current_component; function set_current_component(component) { current_component = component; } function get_current_component() { if (!current_component) throw new Error("Function called outside component initialization"); return current_component; } function onMount(fn) { get_current_component().$$.on_mount.push(fn); } var dirty_components = []; var binding_callbacks = []; var render_callbacks = []; var flush_callbacks = []; var resolved_promise = Promise.resolve(); var update_scheduled = false; function schedule_update() { if (!update_scheduled) { update_scheduled = true; resolved_promise.then(flush); } } function add_render_callback(fn) { render_callbacks.push(fn); } var seen_callbacks = /* @__PURE__ */ new Set(); var flushidx = 0; function flush() { if (flushidx !== 0) { return; } const saved_component = current_component; do { try { while (flushidx < dirty_components.length) { const component = dirty_components[flushidx]; flushidx++; set_current_component(component); update(component.$$); } } catch (e2) { dirty_components.length = 0; flushidx = 0; throw e2; } set_current_component(null); dirty_components.length = 0; flushidx = 0; while (binding_callbacks.length) binding_callbacks.pop()(); for (let i = 0; i < render_callbacks.length; i += 1) { const callback = render_callbacks[i]; if (!seen_callbacks.has(callback)) { seen_callbacks.add(callback); callback(); } } render_callbacks.length = 0; } while (dirty_components.length); while (flush_callbacks.length) { flush_callbacks.pop()(); } update_scheduled = false; seen_callbacks.clear(); set_current_component(saved_component); } function update($$) { if ($$.fragment !== null) { $$.update(); run_all($$.before_update); const dirty = $$.dirty; $$.dirty = [-1]; $$.fragment && $$.fragment.p($$.ctx, dirty); $$.after_update.forEach(add_render_callback); } } var outroing = /* @__PURE__ */ new Set(); function transition_in(block, local) { if (block && block.i) { outroing.delete(block); block.i(local); } } function mount_component(component, target, anchor, customElement) { const { fragment, after_update } = component.$$; fragment && fragment.m(target, anchor); if (!customElement) { add_render_callback(() => { const new_on_destroy = component.$$.on_mount.map(run).filter(is_function); if (component.$$.on_destroy) { component.$$.on_destroy.push(...new_on_destroy); } else { run_all(new_on_destroy); } component.$$.on_mount = []; }); } after_update.forEach(add_render_callback); } function destroy_component(component, detaching) { const $$ = component.$$; if ($$.fragment !== null) { run_all($$.on_destroy); $$.fragment && $$.fragment.d(detaching); $$.on_destroy = $$.fragment = null; $$.ctx = []; } } function make_dirty(component, i) { if (component.$$.dirty[0] === -1) { dirty_components.push(component); schedule_update(); component.$$.dirty.fill(0); } component.$$.dirty[i / 31 | 0] |= 1 << i % 31; } function init2(component, options, instance3, create_fragment3, not_equal, props, append_styles2, dirty = [-1]) { const parent_component = current_component; set_current_component(component); const $$ = component.$$ = { fragment: null, ctx: [], props, update: noop, not_equal, bound: blank_object(), on_mount: [], on_destroy: [], on_disconnect: [], before_update: [], after_update: [], context: new Map(options.context || (parent_component ? parent_component.$$.context : [])), callbacks: blank_object(), dirty, skip_bound: false, root: options.target || parent_component.$$.root }; append_styles2 && append_styles2($$.root); let ready = false; $$.ctx = instance3 ? instance3(component, options.props || {}, (i, ret, ...rest) => { const value = rest.length ? rest[0] : ret; if ($$.ctx && not_equal($$.ctx[i], $$.ctx[i] = value)) { if (!$$.skip_bound && $$.bound[i]) $$.bound[i](value); if (ready) make_dirty(component, i); } return ret; }) : []; $$.update(); ready = true; run_all($$.before_update); $$.fragment = create_fragment3 ? create_fragment3($$.ctx) : false; if (options.target) { if (options.hydrate) { start_hydrating(); const nodes = children(options.target); $$.fragment && $$.fragment.l(nodes); nodes.forEach(detach); } else { $$.fragment && $$.fragment.c(); } if (options.intro) transition_in(component.$$.fragment); mount_component(component, options.target, options.anchor, options.customElement); end_hydrating(); flush(); } set_current_component(parent_component); } var SvelteElement; if (typeof HTMLElement === "function") { SvelteElement = class extends HTMLElement { constructor() { super(); this.attachShadow({ mode: "open" }); } connectedCallback() { const { on_mount } = this.$$; this.$$.on_disconnect = on_mount.map(run).filter(is_function); for (const key in this.$$.slotted) { this.appendChild(this.$$.slotted[key]); } } attributeChangedCallback(attr2, _oldValue, newValue) { this[attr2] = newValue; } disconnectedCallback() { run_all(this.$$.on_disconnect); } $destroy() { destroy_component(this, 1); this.$destroy = noop; } $on(type, callback) { if (!is_function(callback)) { return noop; } const callbacks = this.$$.callbacks[type] || (this.$$.callbacks[type] = []); callbacks.push(callback); return () => { const index5 = callbacks.indexOf(callback); if (index5 !== -1) callbacks.splice(index5, 1); }; } $set($$props) { if (this.$$set && !is_empty($$props)) { this.$$.skip_bound = true; this.$$set($$props); this.$$.skip_bound = false; } } }; } var SvelteComponent = class { $destroy() { destroy_component(this, 1); this.$destroy = noop; } $on(type, callback) { if (!is_function(callback)) { return noop; } const callbacks = this.$$.callbacks[type] || (this.$$.callbacks[type] = []); callbacks.push(callback); return () => { const index5 = callbacks.indexOf(callback); if (index5 !== -1) callbacks.splice(index5, 1); }; } $set($$props) { if (this.$$set && !is_empty($$props)) { this.$$.skip_bound = true; this.$$set($$props); this.$$.skip_bound = false; } } }; // src/lib/src/wrapper.ts var WrappedNotice = class { constructor(message, timeout) { var _a; let strMessage = ""; if (message instanceof DocumentFragment) { strMessage = (_a = message.textContent) != null ? _a : ""; } else { strMessage = message; } Logger(strMessage, LOG_LEVEL.NOTICE); } setMessage(message) { var _a; let strMessage = ""; if (message instanceof DocumentFragment) { strMessage = (_a = message.textContent) != null ? _a : ""; } else { strMessage = message; } Logger(strMessage, LOG_LEVEL.NOTICE); return this; } hide() { } }; var _notice = WrappedNotice; function setNoticeClass(notice) { _notice = notice; } function NewNotice(message, timeout) { return new _notice(message, timeout); } // src/lib/src/lock.ts var externalNotifier = () => { }; var notifyTimer = null; function notifyLock() { if (notifyTimer != null) { clearTimeout(notifyTimer); } notifyTimer = setTimeout(() => { externalNotifier(); }, 100); } var Mutexes = {}; function updateStore() { const allLocks = [...Object.values(Mutexes).map((e2) => e2.peekQueues())].flat(); lockStore.apply((v) => ({ ...v, count: allLocks.length, pending: allLocks.filter((e2) => e2.state == "NONE").map((e2) => { var _a; return (_a = e2.memo) != null ? _a : ""; }), running: allLocks.filter((e2) => e2.state == "RUNNING").map((e2) => { var _a; return (_a = e2.memo) != null ? _a : ""; }) })); } var semaphoreReleasedCount = 0; async function runWithLock(key, ignoreWhenRunning, proc) { if (semaphoreReleasedCount > 200) { const deleteKeys = []; for (const key2 in Mutexes) { if (Mutexes[key2].peekQueues().length == 0) { deleteKeys.push(key2); } } for (const key2 of deleteKeys) { delete Mutexes[key2]; } semaphoreReleasedCount = 0; } if (!(key in Mutexes)) { Mutexes[key] = Semaphore(1, (queue2) => { if (queue2.length == 0) semaphoreReleasedCount++; }); } const timeout = ignoreWhenRunning ? 1 : 0; const releaser = await Mutexes[key].tryAcquire(1, timeout, key); updateStore(); if (!releaser) return null; try { return await proc(); } finally { releaser(); notifyLock(); updateStore(); } } // src/LiveSyncCommands.ts var LiveSyncCommands = class { get app() { return this.plugin.app; } get settings() { return this.plugin.settings; } get localDatabase() { return this.plugin.localDatabase; } id2path(id, entry, stripPrefix2) { return this.plugin.id2path(id, entry, stripPrefix2); } async path2id(filename, prefix) { return await this.plugin.path2id(filename, prefix); } getPath(entry) { return this.plugin.getPath(entry); } constructor(plugin2) { this.plugin = plugin2; } }; // src/CmdPluginAndTheirSettings.ts var PluginAndTheirSettings = class extends LiveSyncCommands { constructor() { super(...arguments); this.pluginDialog = null; this.periodicPluginSweepProcessor = new PeriodicProcessor(this.plugin, async () => await this.sweepPlugin(false)); } get deviceAndVaultName() { return this.plugin.deviceAndVaultName; } showPluginSyncModal() { if (this.pluginDialog != null) { this.pluginDialog.open(); } else { this.pluginDialog = new PluginDialogModal(this.app, this.plugin); this.pluginDialog.open(); } } hidePluginSyncModal() { if (this.pluginDialog != null) { this.pluginDialog.close(); this.pluginDialog = null; } } onload() { this.plugin.addCommand({ id: "livesync-plugin-dialog", name: "Show Plugins and their settings", callback: () => { this.showPluginSyncModal(); } }); } onunload() { var _a; this.hidePluginSyncModal(); (_a = this.periodicPluginSweepProcessor) == null ? void 0 : _a.disable(); } parseReplicationResultItem(doc) { if (isPluginMetadata(doc._id)) { if (this.settings.notifyPluginOrSettingUpdated) { this.triggerCheckPluginUpdate(); return true; } } return false; } async beforeReplicate(showMessage) { if (this.settings.autoSweepPlugins) { await this.sweepPlugin(showMessage); } } async onResume() { if (this.plugin.suspended) return; if (this.settings.autoSweepPlugins) { await this.sweepPlugin(false); } this.periodicPluginSweepProcessor.enable(this.settings.autoSweepPluginsPeriodic && !this.settings.watchInternalFileChanges ? PERIODIC_PLUGIN_SWEEP * 1e3 : 0); } async onInitializeDatabase(showNotice) { if (this.settings.usePluginSync) { try { Logger("Scanning plugins..."); await this.sweepPlugin(showNotice); Logger("Scanning plugins done"); } catch (ex) { Logger("Scanning plugins failed"); Logger(ex, LOG_LEVEL.VERBOSE); } } } async realizeSettingSyncMode() { var _a; (_a = this.periodicPluginSweepProcessor) == null ? void 0 : _a.disable(); if (this.plugin.suspended) return; if (this.settings.autoSweepPlugins) { await this.sweepPlugin(false); } this.periodicPluginSweepProcessor.enable(this.settings.autoSweepPluginsPeriodic && !this.settings.watchInternalFileChanges ? PERIODIC_PLUGIN_SWEEP * 1e3 : 0); } triggerCheckPluginUpdate() { (async () => await this.checkPluginUpdate())(); } async getPluginList() { const docList = await this.localDatabase.allDocsRaw({ startkey: PSCHeader, endkey: PSCHeaderEnd, include_docs: false }); const oldDocs = (await Promise.all(docList.rows.map(async (e2) => await this.localDatabase.getDBEntry(e2.id)))).filter((e2) => e2 !== false).map((e2) => JSON.parse(getDocData(e2.data))); const plugins = {}; const allPlugins = {}; const thisDevicePlugins = {}; for (const v of oldDocs) { if (typeof plugins[v.deviceVaultName] === "undefined") { plugins[v.deviceVaultName] = []; } plugins[v.deviceVaultName].push(v); allPlugins[v._id] = v; if (v.deviceVaultName == this.deviceAndVaultName) { thisDevicePlugins[v.manifest.id] = v; } } return { plugins, allPlugins, thisDevicePlugins }; } async checkPluginUpdate() { var _a, _b; if (!this.plugin.settings.usePluginSync) return; await this.sweepPlugin(false); const { allPlugins, thisDevicePlugins } = await this.getPluginList(); const arrPlugins = Object.values(allPlugins); let updateFound = false; for (const plugin2 of arrPlugins) { const ownPlugin = thisDevicePlugins[plugin2.manifest.id]; if (ownPlugin) { const remoteVersion = versionNumberString2Number(plugin2.manifest.version); const ownVersion = versionNumberString2Number(ownPlugin.manifest.version); if (remoteVersion > ownVersion) { updateFound = true; } if ((plugin2.mtime / 1e3 | 0) > (ownPlugin.mtime / 1e3 | 0) && ((_a = plugin2.dataJson) != null ? _a : "") != ((_b = ownPlugin.dataJson) != null ? _b : "")) { updateFound = true; } } } if (updateFound) { const fragment = createFragment((doc) => { doc.createEl("a", null, (a2) => { a2.text = "There're some new plugins or their settings"; a2.addEventListener("click", () => this.showPluginSyncModal()); }); }); NewNotice(fragment, 1e4); } else { Logger("Everything is up to date.", LOG_LEVEL.NOTICE); } } async sweepPlugin(showMessage = false, specificPluginPath = "") { var _a, _b; if (!this.settings.usePluginSync) return; if (!this.localDatabase.isReady) return; const pl = this.app.plugins; const manifests = Object.values(pl.manifests); let specificPlugin = ""; if (specificPluginPath != "") { specificPlugin = (_b = (_a = manifests.find((e2) => e2.dir.endsWith("/" + specificPluginPath))) == null ? void 0 : _a.id) != null ? _b : ""; } await runWithLock("sweepplugin", true, async () => { const logLevel = showMessage ? LOG_LEVEL.NOTICE : LOG_LEVEL.INFO; if (!this.deviceAndVaultName) { Logger("You have to set your device and vault name.", LOG_LEVEL.NOTICE); return; } Logger("Scanning plugins", logLevel); const oldDocs = await this.localDatabase.allDocsRaw({ startkey: `ps:${this.deviceAndVaultName}-${specificPlugin}`, endkey: `ps:${this.deviceAndVaultName}-${specificPlugin}\u{10FFFF}`, include_docs: true }); const procs = manifests.map( async (m) => { const pluginDataEntryID = `ps:${this.deviceAndVaultName}-${m.id}`; try { if (specificPlugin && m.id != specificPlugin) { return; } Logger(`Reading plugin:${m.name}(${m.id})`, LOG_LEVEL.VERBOSE); const path = normalizePath(m.dir) + "/"; const adapter = this.app.vault.adapter; const files = ["manifest.json", "main.js", "styles.css", "data.json"]; const pluginData = {}; for (const file of files) { const thePath = path + file; if (await adapter.exists(thePath)) { pluginData[file] = await adapter.read(thePath); } } let mtime = 0; if (await adapter.exists(path + "/data.json")) { mtime = (await adapter.stat(path + "/data.json")).mtime; } const p = { _id: pluginDataEntryID, dataJson: pluginData["data.json"], deviceVaultName: this.deviceAndVaultName, mainJs: pluginData["main.js"], styleCss: pluginData["styles.css"], manifest: m, manifestJson: pluginData["manifest.json"], mtime, type: "plugin" }; const d = { _id: p._id, path: p._id, data: JSON.stringify(p), ctime: mtime, mtime, size: 0, children: [], datatype: "plain", type: "plain" }; Logger(`check diff:${m.name}(${m.id})`, LOG_LEVEL.VERBOSE); await runWithLock("plugin-" + m.id, false, async () => { const old = await this.localDatabase.getDBEntry(p._id, null, false, false); if (old !== false) { const oldData = { data: old.data, deleted: old._deleted }; const newData = { data: d.data, deleted: d._deleted }; if (isDocContentSame(oldData.data, newData.data) && oldData.deleted == newData.deleted) { Logger(`Nothing changed:${m.name}`); return; } } await this.localDatabase.putDBEntry(d); Logger(`Plugin saved:${m.name}`, logLevel); }); } catch (ex) { Logger(`Plugin save failed:${m.name}`, LOG_LEVEL.NOTICE); } finally { oldDocs.rows = oldDocs.rows.filter((e2) => e2.id != pluginDataEntryID); } } ); await Promise.all(procs); const delDocs = oldDocs.rows.map((e2) => { if (e2.doc.type == "newnote" || e2.doc.type == "plain") { e2.doc.deleted = true; if (this.settings.deleteMetadataOfDeletedFiles) { e2.doc._deleted = true; } } else { e2.doc._deleted = true; } return e2.doc; }); Logger(`Deleting old plugin:(${delDocs.length})`, LOG_LEVEL.VERBOSE); await this.localDatabase.bulkDocsRaw(delDocs); Logger(`Scan plugin done.`, logLevel); }); } async applyPluginData(plugin2) { await runWithLock("plugin-" + plugin2.manifest.id, false, async () => { const pluginTargetFolderPath = normalizePath(plugin2.manifest.dir) + "/"; const adapter = this.app.vault.adapter; const stat = this.app.plugins.enabledPlugins.has(plugin2.manifest.id) == true; if (stat) { await this.app.plugins.unloadPlugin(plugin2.manifest.id); Logger(`Unload plugin:${plugin2.manifest.id}`, LOG_LEVEL.NOTICE); } if (plugin2.dataJson) await adapter.write(pluginTargetFolderPath + "data.json", plugin2.dataJson); Logger("wrote:" + pluginTargetFolderPath + "data.json", LOG_LEVEL.NOTICE); if (stat) { await this.app.plugins.loadPlugin(plugin2.manifest.id); Logger(`Load plugin:${plugin2.manifest.id}`, LOG_LEVEL.NOTICE); } }); } async applyPlugin(plugin2) { await runWithLock("plugin-" + plugin2.manifest.id, false, async () => { const stat = this.app.plugins.enabledPlugins.has(plugin2.manifest.id) == true; if (stat) { await this.app.plugins.unloadPlugin(plugin2.manifest.id); Logger(`Unload plugin:${plugin2.manifest.id}`, LOG_LEVEL.NOTICE); } const pluginTargetFolderPath = normalizePath(plugin2.manifest.dir) + "/"; const adapter = this.app.vault.adapter; if (await adapter.exists(pluginTargetFolderPath) === false) { await adapter.mkdir(pluginTargetFolderPath); } await adapter.write(pluginTargetFolderPath + "main.js", plugin2.mainJs); await adapter.write(pluginTargetFolderPath + "manifest.json", plugin2.manifestJson); if (plugin2.styleCss) await adapter.write(pluginTargetFolderPath + "styles.css", plugin2.styleCss); if (stat) { await this.app.plugins.loadPlugin(plugin2.manifest.id); Logger(`Load plugin:${plugin2.manifest.id}`, LOG_LEVEL.NOTICE); } }); } }; // src/PluginPane.svelte function add_css(target) { append_styles(target, "svelte-1907s6a", ".ols-plugins-div-buttons.svelte-1907s6a{display:flex;flex-direction:row;justify-content:flex-end;margin-top:8px}.wrapToggle.svelte-1907s6a{display:flex;justify-content:center;align-content:center}"); } function get_each_context(ctx, list, i) { const child_ctx = ctx.slice(); child_ctx[26] = list[i][0]; child_ctx[27] = list[i][1]; return child_ctx; } function get_each_context_1(ctx, list, i) { const child_ctx = ctx.slice(); child_ctx[0] = list[i]; return child_ctx; } function create_else_block(ctx) { let each_1_anchor; let each_value = ctx[2]; let each_blocks = []; for (let i = 0; i < each_value.length; i += 1) { each_blocks[i] = create_each_block(get_each_context(ctx, each_value, i)); } return { c() { for (let i = 0; i < each_blocks.length; i += 1) { each_blocks[i].c(); } each_1_anchor = empty(); }, m(target, anchor) { for (let i = 0; i < each_blocks.length; i += 1) { each_blocks[i].m(target, anchor); } insert(target, each_1_anchor, anchor); }, p(ctx2, dirty) { if (dirty[0] & 204) { each_value = ctx2[2]; let i; for (i = 0; i < each_value.length; i += 1) { const child_ctx = get_each_context(ctx2, each_value, i); if (each_blocks[i]) { each_blocks[i].p(child_ctx, dirty); } else { each_blocks[i] = create_each_block(child_ctx); each_blocks[i].c(); each_blocks[i].m(each_1_anchor.parentNode, each_1_anchor); } } for (; i < each_blocks.length; i += 1) { each_blocks[i].d(1); } each_blocks.length = each_value.length; } }, d(detaching) { destroy_each(each_blocks, detaching); if (detaching) detach(each_1_anchor); } }; } function create_if_block_1(ctx) { let tr; return { c() { tr = element("tr"); tr.innerHTML = `No plugins found.`; }, m(target, anchor) { insert(target, tr, anchor); }, p: noop, d(detaching) { if (detaching) detach(tr); } }; } function create_if_block(ctx) { let tr; return { c() { tr = element("tr"); tr.innerHTML = `Retrieving...`; }, m(target, anchor) { insert(target, tr, anchor); }, p: noop, d(detaching) { if (detaching) detach(tr); } }; } function create_else_block_2(ctx) { let div1; let div0; let mounted; let dispose; function click_handler_1() { return ctx[20](ctx[0]); } return { c() { div1 = element("div"); div0 = element("div"); attr(div0, "class", "checkbox-container"); toggle_class(div0, "is-enabled", ctx[3][ctx[0].deviceVaultName + "---" + ctx[0].manifest.id + "---plugin"]); attr(div1, "class", "wrapToggle svelte-1907s6a"); }, m(target, anchor) { insert(target, div1, anchor); append(div1, div0); if (!mounted) { dispose = listen(div0, "click", click_handler_1); mounted = true; } }, p(new_ctx, dirty) { ctx = new_ctx; if (dirty[0] & 12) { toggle_class(div0, "is-enabled", ctx[3][ctx[0].deviceVaultName + "---" + ctx[0].manifest.id + "---plugin"]); } }, d(detaching) { if (detaching) detach(div1); mounted = false; dispose(); } }; } function create_if_block_3(ctx) { let t2; return { c() { t2 = text("-"); }, m(target, anchor) { insert(target, t2, anchor); }, p: noop, d(detaching) { if (detaching) detach(t2); } }; } function create_else_block_1(ctx) { let div1; let div0; let mounted; let dispose; function click_handler_2() { return ctx[21](ctx[0]); } return { c() { div1 = element("div"); div0 = element("div"); attr(div0, "class", "checkbox-container"); toggle_class(div0, "is-enabled", ctx[3][ctx[0].deviceVaultName + "---" + ctx[0].manifest.id + "---setting"]); attr(div1, "class", "wrapToggle svelte-1907s6a"); }, m(target, anchor) { insert(target, div1, anchor); append(div1, div0); if (!mounted) { dispose = listen(div0, "click", click_handler_2); mounted = true; } }, p(new_ctx, dirty) { ctx = new_ctx; if (dirty[0] & 12) { toggle_class(div0, "is-enabled", ctx[3][ctx[0].deviceVaultName + "---" + ctx[0].manifest.id + "---setting"]); } }, d(detaching) { if (detaching) detach(div1); mounted = false; dispose(); } }; } function create_if_block_2(ctx) { let t2; return { c() { t2 = text("-"); }, m(target, anchor) { insert(target, t2, anchor); }, p: noop, d(detaching) { if (detaching) detach(t2); } }; } function create_each_block_1(ctx) { let tr0; let td0; let t0_value = ctx[0].manifest.name + ""; let t0; let t1; let td1; let t2_value = ctx[0].versionInfo + ""; let t2; let t3_value = getDispString(ctx[0].versionFlag) + ""; let t3; let t4; let td2; let t5; let tr1; let td3; let t7; let td4; let t8_value = ctx[0].mtimeInfo + ""; let t8; let t9_value = getDispString(ctx[0].mtimeFlag) + ""; let t9; let t10; let td5; let t11; let tr2; function select_block_type_1(ctx2, dirty) { if (ctx2[0].versionFlag === "EVEN" || ctx2[0].versionFlag === "") return create_if_block_3; return create_else_block_2; } let current_block_type = select_block_type_1(ctx, [-1, -1]); let if_block0 = current_block_type(ctx); function select_block_type_2(ctx2, dirty) { if (ctx2[0].mtimeFlag === "EVEN" || ctx2[0].mtimeFlag === "") return create_if_block_2; return create_else_block_1; } let current_block_type_1 = select_block_type_2(ctx, [-1, -1]); let if_block1 = current_block_type_1(ctx); return { c() { tr0 = element("tr"); td0 = element("td"); t0 = text(t0_value); t1 = space(); td1 = element("td"); t2 = text(t2_value); t3 = text(t3_value); t4 = space(); td2 = element("td"); if_block0.c(); t5 = space(); tr1 = element("tr"); td3 = element("td"); td3.textContent = "Settings"; t7 = space(); td4 = element("td"); t8 = text(t8_value); t9 = text(t9_value); t10 = space(); td5 = element("td"); if_block1.c(); t11 = space(); tr2 = element("tr"); tr2.innerHTML = ` `; attr(td0, "class", "sls-table-head"); attr(td1, "class", "sls-table-tail tcenter"); attr(td2, "class", "sls-table-tail tcenter"); attr(td3, "class", "sls-table-head"); attr(td4, "class", "sls-table-tail tcenter"); attr(td5, "class", "sls-table-tail tcenter"); attr(tr2, "class", "divider"); }, m(target, anchor) { insert(target, tr0, anchor); append(tr0, td0); append(td0, t0); append(tr0, t1); append(tr0, td1); append(td1, t2); append(td1, t3); append(tr0, t4); append(tr0, td2); if_block0.m(td2, null); insert(target, t5, anchor); insert(target, tr1, anchor); append(tr1, td3); append(tr1, t7); append(tr1, td4); append(td4, t8); append(td4, t9); append(tr1, t10); append(tr1, td5); if_block1.m(td5, null); insert(target, t11, anchor); insert(target, tr2, anchor); }, p(ctx2, dirty) { if (dirty[0] & 4 && t0_value !== (t0_value = ctx2[0].manifest.name + "")) set_data(t0, t0_value); if (dirty[0] & 4 && t2_value !== (t2_value = ctx2[0].versionInfo + "")) set_data(t2, t2_value); if (dirty[0] & 4 && t3_value !== (t3_value = getDispString(ctx2[0].versionFlag) + "")) set_data(t3, t3_value); if (current_block_type === (current_block_type = select_block_type_1(ctx2, dirty)) && if_block0) { if_block0.p(ctx2, dirty); } else { if_block0.d(1); if_block0 = current_block_type(ctx2); if (if_block0) { if_block0.c(); if_block0.m(td2, null); } } if (dirty[0] & 4 && t8_value !== (t8_value = ctx2[0].mtimeInfo + "")) set_data(t8, t8_value); if (dirty[0] & 4 && t9_value !== (t9_value = getDispString(ctx2[0].mtimeFlag) + "")) set_data(t9, t9_value); if (current_block_type_1 === (current_block_type_1 = select_block_type_2(ctx2, dirty)) && if_block1) { if_block1.p(ctx2, dirty); } else { if_block1.d(1); if_block1 = current_block_type_1(ctx2); if (if_block1) { if_block1.c(); if_block1.m(td5, null); } } }, d(detaching) { if (detaching) detach(tr0); if_block0.d(); if (detaching) detach(t5); if (detaching) detach(tr1); if_block1.d(); if (detaching) detach(t11); if (detaching) detach(tr2); } }; } function create_each_block(ctx) { let tr; let th0; let t0_value = ctx[26] + ""; let t0; let t1; let th1; let button; let t3; let each_1_anchor; let mounted; let dispose; function click_handler() { return ctx[19](ctx[26]); } let each_value_1 = ctx[27]; let each_blocks = []; for (let i = 0; i < each_value_1.length; i += 1) { each_blocks[i] = create_each_block_1(get_each_context_1(ctx, each_value_1, i)); } return { c() { tr = element("tr"); th0 = element("th"); t0 = text(t0_value); t1 = space(); th1 = element("th"); button = element("button"); button.textContent = "\u2714"; t3 = space(); for (let i = 0; i < each_blocks.length; i += 1) { each_blocks[i].c(); } each_1_anchor = empty(); attr(th0, "colspan", "2"); attr(th0, "class", "sls-plugins-tbl-device-head"); attr(button, "class", "mod-cta"); attr(th1, "class", "sls-plugins-tbl-device-head"); }, m(target, anchor) { insert(target, tr, anchor); append(tr, th0); append(th0, t0); append(tr, t1); append(tr, th1); append(th1, button); insert(target, t3, anchor); for (let i = 0; i < each_blocks.length; i += 1) { each_blocks[i].m(target, anchor); } insert(target, each_1_anchor, anchor); if (!mounted) { dispose = listen(button, "click", click_handler); mounted = true; } }, p(new_ctx, dirty) { ctx = new_ctx; if (dirty[0] & 4 && t0_value !== (t0_value = ctx[26] + "")) set_data(t0, t0_value); if (dirty[0] & 76) { each_value_1 = ctx[27]; let i; for (i = 0; i < each_value_1.length; i += 1) { const child_ctx = get_each_context_1(ctx, each_value_1, i); if (each_blocks[i]) { each_blocks[i].p(child_ctx, dirty); } else { each_blocks[i] = create_each_block_1(child_ctx); each_blocks[i].c(); each_blocks[i].m(each_1_anchor.parentNode, each_1_anchor); } } for (; i < each_blocks.length; i += 1) { each_blocks[i].d(1); } each_blocks.length = each_value_1.length; } }, d(detaching) { if (detaching) detach(tr); if (detaching) detach(t3); destroy_each(each_blocks, detaching); if (detaching) detach(each_1_anchor); mounted = false; dispose(); } }; } function create_fragment(ctx) { let div5; let h1; let t1; let div1; let t2; let div0; let t3; let div2; let table; let tr; let t9; let t10; let div3; let button0; let t12; let button1; let t14; let div4; let button2; let t16; let button3; let t18; let button4; let mounted; let dispose; function select_block_type(ctx2, dirty) { if (!ctx2[2]) return create_if_block; if (ctx2[2].length == 0) return create_if_block_1; return create_else_block; } let current_block_type = select_block_type(ctx, [-1, -1]); let if_block = current_block_type(ctx); return { c() { div5 = element("div"); h1 = element("h1"); h1.textContent = "Plugins and their settings"; t1 = space(); div1 = element("div"); t2 = text("Show own items\n "); div0 = element("div"); t3 = space(); div2 = element("div"); table = element("table"); tr = element("tr"); tr.innerHTML = `Name Info Target`; t9 = space(); if_block.c(); t10 = space(); div3 = element("div"); button0 = element("button"); button0.textContent = "Replicate and refresh"; t12 = space(); button1 = element("button"); button1.textContent = "Clear Selection"; t14 = space(); div4 = element("div"); button2 = element("button"); button2.textContent = "Check Updates"; t16 = space(); button3 = element("button"); button3.textContent = "Scan installed"; t18 = space(); button4 = element("button"); button4.textContent = "Apply all"; attr(div0, "class", "checkbox-container"); toggle_class(div0, "is-enabled", ctx[1]); attr(div1, "class", "ols-plugins-div-buttons svelte-1907s6a"); set_style(tr, "position", "sticky"); attr(table, "class", "sls-plugins-tbl"); attr(div2, "class", "sls-plugins-wrap"); attr(button0, "class", ""); attr(button1, "class", ""); attr(div3, "class", "ols-plugins-div-buttons svelte-1907s6a"); attr(button2, "class", "mod-cta"); attr(button3, "class", "mod-cta"); attr(button4, "class", "mod-cta"); attr(div4, "class", "ols-plugins-div-buttons svelte-1907s6a"); }, m(target, anchor) { insert(target, div5, anchor); append(div5, h1); append(div5, t1); append(div5, div1); append(div1, t2); append(div1, div0); append(div5, t3); append(div5, div2); append(div2, table); append(table, tr); append(table, t9); if_block.m(table, null); append(div5, t10); append(div5, div3); append(div3, button0); append(div3, t12); append(div3, button1); append(div5, t14); append(div5, div4); append(div4, button2); append(div4, t16); append(div4, button3); append(div4, t18); append(div4, button4); if (!mounted) { dispose = [ listen(div0, "click", ctx[5]), listen(button0, "click", ctx[11]), listen(button1, "click", ctx[4]), listen(button2, "click", ctx[10]), listen(button3, "click", ctx[8]), listen(button4, "click", ctx[9]) ]; mounted = true; } }, p(ctx2, dirty) { if (dirty[0] & 2) { toggle_class(div0, "is-enabled", ctx2[1]); } if (current_block_type === (current_block_type = select_block_type(ctx2, dirty)) && if_block) { if_block.p(ctx2, dirty); } else { if_block.d(1); if_block = current_block_type(ctx2); if (if_block) { if_block.c(); if_block.m(table, null); } } }, i: noop, o: noop, d(detaching) { if (detaching) detach(div5); if_block.d(); mounted = false; run_all(dispose); } }; } function getDispString(stat) { if (stat == "") return ""; if (stat == "NEWER") return " (Newer)"; if (stat == "OLDER") return " (Older)"; if (stat == "EVEN") return " (Even)"; if (stat == "EVEN_BUT_DIFFERENT") return " (Even but different)"; if (stat == "REMOTE_ONLY") return " (Remote Only)"; return ""; } function instance($$self, $$props, $$invalidate) { var _a, _b, _c, _d; let { plugin: plugin2 } = $$props; let plugins = []; let deviceAndPlugins = {}; let devicePluginList = null; let ownPlugins = null; let showOwnPlugins = false; let targetList = {}; let addOn; function saveTargetList() { window.localStorage.setItem("ols-plugin-targetlist", JSON.stringify(targetList)); } function loadTargetList() { let e2 = window.localStorage.getItem("ols-plugin-targetlist") || "{}"; try { $$invalidate(3, targetList = JSON.parse(e2)); } catch (_) { } } function clearSelection() { $$invalidate(3, targetList = {}); } async function updateList() { let x = await addOn.getPluginList(); $$invalidate(18, ownPlugins = x.thisDevicePlugins); $$invalidate(16, plugins = Object.values(x.allPlugins)); let targetListItems = Array.from(new Set(plugins.map((e2) => e2.deviceVaultName + "---" + e2.manifest.id))); let newTargetList = {}; for (const id of targetListItems) { for (const tag of ["---plugin", "---setting"]) { newTargetList[id + tag] = id + tag in targetList && targetList[id + tag]; } } $$invalidate(3, targetList = newTargetList); saveTargetList(); } onMount(async () => { loadTargetList(); await updateList(); }); function toggleShowOwnPlugins() { $$invalidate(1, showOwnPlugins = !showOwnPlugins); } function toggleTarget(key) { $$invalidate(3, targetList[key] = !targetList[key], targetList); saveTargetList(); } function toggleAll(devicename) { for (const c in targetList) { if (c.startsWith(devicename)) { $$invalidate(3, targetList[c] = true, targetList); } } } async function sweepPlugins() { await plugin2.app.plugins.loadManifests(); await addOn.sweepPlugin(true); updateList(); } async function applyPlugins() { for (const c in targetList) { if (targetList[c] == true) { const [deviceAndVault, id, opt] = c.split("---"); if (deviceAndVault in deviceAndPlugins) { const entry = deviceAndPlugins[deviceAndVault].find((e2) => e2.manifest.id == id); if (entry) { if (opt == "plugin") { if (entry.versionFlag != "EVEN") await addOn.applyPlugin(entry); } else if (opt == "setting") { if (entry.mtimeFlag != "EVEN") await addOn.applyPluginData(entry); } } } } } await plugin2.app.plugins.loadManifests(); await addOn.sweepPlugin(true); updateList(); } async function checkUpdates() { await addOn.checkPluginUpdate(); } async function replicateAndRefresh() { await plugin2.replicate(true); updateList(); } const click_handler = (deviceName) => toggleAll(deviceName); const click_handler_1 = (plugin3) => toggleTarget(plugin3.deviceVaultName + "---" + plugin3.manifest.id + "---plugin"); const click_handler_2 = (plugin3) => toggleTarget(plugin3.deviceVaultName + "---" + plugin3.manifest.id + "---setting"); $$self.$$set = ($$props2) => { if ("plugin" in $$props2) $$invalidate(0, plugin2 = $$props2.plugin); }; $$self.$$.update = () => { if ($$self.$$.dirty[0] & 1) { $: { const f3 = plugin2.addOns.filter((e2) => e2 instanceof PluginAndTheirSettings); if (f3 && f3.length > 0) { addOn = f3[0]; } } } if ($$self.$$.dirty[0] & 520195) { $: { $$invalidate(17, deviceAndPlugins = {}); for (const p of plugins) { if (p.deviceVaultName == plugin2.deviceAndVaultName && !showOwnPlugins) { continue; } if (!(p.deviceVaultName in deviceAndPlugins)) { $$invalidate(17, deviceAndPlugins[p.deviceVaultName] = [], deviceAndPlugins); } let dispInfo = { ...p, versionInfo: "", mtimeInfo: "", versionFlag: "", mtimeFlag: "" }; dispInfo.versionInfo = p.manifest.version; let x = new Date().getTime() / 1e3; let mtime = p.mtime / 1e3; let diff = (x - mtime) / 60; if (p.mtime == 0) { dispInfo.mtimeInfo = `-`; } else if (diff < 60) { dispInfo.mtimeInfo = `${diff | 0} Mins ago`; } else if (diff < 60 * 24) { dispInfo.mtimeInfo = `${diff / 60 | 0} Hours ago`; } else if (diff < 60 * 24 * 10) { dispInfo.mtimeInfo = `${diff / (60 * 24) | 0} Days ago`; } else { dispInfo.mtimeInfo = new Date(dispInfo.mtime).toLocaleString(); } let id = p.manifest.id; if (id in ownPlugins) { const ownPlugin = ownPlugins[id]; let localVer = versionNumberString2Number(ownPlugin.manifest.version); let pluginVer = versionNumberString2Number(p.manifest.version); if (localVer > pluginVer) { dispInfo.versionFlag = "OLDER"; } else if (localVer == pluginVer) { if (ownPlugin.manifestJson + ($$invalidate(12, _a = ownPlugin.styleCss) !== null && _a !== void 0 ? _a : "") + ownPlugin.mainJs != p.manifestJson + ($$invalidate(13, _b = p.styleCss) !== null && _b !== void 0 ? _b : "") + p.mainJs) { dispInfo.versionFlag = "EVEN_BUT_DIFFERENT"; } else { dispInfo.versionFlag = "EVEN"; } } else if (localVer < pluginVer) { dispInfo.versionFlag = "NEWER"; } if (($$invalidate(14, _c = ownPlugin.dataJson) !== null && _c !== void 0 ? _c : "") == ($$invalidate(15, _d = p.dataJson) !== null && _d !== void 0 ? _d : "")) { if (ownPlugin.mtime == 0 && p.mtime == 0) { dispInfo.mtimeFlag = ""; } else { dispInfo.mtimeFlag = "EVEN"; } } else { if ((ownPlugin.mtime / 1e3 | 0) > (p.mtime / 1e3 | 0)) { dispInfo.mtimeFlag = "OLDER"; } else if ((ownPlugin.mtime / 1e3 | 0) == (p.mtime / 1e3 | 0)) { dispInfo.mtimeFlag = "EVEN_BUT_DIFFERENT"; } else if ((ownPlugin.mtime / 1e3 | 0) < (p.mtime / 1e3 | 0)) { dispInfo.mtimeFlag = "NEWER"; } } } else { dispInfo.versionFlag = "REMOTE_ONLY"; dispInfo.mtimeFlag = "REMOTE_ONLY"; } deviceAndPlugins[p.deviceVaultName].push(dispInfo); } $$invalidate(2, devicePluginList = Object.entries(deviceAndPlugins)); } } }; return [ plugin2, showOwnPlugins, devicePluginList, targetList, clearSelection, toggleShowOwnPlugins, toggleTarget, toggleAll, sweepPlugins, applyPlugins, checkUpdates, replicateAndRefresh, _a, _b, _c, _d, plugins, deviceAndPlugins, ownPlugins, click_handler, click_handler_1, click_handler_2 ]; } var PluginPane = class extends SvelteComponent { constructor(options) { super(); init2(this, options, instance, create_fragment, safe_not_equal, { plugin: 0 }, add_css, [-1, -1]); } }; var PluginPane_default = PluginPane; // src/dialogs.ts var PluginDialogModal = class extends import_obsidian.Modal { constructor(app2, plugin2) { super(app2); this.component = null; this.plugin = plugin2; } onOpen() { const { contentEl } = this; if (this.component == null) { this.component = new PluginPane_default({ target: contentEl, props: { plugin: this.plugin } }); } } onClose() { if (this.component != null) { this.component.$destroy(); this.component = null; } } }; var InputStringDialog = class extends import_obsidian.Modal { constructor(app2, title, key, placeholder, onSubmit) { super(app2); this.result = false; this.isManuallyClosed = false; this.onSubmit = onSubmit; this.title = title; this.placeholder = placeholder; this.key = key; } onOpen() { const { contentEl } = this; contentEl.createEl("h1", { text: this.title }); const formEl = contentEl.createEl("form"); new import_obsidian.Setting(formEl).setName(this.key).addText( (text2) => text2.onChange((value) => { this.result = value; }) ); new import_obsidian.Setting(formEl).addButton( (btn) => btn.setButtonText("Ok").setCta().onClick(() => { this.isManuallyClosed = true; this.close(); }) ).addButton( (btn) => btn.setButtonText("Cancel").setCta().onClick(() => { this.close(); }) ); } onClose() { const { contentEl } = this; contentEl.empty(); if (this.isManuallyClosed) { this.onSubmit(this.result); } else { this.onSubmit(false); } } }; var PopoverSelectString = class extends import_obsidian.FuzzySuggestModal { constructor(app2, note, placeholder, getItemsFun, callback) { super(app2); this.callback = () => { }; this.getItemsFun = () => { return ["yes", "no"]; }; this.app = app2; this.setPlaceholder((placeholder != null ? placeholder : "y/n) ") + note); if (getItemsFun) this.getItemsFun = getItemsFun; this.callback = callback; } getItems() { return this.getItemsFun(); } getItemText(item) { return item; } onChooseItem(item, evt) { this.callback(item); this.callback = null; } onClose() { setTimeout(() => { if (this.callback != null) { this.callback(""); } }, 100); } }; var MessageBox = class extends import_obsidian.Modal { constructor(plugin2, title, contentMd, buttons, defaultAction, timeout, onSubmit) { super(plugin2.app); this.isManuallyClosed = false; this.timer = void 0; this.plugin = plugin2; this.title = title; this.contentMd = contentMd; this.buttons = buttons; this.onSubmit = onSubmit; this.defaultAction = defaultAction; this.timeout = timeout; if (this.timeout) { this.timer = setInterval(() => { this.timeout--; if (this.timeout < 0) { if (this.timer) { clearInterval(this.timer); this.timer = void 0; } this.result = defaultAction; this.isManuallyClosed = true; this.close(); } else { this.defaultButtonComponent.setButtonText(`( ${this.timeout} ) ${defaultAction}`); } }, 1e3); } } onOpen() { const { contentEl } = this; contentEl.addEventListener("click", () => { if (this.timer) { clearInterval(this.timer); this.timer = void 0; } }); contentEl.createEl("h1", { text: this.title }); const div = contentEl.createDiv(); import_obsidian.MarkdownRenderer.renderMarkdown(this.contentMd, div, "/", null); const buttonSetting = new import_obsidian.Setting(contentEl); for (const button of this.buttons) { buttonSetting.addButton( (btn) => { btn.setButtonText(button).onClick(() => { this.isManuallyClosed = true; this.result = button; if (this.timer) { clearInterval(this.timer); this.timer = void 0; } this.close(); }); if (button == this.defaultAction) { this.defaultButtonComponent = btn; } return btn; } ); } } onClose() { const { contentEl } = this; contentEl.empty(); if (this.timer) { clearInterval(this.timer); this.timer = void 0; } if (this.isManuallyClosed) { this.onSubmit(this.result); } else { this.onSubmit(false); } } }; function confirmWithMessage(plugin2, title, contentMd, buttons, defaultAction, timeout) { return new Promise((res2) => { const dialog = new MessageBox(plugin2, title, contentMd, buttons, defaultAction, timeout, (result) => res2(result)); dialog.open(); }); } // src/utils.ts async function path2id(filename, obfuscatePassphrase) { const temp = filename.split(":"); const path = temp.pop(); const normalizedPath = normalizePath(path); temp.push(normalizedPath); const fixedPath = temp.join(":"); const out = await path2id_base(fixedPath, obfuscatePassphrase); return out; } function id2path(id, entry) { const filename = id2path_base(id, entry); const temp = filename.split(":"); const path = temp.pop(); const normalizedPath = normalizePath(path); temp.push(normalizedPath); const fixedPath = temp.join(":"); return fixedPath; } function getPath2(entry) { return id2path(entry._id, entry); } function getPathWithoutPrefix(entry) { const f3 = getPath2(entry); return stripAllPrefixes(f3); } function getPathFromTFile(file) { return file.path; } var tasks = {}; function scheduleTask(key, timeout, proc) { cancelTask(key); tasks[key] = setTimeout(async () => { delete tasks[key]; await proc(); }, timeout); } function cancelTask(key) { if (key in tasks) { clearTimeout(tasks[key]); delete tasks[key]; } } function cancelAllTasks() { for (const v in tasks) { clearTimeout(tasks[v]); delete tasks[v]; } } var intervals = {}; function cancelAllPeriodicTask() { for (const v in intervals) { clearInterval(intervals[v]); delete intervals[v]; } } var memos = {}; function memoObject(key, obj) { memos[key] = obj; return memos[key]; } async function memoIfNotExist(key, func) { if (!(key in memos)) { const w = func(); const v = w instanceof Promise ? await w : w; memos[key] = v; } return memos[key]; } function retrieveMemoObject(key) { if (key in memos) { return memos[key]; } else { return false; } } function disposeMemoObject(key) { delete memos[key]; } function isSensibleMargeApplicable(path) { if (path.endsWith(".md")) return true; return false; } function isObjectMargeApplicable(path) { if (path.endsWith(".canvas")) return true; if (path.endsWith(".json")) return true; return false; } function tryParseJSON(str, fallbackValue) { try { return JSON.parse(str); } catch (ex) { return fallbackValue; } } var MARK_OPERATOR = ``; var MARK_DELETED = `${MARK_OPERATOR}__DELETED`; var MARK_ISARRAY = `${MARK_OPERATOR}__ARRAY`; var MARK_SWAPPED = `${MARK_OPERATOR}__SWAP`; function unorderedArrayToObject(obj) { return obj.map((e2) => ({ [e2.id]: e2 })).reduce((p, c) => ({ ...p, ...c }), {}); } function objectToUnorderedArray(obj) { const entries = Object.entries(obj); if (entries.some((e2) => { var _a; return e2[0] != ((_a = e2[1]) == null ? void 0 : _a.id); })) throw new Error("Item looks like not unordered array"); return entries.map((e2) => e2[1]); } function generatePatchUnorderedArray(from, to) { if (from.every((e2) => typeof e2 == "object" && "id" in e2) && to.every((e2) => typeof e2 == "object" && "id" in e2)) { const fObj = unorderedArrayToObject(from); const tObj = unorderedArrayToObject(to); const diff = generatePatchObj(fObj, tObj); if (Object.keys(diff).length > 0) { return { [MARK_ISARRAY]: diff }; } else { return {}; } } return { [MARK_SWAPPED]: to }; } function generatePatchObj(from, to) { const entries = Object.entries(from); const tempMap = new Map(entries); const ret = {}; const newEntries = Object.entries(to); for (const [key, value] of newEntries) { if (!tempMap.has(key)) { ret[key] = value; tempMap.delete(key); } else { const v = tempMap.get(key); if (typeof v !== typeof value || Array.isArray(v) !== Array.isArray(value)) { ret[key] = { [MARK_SWAPPED]: value }; } else { if (typeof v == "object" && typeof value == "object" && !Array.isArray(v) && !Array.isArray(value)) { const wk = generatePatchObj(v, value); if (Object.keys(wk).length > 0) ret[key] = wk; } else if (typeof v == "object" && typeof value == "object" && Array.isArray(v) && Array.isArray(value)) { const wk = generatePatchUnorderedArray(v, value); if (Object.keys(wk).length > 0) ret[key] = wk; } else if (typeof v != "object" && typeof value != "object") { if (JSON.stringify(tempMap.get(key)) !== JSON.stringify(value)) { ret[key] = value; } } else { if (JSON.stringify(tempMap.get(key)) !== JSON.stringify(value)) { ret[key] = { [MARK_SWAPPED]: value }; } } } tempMap.delete(key); } } for (const [key] of tempMap) { ret[key] = MARK_DELETED; } return ret; } function applyPatch(from, patch) { const ret = from; const patches = Object.entries(patch); for (const [key, value] of patches) { if (value == MARK_DELETED) { delete ret[key]; continue; } if (typeof value == "object") { if (MARK_SWAPPED in value) { ret[key] = value[MARK_SWAPPED]; continue; } if (MARK_ISARRAY in value) { if (!(key in ret)) ret[key] = []; if (!Array.isArray(ret[key])) { throw new Error("Patch target type is mismatched (array to something)"); } const orgArrayObject = unorderedArrayToObject(ret[key]); const appliedObject = applyPatch(orgArrayObject, value[MARK_ISARRAY]); const appliedArray = objectToUnorderedArray(appliedObject); ret[key] = [...appliedArray]; } else { if (!(key in ret)) { ret[key] = value; continue; } ret[key] = applyPatch(ret[key], value); } } else { ret[key] = value; } } return ret; } function mergeObject(objA, objB) { const newEntries = Object.entries(objB); const ret = { ...objA }; if (typeof objA !== typeof objB || Array.isArray(objA) !== Array.isArray(objB)) { return objB; } for (const [key, v] of newEntries) { if (key in ret) { const value = ret[key]; if (typeof v !== typeof value || Array.isArray(v) !== Array.isArray(value)) { ret[key] = v; } else { if (typeof v == "object" && typeof value == "object" && !Array.isArray(v) && !Array.isArray(value)) { ret[key] = mergeObject(v, value); } else if (typeof v == "object" && typeof value == "object" && Array.isArray(v) && Array.isArray(value)) { ret[key] = [.../* @__PURE__ */ new Set([...v, ...value])]; } else { ret[key] = v; } } } else { ret[key] = v; } } return Object.entries(ret).sort().reduce((p, [key, value]) => ({ ...p, [key]: value }), {}); } function flattenObject(obj, path = []) { if (typeof obj != "object") return [[path.join("."), obj]]; if (Array.isArray(obj)) return [[path.join("."), JSON.stringify(obj)]]; const e2 = Object.entries(obj); const ret = []; for (const [key, value] of e2) { const p = flattenObject(value, [...path, key]); ret.push(...p); } return ret; } function modifyFile(file, data, options) { if (typeof data === "string") { return app.vault.modify(file, data, options); } else { return app.vault.modifyBinary(file, data, options); } } function createFile(path, data, options) { if (typeof data === "string") { return app.vault.create(path, data, options); } else { return app.vault.createBinary(path, data, options); } } function isValidPath(filename) { if (import_obsidian.Platform.isDesktop) { if (process.platform == "darwin") return isValidFilenameInDarwin(filename); if (process.platform == "linux") return isValidFilenameInLinux(filename); return isValidFilenameInWidows(filename); } if (import_obsidian.Platform.isAndroidApp) return isValidFilenameInAndroid(filename); if (import_obsidian.Platform.isIosApp) return isValidFilenameInDarwin(filename); Logger("Could not determine platform for checking filename", LOG_LEVEL.VERBOSE); return isValidFilenameInWidows(filename); } var touchedFiles = []; function getAbstractFileByPath(path) { return app.vault.getAbstractFileByPath(path); } function trimPrefix(target, prefix) { return target.startsWith(prefix) ? target.substring(prefix.length) : target; } function touch(file) { const f3 = file instanceof import_obsidian.TFile ? file : getAbstractFileByPath(file); const key = `${f3.path}-${f3.stat.mtime}-${f3.stat.size}`; touchedFiles.unshift(key); touchedFiles = touchedFiles.slice(0, 100); } function recentlyTouched(file) { const key = `${file.path}-${file.stat.mtime}-${file.stat.size}`; if (touchedFiles.indexOf(key) == -1) return false; return true; } function clearTouched() { touchedFiles = []; } function isIdOfInternalMetadata(id) { return id.startsWith(ICHeader); } function stripInternalMetadataPrefix(id) { return id.substring(ICHeaderLength); } function isChunk(str) { return str.startsWith(CHeader); } function isPluginMetadata(str) { return str.startsWith(PSCHeader); } var askYesNo = (app2, message) => { return new Promise((res2) => { const popover = new PopoverSelectString(app2, message, null, null, (result) => res2(result)); popover.open(); }); }; var askSelectString = (app2, message, items) => { const getItemsFun = () => items; return new Promise((res2) => { const popover = new PopoverSelectString(app2, message, "", getItemsFun, (result) => res2(result)); popover.open(); }); }; var askString = (app2, title, key, placeholder) => { return new Promise((res2) => { const dialog = new InputStringDialog(app2, title, key, placeholder, (result) => res2(result)); dialog.open(); }); }; var PeriodicProcessor = class { constructor(plugin2, process2) { this._plugin = plugin2; this._process = process2; } async process() { try { await this._process(); } catch (ex) { Logger(ex); } } enable(interval) { this.disable(); if (interval == 0) return; this._timer = window.setInterval(() => this._process().then(() => { }), interval); this._plugin.registerInterval(this._timer); } disable() { if (this._timer) clearInterval(this._timer); } }; function sizeToHumanReadable(size) { if (!size) return "-"; const i = Math.floor(Math.log(size) / Math.log(1024)); return Number.parseInt((size / Math.pow(1024, i)).toFixed(2)) + " " + ["B", "kB", "MB", "GB", "TB"][i]; } var _requestToCouchDBFetch = async (baseUri, username, password, path, body, method) => { const utf8str = String.fromCharCode.apply(null, new TextEncoder().encode(`${username}:${password}`)); const encoded = window.btoa(utf8str); const authHeader = "Basic " + encoded; const transformedHeaders = { authorization: authHeader, "content-type": "application/json" }; const uri = `${baseUri}/${path}`; const requestParam = { url: uri, method: method || (body ? "PUT" : "GET"), headers: new Headers(transformedHeaders), contentType: "application/json", body: JSON.stringify(body) }; return await fetch(uri, requestParam); }; var _requestToCouchDB = async (baseUri, username, password, origin2, path, body, method) => { const utf8str = String.fromCharCode.apply(null, new TextEncoder().encode(`${username}:${password}`)); const encoded = window.btoa(utf8str); const authHeader = "Basic " + encoded; const transformedHeaders = { authorization: authHeader, origin: origin2 }; const uri = `${baseUri}/${path}`; const requestParam = { url: uri, method: method || (body ? "PUT" : "GET"), headers: transformedHeaders, contentType: "application/json", body: body ? JSON.stringify(body) : void 0 }; return await (0, import_obsidian.requestUrl)(requestParam); }; var requestToCouchDB = async (baseUri, username, password, origin2, key, body, method) => { const uri = `_node/_local/_config${key ? "/" + key : ""}`; return await _requestToCouchDB(baseUri, username, password, origin2, uri, body, method); }; async function performRebuildDB(plugin2, method) { if (method == "localOnly") { await plugin2.addOnSetup.fetchLocal(); } if (method == "remoteOnly") { await plugin2.addOnSetup.rebuildRemote(); } if (method == "rebuildBothByThisDevice") { await plugin2.addOnSetup.rebuildEverything(); } } var gatherChunkUsage = async (db) => { const used = /* @__PURE__ */ new Map(); const unreferenced = /* @__PURE__ */ new Map(); const removed = /* @__PURE__ */ new Map(); const missing = /* @__PURE__ */ new Map(); const xx = await db.allDocs({ startkey: "h:", endkey: `h:\u{10FFFF}` }); for (const xxd of xx.rows) { const chunk = xxd.id; unreferenced.set(chunk, xxd.value.rev); } const x = await db.find({ limit: 999999999, selector: { children: { $exists: true, $type: "array" } }, fields: ["_id", "path", "mtime", "children"] }); for (const temp of x.docs) { for (const chunk of temp.children) { used.set(chunk, (used.has(chunk) ? used.get(chunk) : 0) + 1); if (unreferenced.has(chunk)) { removed.set(chunk, unreferenced.get(chunk)); unreferenced.delete(chunk); } else { if (!removed.has(chunk)) { if (!missing.has(temp._id)) { missing.set(temp._id, []); } missing.get(temp._id).push(chunk); } } } } return { used, unreferenced, missing }; }; var localDatabaseCleanUp = async (plugin2, force, dryRun) => { await runWithLock("clean-up:local", true, async () => { const db = plugin2.localDatabase.localDatabase; if ((db == null ? void 0 : db.adapter) != "indexeddb") { if (force && !dryRun) { Logger("Fetch from the remote database", LOG_LEVEL.NOTICE, "clean-up-db"); await performRebuildDB(plugin2, "localOnly"); return; } else { Logger("This feature requires enabling `Use new adapter`. Please enable it", LOG_LEVEL.NOTICE, "clean-up-db"); return; } } Logger(`The remote database has been locked for garbage collection`, LOG_LEVEL.NOTICE, "clean-up-db"); Logger(`Gathering chunk usage information`, LOG_LEVEL.NOTICE, "clean-up-db"); const { unreferenced, missing } = await gatherChunkUsage(db); if (missing.size != 0) { Logger(`Some chunks are not found! We have to rescue`, LOG_LEVEL.NOTICE); Logger(missing, LOG_LEVEL.VERBOSE); } else { Logger(`All chunks are OK`, LOG_LEVEL.NOTICE); } const payload = {}; for (const [id, rev2] of unreferenced) { payload[id] = [rev2]; } const removeItems = Object.keys(payload).length; if (removeItems == 0) { Logger(`No unreferenced chunks found (Local)`, LOG_LEVEL.NOTICE); await plugin2.markRemoteResolved(); } if (dryRun) { Logger(`There are ${removeItems} unreferenced chunks (Local)`, LOG_LEVEL.NOTICE); return; } Logger(`Deleting unreferenced chunks: ${removeItems}`, LOG_LEVEL.NOTICE, "clean-up-db"); for (const [id, rev2] of unreferenced) { const ret = await db.purge(id, rev2); Logger(ret, LOG_LEVEL.VERBOSE); } plugin2.localDatabase.refreshSettings(); Logger(`Compacting local database...`, LOG_LEVEL.NOTICE, "clean-up-db"); await db.compact(); await plugin2.markRemoteResolved(); Logger("Done!", LOG_LEVEL.NOTICE, "clean-up-db"); }); }; var balanceChunks = async (plugin2, dryRun) => { await runWithLock("clean-up:balance", true, async () => { const localDB = plugin2.localDatabase.localDatabase; Logger(`Gathering chunk usage information`, LOG_LEVEL.NOTICE, "clean-up-db"); const ret = await plugin2.replicator.connectRemoteCouchDBWithSetting(plugin2.settings, plugin2.isMobile); if (typeof ret === "string") { Logger(`Connect error: ${ret}`, LOG_LEVEL.NOTICE, "clean-up-db"); return; } const localChunks = /* @__PURE__ */ new Map(); const xx = await localDB.allDocs({ startkey: "h:", endkey: `h:\u{10FFFF}` }); for (const xxd of xx.rows) { const chunk = xxd.id; localChunks.set(chunk, xxd.value.rev); } const remoteDB = ret.db; const remoteChunks = /* @__PURE__ */ new Map(); const xxr = await remoteDB.allDocs({ startkey: "h:", endkey: `h:\u{10FFFF}` }); for (const xxd of xxr.rows) { const chunk = xxd.id; remoteChunks.set(chunk, xxd.value.rev); } const localToRemote = new Map([...localChunks]); const remoteToLocal = new Map([...remoteChunks]); for (const id of /* @__PURE__ */ new Set([...localChunks.keys(), ...remoteChunks.keys()])) { if (remoteChunks.has(id)) { localToRemote.delete(id); } if (localChunks.has(id)) { remoteToLocal.delete(id); } } function arrayToChunkedArray(src, size = 25) { const ret2 = []; let i = 0; while (i < src.length) { ret2.push(src.slice(i, i += size)); } return ret2; } if (localToRemote.size == 0) { Logger(`No chunks need to be sent`, LOG_LEVEL.NOTICE); } else { Logger(`${localToRemote.size} chunks need to be sent`, LOG_LEVEL.NOTICE); if (!dryRun) { const w = arrayToChunkedArray([...localToRemote]); for (const chunk of w) { for (const [id] of chunk) { const queryRet = await localDB.allDocs({ keys: [id], include_docs: true }); const docs = queryRet.rows.filter((e2) => !("error" in e2)).map((x) => x.doc); const ret2 = await remoteDB.bulkDocs(docs, { new_edits: false }); Logger(ret2, LOG_LEVEL.VERBOSE); } } Logger(`Done! ${remoteToLocal.size} chunks have been sent`, LOG_LEVEL.NOTICE); } } if (remoteToLocal.size == 0) { Logger(`No chunks need to be retrieved`, LOG_LEVEL.NOTICE); } else { Logger(`${remoteToLocal.size} chunks need to be retrieved`, LOG_LEVEL.NOTICE); if (!dryRun) { const w = arrayToChunkedArray([...remoteToLocal]); for (const chunk of w) { for (const [id] of chunk) { const queryRet = await remoteDB.allDocs({ keys: [id], include_docs: true }); const docs = queryRet.rows.filter((e2) => !("error" in e2)).map((x) => x.doc); const ret2 = await localDB.bulkDocs(docs, { new_edits: false }); Logger(ret2, LOG_LEVEL.VERBOSE); } } Logger(`Done! ${remoteToLocal.size} chunks have been retrieved`, LOG_LEVEL.NOTICE); } } }); }; var remoteDatabaseCleanup = async (plugin2, dryRun) => { const getSize = function(info2, key) { var _a, _b; return Number.parseInt((_b = (_a = info2 == null ? void 0 : info2.sizes) == null ? void 0 : _a[key]) != null ? _b : 0); }; await runWithLock("clean-up:remote", true, async () => { try { const ret = await plugin2.replicator.connectRemoteCouchDBWithSetting(plugin2.settings, plugin2.isMobile); if (typeof ret === "string") { Logger(`Connect error: ${ret}`, LOG_LEVEL.NOTICE, "clean-up-db"); return; } const info2 = ret.info; Logger(JSON.stringify(info2), LOG_LEVEL.VERBOSE, "clean-up-db"); Logger(`Database active-size: ${sizeToHumanReadable(getSize(info2, "active"))}, external-size:${sizeToHumanReadable(getSize(info2, "external"))}, file-size: ${sizeToHumanReadable(getSize(info2, "file"))}`, LOG_LEVEL.NOTICE); if (!dryRun) { Logger(`The remote database has been locked for garbage collection`, LOG_LEVEL.NOTICE, "clean-up-db"); await plugin2.markRemoteLocked(true); } Logger(`Gathering chunk usage information`, LOG_LEVEL.NOTICE, "clean-up-db"); const db = ret.db; const { unreferenced, missing } = await gatherChunkUsage(db); if (missing.size != 0) { Logger(`Some chunks are not found! We have to rescue`, LOG_LEVEL.NOTICE); Logger(missing, LOG_LEVEL.VERBOSE); } else { Logger(`All chunks are OK`, LOG_LEVEL.NOTICE); } const payload = {}; for (const [id, rev2] of unreferenced) { payload[id] = [rev2]; } const removeItems = Object.keys(payload).length; if (removeItems == 0) { Logger(`No unreferenced chunk found (Remote)`, LOG_LEVEL.NOTICE); return; } if (dryRun) { Logger(`There are ${removeItems} unreferenced chunks (Remote)`, LOG_LEVEL.NOTICE); return; } Logger(`Deleting unreferenced chunks: ${removeItems}`, LOG_LEVEL.NOTICE, "clean-up-db"); const rets = await _requestToCouchDBFetch( `${plugin2.settings.couchDB_URI}/${plugin2.settings.couchDB_DBNAME}`, plugin2.settings.couchDB_USER, plugin2.settings.couchDB_PASSWORD, "_purge", payload, "POST" ); Logger(JSON.stringify(await rets.json()), LOG_LEVEL.VERBOSE); Logger(`Compacting database...`, LOG_LEVEL.NOTICE, "clean-up-db"); await db.compact(); const endInfo = await db.info(); Logger(`Processed database active-size: ${sizeToHumanReadable(getSize(endInfo, "active"))}, external-size:${sizeToHumanReadable(getSize(endInfo, "external"))}, file-size: ${sizeToHumanReadable(getSize(endInfo, "file"))}`, LOG_LEVEL.NOTICE); Logger(`Reduced sizes: active-size: ${sizeToHumanReadable(getSize(info2, "active") - getSize(endInfo, "active"))}, external-size:${sizeToHumanReadable(getSize(info2, "external") - getSize(endInfo, "external"))}, file-size: ${sizeToHumanReadable(getSize(info2, "file") - getSize(endInfo, "file"))}`, LOG_LEVEL.NOTICE); Logger(JSON.stringify(endInfo), LOG_LEVEL.VERBOSE, "clean-up-db"); Logger(`Local database cleaning up...`); await localDatabaseCleanUp(plugin2, true, false); } catch (ex) { Logger("Failed to clean up db."); Logger(ex, LOG_LEVEL.VERBOSE); } }); }; // src/ObsidianLiveSyncSettingTab.ts var ObsidianLiveSyncSettingTab = class extends import_obsidian.PluginSettingTab { constructor(app2, plugin2) { super(app2, plugin2); this.selectedScreen = ""; this.plugin = plugin2; } async testConnection() { const db = await this.plugin.replicator.connectRemoteCouchDBWithSetting(this.plugin.settings, this.plugin.isMobile); if (typeof db === "string") { this.plugin.addLog(`could not connect to ${this.plugin.settings.couchDB_URI} : ${this.plugin.settings.couchDB_DBNAME} (${db})`, LOG_LEVEL.NOTICE); return; } this.plugin.addLog(`Connected to ${db.info.db_name}`, LOG_LEVEL.NOTICE); } display() { const { containerEl } = this; let encrypt2 = this.plugin.settings.encrypt; let passphrase = this.plugin.settings.passphrase; let useDynamicIterationCount = this.plugin.settings.useDynamicIterationCount; containerEl.empty(); containerEl.createEl("h2", { text: "Settings for Self-hosted LiveSync." }); containerEl.addClass("sls-setting"); containerEl.removeClass("isWizard"); const w = containerEl.createDiv(""); const screenElements = {}; const addScreenElement = (key, element2) => { if (!(key in screenElements)) { screenElements[key] = []; } screenElements[key].push(element2); }; w.addClass("sls-setting-menu"); w.innerHTML = ` `; const menuTabs = w.querySelectorAll(".sls-setting-label"); const changeDisplay = (screen) => { for (const k in screenElements) { if (k == screen) { screenElements[k].forEach((element2) => element2.removeClass("setting-collapsed")); } else { screenElements[k].forEach((element2) => element2.addClass("setting-collapsed")); } } w.querySelectorAll(`.sls-setting-label`).forEach((element2) => { element2.removeClass("selected"); element2.querySelector("input[type=radio]").checked = false; }); w.querySelectorAll(`.sls-setting-label.c-${screen}`).forEach((element2) => { element2.addClass("selected"); element2.querySelector("input[type=radio]").checked = true; }); this.selectedScreen = screen; }; menuTabs.forEach((element2) => { const e2 = element2.querySelector(".sls-setting-tab"); if (!e2) return; e2.addEventListener("change", (event) => { menuTabs.forEach((element3) => element3.removeClass("selected")); changeDisplay(event.currentTarget.value); element2.addClass("selected"); }); }); const containerInformationEl = containerEl.createDiv(); const h3El = containerInformationEl.createEl("h3", { text: "Updates" }); const informationDivEl = containerInformationEl.createEl("div", { text: "" }); const manifestVersion = "0.18.6"; const updateInformation = "### 0.18.0\n\n#### Now, paths of files in the database can now be obfuscated. (Experimental Feature)\nAt before v0.18.0, Self-hosted LiveSync used the path of files, to detect and resolve conflicts. In naive. The ID of the document stored in the CouchDB was naturally the filename.\nHowever, it means a sort of lacking confidentiality. If the credentials of the database have been leaked, the attacker (or an innocent bystander) can read the path of files. So we could not use confidential things in the filename in some environments.\nSince v0.18.0, they can be obfuscated. so it is no longer possible to decipher the path from the ID. Instead of that, it costs a bit CPU load than before, and the data structure has been changed a bit.\n\nWe can configure the `Path Obfuscation` in the `Remote database configuration` pane. \nNote: **When changing this configuration, we need to rebuild both of the local and the remote databases**.\n\n#### Minors \n- 0.18.1\n - Fixed:\n - Some messages are fixed (Typo)\n - File type detection now works fine!\n- 0.18.2\n - Improved:\n - The setting pane has been refined.\n - We can enable `hidden files sync` with several initial behaviours; `Merge`, `Fetch` remote, and `Overwrite` remote.\n - No longer `Touch hidden files`.\n- 0.18.3\n - Fixed Pop-up is now correctly shown after hidden file synchronisation.\n- 0.18.4\n - Fixed:\n - `Fetch` and `Rebuild database` will work more safely.\n - Case-sensitive renaming now works fine.\n Revoked the logic which was made at #130, however, looks fine now.\n- 0.18.5\n - Improved:\n - Actions for maintaining databases moved to the `\u{1F39B}\uFE0FMaintain databases`.\n - Clean-up of unreferenced chunks has been implemented on an **experimental**.\n - This feature requires enabling `Use new adapter`.\n - Be sure to fully all devices synchronised before perform it.\n - After cleaning up the remote, all devices will be locked out. If we are sure had it be synchronised, we can perform only cleaning-up locally. If not, we have to perform `Fetch`.\n\n- 0.18.6\n - New features:\n - Now remote database cleaning-up will be detected automatically.\n - A solution selection dialogue will be shown if synchronisation is rejected after cleaning or rebuilding the remote database.\n - During fetching or rebuilding, we can configure `Hidden file synchronisation` on the spot.\n - It let us free from conflict resolution on initial synchronising.\n\n... To continue on to `updates_old.md`.\n"; const lastVersion = ~~(versionNumberString2Number(manifestVersion) / 1e3); const tmpDiv = createSpan(); tmpDiv.addClass("sls-header-button"); tmpDiv.innerHTML = ``; if (lastVersion > this.plugin.settings.lastReadUpdates) { const informationButtonDiv = h3El.appendChild(tmpDiv); informationButtonDiv.querySelector("button").addEventListener("click", async () => { this.plugin.settings.lastReadUpdates = lastVersion; await this.plugin.saveSettings(); informationButtonDiv.remove(); }); } import_obsidian.MarkdownRenderer.renderMarkdown(updateInformation, informationDivEl, "/", null); addScreenElement("100", containerInformationEl); const isAnySyncEnabled = () => { if (this.plugin.settings.liveSync) return true; if (this.plugin.settings.periodicReplication) return true; if (this.plugin.settings.syncOnFileOpen) return true; if (this.plugin.settings.syncOnSave) return true; if (this.plugin.settings.syncOnStart) return true; if (this.plugin.settings.syncAfterMerge) return true; if (this.plugin.replicator.syncStatus == "CONNECTED") return true; if (this.plugin.replicator.syncStatus == "PAUSED") return true; return false; }; let inWizard = false; const setupWizardEl = containerEl.createDiv(); setupWizardEl.createEl("h3", { text: "Setup wizard" }); new import_obsidian.Setting(setupWizardEl).setName("Discard the existing configuration and set up").addButton((text2) => { text2.setButtonText("Next").onClick(() => { if (JSON.stringify(this.plugin.settings) != JSON.stringify(DEFAULT_SETTINGS)) { this.plugin.replicator.closeReplication(); this.plugin.settings = { ...DEFAULT_SETTINGS }; this.plugin.saveSettings(); Logger("Configuration has been flushed, please open it again", LOG_LEVEL.NOTICE); this.plugin.app.setting.close(); } else { containerEl.addClass("isWizard"); applyDisplayEnabled(); inWizard = true; changeDisplay("0"); } }); }); new import_obsidian.Setting(setupWizardEl).setName("Do not discard the existing configuration and set up again").addButton((text2) => { text2.setButtonText("Next").onClick(async () => { this.plugin.settings.liveSync = false; this.plugin.settings.periodicReplication = false; this.plugin.settings.syncOnSave = false; this.plugin.settings.syncOnStart = false; this.plugin.settings.syncOnFileOpen = false; this.plugin.settings.syncAfterMerge = false; this.plugin.replicator.closeReplication(); await this.plugin.saveSettings(); containerEl.addClass("isWizard"); applyDisplayEnabled(); inWizard = true; changeDisplay("0"); }); }); const infoWarnForSubsequent = setupWizardEl.createEl("div", { text: `To set up second or subsequent device, please use 'Copy setup URI' and 'Open setup URI'` }); infoWarnForSubsequent.addClass("op-warn-info"); new import_obsidian.Setting(setupWizardEl).setName("Copy setup URI").addButton((text2) => { text2.setButtonText("Copy setup URI").onClick(() => { this.plugin.app.commands.executeCommandById("obsidian-livesync:livesync-copysetupuri"); }); }).addButton((text2) => { text2.setButtonText("Open setup URI").onClick(() => { this.plugin.app.commands.executeCommandById("obsidian-livesync:livesync-opensetupuri"); }); }); addScreenElement("110", setupWizardEl); const containerRemoteDatabaseEl = containerEl.createDiv(); containerRemoteDatabaseEl.createEl("h3", { text: "Remote Database configuration" }); const syncWarn = containerRemoteDatabaseEl.createEl("div", { text: `These settings are kept locked while any synchronization options are enabled. Disable these options in the "Sync Settings" tab to unlock.` }); syncWarn.addClass("op-warn-info"); syncWarn.addClass("sls-hidden"); const applyDisplayEnabled = () => { if (isAnySyncEnabled()) { dbSettings.forEach((e2) => { e2.setDisabled(true).setTooltip("Could not change this while any synchronization options are enabled."); }); syncWarn.removeClass("sls-hidden"); } else { dbSettings.forEach((e2) => { e2.setDisabled(false).setTooltip(""); }); syncWarn.addClass("sls-hidden"); } if (this.plugin.settings.liveSync) { syncNonLive.forEach((e2) => { e2.setDisabled(true).setTooltip(""); }); syncLive.forEach((e2) => { e2.setDisabled(false).setTooltip(""); }); } else if (this.plugin.settings.syncOnFileOpen || this.plugin.settings.syncOnSave || this.plugin.settings.syncOnStart || this.plugin.settings.periodicReplication || this.plugin.settings.syncAfterMerge) { syncNonLive.forEach((e2) => { e2.setDisabled(false).setTooltip(""); }); syncLive.forEach((e2) => { e2.setDisabled(true).setTooltip(""); }); } else { syncNonLive.forEach((e2) => { e2.setDisabled(false).setTooltip(""); }); syncLive.forEach((e2) => { e2.setDisabled(false).setTooltip(""); }); } }; const dbSettings = []; dbSettings.push( new import_obsidian.Setting(containerRemoteDatabaseEl).setName("URI").addText( (text2) => text2.setPlaceholder("https://........").setValue(this.plugin.settings.couchDB_URI).onChange(async (value) => { this.plugin.settings.couchDB_URI = value; await this.plugin.saveSettings(); }) ), new import_obsidian.Setting(containerRemoteDatabaseEl).setName("Username").setDesc("username").addText( (text2) => text2.setPlaceholder("").setValue(this.plugin.settings.couchDB_USER).onChange(async (value) => { this.plugin.settings.couchDB_USER = value; await this.plugin.saveSettings(); }) ), new import_obsidian.Setting(containerRemoteDatabaseEl).setName("Password").setDesc("password").addText((text2) => { text2.setPlaceholder("").setValue(this.plugin.settings.couchDB_PASSWORD).onChange(async (value) => { this.plugin.settings.couchDB_PASSWORD = value; await this.plugin.saveSettings(); }); text2.inputEl.setAttribute("type", "password"); }), new import_obsidian.Setting(containerRemoteDatabaseEl).setName("Database name").addText( (text2) => text2.setPlaceholder("").setValue(this.plugin.settings.couchDB_DBNAME).onChange(async (value) => { this.plugin.settings.couchDB_DBNAME = value; await this.plugin.saveSettings(); }) ) ); const e2e = new import_obsidian.Setting(containerRemoteDatabaseEl).setName("End to End Encryption").setDesc("Encrypt contents on the remote database. If you use the plugin's synchronization feature, enabling this is recommend.").addToggle( (toggle) => toggle.setValue(encrypt2).onChange(async (value) => { if (inWizard) { this.plugin.settings.encrypt = value; passphraseSetting.setDisabled(!value); dynamicIteration.setDisabled(!value); usePathObfuscationEl.setDisabled(!value); await this.plugin.saveSettings(); } else { encrypt2 = value; passphraseSetting.setDisabled(!value); dynamicIteration.setDisabled(!value); usePathObfuscationEl.setDisabled(!value); await this.plugin.saveSettings(); markDirtyControl(); } }) ); const markDirtyControl = () => { passphraseSetting.controlEl.toggleClass("sls-item-dirty", passphrase != this.plugin.settings.passphrase); e2e.controlEl.toggleClass("sls-item-dirty", encrypt2 != this.plugin.settings.encrypt); dynamicIteration.controlEl.toggleClass("sls-item-dirty", useDynamicIterationCount != this.plugin.settings.useDynamicIterationCount); usePathObfuscationEl.controlEl.toggleClass("sls-item-dirty", usePathObfuscation != this.plugin.settings.usePathObfuscation); }; const passphraseSetting = new import_obsidian.Setting(containerRemoteDatabaseEl).setName("Passphrase").setDesc("Encrypting passphrase. If you change the passphrase of a existing database, overwriting the remote database is strongly recommended.").addText((text2) => { text2.setPlaceholder("").setValue(passphrase).onChange(async (value) => { if (inWizard) { this.plugin.settings.passphrase = value; await this.plugin.saveSettings(); } else { passphrase = value; await this.plugin.saveSettings(); markDirtyControl(); } }); text2.inputEl.setAttribute("type", "password"); }); passphraseSetting.setDisabled(!encrypt2); let usePathObfuscation = this.plugin.settings.usePathObfuscation; const usePathObfuscationEl = new import_obsidian.Setting(containerRemoteDatabaseEl).setName("Path Obfuscation").setDesc("(Experimental) Obfuscate paths of files. If we configured, we should rebuild the database.").addToggle( (toggle) => toggle.setValue(usePathObfuscation).onChange(async (value) => { if (inWizard) { this.plugin.settings.usePathObfuscation = value; await this.plugin.saveSettings(); } else { usePathObfuscation = value; await this.plugin.saveSettings(); markDirtyControl(); } }) ); const dynamicIteration = new import_obsidian.Setting(containerRemoteDatabaseEl).setName("Use dynamic iteration count (experimental)").setDesc("Balancing the encryption/decryption load against the length of the passphrase if toggled. (v0.17.5 or higher required)").addToggle((toggle) => { toggle.setValue(useDynamicIterationCount).onChange(async (value) => { if (inWizard) { this.plugin.settings.useDynamicIterationCount = value; await this.plugin.saveSettings(); } else { useDynamicIterationCount = value; await this.plugin.saveSettings(); markDirtyControl(); } }); }).setClass("wizardHidden"); dynamicIteration.setDisabled(!encrypt2); const checkWorkingPassphrase = async () => { const settingForCheck = { ...this.plugin.settings, encrypt: encrypt2, passphrase, useDynamicIterationCount }; console.dir(settingForCheck); const db = await this.plugin.replicator.connectRemoteCouchDBWithSetting(settingForCheck, this.plugin.isMobile); if (typeof db === "string") { Logger("Could not connect to the database.", LOG_LEVEL.NOTICE); return false; } else { if (await checkSyncInfo(db.db)) { return true; } else { Logger("Failed to read remote database", LOG_LEVEL.NOTICE); return false; } } }; const applyEncryption = async (sendToServer) => { if (encrypt2 && passphrase == "") { Logger("If you enable encryption, you have to set the passphrase", LOG_LEVEL.NOTICE); return; } if (encrypt2 && !await testCrypt()) { Logger("WARNING! Your device would not support encryption.", LOG_LEVEL.NOTICE); return; } if (!await checkWorkingPassphrase() && !sendToServer) { return; } if (!encrypt2) { passphrase = ""; } this.plugin.addOnSetup.suspendAllSync(); this.plugin.addOnSetup.suspendExtraSync(); this.plugin.settings.encrypt = encrypt2; this.plugin.settings.passphrase = passphrase; this.plugin.settings.useDynamicIterationCount = useDynamicIterationCount; this.plugin.settings.usePathObfuscation = usePathObfuscation; await this.plugin.saveSettings(); markDirtyControl(); if (sendToServer) { await this.plugin.addOnSetup.rebuildRemote(); } else { await this.plugin.markRemoteResolved(); await this.plugin.replicate(true); } }; new import_obsidian.Setting(containerRemoteDatabaseEl).setName("Apply").setDesc("Apply encryption settings").setClass("wizardHidden").addButton( (button) => button.setButtonText("Just apply").setWarning().setDisabled(false).onClick(async () => { await applyEncryption(false); }) ).addButton( (button) => button.setButtonText("Apply and Fetch").setWarning().setDisabled(false).onClick(async () => { await rebuildDB("localOnly"); }) ).addButton( (button) => button.setButtonText("Apply and Rebuild").setWarning().setDisabled(false).onClick(async () => { await rebuildDB("rebuildBothByThisDevice"); }) ); const rebuildDB = async (method) => { if (encrypt2 && passphrase == "") { Logger("If you enable encryption, you have to set the passphrase", LOG_LEVEL.NOTICE); return; } if (encrypt2 && !await testCrypt()) { Logger("WARNING! Your device would not support encryption.", LOG_LEVEL.NOTICE); return; } if (!encrypt2) { passphrase = ""; } this.plugin.addOnSetup.suspendAllSync(); this.plugin.addOnSetup.suspendExtraSync(); this.plugin.settings.encrypt = encrypt2; this.plugin.settings.passphrase = passphrase; this.plugin.settings.useDynamicIterationCount = useDynamicIterationCount; this.plugin.settings.usePathObfuscation = usePathObfuscation; Logger("All synchronization have been temporarily disabled. Please enable them after the fetching, if you need them.", LOG_LEVEL.NOTICE); await this.plugin.saveSettings(); markDirtyControl(); applyDisplayEnabled(); this.plugin.app.setting.close(); await delay(2e3); await performRebuildDB(this.plugin, method); }; new import_obsidian.Setting(containerRemoteDatabaseEl).setName("Test Database Connection").setDesc("Open database connection. If the remote database is not found and you have the privilege to create a database, the database will be created.").addButton( (button) => button.setButtonText("Test").setDisabled(false).onClick(async () => { await this.testConnection(); }) ); new import_obsidian.Setting(containerRemoteDatabaseEl).setName("Check database configuration").addButton( (button) => button.setButtonText("Check").setDisabled(false).onClick(async () => { const checkConfig = async () => { var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k; try { if (isCloudantURI(this.plugin.settings.couchDB_URI)) { Logger("This feature cannot be used with IBM Cloudant.", LOG_LEVEL.NOTICE); return; } const r = await requestToCouchDB(this.plugin.settings.couchDB_URI, this.plugin.settings.couchDB_USER, this.plugin.settings.couchDB_PASSWORD, window.origin); Logger(JSON.stringify(r.json, null, 2)); const responseConfig = r.json; const emptyDiv = createDiv(); emptyDiv.innerHTML = ""; checkResultDiv.replaceChildren(...[emptyDiv]); const addResult = (msg, classes) => { const tmpDiv2 = createDiv(); tmpDiv2.addClass("ob-btn-config-fix"); if (classes) { tmpDiv2.addClasses(classes); } tmpDiv2.innerHTML = `${msg}`; checkResultDiv.appendChild(tmpDiv2); }; const addConfigFixButton = (title, key, value) => { const tmpDiv2 = createDiv(); tmpDiv2.addClass("ob-btn-config-fix"); tmpDiv2.innerHTML = ``; const x = checkResultDiv.appendChild(tmpDiv2); x.querySelector("button").addEventListener("click", async () => { console.dir({ key, value }); const res2 = await requestToCouchDB(this.plugin.settings.couchDB_URI, this.plugin.settings.couchDB_USER, this.plugin.settings.couchDB_PASSWORD, void 0, key, value); console.dir(res2); if (res2.status == 200) { Logger(`${title} successfully updated`, LOG_LEVEL.NOTICE); checkResultDiv.removeChild(x); checkConfig(); } else { Logger(`${title} failed`, LOG_LEVEL.NOTICE); Logger(res2.text); } }); }; addResult("---Notice---", ["ob-btn-config-head"]); addResult( "If the server configuration is not persistent (e.g., running on docker), the values set from here will also be volatile. Once you are able to connect, please reflect the settings in the server's local.ini.", ["ob-btn-config-info"] ); addResult("Your configuration is dumped to Log", ["ob-btn-config-info"]); addResult("--Config check--", ["ob-btn-config-head"]); if (!(this.plugin.settings.couchDB_USER in responseConfig.admins)) { addResult(`\u26A0 You do not have administrative privileges.`); } else { addResult("\u2714 You have administrative privileges."); } if (((_a = responseConfig == null ? void 0 : responseConfig.chttpd) == null ? void 0 : _a.require_valid_user) != "true") { addResult("\u2757 chttpd.require_valid_user looks like wrong."); addConfigFixButton("Set chttpd.require_valid_user = true", "chttpd/require_valid_user", "true"); } else { addResult("\u2714 chttpd.require_valid_user is ok."); } if (((_b = responseConfig == null ? void 0 : responseConfig.chttpd_auth) == null ? void 0 : _b.require_valid_user) != "true") { addResult("\u2757 chttpd_auth.require_valid_user looks like wrong."); addConfigFixButton("Set chttpd_auth.require_valid_user = true", "chttpd_auth/require_valid_user", "true"); } else { addResult("\u2714 chttpd_auth.require_valid_user is ok."); } if (!(responseConfig == null ? void 0 : responseConfig.httpd["WWW-Authenticate"])) { addResult("\u2757 httpd.WWW-Authenticate is missing"); addConfigFixButton("Set httpd.WWW-Authenticate", "httpd/WWW-Authenticate", 'Basic realm="couchdb"'); } else { addResult("\u2714 httpd.WWW-Authenticate is ok."); } if (((_c = responseConfig == null ? void 0 : responseConfig.httpd) == null ? void 0 : _c.enable_cors) != "true") { addResult("\u2757 httpd.enable_cors is wrong"); addConfigFixButton("Set httpd.enable_cors", "httpd/enable_cors", "true"); } else { addResult("\u2714 httpd.enable_cors is ok."); } if (!isCloudantURI(this.plugin.settings.couchDB_URI)) { if (Number((_e = (_d = responseConfig == null ? void 0 : responseConfig.chttpd) == null ? void 0 : _d.max_http_request_size) != null ? _e : 0) < 4294967296) { addResult("\u2757 chttpd.max_http_request_size is low)"); addConfigFixButton("Set chttpd.max_http_request_size", "chttpd/max_http_request_size", "4294967296"); } else { addResult("\u2714 chttpd.max_http_request_size is ok."); } if (Number((_g = (_f = responseConfig == null ? void 0 : responseConfig.couchdb) == null ? void 0 : _f.max_document_size) != null ? _g : 0) < 5e7) { addResult("\u2757 couchdb.max_document_size is low)"); addConfigFixButton("Set couchdb.max_document_size", "couchdb/max_document_size", "50000000"); } else { addResult("\u2714 couchdb.max_document_size is ok."); } } if (((_h = responseConfig == null ? void 0 : responseConfig.cors) == null ? void 0 : _h.credentials) != "true") { addResult("\u2757 cors.credentials is wrong"); addConfigFixButton("Set cors.credentials", "cors/credentials", "true"); } else { addResult("\u2714 cors.credentials is ok."); } const ConfiguredOrigins = (((_j = (_i = responseConfig == null ? void 0 : responseConfig.cors) == null ? void 0 : _i.origins) != null ? _j : "") + "").split(","); if (((_k = responseConfig == null ? void 0 : responseConfig.cors) == null ? void 0 : _k.origins) == "*" || ConfiguredOrigins.indexOf("app://obsidian.md") !== -1 && ConfiguredOrigins.indexOf("capacitor://localhost") !== -1 && ConfiguredOrigins.indexOf("http://localhost") !== -1) { addResult("\u2714 cors.origins is ok."); } else { addResult("\u2757 cors.origins is wrong"); addConfigFixButton("Set cors.origins", "cors/origins", "app://obsidian.md,capacitor://localhost,http://localhost"); } addResult("--Connection check--", ["ob-btn-config-head"]); addResult(`Current origin:${window.location.origin}`); const origins = ["app://obsidian.md", "capacitor://localhost", "http://localhost"]; for (const org of origins) { const rr = await requestToCouchDB(this.plugin.settings.couchDB_URI, this.plugin.settings.couchDB_USER, this.plugin.settings.couchDB_PASSWORD, org); const responseHeaders = Object.entries(rr.headers).map((e2) => { e2[0] = (e2[0] + "").toLowerCase(); return e2; }).reduce((obj, [key, val]) => { obj[key] = val; return obj; }, {}); addResult(`Origin check:${org}`); if (responseHeaders["access-control-allow-credentials"] != "true") { addResult("\u2757 CORS is not allowing credential"); } else { addResult("\u2714 CORS credential OK"); } if (responseHeaders["access-control-allow-origin"] != org) { addResult(`\u2757 CORS Origin is unmatched:${origin}->${responseHeaders["access-control-allow-origin"]}`); } else { addResult("\u2714 CORS origin OK"); } } addResult("--Done--", ["ob-btn-config-head"]); addResult("If you have some trouble with Connection-check even though all Config-check has been passed, Please check your reverse proxy's configuration.", ["ob-btn-config-info"]); } catch (ex) { Logger(`Checking configuration failed`, LOG_LEVEL.NOTICE); Logger(ex); } }; await checkConfig(); }) ); const checkResultDiv = containerRemoteDatabaseEl.createEl("div", { text: "" }); let rebuildRemote = false; new import_obsidian.Setting(containerRemoteDatabaseEl).setName("").setClass("wizardOnly").addButton( (button) => button.setButtonText("Next").setClass("mod-cta").setDisabled(false).onClick(() => { if (!this.plugin.settings.encrypt) { this.plugin.settings.passphrase = ""; } if (isCloudantURI(this.plugin.settings.couchDB_URI)) { this.plugin.settings.customChunkSize = 0; } else { this.plugin.settings.customChunkSize = 100; } rebuildRemote = false; changeDisplay("10"); }) ); new import_obsidian.Setting(containerRemoteDatabaseEl).setName("").setClass("wizardOnly").addButton( (button) => button.setButtonText("Discard exist database and proceed").setDisabled(false).setWarning().onClick(() => { if (!this.plugin.settings.encrypt) { this.plugin.settings.passphrase = ""; } if (isCloudantURI(this.plugin.settings.couchDB_URI)) { this.plugin.settings.customChunkSize = 0; } else { this.plugin.settings.customChunkSize = 100; } rebuildRemote = true; changeDisplay("10"); }) ); addScreenElement("0", containerRemoteDatabaseEl); const containerLocalDatabaseEl = containerEl.createDiv(); containerLocalDatabaseEl.createEl("h3", { text: "Local Database configuration" }); new import_obsidian.Setting(containerLocalDatabaseEl).setName("Batch database update").setDesc("Delay all changes, save once before replication or opening another file.").setClass("wizardHidden").addToggle( (toggle) => toggle.setValue(this.plugin.settings.batchSave).onChange(async (value) => { if (value && this.plugin.settings.liveSync) { Logger("LiveSync and Batch database update cannot be used at the same time.", LOG_LEVEL.NOTICE); toggle.setValue(false); return; } this.plugin.settings.batchSave = value; await this.plugin.saveSettings(); }) ); let newDatabaseName = this.plugin.settings.additionalSuffixOfDatabaseName + ""; new import_obsidian.Setting(containerLocalDatabaseEl).setName("Database suffix").setDesc("Optional: Set unique name for using same vault name on different directory.").addText((text2) => { text2.setPlaceholder("").setValue(newDatabaseName).onChange((value) => { newDatabaseName = value; }); }).addButton((button) => { button.setButtonText("Change").onClick(async () => { if (this.plugin.settings.additionalSuffixOfDatabaseName == newDatabaseName) { Logger("Suffix was not changed.", LOG_LEVEL.NOTICE); return; } this.plugin.settings.additionalSuffixOfDatabaseName = newDatabaseName; await this.plugin.saveSettings(); Logger("Suffix has been changed. Reopening database...", LOG_LEVEL.NOTICE); await this.plugin.initializeDatabase(); }); }); new import_obsidian.Setting(containerLocalDatabaseEl).setName("").setClass("wizardOnly").addButton( (button) => button.setButtonText("Next").setDisabled(false).onClick(() => { changeDisplay("40"); }) ); containerLocalDatabaseEl.createEl("h3", { text: (0, import_obsidian.sanitizeHTMLToDom)(`Experimental`), cls: "wizardHidden" }); new import_obsidian.Setting(containerLocalDatabaseEl).setName("Use new adapter").setDesc("This option is not compatible with a database made by older versions. Changing this configuration will fetch the remote database again.").setClass("wizardHidden").addToggle( (toggle) => toggle.setValue(this.plugin.settings.useIndexedDBAdapter).onChange(async (value) => { this.plugin.settings.useIndexedDBAdapter = value; await this.plugin.saveSettings(); await rebuildDB("localOnly"); }) ); addScreenElement("10", containerLocalDatabaseEl); const containerGeneralSettingsEl = containerEl.createDiv(); containerGeneralSettingsEl.createEl("h3", { text: "General Settings" }); new import_obsidian.Setting(containerGeneralSettingsEl).setName("Do not show low-priority Log").setDesc("Reduce log information").addToggle( (toggle) => toggle.setValue(this.plugin.settings.lessInformationInLog).onChange(async (value) => { this.plugin.settings.lessInformationInLog = value; await this.plugin.saveSettings(); }) ); new import_obsidian.Setting(containerGeneralSettingsEl).setName("Verbose Log").setDesc("Show verbose log").addToggle( (toggle) => toggle.setValue(this.plugin.settings.showVerboseLog).onChange(async (value) => { this.plugin.settings.showVerboseLog = value; await this.plugin.saveSettings(); }) ); new import_obsidian.Setting(containerGeneralSettingsEl).setName("Delete metadata of deleted files.").setClass("wizardHidden").addToggle( (toggle) => { toggle.setValue(this.plugin.settings.deleteMetadataOfDeletedFiles).onChange(async (value) => { this.plugin.settings.deleteMetadataOfDeletedFiles = value; await this.plugin.saveSettings(); }); } ); new import_obsidian.Setting(containerGeneralSettingsEl).setName("Delete old metadata of deleted files on start-up").setClass("wizardHidden").setDesc("(Days passed, 0 to disable automatic-deletion)").addText((text2) => { text2.setPlaceholder("").setValue(this.plugin.settings.automaticallyDeleteMetadataOfDeletedFiles + "").onChange(async (value) => { let v = Number(value); if (isNaN(v)) { v = 0; } this.plugin.settings.automaticallyDeleteMetadataOfDeletedFiles = v; await this.plugin.saveSettings(); }); text2.inputEl.setAttribute("type", "number"); }); new import_obsidian.Setting(containerGeneralSettingsEl).setName("Monitor changes to hidden files and plugin").addToggle( (toggle) => toggle.setValue(this.plugin.settings.watchInternalFileChanges).onChange(async (value) => { this.plugin.settings.watchInternalFileChanges = value; await this.plugin.saveSettings(); }) ); addScreenElement("20", containerGeneralSettingsEl); const containerSyncSettingEl = containerEl.createDiv(); containerSyncSettingEl.createEl("h3", { text: "Sync Settings" }); containerSyncSettingEl.addClass("wizardHidden"); if (this.plugin.settings.versionUpFlash != "") { const c = containerSyncSettingEl.createEl("div", { text: this.plugin.settings.versionUpFlash }); c.createEl("button", { text: "I got it and updated." }, (e2) => { e2.addClass("mod-cta"); e2.addEventListener("click", async () => { this.plugin.settings.versionUpFlash = ""; await this.plugin.saveSettings(); applyDisplayEnabled(); c.remove(); }); }); c.addClass("op-warn"); } containerSyncSettingEl.createEl("h3", { text: "Synchronization Methods" }); const syncLive = []; const syncNonLive = []; syncLive.push( new import_obsidian.Setting(containerSyncSettingEl).setName("LiveSync").setDesc("Sync realtime").addToggle( (toggle) => toggle.setValue(this.plugin.settings.liveSync).onChange(async (value) => { if (value && this.plugin.settings.batchSave) { Logger("LiveSync and Batch database update cannot be used at the same time.", LOG_LEVEL.NOTICE); toggle.setValue(false); return; } this.plugin.settings.liveSync = value; await this.plugin.saveSettings(); applyDisplayEnabled(); await this.plugin.realizeSettingSyncMode(); }) ) ); syncNonLive.push( new import_obsidian.Setting(containerSyncSettingEl).setName("Periodic Sync").setDesc("Sync periodically").addToggle( (toggle) => toggle.setValue(this.plugin.settings.periodicReplication).onChange(async (value) => { this.plugin.settings.periodicReplication = value; await this.plugin.saveSettings(); applyDisplayEnabled(); }) ), new import_obsidian.Setting(containerSyncSettingEl).setName("Periodic Sync interval").setDesc("Interval (sec)").addText((text2) => { text2.setPlaceholder("").setValue(this.plugin.settings.periodicReplicationInterval + "").onChange(async (value) => { let v = Number(value); if (isNaN(v) || v > 5e3) { v = 0; } this.plugin.settings.periodicReplicationInterval = v; await this.plugin.saveSettings(); applyDisplayEnabled(); }); text2.inputEl.setAttribute("type", "number"); }), new import_obsidian.Setting(containerSyncSettingEl).setName("Sync on Save").setDesc("When you save file, sync automatically").addToggle( (toggle) => toggle.setValue(this.plugin.settings.syncOnSave).onChange(async (value) => { this.plugin.settings.syncOnSave = value; await this.plugin.saveSettings(); applyDisplayEnabled(); }) ), new import_obsidian.Setting(containerSyncSettingEl).setName("Sync on File Open").setDesc("When you open file, sync automatically").addToggle( (toggle) => toggle.setValue(this.plugin.settings.syncOnFileOpen).onChange(async (value) => { this.plugin.settings.syncOnFileOpen = value; await this.plugin.saveSettings(); applyDisplayEnabled(); }) ), new import_obsidian.Setting(containerSyncSettingEl).setName("Sync on Start").setDesc("Start synchronization after launching Obsidian.").addToggle( (toggle) => toggle.setValue(this.plugin.settings.syncOnStart).onChange(async (value) => { this.plugin.settings.syncOnStart = value; await this.plugin.saveSettings(); applyDisplayEnabled(); }) ), new import_obsidian.Setting(containerSyncSettingEl).setName("Sync after merging file").setDesc("Sync automatically after merging files").addToggle( (toggle) => toggle.setValue(this.plugin.settings.syncAfterMerge).onChange(async (value) => { this.plugin.settings.syncAfterMerge = value; await this.plugin.saveSettings(); applyDisplayEnabled(); }) ) ); containerSyncSettingEl.createEl("h3", { text: "File deletion" }); new import_obsidian.Setting(containerSyncSettingEl).setName("Use Trash for deleted files").setDesc("Do not delete files that are deleted in remote, just move to trash.").addToggle( (toggle) => toggle.setValue(this.plugin.settings.trashInsteadDelete).onChange(async (value) => { this.plugin.settings.trashInsteadDelete = value; await this.plugin.saveSettings(); }) ); new import_obsidian.Setting(containerSyncSettingEl).setName("Do not delete empty folder").setDesc("Normally, a folder is deleted when it becomes empty after a replication. Enabling this will prevent it from getting deleted").addToggle( (toggle) => toggle.setValue(this.plugin.settings.doNotDeleteFolder).onChange(async (value) => { this.plugin.settings.doNotDeleteFolder = value; await this.plugin.saveSettings(); }) ); containerSyncSettingEl.createEl("h3", { text: "Conflict resolution" }); new import_obsidian.Setting(containerSyncSettingEl).setName("Use newer file if conflicted (beta)").setDesc("Resolve conflicts by newer files automatically.").addToggle( (toggle) => toggle.setValue(this.plugin.settings.resolveConflictsByNewerFile).onChange(async (value) => { this.plugin.settings.resolveConflictsByNewerFile = value; await this.plugin.saveSettings(); }) ); new import_obsidian.Setting(containerSyncSettingEl).setName("Check conflict only on opened files").setDesc("Do not check conflict for replication").addToggle( (toggle) => toggle.setValue(this.plugin.settings.checkConflictOnlyOnOpen).onChange(async (value) => { this.plugin.settings.checkConflictOnlyOnOpen = value; await this.plugin.saveSettings(); }) ); new import_obsidian.Setting(containerSyncSettingEl).setName("Disable sensible auto merging on markdown files").setDesc("If this switch is turned on, a merge dialog will be displayed, even if the sensible-merge is possible automatically. (Turn on to previous behavior)").addToggle( (toggle) => toggle.setValue(this.plugin.settings.disableMarkdownAutoMerge).onChange(async (value) => { this.plugin.settings.disableMarkdownAutoMerge = value; await this.plugin.saveSettings(); }) ); new import_obsidian.Setting(containerSyncSettingEl).setName("Write documents after synchronization even if they have conflict").setDesc("Turn on to previous behavior").addToggle( (toggle) => toggle.setValue(this.plugin.settings.writeDocumentsIfConflicted).onChange(async (value) => { this.plugin.settings.writeDocumentsIfConflicted = value; await this.plugin.saveSettings(); }) ); containerSyncSettingEl.createEl("h3", { text: "Hidden files" }); const LABEL_ENABLED = "\u{1F501} : Enabled"; const LABEL_DISABLED = "\u23F9\uFE0F : Disabled"; const hiddenFileSyncSetting = new import_obsidian.Setting(containerSyncSettingEl).setName("Hidden file synchronization"); const hiddenFileSyncSettingEl = hiddenFileSyncSetting.settingEl; const hiddenFileSyncSettingDiv = hiddenFileSyncSettingEl.createDiv(""); hiddenFileSyncSettingDiv.innerText = this.plugin.settings.syncInternalFiles ? LABEL_ENABLED : LABEL_DISABLED; if (this.plugin.settings.syncInternalFiles) { new import_obsidian.Setting(containerSyncSettingEl).setName("Disable Hidden files sync").addButton((button) => { button.setButtonText("Disable").onClick(async () => { this.plugin.settings.syncInternalFiles = false; await this.plugin.saveSettings(); this.display(); }); }); } else { new import_obsidian.Setting(containerSyncSettingEl).setName("Enable Hidden files sync").addButton((button) => { button.setButtonText("Merge").onClick(async () => { this.plugin.app.setting.close(); await this.plugin.addOnSetup.configureHiddenFileSync("MERGE"); }); }).addButton((button) => { button.setButtonText("Fetch").onClick(async () => { this.plugin.app.setting.close(); await this.plugin.addOnSetup.configureHiddenFileSync("FETCH"); }); }).addButton((button) => { button.setButtonText("Overwrite").onClick(async () => { this.plugin.app.setting.close(); await this.plugin.addOnSetup.configureHiddenFileSync("OVERWRITE"); }); }); } new import_obsidian.Setting(containerSyncSettingEl).setName("Scan for hidden files before replication").setDesc("This configuration will be ignored if monitoring changes is enabled.").addToggle( (toggle) => toggle.setValue(this.plugin.settings.syncInternalFilesBeforeReplication).onChange(async (value) => { this.plugin.settings.syncInternalFilesBeforeReplication = value; await this.plugin.saveSettings(); }) ); new import_obsidian.Setting(containerSyncSettingEl).setName("Scan hidden files periodically").setDesc("Seconds, 0 to disable. This configuration will be ignored if monitoring changes is enabled.").addText((text2) => { text2.setPlaceholder("").setValue(this.plugin.settings.syncInternalFilesInterval + "").onChange(async (value) => { let v = Number(value); if (isNaN(v) || v < 10) { v = 10; } this.plugin.settings.syncInternalFilesInterval = v; await this.plugin.saveSettings(); }); text2.inputEl.setAttribute("type", "number"); }); let skipPatternTextArea = null; const defaultSkipPattern = "\\/node_modules\\/, \\/\\.git\\/, \\/obsidian-livesync\\/"; const defaultSkipPatternXPlat = defaultSkipPattern + ",\\/workspace$ ,\\/workspace.json$"; new import_obsidian.Setting(containerSyncSettingEl).setName("Skip patterns").setDesc( "Regular expression, If you use hidden file sync between desktop and mobile, adding `workspace$` is recommended." ).addTextArea( (text2) => { text2.setValue(this.plugin.settings.syncInternalFilesIgnorePatterns).setPlaceholder("\\/node_modules\\/, \\/\\.git\\/").onChange(async (value) => { this.plugin.settings.syncInternalFilesIgnorePatterns = value; await this.plugin.saveSettings(); }); skipPatternTextArea = text2; return text2; } ); new import_obsidian.Setting(containerSyncSettingEl).setName("Restore the skip pattern to default").addButton((button) => { button.setButtonText("Default").onClick(async () => { skipPatternTextArea.setValue(defaultSkipPattern); this.plugin.settings.syncInternalFilesIgnorePatterns = defaultSkipPattern; await this.plugin.saveSettings(); }); }).addButton((button) => { button.setButtonText("Cross-platform").onClick(async () => { skipPatternTextArea.setValue(defaultSkipPatternXPlat); this.plugin.settings.syncInternalFilesIgnorePatterns = defaultSkipPatternXPlat; await this.plugin.saveSettings(); }); }); containerSyncSettingEl.createEl("h3", { text: (0, import_obsidian.sanitizeHTMLToDom)(`Synchronization filters`) }); new import_obsidian.Setting(containerSyncSettingEl).setName("Regular expression to ignore files").setDesc("If this is set, any changes to local and remote files that match this will be skipped.").addTextArea( (text2) => { text2.setValue(this.plugin.settings.syncIgnoreRegEx).setPlaceholder("\\.pdf$").onChange(async (value) => { let isValidRegExp = false; try { new RegExp(value); isValidRegExp = true; } catch (_) { } if (isValidRegExp || value.trim() == "") { this.plugin.settings.syncIgnoreRegEx = value; await this.plugin.saveSettings(); } }); return text2; } ); new import_obsidian.Setting(containerSyncSettingEl).setName("Regular expression for restricting synchronization targets").setDesc("If this is set, changes to local and remote files that only match this will be processed.").addTextArea( (text2) => { text2.setValue(this.plugin.settings.syncOnlyRegEx).setPlaceholder("\\.md$|\\.txt").onChange(async (value) => { let isValidRegExp = false; try { new RegExp(value); isValidRegExp = true; } catch (_) { } if (isValidRegExp || value.trim() == "") { this.plugin.settings.syncOnlyRegEx = value; await this.plugin.saveSettings(); } }); return text2; } ); containerSyncSettingEl.createEl("h3", { text: "Efficiency" }); new import_obsidian.Setting(containerSyncSettingEl).setName("Chunk size").setDesc("Customize chunk size for binary files (0.1MBytes). This cannot be increased when using IBM Cloudant.").addText((text2) => { text2.setPlaceholder("").setValue(this.plugin.settings.customChunkSize + "").onChange(async (value) => { let v = Number(value); if (isNaN(v) || v < 1) { v = 1; } this.plugin.settings.customChunkSize = v; await this.plugin.saveSettings(); }); text2.inputEl.setAttribute("type", "number"); }); new import_obsidian.Setting(containerSyncSettingEl).setName("Read chunks online").setDesc("If this option is enabled, LiveSync reads chunks online directly instead of replicating them locally. Increasing Custom chunk size is recommended.").addToggle((toggle) => { toggle.setValue(this.plugin.settings.readChunksOnline).onChange(async (value) => { this.plugin.settings.readChunksOnline = value; await this.plugin.saveSettings(); }); return toggle; }); containerSyncSettingEl.createEl("h3", { text: (0, import_obsidian.sanitizeHTMLToDom)(`Advanced settings`) }); containerSyncSettingEl.createEl("div", { text: `If you reached the payload size limit when using IBM Cloudant, please decrease batch size and batch limit to a lower value.` }); new import_obsidian.Setting(containerSyncSettingEl).setName("Batch size").setDesc("Number of change feed items to process at a time. Defaults to 250.").addText((text2) => { text2.setPlaceholder("").setValue(this.plugin.settings.batch_size + "").onChange(async (value) => { let v = Number(value); if (isNaN(v) || v < 10) { v = 10; } this.plugin.settings.batch_size = v; await this.plugin.saveSettings(); }); text2.inputEl.setAttribute("type", "number"); }); new import_obsidian.Setting(containerSyncSettingEl).setName("Batch limit").setDesc("Number of batches to process at a time. Defaults to 40. This along with batch size controls how many docs are kept in memory at a time.").addText((text2) => { text2.setPlaceholder("").setValue(this.plugin.settings.batches_limit + "").onChange(async (value) => { let v = Number(value); if (isNaN(v) || v < 10) { v = 10; } this.plugin.settings.batches_limit = v; await this.plugin.saveSettings(); }); text2.inputEl.setAttribute("type", "number"); }); new import_obsidian.Setting(containerSyncSettingEl).setName("Use timeouts instead of heartbeats").setDesc("If this option is enabled, PouchDB will hold the connection open for 60 seconds, and if no change arrives in that time, close and reopen the socket, instead of holding it open indefinitely. Useful when a proxy limits request duration but can increase resource usage.").addToggle( (toggle) => { toggle.setValue(this.plugin.settings.useTimeouts).onChange(async (value) => { this.plugin.settings.useTimeouts = value; await this.plugin.saveSettings(); }); return toggle; } ); new import_obsidian.Setting(containerSyncSettingEl).setName("A number of hashes to be cached").setDesc("").addText((text2) => { text2.setPlaceholder("").setValue(this.plugin.settings.hashCacheMaxCount + "").onChange(async (value) => { let v = Number(value); if (isNaN(v) || v < 10) { v = 10; } this.plugin.settings.hashCacheMaxCount = v; await this.plugin.saveSettings(); }); text2.inputEl.setAttribute("type", "number"); }); new import_obsidian.Setting(containerSyncSettingEl).setName("The total length of hashes to be cached").setDesc("(Mega chars)").addText((text2) => { text2.setPlaceholder("").setValue(this.plugin.settings.hashCacheMaxAmount + "").onChange(async (value) => { let v = Number(value); if (isNaN(v) || v < 1) { v = 1; } this.plugin.settings.hashCacheMaxAmount = v; await this.plugin.saveSettings(); }); text2.inputEl.setAttribute("type", "number"); }); new import_obsidian.Setting(containerSyncSettingEl).setName("The maximum number of reading chunks online concurrently").setDesc("").addText((text2) => { text2.setPlaceholder("").setValue(this.plugin.settings.concurrencyOfReadChunksOnline + "").onChange(async (value) => { let v = Number(value); if (isNaN(v) || v < 10) { v = 10; } this.plugin.settings.concurrencyOfReadChunksOnline = v; await this.plugin.saveSettings(); }); text2.inputEl.setAttribute("type", "number"); }); new import_obsidian.Setting(containerSyncSettingEl).setName("The minimum interval for reading chunks online").setDesc("").addText((text2) => { text2.setPlaceholder("").setValue(this.plugin.settings.minimumIntervalOfReadChunksOnline + "").onChange(async (value) => { let v = Number(value); if (isNaN(v) || v < 10) { v = 10; } this.plugin.settings.minimumIntervalOfReadChunksOnline = v; await this.plugin.saveSettings(); }); text2.inputEl.setAttribute("type", "number"); }); addScreenElement("30", containerSyncSettingEl); const containerMiscellaneousEl = containerEl.createDiv(); containerMiscellaneousEl.createEl("h3", { text: "Miscellaneous" }); new import_obsidian.Setting(containerMiscellaneousEl).setName("Show status inside editor").setDesc("").addToggle( (toggle) => toggle.setValue(this.plugin.settings.showStatusOnEditor).onChange(async (value) => { this.plugin.settings.showStatusOnEditor = value; await this.plugin.saveSettings(); }) ); let currentPreset = "NONE"; new import_obsidian.Setting(containerMiscellaneousEl).setName("Presets").setDesc("Apply preset configuration").addDropdown( (dropdown) => dropdown.addOptions({ NONE: "", LIVESYNC: "LiveSync", PERIODIC: "Periodic w/ batch", DISABLE: "Disable all sync" }).setValue(currentPreset).onChange((value) => currentPreset = value) ).addButton( (button) => button.setButtonText("Apply").setDisabled(false).setCta().onClick(async () => { if (currentPreset == "") { Logger("Select any preset.", LOG_LEVEL.NOTICE); return; } const presetAllDisabled = { batchSave: false, liveSync: false, periodicReplication: false, syncOnSave: false, syncOnStart: false, syncOnFileOpen: false, syncAfterMerge: false }; const presetLiveSync = { ...presetAllDisabled, liveSync: true }; const presetPeriodic = { ...presetAllDisabled, batchSave: true, periodicReplication: true, syncOnSave: false, syncOnStart: true, syncOnFileOpen: true, syncAfterMerge: true }; if (currentPreset == "LIVESYNC") { this.plugin.settings = { ...this.plugin.settings, ...presetLiveSync }; Logger("Synchronization setting configured as LiveSync.", LOG_LEVEL.NOTICE); } else if (currentPreset == "PERIODIC") { this.plugin.settings = { ...this.plugin.settings, ...presetPeriodic }; Logger("Synchronization setting configured as Periodic sync with batch database update.", LOG_LEVEL.NOTICE); } else { Logger("All synchronization disabled.", LOG_LEVEL.NOTICE); this.plugin.settings = { ...this.plugin.settings, ...presetAllDisabled }; } this.plugin.saveSettings(); this.display(); await this.plugin.realizeSettingSyncMode(); if (inWizard) { this.plugin.app.setting.close(); await this.plugin.resetLocalDatabase(); await this.plugin.initializeDatabase(true); if (rebuildRemote) { await this.plugin.markRemoteLocked(); await this.plugin.tryResetRemoteDatabase(); await this.plugin.markRemoteLocked(); await this.plugin.markRemoteResolved(); } await this.plugin.replicate(true); Logger("All done! Please set up subsequent devices with 'Copy setup URI' and 'Open setup URI'.", LOG_LEVEL.NOTICE); this.plugin.app.commands.executeCommandById("obsidian-livesync:livesync-copysetupuri"); } }) ); const passphrase_options = { "": "Default", LOCALSTORAGE: "Use a custom passphrase", ASK_AT_LAUNCH: "Ask an passphrase at every launch" }; new import_obsidian.Setting(containerMiscellaneousEl).setName("Encrypting sensitive configuration items").addDropdown( (dropdown) => dropdown.addOptions(passphrase_options).setValue(this.plugin.settings.configPassphraseStore).onChange(async (value) => { this.plugin.settings.configPassphraseStore = value; this.plugin.usedPassphrase = ""; confPassphraseSetting.setDisabled(this.plugin.settings.configPassphraseStore != "LOCALSTORAGE"); await this.plugin.saveSettings(); }) ).setClass("wizardHidden"); const confPassphrase = localStorage.getItem("ls-setting-passphrase") || ""; const confPassphraseSetting = new import_obsidian.Setting(containerMiscellaneousEl).setName("Passphrase of sensitive configuration items").setDesc("This passphrase will not be copied to another device. It will be set to `Default` until you configure it again.").addText((text2) => { text2.setPlaceholder("").setValue(confPassphrase).onChange(async (value) => { this.plugin.usedPassphrase = ""; localStorage.setItem("ls-setting-passphrase", value); await this.plugin.saveSettings(); markDirtyControl(); }); text2.inputEl.setAttribute("type", "password"); }).setClass("wizardHidden"); confPassphraseSetting.setDisabled(this.plugin.settings.configPassphraseStore != "LOCALSTORAGE"); const infoApply = containerMiscellaneousEl.createEl("div", { text: `To finish setup, please select one of the presets` }); infoApply.addClass("op-warn-info"); infoApply.addClass("wizardOnly"); addScreenElement("40", containerMiscellaneousEl); const containerHatchEl = containerEl.createDiv(); containerHatchEl.createEl("h3", { text: "Hatch" }); new import_obsidian.Setting(containerHatchEl).setName("Make report to inform the issue").addButton( (button) => button.setButtonText("Make report").setDisabled(false).onClick(async () => { let responseConfig = {}; const REDACTED = "\u{1D445}\u{1D438}\u{1D437}\u{1D434}\u{1D436}\u{1D447}\u{1D438}\u{1D437}"; try { const r = await requestToCouchDB(this.plugin.settings.couchDB_URI, this.plugin.settings.couchDB_USER, this.plugin.settings.couchDB_PASSWORD, window.origin); Logger(JSON.stringify(r.json, null, 2)); responseConfig = r.json; responseConfig["couch_httpd_auth"].secret = REDACTED; responseConfig["couch_httpd_auth"].authentication_db = REDACTED; responseConfig["couch_httpd_auth"].authentication_redirect = REDACTED; responseConfig["couchdb"].uuid = REDACTED; responseConfig["admins"] = REDACTED; } catch (ex) { responseConfig = "Requesting information to the remote CouchDB has been failed. If you are using IBM Cloudant, it is the normal behaviour."; } const pluginConfig = JSON.parse(JSON.stringify(this.plugin.settings)); pluginConfig.couchDB_DBNAME = REDACTED; pluginConfig.couchDB_PASSWORD = REDACTED; pluginConfig.couchDB_URI = isCloudantURI(pluginConfig.couchDB_URI) ? "cloudant" : "self-hosted"; pluginConfig.couchDB_USER = REDACTED; pluginConfig.passphrase = REDACTED; pluginConfig.encryptedPassphrase = REDACTED; pluginConfig.encryptedCouchDBConnection = REDACTED; const msgConfig = `----remote config---- ${(0, import_obsidian.stringifyYaml)(responseConfig)} ---- Plug-in config --- ${(0, import_obsidian.stringifyYaml)(pluginConfig)}`; console.log(msgConfig); await navigator.clipboard.writeText(msgConfig); Logger(`Information has been copied to clipboard`, LOG_LEVEL.NOTICE); }) ); if (this.plugin.replicator.remoteLockedAndDeviceNotAccepted) { const c = containerHatchEl.createEl("div", { text: "To prevent unwanted vault corruption, the remote database has been locked for synchronization, and this device was not marked as 'resolved'. it caused by some operations like this. re-initialized. Local database initialization should be required. please back your vault up, reset local database, and press 'Mark this device as resolved'. " }); c.createEl("button", { text: "I'm ready, mark this device 'resolved'" }, (e2) => { e2.addClass("mod-warning"); e2.addEventListener("click", async () => { await this.plugin.markRemoteResolved(); c.remove(); }); }); c.addClass("op-warn"); } else { if (this.plugin.replicator.remoteLocked) { const c = containerHatchEl.createEl("div", { text: "To prevent unwanted vault corruption, the remote database has been locked for synchronization. (This device is marked 'resolved') When all your devices are marked 'resolved', unlock the database." }); c.createEl("button", { text: "I'm ready, unlock the database" }, (e2) => { e2.addClass("mod-warning"); e2.addEventListener("click", async () => { await this.plugin.markRemoteUnlocked(); c.remove(); }); }); c.addClass("op-warn"); } } const hatchWarn = containerHatchEl.createEl("div", { text: `To stop the boot up sequence for fixing problems on databases, you can put redflag.md on top of your vault (Rebooting obsidian is required).` }); hatchWarn.addClass("op-warn-info"); new import_obsidian.Setting(containerHatchEl).setName("Verify and repair all files").setDesc("Verify and repair all files and update database without restoring").addButton( (button) => button.setButtonText("Verify and repair").setDisabled(false).setWarning().onClick(async () => { const semaphore = Semaphore(10); const files = this.app.vault.getFiles(); let i = 0; const processes = files.map((e2) => (async (file) => { const releaser = await semaphore.acquire(1, "verifyAndRepair"); try { Logger(`UPDATE DATABASE ${file.path}`); await this.plugin.updateIntoDB(file, false, null, true); i++; Logger(`${i}/${files.length} ${file.path}`, LOG_LEVEL.NOTICE, "verify"); } catch (ex) { i++; Logger(`Error while verifyAndRepair`, LOG_LEVEL.NOTICE); Logger(ex); } finally { releaser(); } })(e2)); await Promise.all(processes); Logger("done", LOG_LEVEL.NOTICE, "verify"); }) ); new import_obsidian.Setting(containerHatchEl).setName("Suspend file watching").setDesc("Stop watching for file change.").addToggle( (toggle) => toggle.setValue(this.plugin.settings.suspendFileWatching).onChange(async (value) => { this.plugin.settings.suspendFileWatching = value; await this.plugin.saveSettings(); }) ); new import_obsidian.Setting(containerHatchEl).setName("Write logs into the file").setDesc("Warning! This will have a serious impact on performance. And the logs will not be synchronised under the default name. Please be careful with logs; they often contain your confidential information.").addToggle( (toggle) => toggle.setValue(this.plugin.settings.writeLogToTheFile).onChange(async (value) => { this.plugin.settings.writeLogToTheFile = value; await this.plugin.saveSettings(); }) ); addScreenElement("50", containerHatchEl); const containerPluginSettings = containerEl.createDiv(); containerPluginSettings.createEl("h3", { text: "Plugins and settings (beta)" }); const updateDisabledOfDeviceAndVaultName = () => { vaultName.setDisabled(this.plugin.settings.autoSweepPlugins || this.plugin.settings.autoSweepPluginsPeriodic); vaultName.setTooltip(this.plugin.settings.autoSweepPlugins || this.plugin.settings.autoSweepPluginsPeriodic ? "You could not change when you enabling auto scan." : ""); }; new import_obsidian.Setting(containerPluginSettings).setName("Enable plugin synchronization").addToggle( (toggle) => toggle.setValue(this.plugin.settings.usePluginSync).onChange(async (value) => { this.plugin.settings.usePluginSync = value; await this.plugin.saveSettings(); }) ); new import_obsidian.Setting(containerPluginSettings).setName("Scan plugins automatically").setDesc("Scan plugins before replicating.").addToggle( (toggle) => toggle.setValue(this.plugin.settings.autoSweepPlugins).onChange(async (value) => { this.plugin.settings.autoSweepPlugins = value; updateDisabledOfDeviceAndVaultName(); await this.plugin.saveSettings(); }) ); new import_obsidian.Setting(containerPluginSettings).setName("Scan plugins periodically").setDesc("Scan plugins every 1 minute. This configuration will be ignored if monitoring changes of hidden files has been enabled.").addToggle( (toggle) => toggle.setValue(this.plugin.settings.autoSweepPluginsPeriodic).onChange(async (value) => { this.plugin.settings.autoSweepPluginsPeriodic = value; updateDisabledOfDeviceAndVaultName(); await this.plugin.saveSettings(); }) ); new import_obsidian.Setting(containerPluginSettings).setName("Notify updates").setDesc("Notify when any device has a newer plugin or its setting.").addToggle( (toggle) => toggle.setValue(this.plugin.settings.notifyPluginOrSettingUpdated).onChange(async (value) => { this.plugin.settings.notifyPluginOrSettingUpdated = value; await this.plugin.saveSettings(); }) ); const vaultName = new import_obsidian.Setting(containerPluginSettings).setName("Device and Vault name").setDesc("").addText((text2) => { text2.setPlaceholder("desktop-main").setValue(this.plugin.deviceAndVaultName).onChange(async (value) => { this.plugin.deviceAndVaultName = value; await this.plugin.saveSettings(); }); }); new import_obsidian.Setting(containerPluginSettings).setName("Open").setDesc("Open the plugin dialog").addButton((button) => { button.setButtonText("Open").setDisabled(false).onClick(() => { this.plugin.addOnPluginAndTheirSettings.showPluginSyncModal(); }); }); updateDisabledOfDeviceAndVaultName(); addScreenElement("60", containerPluginSettings); const containerMaintenanceEl = containerEl.createDiv(); containerMaintenanceEl.createEl("h3", { text: "Maintain databases" }); containerMaintenanceEl.createEl("h4", { text: "The remote database" }); new import_obsidian.Setting(containerMaintenanceEl).setName("Lock remote database").setDesc("Lock remote database to prevent synchronization with other devices.").addButton( (button) => button.setButtonText("Lock").setDisabled(false).setWarning().onClick(async () => { await this.plugin.markRemoteLocked(); }) ); new import_obsidian.Setting(containerMaintenanceEl).setName("Overwrite remote database").setDesc("Overwrite remote database with local DB and passphrase.").addButton( (button) => button.setButtonText("Send").setWarning().setDisabled(false).onClick(async () => { await rebuildDB("remoteOnly"); }) ); new import_obsidian.Setting(containerMaintenanceEl).setName("(Beta) Clean the remote database").setDesc("").addButton( (button) => button.setButtonText("Count").setDisabled(false).onClick(async () => { await remoteDatabaseCleanup(this.plugin, true); }) ).addButton( (button) => button.setButtonText("Perform cleaning").setDisabled(false).setWarning().onClick(async () => { this.plugin.app.setting.close(); await remoteDatabaseCleanup(this.plugin, false); await balanceChunks(this.plugin, false); }) ); containerMaintenanceEl.createEl("h4", { text: "The local database" }); new import_obsidian.Setting(containerMaintenanceEl).setName("Fetch rebuilt DB").setDesc("Restore or reconstruct local database from remote database.").addButton( (button) => button.setButtonText("Fetch").setWarning().setDisabled(false).onClick(async () => { await rebuildDB("localOnly"); }) ); new import_obsidian.Setting(containerMaintenanceEl).setName("(Beta) Clean the local database").setDesc("This feature requires enabling 'Use new Adapter'").addButton( (button) => button.setButtonText("Count").setDisabled(false).onClick(async () => { await localDatabaseCleanUp(this.plugin, false, true); }) ).addButton( (button) => button.setButtonText("Perform cleaning").setDisabled(false).setWarning().onClick(async () => { this.plugin.app.setting.close(); await localDatabaseCleanUp(this.plugin, false, false); }) ); new import_obsidian.Setting(containerMaintenanceEl).setName("Discard local database to reset or uninstall Self-hosted LiveSync").addButton( (button) => button.setButtonText("Discard").setWarning().setDisabled(false).onClick(async () => { await this.plugin.resetLocalDatabase(); await this.plugin.initializeDatabase(); }) ); containerMaintenanceEl.createEl("h4", { text: "Both databases" }); new import_obsidian.Setting(containerMaintenanceEl).setName("Rebuild everything").setDesc("Rebuild local and remote database with local files.").addButton( (button) => button.setButtonText("Rebuild").setWarning().setDisabled(false).onClick(async () => { await rebuildDB("rebuildBothByThisDevice"); }) ); new import_obsidian.Setting(containerMaintenanceEl).setName("(Beta) Complement each other with possible missing chunks.").setDesc("").addButton( (button) => button.setButtonText("Balance").setWarning().setDisabled(false).onClick(async () => { await balanceChunks(this.plugin, false); }) ); applyDisplayEnabled(); addScreenElement("70", containerMaintenanceEl); applyDisplayEnabled(); if (this.selectedScreen == "") { if (lastVersion != this.plugin.settings.lastReadUpdates) { if (JSON.stringify(this.plugin.settings) != JSON.stringify(DEFAULT_SETTINGS)) { changeDisplay("100"); } else { changeDisplay("110"); } } else { if (isAnySyncEnabled()) { changeDisplay("0"); } else { changeDisplay("110"); } } } else { changeDisplay(this.selectedScreen); } } }; // src/DocumentHistoryModal.ts var import_diff_match_patch2 = __toESM(require_diff_match_patch(), 1); var DocumentHistoryModal = class extends import_obsidian.Modal { constructor(app2, plugin2, file, id) { super(app2); this.showDiff = false; this.revs_info = []; this.currentText = ""; this.currentDeleted = false; this.plugin = plugin2; this.file = file instanceof import_obsidian.TFile ? getPathFromTFile(file) : file; this.id = id; if (!file) { this.file = this.plugin.id2path(id, null); } if (localStorage.getItem("ols-history-highlightdiff") == "1") { this.showDiff = true; } } async loadFile() { if (!this.id) { this.id = await this.plugin.path2id(this.file); } const db = this.plugin.localDatabase; try { const w = await db.localDatabase.get(this.id, { revs_info: true }); this.revs_info = w._revs_info.filter((e2) => (e2 == null ? void 0 : e2.status) == "available"); this.range.max = `${this.revs_info.length - 1}`; this.range.value = this.range.max; this.fileInfo.setText(`${this.file} / ${this.revs_info.length} revisions`); await this.loadRevs(); } catch (ex) { if (isErrorOfMissingDoc(ex)) { this.range.max = "0"; this.range.value = ""; this.range.disabled = true; this.showDiff; this.contentView.setText(`History of this file was not recorded.`); } else { this.contentView.setText(`Error occurred.`); Logger(ex, LOG_LEVEL.VERBOSE); } } } async loadRevs() { if (this.revs_info.length == 0) return; const db = this.plugin.localDatabase; const index5 = this.revs_info.length - 1 - this.range.value / 1; const rev2 = this.revs_info[index5]; const w = await db.getDBEntry(this.file, { rev: rev2.rev }, false, false, true); this.currentText = ""; this.currentDeleted = false; if (w === false) { this.currentDeleted = true; this.info.innerHTML = ""; this.contentView.innerHTML = `Could not read this revision
(${rev2.rev})`; } else { this.currentDoc = w; this.info.innerHTML = `Modified:${new Date(w.mtime).toLocaleString()}`; let result = ""; const w1data = w.datatype == "plain" ? getDocData(w.data) : base64ToString(w.data); this.currentDeleted = w.deleted; this.currentText = w1data; if (this.showDiff) { const prevRevIdx = this.revs_info.length - 1 - (this.range.value / 1 - 1); if (prevRevIdx >= 0 && prevRevIdx < this.revs_info.length) { const oldRev = this.revs_info[prevRevIdx].rev; const w2 = await db.getDBEntry(this.file, { rev: oldRev }, false, false, true); if (w2 != false) { const dmp = new import_diff_match_patch2.diff_match_patch(); const w2data = w2.datatype == "plain" ? getDocData(w2.data) : base64ToString(w2.data); const diff = dmp.diff_main(w2data, w1data); dmp.diff_cleanupSemantic(diff); for (const v of diff) { const x1 = v[0]; const x2 = v[1]; if (x1 == import_diff_match_patch2.DIFF_DELETE) { result += "" + escapeStringToHTML(x2) + ""; } else if (x1 == import_diff_match_patch2.DIFF_EQUAL) { result += "" + escapeStringToHTML(x2) + ""; } else if (x1 == import_diff_match_patch2.DIFF_INSERT) { result += "" + escapeStringToHTML(x2) + ""; } } result = result.replace(/\n/g, "
"); } else { result = escapeStringToHTML(w1data); } } else { result = escapeStringToHTML(w1data); } } else { result = escapeStringToHTML(w1data); } this.contentView.innerHTML = (this.currentDeleted ? "(At this revision, the file has been deleted)\n" : "") + result; } } onOpen() { const { contentEl } = this; contentEl.empty(); contentEl.createEl("h2", { text: "Document History" }); this.fileInfo = contentEl.createDiv(""); this.fileInfo.addClass("op-info"); const divView = contentEl.createDiv(""); divView.addClass("op-flex"); divView.createEl("input", { type: "range" }, (e2) => { this.range = e2; e2.addEventListener("change", (e3) => { this.loadRevs(); }); e2.addEventListener("input", (e3) => { this.loadRevs(); }); }); contentEl.createDiv("", (e2) => { e2.createEl("label", {}, (label) => { label.appendChild( createEl("input", { type: "checkbox" }, (checkbox) => { if (this.showDiff) { checkbox.checked = true; } checkbox.addEventListener("input", (evt) => { this.showDiff = checkbox.checked; localStorage.setItem("ols-history-highlightdiff", this.showDiff == true ? "1" : ""); this.loadRevs(); }); }) ); label.appendText("Highlight diff"); }); }).addClass("op-info"); this.info = contentEl.createDiv(""); this.info.addClass("op-info"); this.loadFile(); const div = contentEl.createDiv({ text: "Loading old revisions..." }); this.contentView = div; div.addClass("op-scrollable"); div.addClass("op-pre"); const buttons = contentEl.createDiv(""); buttons.createEl("button", { text: "Copy to clipboard" }, (e2) => { e2.addClass("mod-cta"); e2.addEventListener("click", async () => { await navigator.clipboard.writeText(this.currentText); Logger(`Old content copied to clipboard`, LOG_LEVEL.NOTICE); }); }); async function focusFile(path) { const targetFile = app.vault.getFiles().find((f3) => f3.path === path); if (targetFile) { const leaf = app.workspace.getLeaf(false); await leaf.openFile(targetFile); } else { Logger("The file could not view on the editor", LOG_LEVEL.NOTICE); } } buttons.createEl("button", { text: "Back to this revision" }, (e2) => { e2.addClass("mod-cta"); e2.addEventListener("click", async () => { var _a, _b; const pathToWrite = stripPrefix(this.file); if (!isValidPath(pathToWrite)) { Logger("Path is not valid to write content.", LOG_LEVEL.INFO); } if (((_a = this.currentDoc) == null ? void 0 : _a.datatype) == "plain") { await this.app.vault.adapter.write(pathToWrite, getDocData(this.currentDoc.data)); await focusFile(pathToWrite); this.close(); } else if (((_b = this.currentDoc) == null ? void 0 : _b.datatype) == "newnote") { await this.app.vault.adapter.writeBinary(pathToWrite, base64ToArrayBuffer(this.currentDoc.data)); await focusFile(pathToWrite); this.close(); } else { Logger(`Could not parse entry`, LOG_LEVEL.NOTICE); } }); }); } onClose() { const { contentEl } = this; contentEl.empty(); } }; // src/StorageEventManager.ts var StorageEventManager = class { }; var StorageEventManagerObsidian = class extends StorageEventManager { constructor(plugin2) { super(); this.queuedFilesStore = getGlobalStore("queuedFiles", { queuedItems: [], fileEventItems: [] }); this.watchedFileEventQueue = []; this.plugin = plugin2; this.watchVaultChange = this.watchVaultChange.bind(this); this.watchVaultCreate = this.watchVaultCreate.bind(this); this.watchVaultDelete = this.watchVaultDelete.bind(this); this.watchVaultRename = this.watchVaultRename.bind(this); this.watchVaultRawEvents = this.watchVaultRawEvents.bind(this); plugin2.registerEvent(app.vault.on("modify", this.watchVaultChange)); plugin2.registerEvent(app.vault.on("delete", this.watchVaultDelete)); plugin2.registerEvent(app.vault.on("rename", this.watchVaultRename)); plugin2.registerEvent(app.vault.on("create", this.watchVaultCreate)); plugin2.registerEvent(app.vault.on("raw", this.watchVaultRawEvents)); } watchVaultCreate(file, ctx) { this.appendWatchEvent([{ type: "CREATE", file }], ctx); } watchVaultChange(file, ctx) { this.appendWatchEvent([{ type: "CHANGED", file }], ctx); } watchVaultDelete(file, ctx) { this.appendWatchEvent([{ type: "DELETE", file }], ctx); } watchVaultRename(file, oldFile, ctx) { if (file instanceof import_obsidian.TFile) { this.appendWatchEvent([ { type: "DELETE", file: { path: oldFile, mtime: file.stat.mtime, ctime: file.stat.ctime, size: file.stat.size, deleted: true } }, { type: "CREATE", file } ], ctx); } } watchVaultRawEvents(path) { if (!this.plugin.settings.syncInternalFiles) return; if (!this.plugin.settings.watchInternalFileChanges) return; if (!path.startsWith(app.vault.configDir)) return; const ignorePatterns = this.plugin.settings.syncInternalFilesIgnorePatterns.replace(/\n| /g, "").split(",").filter((e2) => e2).map((e2) => new RegExp(e2, "i")); if (ignorePatterns.some((e2) => path.match(e2))) return; this.appendWatchEvent( [{ type: "INTERNAL", file: { path, mtime: 0, ctime: 0, size: 0 } }], null ); } async appendWatchEvent(params, ctx) { let forcePerform = false; for (const param of params) { if (shouldBeIgnored(param.file.path)) { continue; } const atomicKey = [0, 0, 0, 0, 0, 0].map((e2) => `${Math.floor(Math.random() * 1e5)}`).join("-"); const type = param.type; const file = param.file; const oldPath = param.oldPath; if (file instanceof import_obsidian.TFolder) continue; if (!this.plugin.isTargetFile(file.path)) continue; if (this.plugin.settings.suspendFileWatching) continue; let cache; if (file instanceof import_obsidian.TFile && (type == "CREATE" || type == "CHANGED")) { if (recentlyTouched(file)) { continue; } if (!isPlainText(file.name)) { cache = await app.vault.readBinary(file); } else { cache = await app.vault.cachedRead(file); if (!cache) cache = await app.vault.read(file); } } if (type == "DELETE" || type == "RENAME") { forcePerform = true; } if (this.plugin.settings.batchSave) { let i = this.watchedFileEventQueue.length; L1: while (i >= 0) { i--; if (i < 0) break L1; if (this.watchedFileEventQueue[i].args.file.path != file.path) { continue L1; } if (this.watchedFileEventQueue[i].type != type) break L1; this.watchedFileEventQueue.remove(this.watchedFileEventQueue[i]); this.queuedFilesStore.apply((value) => ({ ...value, fileEventItems: this.watchedFileEventQueue })); } } const fileInfo = file instanceof import_obsidian.TFile ? { ctime: file.stat.ctime, mtime: file.stat.mtime, file, path: file.path, size: file.stat.size } : file; this.watchedFileEventQueue.push({ type, args: { file: fileInfo, oldPath, cache, ctx }, key: atomicKey }); } this.queuedFilesStore.apply((value) => ({ ...value, fileEventItems: this.watchedFileEventQueue })); this.plugin.procFileEvent(forcePerform); } fetchEvent() { if (this.watchedFileEventQueue.length == 0) return false; const item = this.watchedFileEventQueue.shift(); this.queuedFilesStore.apply((value) => ({ ...value, fileEventItems: this.watchedFileEventQueue })); return item; } cancelRelativeEvent(item) { this.watchedFileEventQueue = [...this.watchedFileEventQueue].filter((e2) => e2.key != item.key); this.queuedFilesStore.apply((value) => ({ ...value, fileEventItems: this.watchedFileEventQueue })); } getQueueLength() { return this.watchedFileEventQueue.length; } }; // node_modules/xxhash-wasm/esm/xxhash-wasm.js var t = new Uint8Array([0, 97, 115, 109, 1, 0, 0, 0, 1, 13, 2, 96, 2, 127, 127, 0, 96, 3, 127, 127, 127, 1, 127, 3, 3, 2, 1, 0, 5, 3, 1, 0, 1, 7, 23, 3, 3, 109, 101, 109, 2, 0, 5, 120, 120, 104, 51, 50, 0, 0, 5, 120, 120, 104, 54, 52, 0, 1, 10, 152, 9, 2, 242, 2, 1, 4, 127, 32, 0, 32, 1, 106, 33, 3, 32, 1, 32, 1, 65, 16, 79, 4, 127, 32, 3, 65, 16, 107, 33, 6, 32, 2, 65, 168, 136, 141, 161, 2, 106, 33, 1, 32, 2, 65, 137, 235, 208, 208, 7, 107, 33, 4, 32, 2, 65, 207, 140, 162, 142, 6, 106, 33, 5, 3, 64, 32, 1, 32, 0, 40, 2, 0, 65, 247, 148, 175, 175, 120, 108, 106, 65, 13, 119, 65, 177, 243, 221, 241, 121, 108, 33, 1, 32, 4, 32, 0, 65, 4, 106, 34, 0, 40, 2, 0, 65, 247, 148, 175, 175, 120, 108, 106, 65, 13, 119, 65, 177, 243, 221, 241, 121, 108, 33, 4, 32, 2, 32, 0, 65, 4, 106, 34, 0, 40, 2, 0, 65, 247, 148, 175, 175, 120, 108, 106, 65, 13, 119, 65, 177, 243, 221, 241, 121, 108, 33, 2, 32, 5, 32, 0, 65, 4, 106, 34, 0, 40, 2, 0, 65, 247, 148, 175, 175, 120, 108, 106, 65, 13, 119, 65, 177, 243, 221, 241, 121, 108, 33, 5, 32, 6, 32, 0, 65, 4, 106, 34, 0, 79, 13, 0, 11, 32, 2, 65, 12, 119, 32, 5, 65, 18, 119, 106, 32, 4, 65, 7, 119, 106, 32, 1, 65, 1, 119, 106, 5, 32, 2, 65, 177, 207, 217, 178, 1, 106, 11, 106, 33, 2, 3, 64, 32, 3, 32, 0, 65, 4, 106, 79, 4, 64, 32, 2, 32, 0, 40, 2, 0, 65, 189, 220, 202, 149, 124, 108, 106, 65, 17, 119, 65, 175, 214, 211, 190, 2, 108, 33, 2, 32, 0, 65, 4, 106, 33, 0, 12, 1, 11, 11, 3, 64, 32, 0, 32, 3, 73, 4, 64, 32, 2, 32, 0, 45, 0, 0, 65, 177, 207, 217, 178, 1, 108, 106, 65, 11, 119, 65, 177, 243, 221, 241, 121, 108, 33, 2, 32, 0, 65, 1, 106, 33, 0, 12, 1, 11, 11, 32, 2, 32, 2, 65, 15, 118, 115, 65, 247, 148, 175, 175, 120, 108, 34, 0, 65, 13, 118, 32, 0, 115, 65, 189, 220, 202, 149, 124, 108, 34, 0, 65, 16, 118, 32, 0, 115, 11, 161, 6, 2, 4, 126, 3, 127, 32, 0, 65, 4, 106, 53, 2, 0, 32, 0, 53, 2, 0, 66, 32, 134, 132, 33, 2, 32, 1, 32, 0, 65, 8, 106, 34, 6, 106, 33, 7, 32, 1, 65, 32, 79, 4, 126, 32, 7, 65, 32, 107, 33, 8, 32, 2, 66, 214, 235, 130, 238, 234, 253, 137, 245, 224, 0, 124, 33, 3, 32, 2, 66, 177, 169, 172, 193, 173, 184, 212, 166, 61, 125, 33, 4, 32, 2, 66, 249, 234, 208, 208, 231, 201, 161, 228, 225, 0, 124, 33, 5, 3, 64, 32, 3, 32, 6, 41, 3, 0, 66, 207, 214, 211, 190, 210, 199, 171, 217, 66, 126, 124, 66, 31, 137, 66, 135, 149, 175, 175, 152, 182, 222, 155, 158, 127, 126, 33, 3, 32, 4, 32, 6, 65, 8, 106, 34, 6, 41, 3, 0, 66, 207, 214, 211, 190, 210, 199, 171, 217, 66, 126, 124, 66, 31, 137, 66, 135, 149, 175, 175, 152, 182, 222, 155, 158, 127, 126, 33, 4, 32, 2, 32, 6, 65, 8, 106, 34, 6, 41, 3, 0, 66, 207, 214, 211, 190, 210, 199, 171, 217, 66, 126, 124, 66, 31, 137, 66, 135, 149, 175, 175, 152, 182, 222, 155, 158, 127, 126, 33, 2, 32, 5, 32, 6, 65, 8, 106, 34, 6, 41, 3, 0, 66, 207, 214, 211, 190, 210, 199, 171, 217, 66, 126, 124, 66, 31, 137, 66, 135, 149, 175, 175, 152, 182, 222, 155, 158, 127, 126, 33, 5, 32, 8, 32, 6, 65, 8, 106, 34, 6, 79, 13, 0, 11, 32, 2, 66, 12, 137, 32, 5, 66, 18, 137, 124, 32, 4, 66, 7, 137, 124, 32, 3, 66, 1, 137, 124, 32, 3, 66, 207, 214, 211, 190, 210, 199, 171, 217, 66, 126, 66, 31, 137, 66, 135, 149, 175, 175, 152, 182, 222, 155, 158, 127, 126, 133, 66, 135, 149, 175, 175, 152, 182, 222, 155, 158, 127, 126, 66, 157, 163, 181, 234, 131, 177, 141, 138, 250, 0, 125, 32, 4, 66, 207, 214, 211, 190, 210, 199, 171, 217, 66, 126, 66, 31, 137, 66, 135, 149, 175, 175, 152, 182, 222, 155, 158, 127, 126, 133, 66, 135, 149, 175, 175, 152, 182, 222, 155, 158, 127, 126, 66, 157, 163, 181, 234, 131, 177, 141, 138, 250, 0, 125, 32, 2, 66, 207, 214, 211, 190, 210, 199, 171, 217, 66, 126, 66, 31, 137, 66, 135, 149, 175, 175, 152, 182, 222, 155, 158, 127, 126, 133, 66, 135, 149, 175, 175, 152, 182, 222, 155, 158, 127, 126, 66, 157, 163, 181, 234, 131, 177, 141, 138, 250, 0, 125, 32, 5, 66, 207, 214, 211, 190, 210, 199, 171, 217, 66, 126, 66, 31, 137, 66, 135, 149, 175, 175, 152, 182, 222, 155, 158, 127, 126, 133, 66, 135, 149, 175, 175, 152, 182, 222, 155, 158, 127, 126, 66, 157, 163, 181, 234, 131, 177, 141, 138, 250, 0, 125, 5, 32, 2, 66, 197, 207, 217, 178, 241, 229, 186, 234, 39, 124, 11, 32, 1, 173, 124, 33, 2, 3, 64, 32, 7, 32, 6, 65, 8, 106, 79, 4, 64, 32, 2, 32, 6, 41, 3, 0, 66, 207, 214, 211, 190, 210, 199, 171, 217, 66, 126, 66, 31, 137, 66, 135, 149, 175, 175, 152, 182, 222, 155, 158, 127, 126, 133, 66, 27, 137, 66, 135, 149, 175, 175, 152, 182, 222, 155, 158, 127, 126, 66, 157, 163, 181, 234, 131, 177, 141, 138, 250, 0, 125, 33, 2, 32, 6, 65, 8, 106, 33, 6, 12, 1, 11, 11, 32, 6, 65, 4, 106, 32, 7, 77, 4, 64, 32, 2, 32, 6, 53, 2, 0, 66, 135, 149, 175, 175, 152, 182, 222, 155, 158, 127, 126, 133, 66, 23, 137, 66, 207, 214, 211, 190, 210, 199, 171, 217, 66, 126, 66, 249, 243, 221, 241, 153, 246, 153, 171, 22, 124, 33, 2, 32, 6, 65, 4, 106, 33, 6, 11, 3, 64, 32, 6, 32, 7, 73, 4, 64, 32, 2, 32, 6, 49, 0, 0, 66, 197, 207, 217, 178, 241, 229, 186, 234, 39, 126, 133, 66, 11, 137, 66, 135, 149, 175, 175, 152, 182, 222, 155, 158, 127, 126, 33, 2, 32, 6, 65, 1, 106, 33, 6, 12, 1, 11, 11, 32, 0, 32, 2, 32, 2, 66, 33, 136, 133, 66, 207, 214, 211, 190, 210, 199, 171, 217, 66, 126, 34, 2, 66, 29, 136, 32, 2, 133, 66, 249, 243, 221, 241, 153, 246, 153, 171, 22, 126, 34, 2, 66, 32, 136, 32, 2, 133, 34, 2, 66, 32, 136, 62, 2, 0, 32, 0, 65, 4, 106, 32, 2, 62, 2, 0, 11]); var e; function n(t2, e2, n2) { if (e2.buffer.byteLength < t2.byteLength + n2) { const i = Math.ceil((t2.byteLength + n2 - e2.buffer.byteLength) / 65536); e2.grow(i); } new Uint8Array(e2.buffer, n2).set(t2); } async function xxhash_wasm_default() { const { instance: { exports: { mem: i, xxh32: o, xxh64: r } } } = await WebAssembly.instantiate(t); function h2(t2) { let e2 = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : 0; return n(t2, i, 0), o(0, t2.byteLength, e2) >>> 0; } function c(t2) { let e2 = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : 0, o2 = arguments.length > 2 && void 0 !== arguments[2] ? arguments[2] : 0; n(t2, i, 8); const h3 = new DataView(i.buffer); return h3.setUint32(0, e2, true), h3.setUint32(4, o2, true), r(0, t2.byteLength), h3; } return { h32: function(t2) { let n2 = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : 0; e || (e = new TextEncoder()); const i2 = e.encode(t2); return h2(i2, n2).toString(16); }, h32Raw: h2, h64: function(t2) { let n2 = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : 0, i2 = arguments.length > 2 && void 0 !== arguments[2] ? arguments[2] : 0; e || (e = new TextEncoder()); const o2 = e.encode(t2), r2 = c(o2, n2, i2), h3 = r2.getUint32(0, true).toString(16) + r2.getUint32(4, true).toString(16); return h3; }, h64Raw: function(t2) { let e2 = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : 0, n2 = arguments.length > 2 && void 0 !== arguments[2] ? arguments[2] : 0; return new Uint8Array(c(t2, e2, n2).buffer, 0, 8); } }; } // src/lib/src/LiveSyncDBFunctions.ts async function putDBEntry(env, note, saveAsBigChunk) { var _a; const filename = env.id2path(note._id, note); if (!env.isTargetFile(filename)) { return false; } const dispFilename = stripAllPrefixes(filename); const savedNotes = []; let processed = 0; let made = 0; let skipped = 0; const maxChunkSize = MAX_DOC_SIZE_BIN * Math.max(env.settings.customChunkSize, 1); const pieceSize = maxChunkSize; let plainSplit = false; let cacheUsed = 0; const userPasswordHash = env.h32Raw(new TextEncoder().encode(env.settings.passphrase)); const minimumChunkSize = env.settings.minimumChunkSize; if (!saveAsBigChunk && shouldSplitAsPlainText(filename)) { plainSplit = true; } const newLeafs = []; const pieces = splitPieces2(note.data, pieceSize, plainSplit, minimumChunkSize, 0); const currentDocPiece = /* @__PURE__ */ new Map(); let saved = true; for (const piece of pieces()) { processed++; let leafId = ""; let hashedPiece = ""; const cache = env.hashCaches.revGet(piece); if (cache) { hashedPiece = ""; leafId = cache; skipped++; cacheUsed++; currentDocPiece.set(leafId, piece); } else { if (env.settings.encrypt) { hashedPiece = "+" + (env.h32Raw(new TextEncoder().encode(piece)) ^ userPasswordHash ^ piece.length).toString(36); } else { hashedPiece = (env.h32Raw(new TextEncoder().encode(piece)) ^ piece.length).toString(36); } leafId = "h:" + hashedPiece; } if (currentDocPiece.has(leafId)) { if (currentDocPiece.get(leafId) != piece) { Logger(`Hash collided! If possible, please report the following string A:--${currentDocPiece.get(leafId)}-- B:--${piece}--`, LOG_LEVEL.NOTICE); Logger(`This document could not be saved:${dispFilename}`, LOG_LEVEL.NOTICE); saved = false; } } else { currentDocPiece.set(leafId, piece); } savedNotes.push(leafId); } const newChunkIds = [...currentDocPiece.keys()]; do { const procChunks = newChunkIds.splice(0, 100); if (procChunks.length > 0) { const existChunks = await env.localDatabase.allDocs({ keys: [...procChunks], include_docs: true }); for (const chunk of existChunks.rows) { if ("error" in chunk && chunk.error == "not_found") { const data = currentDocPiece.get(chunk.key); if (typeof data === "undefined") { Logger("Saving chunk error: Missing data:" + chunk.key); console.log(data); saved = false; continue; } const d = { _id: chunk.key, data, type: "leaf" }; newLeafs.push(d); } else if ("error" in chunk) { Logger("Saving chunk error: " + chunk.error); saved = false; } else { const pieceData = chunk.doc; if (pieceData.type == "leaf" && pieceData.data == currentDocPiece.get(chunk.key)) { skipped++; } else if (pieceData.type == "leaf") { Logger(`Hash collided on saving! If possible, please report the following string A:--${currentDocPiece.get(chunk.key)}-- B:--${pieceData.data}--`, LOG_LEVEL.NOTICE); Logger(`This document could not be saved:${dispFilename}`, LOG_LEVEL.NOTICE); saved = false; } } } } } while (newChunkIds.length > 0); if (newLeafs.length > 0) { try { const result = await env.localDatabase.bulkDocs(newLeafs); for (const item of result) { if ("ok" in item) { const id = item.id; const pieceData = currentDocPiece.get(id); if (typeof pieceData === "undefined") { saved = false; Logger(`Save failed.: ${dispFilename} (${item.id} rev:${item.rev})`, LOG_LEVEL.NOTICE); continue; } env.hashCaches.set(id, pieceData); made++; } else { if ((item == null ? void 0 : item.status) == 409) { skipped++; } else { Logger(`Save failed..: ${dispFilename} (${item.id} rev:${item.rev})`, LOG_LEVEL.NOTICE); Logger(item); saved = false; } } } } catch (ex) { Logger("Chunk save failed:", LOG_LEVEL.NOTICE); Logger(ex, LOG_LEVEL.NOTICE); saved = false; } } if (saved) { Logger(`Content saved:${dispFilename} ,chunks: ${processed} (new:${made}, skip:${skipped}, cache:${cacheUsed})`); const newDoc = { children: savedNotes, _id: note._id, path: note.path, ctime: note.ctime, mtime: note.mtime, size: note.size, type: note.datatype }; return (_a = await runWithLock("file:" + filename, false, async () => { try { const old = await env.localDatabase.get(newDoc._id); if (!old.type || old.type == "notes" || old.type == "newnote" || old.type == "plain") { newDoc._rev = old._rev; } } catch (ex) { if (isErrorOfMissingDoc(ex)) { } else { throw ex; } } const r = await env.localDatabase.put(newDoc, { force: true }); if (typeof env.corruptedEntries[note._id] != "undefined") { delete env.corruptedEntries[note._id]; } if (r.ok) { return r; } else { return false; } })) != null ? _a : false; } else { Logger(`note could not saved:${dispFilename}`); return false; } } async function getDBEntryMeta(env, path, opt, includeDeleted = false) { if (!env.isTargetFile(path)) { return false; } const id = await env.path2id(path); try { let obj = null; if (opt) { obj = await env.localDatabase.get(id, opt); } else { obj = await env.localDatabase.get(id); } const deleted = "deleted" in obj ? obj.deleted : void 0; if (!includeDeleted && deleted) return false; if (obj.type && obj.type == "leaf") { return false; } if (!obj.type || obj.type && obj.type == "notes" || obj.type == "newnote" || obj.type == "plain") { const note = obj; let children2 = []; let type = "plain"; if (obj.type == "newnote" || obj.type == "plain") { children2 = obj.children; type = obj.type; } const doc = { data: "", _id: note._id, path, ctime: note.ctime, mtime: note.mtime, size: note.size, _rev: obj._rev, _conflicts: obj._conflicts, children: children2, datatype: type, deleted, type }; return doc; } } catch (ex) { if (isErrorOfMissingDoc(ex)) { return false; } throw ex; } return false; } async function getDBEntryFromMeta(env, obj, opt, dump = false, waitForReady = true, includeDeleted = false) { const filename = env.id2path(obj._id, obj); if (!env.isTargetFile(filename)) { return false; } const dispFilename = stripAllPrefixes(filename); const deleted = "deleted" in obj ? obj.deleted : void 0; if (!obj.type || obj.type && obj.type == "notes") { const note = obj; const doc = { data: note.data, path: note.path, _id: note._id, ctime: note.ctime, mtime: note.mtime, size: note.size, _rev: obj._rev, _conflicts: obj._conflicts, children: [], datatype: "newnote", deleted, type: "newnote" }; if (typeof env.corruptedEntries[doc._id] != "undefined") { delete env.corruptedEntries[doc._id]; } if (dump) { Logger(`Simple doc`); Logger(doc); } return doc; } if (obj.type == "newnote" || obj.type == "plain") { try { if (dump) { Logger(`Enhanced doc`); Logger(obj); } let children2 = []; if (env.settings.readChunksOnline) { const items = await env.collectChunks(obj.children, false, waitForReady); if (items) { for (const v of items) { if (v && v.type == "leaf") { children2.push(v.data); } else { if (!opt) { Logger(`Chunks of ${dispFilename} (${obj._id}) are not valid.`, LOG_LEVEL.NOTICE); env.corruptedEntries[obj._id] = obj; } return false; } } } else { if (opt) { Logger(`Could not retrieve chunks of ${dispFilename} (${obj._id}). we have to `, LOG_LEVEL.NOTICE); } return false; } } else { try { if (waitForReady) { children2 = await Promise.all(obj.children.map((e2) => env.getDBLeaf(e2, waitForReady))); if (dump) { Logger(`Chunks:`); Logger(children2); } } else { const chunkDocs = await env.localDatabase.allDocs({ keys: obj.children, include_docs: true }); if (chunkDocs.rows.some((e2) => "error" in e2)) { const missingChunks = chunkDocs.rows.filter((e2) => "error" in e2).map((e2) => e2.id).join(", "); Logger(`Could not retrieve chunks of ${dispFilename}(${obj._id}). Chunks are missing:${missingChunks}`, LOG_LEVEL.NOTICE); return false; } if (chunkDocs.rows.some((e2) => e2.doc && e2.doc.type != "leaf")) { const missingChunks = chunkDocs.rows.filter((e2) => e2.doc && e2.doc.type != "leaf").map((e2) => e2.id).join(", "); Logger(`Could not retrieve chunks of ${dispFilename}(${obj._id}). corrupted chunks::${missingChunks}`, LOG_LEVEL.NOTICE); return false; } children2 = chunkDocs.rows.map((e2) => e2.doc.data); } } catch (ex) { Logger(`Something went wrong on reading chunks of ${dispFilename}(${obj._id}) from database, see verbose info for detail.`, LOG_LEVEL.NOTICE); Logger(ex, LOG_LEVEL.VERBOSE); env.corruptedEntries[obj._id] = obj; return false; } } const data = children2; const doc = { data, path: obj.path, _id: obj._id, ctime: obj.ctime, mtime: obj.mtime, size: obj.size, _rev: obj._rev, children: obj.children, datatype: obj.type, _conflicts: obj._conflicts, deleted, type: obj.type }; if (dump) { Logger(`therefore:`); Logger(doc); } if (typeof env.corruptedEntries[doc._id] != "undefined") { delete env.corruptedEntries[doc._id]; } return doc; } catch (ex) { if (isErrorOfMissingDoc(ex)) { Logger(`Missing document content!, could not read ${dispFilename}(${obj._id}) from database.`, LOG_LEVEL.NOTICE); return false; } Logger(`Something went wrong on reading ${dispFilename}(${obj._id}) from database:`, LOG_LEVEL.NOTICE); Logger(ex); } } return false; } async function getDBEntry(env, path, opt, dump = false, waitForReady = true, includeDeleted = false) { const meta = await getDBEntryMeta(env, path, opt, includeDeleted); if (meta) { return await getDBEntryFromMeta(env, meta, opt, dump, waitForReady, includeDeleted); } else { return false; } } async function deleteDBEntry(env, path, opt) { var _a; if (!env.isTargetFile(path)) { return false; } const id = await env.path2id(path); try { return (_a = await runWithLock("file:" + path, false, async () => { let obj = null; if (opt) { obj = await env.localDatabase.get(id, opt); } else { obj = await env.localDatabase.get(id); } const revDeletion = opt && ("rev" in opt ? opt.rev : "") != ""; if (obj.type && obj.type == "leaf") { return false; } if (!obj.type || obj.type && obj.type == "notes") { obj._deleted = true; const r = await env.localDatabase.put(obj); Logger(`Entry removed:${path} (${obj._id}-${r.rev})`); if (typeof env.corruptedEntries[obj._id] != "undefined") { delete env.corruptedEntries[obj._id]; } return true; } if (obj.type == "newnote" || obj.type == "plain") { if (revDeletion) { obj._deleted = true; } else { obj.deleted = true; obj.mtime = Date.now(); if (env.settings.deleteMetadataOfDeletedFiles) { obj._deleted = true; } } const r = await env.localDatabase.put(obj); Logger(`Entry removed:${path} (${obj._id}-${r.rev})`); if (typeof env.corruptedEntries[obj._id] != "undefined") { delete env.corruptedEntries[obj._id]; } return true; } else { return false; } })) != null ? _a : false; } catch (ex) { if (isErrorOfMissingDoc(ex)) { return false; } throw ex; } } async function deleteDBEntryPrefix(env, prefix) { let c = 0; let readCount = 0; const delDocs = []; do { const result = await env.localDatabase.allDocs({ include_docs: false, skip: c, limit: 100, conflicts: true }); readCount = result.rows.length; if (readCount > 0) { for (const v of result.rows) { const decodedPath = env.id2path(v.id, v.doc); if (decodedPath.startsWith(prefix)) { if (env.isTargetFile(decodedPath)) delDocs.push(v.id); } else { if (!v.id.startsWith("h:")) { } } } } c += readCount; } while (readCount != 0); let deleteCount = 0; let notfound = 0; for (const v of delDocs) { try { await runWithLock("file:" + v, false, async () => { const item = await env.localDatabase.get(v); if (item.type == "newnote" || item.type == "plain") { item.deleted = true; if (env.settings.deleteMetadataOfDeletedFiles) { item._deleted = true; } item.mtime = Date.now(); } else { item._deleted = true; } await env.localDatabase.put(item); }); deleteCount++; } catch (ex) { if (isErrorOfMissingDoc(ex)) { notfound++; } else { throw ex; } } } Logger(`deleteDBEntryPrefix:deleted ${deleteCount} items, skipped ${notfound}`); return true; } async function ensureDatabaseIsCompatible(db, setting, deviceNodeID, currentVersionRange2) { const defMilestonePoint = { _id: MILSTONE_DOCID, type: "milestoneinfo", created: new Date() / 1, locked: false, accepted_nodes: [deviceNodeID], node_chunk_info: { [deviceNodeID]: currentVersionRange2 } }; const remoteMilestone = { ...defMilestonePoint, ...await resolveWithIgnoreKnownError(db.get(MILSTONE_DOCID), defMilestonePoint) }; remoteMilestone.node_chunk_info = { ...defMilestonePoint.node_chunk_info, ...remoteMilestone.node_chunk_info }; const writeMilestone = remoteMilestone.node_chunk_info[deviceNodeID].min != currentVersionRange2.min || remoteMilestone.node_chunk_info[deviceNodeID].max != currentVersionRange2.max || typeof remoteMilestone._rev == "undefined"; if (writeMilestone) { remoteMilestone.node_chunk_info[deviceNodeID].min = currentVersionRange2.min; remoteMilestone.node_chunk_info[deviceNodeID].max = currentVersionRange2.max; await db.put(remoteMilestone); } let globalMin = currentVersionRange2.min; let globalMax = currentVersionRange2.max; for (const nodeId of remoteMilestone.accepted_nodes) { if (nodeId == deviceNodeID) continue; if (nodeId in remoteMilestone.node_chunk_info) { const nodeInfo = remoteMilestone.node_chunk_info[nodeId]; globalMin = Math.max(nodeInfo.min, globalMin); globalMax = Math.min(nodeInfo.max, globalMax); } else { globalMin = 0; globalMax = 0; } } if (globalMax < globalMin) { if (!setting.ignoreVersionCheck) { return "INCOMPATIBLE"; } } if (remoteMilestone.locked) { if (remoteMilestone.accepted_nodes.indexOf(deviceNodeID) == -1) { if (remoteMilestone.cleaned) { return "NODE_CLEANED"; } return "NODE_LOCKED"; } return "LOCKED"; } return "OK"; } // src/lib/src/LiveSyncLocalDB.ts var LiveSyncLocalDB = class { constructor(dbname, env) { this.isReady = false; this.hashCaches = new LRUCache(10, 1e3); this.corruptedEntries = {}; this.changeHandler = null; this.leafArrivedCallbacks = {}; this.docSeq = ""; this.chunkVersion = -1; this.maxChunkVersion = -1; this.minChunkVersion = -1; this.needScanning = false; this.collectThrottleTimeout = null; this.collectThrottleQueuedIds = []; this.chunkCollectedCallbacks = {}; this.auth = { username: "", password: "" }; this.dbname = dbname; this.env = env; this.refreshSettings(); } onunload() { var _a, _b; this.env.beforeOnUnload(this); this.leafArrivedCallbacks; (_a = this.changeHandler) == null ? void 0 : _a.cancel(); (_b = this.changeHandler) == null ? void 0 : _b.removeAllListeners(); this.localDatabase.removeAllListeners(); } refreshSettings() { const settings = this.env.getSettings(); this.settings = settings; this.hashCaches = new LRUCache(settings.hashCacheMaxCount, settings.hashCacheMaxAmount); } id2path(id, entry, stripPrefix2) { return this.env.id2path(id, entry, stripPrefix2); } async path2id(filename, prefix) { return await this.env.path2id(filename, prefix); } async close() { var _a, _b; Logger("Database closed (by close)"); this.isReady = false; (_a = this.changeHandler) == null ? void 0 : _a.cancel(); (_b = this.changeHandler) == null ? void 0 : _b.removeAllListeners(); if (this.localDatabase != null) { await this.localDatabase.close(); } this.env.onClose(this); } async initializeDatabase() { var _a, _b; await this.prepareHashFunctions(); if (this.localDatabase != null) await this.localDatabase.close(); (_a = this.changeHandler) == null ? void 0 : _a.cancel(); (_b = this.changeHandler) == null ? void 0 : _b.removeAllListeners(); this.localDatabase = null; this.localDatabase = this.env.createPouchDBInstance(this.dbname + "-livesync-v2", { auto_compaction: false, revs_limit: 100, deterministic_revs: true }); await this.env.onInitializeDatabase(this); Logger("Opening Database..."); Logger("Database info", LOG_LEVEL.VERBOSE); Logger(await this.localDatabase.info(), LOG_LEVEL.VERBOSE); this.localDatabase.on("close", () => { var _a2; Logger("Database closed."); this.isReady = false; this.localDatabase.removeAllListeners(); (_a2 = this.env.getReplicator()) == null ? void 0 : _a2.closeReplication(); }); const changes3 = this.localDatabase.changes({ since: "now", live: true, filter: (doc) => doc.type == "leaf" }).on("change", (e2) => { if (e2.deleted) return; this.leafArrived(e2.id); this.docSeq = `${e2.seq}`; }); this.changeHandler = changes3; this.isReady = true; Logger("Database is now ready."); return true; } async prepareHashFunctions() { if (this.h32 != null) return; const { h32, h32Raw } = await xxhash_wasm_default(); this.h32 = h32; this.h32Raw = h32Raw; } leafArrived(id) { if (typeof this.leafArrivedCallbacks[id] !== "undefined") { for (const func of this.leafArrivedCallbacks[id]) { func(); } delete this.leafArrivedCallbacks[id]; } } waitForLeafReady(id) { return new Promise((res2, rej) => { const timer = setTimeout(() => rej(new Error(`Chunk reading timed out:${id}`)), LEAF_WAIT_TIMEOUT); if (typeof this.leafArrivedCallbacks[id] == "undefined") { this.leafArrivedCallbacks[id] = []; } this.leafArrivedCallbacks[id].push(() => { clearTimeout(timer); res2(true); }); }); } async getDBLeaf(id, waitForReady) { const leaf = this.hashCaches.revGet(id); if (leaf) { return leaf; } try { const w = await this.localDatabase.get(id); if (w.type == "leaf") { this.hashCaches.set(id, w.data); return w.data; } throw new Error(`Corrupted chunk detected: ${id}`); } catch (ex) { if (isErrorOfMissingDoc(ex)) { if (waitForReady) { if (await this.waitForLeafReady(id) === false) { throw new Error(`time out (waiting chunk)`); } return this.getDBLeaf(id, false); } else { throw new Error(`Chunk was not found: ${id}`); } } else { Logger(`Something went wrong while retrieving chunks`); throw ex; } } } async getDBEntryMeta(path, opt, includeDeleted = false) { return getDBEntryMeta(this, path, opt, includeDeleted); } async getDBEntry(path, opt, dump = false, waitForReady = true, includeDeleted = false) { return getDBEntry(this, path, opt, dump, waitForReady, includeDeleted); } async deleteDBEntry(path, opt) { return deleteDBEntry(this, path, opt); } async deleteDBEntryPrefix(prefixSrc) { return deleteDBEntryPrefix(this, prefixSrc); } async putDBEntry(note, saveAsBigChunk) { return putDBEntry(this, note, saveAsBigChunk); } async resetDatabase() { var _a, _b; (_a = this.changeHandler) == null ? void 0 : _a.cancel(); (_b = this.changeHandler) == null ? void 0 : _b.removeAllListeners(); this.env.getReplicator().closeReplication(); await this.env.onResetDatabase(this); Logger("Database closed for reset Database."); this.isReady = false; await this.localDatabase.destroy(); this.localDatabase = null; await this.initializeDatabase(); Logger("Local Database Reset", LOG_LEVEL.NOTICE); } async sanCheck(entry) { if (entry.type == "plain" || entry.type == "newnote") { const children2 = entry.children; Logger(`sancheck:checking:${entry._id} : ${children2.length}`, LOG_LEVEL.VERBOSE); try { const dc = await this.localDatabase.allDocs({ keys: [...children2] }); if (dc.rows.some((e2) => "error" in e2)) { this.corruptedEntries[entry._id] = entry; Logger(`sancheck:corrupted:${entry._id} : ${children2.length}`, LOG_LEVEL.VERBOSE); return false; } return true; } catch (ex) { Logger(ex); } } return false; } isVersionUpgradable(ver) { if (this.maxChunkVersion < 0) return false; if (this.minChunkVersion < 0) return false; if (this.maxChunkVersion > 0 && this.maxChunkVersion < ver) return false; if (this.minChunkVersion > 0 && this.minChunkVersion > ver) return false; return true; } isTargetFile(filenameSrc) { const file = filenameSrc.startsWith("i:") ? filenameSrc.substring(2) : filenameSrc; if (file.startsWith("ps:")) return true; if (file.includes(":")) return false; if (this.settings.syncOnlyRegEx) { const syncOnly = new RegExp(this.settings.syncOnlyRegEx); if (!file.match(syncOnly)) return false; } if (this.settings.syncIgnoreRegEx) { const syncIgnore = new RegExp(this.settings.syncIgnoreRegEx); if (file.match(syncIgnore)) return false; } return true; } chunkCollected(chunk) { const id = chunk._id; if (typeof this.chunkCollectedCallbacks[id] !== "undefined") { for (const func of this.chunkCollectedCallbacks[id].ok) { func(chunk); } delete this.chunkCollectedCallbacks[id]; } else { Logger(`Collected handler of ${id} is missing, it might be error but perhaps it already timed out.`, LOG_LEVEL.VERBOSE); } } async collectChunks(ids, showResult = false, waitForReady) { const promises = ids.map((id) => new Promise((res3, rej) => { if (typeof this.chunkCollectedCallbacks[id] == "undefined") { this.chunkCollectedCallbacks[id] = { ok: [], failed: () => { delete this.chunkCollectedCallbacks[id]; rej(new Error("Failed to collect one of chunks")); } }; } this.chunkCollectedCallbacks[id].ok.push((chunk) => { res3(chunk); }); })); this.collectThrottleQueuedIds = [.../* @__PURE__ */ new Set([...this.collectThrottleQueuedIds, ...ids])]; this.execCollect(); const res2 = await Promise.all(promises); return res2; } execCollect() { runWithLock("execCollect", true, async () => { do { const minimumInterval = this.settings.minimumIntervalOfReadChunksOnline; const start = Date.now(); const requesting = this.collectThrottleQueuedIds.splice(0, this.settings.concurrencyOfReadChunksOnline); if (requesting.length == 0) return; try { const chunks = await this.CollectChunksInternal(requesting, false); if (chunks) { this.collectThrottleQueuedIds = this.collectThrottleQueuedIds.filter((e2) => !chunks.some((f3) => f3._id == e2)); for (const chunk of chunks) { this.chunkCollected(chunk); } } else { Logger(`Could not retrieve chunks`, LOG_LEVEL.NOTICE); for (const id of requesting) { if (id in this.chunkCollectedCallbacks) { this.chunkCollectedCallbacks[id].failed(); } } } } catch (ex) { Logger(`Exception raised while retrieving chunks`, LOG_LEVEL.NOTICE); Logger(ex, LOG_LEVEL.VERBOSE); for (const id of requesting) { if (id in this.chunkCollectedCallbacks) { this.chunkCollectedCallbacks[id].failed(); } } } const passed = Date.now() - start; const intervalLeft = minimumInterval - passed; if (this.collectThrottleQueuedIds.length == 0) return; await delay(intervalLeft < 0 ? 0 : intervalLeft); } while (this.collectThrottleQueuedIds.length > 0); }).then(() => { }); } async CollectChunksInternal(ids, showResult = false) { const localChunks = await this.localDatabase.allDocs({ keys: ids, include_docs: true }); const missingChunks = localChunks.rows.filter((e2) => "error" in e2).map((e2) => e2.key); if (missingChunks.length == 0) { return localChunks.rows.map((e2) => e2.doc); } const remoteDocs = await this.env.getReplicator().fetchRemoteChunks(missingChunks, showResult); if (remoteDocs == false) { return false; } const max2 = remoteDocs.length; remoteDocs.forEach((e2) => this.hashCaches.set(e2._id, e2.data)); await this.localDatabase.bulkDocs(remoteDocs, { new_edits: false }); let last = 0; function findChunk(key) { if (!remoteDocs) throw Error("Chunk collecting error"); const offset = last; for (let i = 0; i < max2; i++) { const idx = (offset + i) % max2; last = i; if (remoteDocs[idx]._id == key) return remoteDocs[idx]; } throw Error("Chunk collecting error"); } return localChunks.rows.map((e2) => "error" in e2 ? findChunk(e2.key) : e2.doc); } async *findEntries(startKey, endKey, opt) { const pageLimit = 100; let nextKey = startKey; do { const docs = await this.localDatabase.allDocs({ limit: pageLimit, startkey: nextKey, endkey: endKey, include_docs: true, ...opt }); nextKey = ""; for (const row of docs.rows) { const doc = row.doc; nextKey = `${row.id}\u{10FFFF}`; if (!("type" in doc)) continue; if (doc.type == "newnote" || doc.type == "plain") { yield doc; } } } while (nextKey != ""); } async *findAllDocs(opt) { const f1 = this.findEntries("", "h:", opt != null ? opt : {}); const f22 = this.findEntries(`h:\u{10FFFF}`, "", opt != null ? opt : {}); for await (const f3 of f1) { yield f3; } for await (const f3 of f22) { yield f3; } } async *findEntryNames(startKey, endKey, opt) { const pageLimit = 100; let nextKey = startKey; do { const docs = await this.localDatabase.allDocs({ limit: pageLimit, startkey: nextKey, endkey: endKey, ...opt }); nextKey = ""; for (const row of docs.rows) { nextKey = `${row.id}\u{10FFFF}`; yield row.id; } } while (nextKey != ""); } async *findAllDocNames(opt) { const targets = [ this.findEntryNames("", "h:", opt != null ? opt : {}), this.findEntryNames(`h:\u{10FFFF}`, "i:", opt != null ? opt : {}), this.findEntryNames(`i:\u{10FFFF}`, "ps:", opt != null ? opt : {}), this.findEntryNames(`ps:\u{10FFFF}`, "", opt != null ? opt : {}) ]; for (const target of targets) { for await (const f3 of target) { if (f3.startsWith("_")) continue; if (f3 == VERSIONINFO_DOCID) continue; yield f3; } } } async *findAllNormalDocs(opt) { const targets = [ this.findEntries("", "h:", opt != null ? opt : {}), this.findEntries(`h:\u{10FFFF}`, "i:", opt != null ? opt : {}), this.findEntries(`i:\u{10FFFF}`, "ps:", opt != null ? opt : {}), this.findEntries(`ps:\u{10FFFF}`, "", opt != null ? opt : {}) ]; for (const target of targets) { for await (const f3 of target) { if (f3._id.startsWith("_")) continue; if (f3.type != "newnote" && f3.type != "plain") continue; yield f3; } } } getRaw(docId, options) { return this.localDatabase.get(docId, options || {}); } removeRaw(docId, revision, options) { return this.localDatabase.remove(docId, revision, options || {}); } putRaw(doc, options) { return this.localDatabase.put(doc, options || {}); } allDocsRaw(options) { return this.localDatabase.allDocs(options); } bulkDocsRaw(docs, options) { return this.localDatabase.bulkDocs(docs, options || {}); } }; // src/lib/src/LiveSyncReplicator.ts var currentVersionRange = { min: 0, max: 2, current: 2 }; async function* genReplication(s, signal) { const p = []; let locker = () => Promise.resolve(); let unlock = () => { locker = () => new Promise((res2) => unlock = res2); }; unlock(); const push = function(e2) { p.push(e2); unlock(); }; s.on("complete", (result) => push(["complete", result])); s.on("change", (result) => push(["change", result])); s.on("active", () => push(["active"])); s.on("denied", (err) => push(["denied", err])); s.on("error", (err) => push(["error", err])); s.on("paused", (err) => push(["paused", err])); s.then(() => push(["finally"])).catch(() => push(["finally"])); try { L1: do { const r = p.shift(); if (r) { yield r; if (r[0] == "finally") break; continue; } else { const dx = async () => { await locker(); return true; }; do { const timeout = async () => { await delay(100); return false; }; const raced = await Promise.race([dx(), timeout()]); if (raced) continue L1; if (signal.aborted) break L1; } while (true); } } while (true); } finally { s.cancel(); } } var LiveSyncDBReplicator = class { constructor(env) { this.syncStatus = "NOT_CONNECTED"; this.docArrived = 0; this.docSent = 0; this.lastSyncPullSeq = 0; this.maxPullSeq = 0; this.lastSyncPushSeq = 0; this.maxPushSeq = 0; this.originalSetting = null; this.nodeid = ""; this.remoteLocked = false; this.remoteCleaned = false; this.remoteLockedAndDeviceNotAccepted = false; this.updateInfo = () => { this.env.replicationStat.set({ sent: this.docSent, arrived: this.docArrived, maxPullSeq: this.maxPullSeq, maxPushSeq: this.maxPushSeq, lastSyncPullSeq: this.lastSyncPullSeq, lastSyncPushSeq: this.lastSyncPushSeq, syncStatus: this.syncStatus }); }; this.env = env; this.initializeDatabaseForReplication(); this.env.getDatabase().on("close", () => { this.closeReplication(); }); } async initializeDatabaseForReplication() { const db = this.env.getDatabase(); try { const nodeinfo = await resolveWithIgnoreKnownError(db.get(NODEINFO_DOCID), { _id: NODEINFO_DOCID, type: "nodeinfo", nodeid: "", v20220607: true }); if (nodeinfo.nodeid == "") { nodeinfo.nodeid = Math.random().toString(36).slice(-10); await db.put(nodeinfo); } this.nodeid = nodeinfo.nodeid; await putDesignDocuments(db); } catch (ex) { Logger(ex); return false; } } async migrate(from, to) { Logger(`Database updated from ${from} to ${to}`, LOG_LEVEL.NOTICE); return true; } terminateSync() { if (!this.controller) { return; } this.controller.abort(); this.controller = null; } async openReplication(setting, keepAlive, showResult) { await this.initializeDatabaseForReplication(); if (keepAlive) { this.openContinuousReplication(setting, showResult, false); } else { return this.openOneShotReplication(setting, showResult, false, "sync"); } } replicationActivated(showResult) { this.syncStatus = "CONNECTED"; this.updateInfo(); Logger("Replication activated", showResult ? LOG_LEVEL.NOTICE : LOG_LEVEL.INFO, "sync"); } async replicationChangeDetected(e2, showResult, docSentOnStart, docArrivedOnStart) { try { if (e2.direction == "pull") { await this.env.processReplication(e2.change.docs); this.docArrived += e2.change.docs.length; } else { this.docSent += e2.change.docs.length; } if (showResult) { const maxPullSeq = this.maxPullSeq; const maxPushSeq = this.maxPushSeq; const lastSyncPullSeq = this.lastSyncPullSeq; const lastSyncPushSeq = this.lastSyncPushSeq; const pushLast = lastSyncPushSeq == 0 ? "" : lastSyncPushSeq >= maxPushSeq ? " (LIVE)" : ` (${maxPushSeq - lastSyncPushSeq})`; const pullLast = lastSyncPullSeq == 0 ? "" : lastSyncPullSeq >= maxPullSeq ? " (LIVE)" : ` (${maxPullSeq - lastSyncPullSeq})`; Logger(`\u2191${this.docSent - docSentOnStart}${pushLast} \u2193${this.docArrived - docArrivedOnStart}${pullLast}`, LOG_LEVEL.NOTICE, "sync"); } this.updateInfo(); } catch (ex) { Logger("Replication callback error", LOG_LEVEL.NOTICE, "sync"); Logger(ex, LOG_LEVEL.NOTICE); } } replicationCompleted(showResult) { this.syncStatus = "COMPLETED"; this.updateInfo(); Logger("Replication completed", showResult ? LOG_LEVEL.NOTICE : LOG_LEVEL.INFO, showResult ? "sync" : ""); this.terminateSync(); } replicationDenied(e2) { this.syncStatus = "ERRORED"; this.updateInfo(); this.terminateSync(); Logger("Replication denied", LOG_LEVEL.NOTICE, "sync"); Logger(e2); } replicationErrored(e2) { this.syncStatus = "ERRORED"; this.terminateSync(); this.updateInfo(); Logger("Replication error", LOG_LEVEL.NOTICE, "sync"); Logger(e2); } replicationPaused() { this.syncStatus = "PAUSED"; this.updateInfo(); Logger("Replication paused", LOG_LEVEL.VERBOSE, "sync"); } async processSync(syncHandler, showResult, docSentOnStart, docArrivedOnStart, syncMode, retrying) { const controller = new AbortController(); if (this.controller) { this.controller.abort(); } this.controller = controller; const gen = genReplication(syncHandler, controller.signal); try { for await (const [type, e2] of gen) { switch (type) { case "change": if ("direction" in e2) { if (e2.direction == "pull") { this.lastSyncPullSeq = Number(`${e2.change.last_seq}`.split("-")[0]); } else { this.lastSyncPushSeq = Number(`${e2.change.last_seq}`.split("-")[0]); } await this.replicationChangeDetected(e2, showResult, docSentOnStart, docArrivedOnStart); } else { if (syncMode == "pullOnly") { this.lastSyncPullSeq = Number(`${e2.last_seq}`.split("-")[0]); await this.replicationChangeDetected({ direction: "pull", change: e2 }, showResult, docSentOnStart, docArrivedOnStart); } else if (syncMode == "pushOnly") { this.lastSyncPushSeq = Number(`${e2.last_seq}`.split("-")[0]); this.updateInfo(); await this.replicationChangeDetected({ direction: "push", change: e2 }, showResult, docSentOnStart, docArrivedOnStart); } } if (retrying) { if (this.docSent - docSentOnStart + (this.docArrived - docArrivedOnStart) > this.originalSetting.batch_size * 2) { return "NEED_RESURRECT"; } } break; case "complete": this.replicationCompleted(showResult); return "DONE"; case "active": this.replicationActivated(showResult); break; case "denied": this.replicationDenied(e2); return "FAILED"; case "error": this.replicationErrored(e2); Logger("Replication stopped.", showResult ? LOG_LEVEL.NOTICE : LOG_LEVEL.INFO, "sync"); if (this.env.getLastPostFailedBySize()) { if (e2 && (e2 == null ? void 0 : e2.status) == 413) { Logger(`Self-hosted LiveSync has detected some remote-database-incompatible chunks that exist in the local database. It means synchronization with the server had been no longer possible. The problem may be caused by chunks that were created with the faulty version or by switching platforms of the database. To solve the circumstance, configure the remote database correctly or we have to rebuild both local and remote databases.`, LOG_LEVEL.NOTICE); return; } return "NEED_RETRY"; } else { Logger("Replication error", LOG_LEVEL.NOTICE, "sync"); Logger(e2); } return "FAILED"; case "paused": this.replicationPaused(); break; case "finally": break; default: Logger(`Unexpected synchronization status:${JSON.stringify(e2)}`); } } return "DONE"; } catch (ex) { Logger(`Unexpected synchronization exception`); Logger(ex, LOG_LEVEL.VERBOSE); } finally { this.terminateSync(); this.controller = null; } } async openOneShotReplication(setting, showResult, retrying, syncMode) { if (this.controller != null) { Logger("Replication is already in progress.", showResult ? LOG_LEVEL.NOTICE : LOG_LEVEL.INFO, "sync"); return false; } const localDB = this.env.getDatabase(); Logger(`OneShot Sync begin... (${syncMode})`); const ret = await this.checkReplicationConnectivity(setting, true, retrying, showResult); if (ret === false) { Logger("Could not connect to server.", showResult ? LOG_LEVEL.NOTICE : LOG_LEVEL.INFO, "sync"); return false; } this.maxPullSeq = Number(`${ret.info.update_seq}`.split("-")[0]); this.maxPushSeq = Number(`${(await localDB.info()).update_seq}`.split("-")[0]); if (showResult) { Logger("Looking for the point last synchronized point.", LOG_LEVEL.NOTICE, "sync"); } const { db, syncOptionBase } = ret; this.syncStatus = "STARTED"; this.updateInfo(); const docArrivedOnStart = this.docArrived; const docSentOnStart = this.docSent; if (!retrying) { this.originalSetting = setting; } this.terminateSync(); let syncHandler; if (syncMode == "sync") { syncHandler = localDB.sync(db, { checkpoint: "target", ...syncOptionBase }); } else if (syncMode == "pullOnly") { syncHandler = localDB.replicate.from(db, { checkpoint: "target", ...syncOptionBase, ...setting.readChunksOnline ? { filter: "replicate/pull" } : {} }); } else if (syncMode == "pushOnly") { syncHandler = localDB.replicate.to(db, { checkpoint: "target", ...syncOptionBase, ...setting.readChunksOnline ? { filter: "replicate/push" } : {} }); } const syncResult = await this.processSync(syncHandler, showResult, docSentOnStart, docArrivedOnStart, syncMode, retrying); if (syncResult == "DONE") { return true; } if (syncResult == "FAILED") { return false; } if (syncResult == "NEED_RESURRECT") { this.terminateSync(); return await this.openOneShotReplication(this.originalSetting, showResult, false, syncMode); } if (syncResult == "NEED_RETRY") { const tempSetting = JSON.parse(JSON.stringify(setting)); tempSetting.batch_size = Math.ceil(tempSetting.batch_size / 2) + 2; tempSetting.batches_limit = Math.ceil(tempSetting.batches_limit / 2) + 2; if (tempSetting.batch_size <= 5 && tempSetting.batches_limit <= 5) { Logger("We can't replicate more lower value.", showResult ? LOG_LEVEL.NOTICE : LOG_LEVEL.INFO); return false; } else { Logger(`Retry with lower batch size:${tempSetting.batch_size}/${tempSetting.batches_limit}`, showResult ? LOG_LEVEL.NOTICE : LOG_LEVEL.INFO); return await this.openOneShotReplication(tempSetting, showResult, true, syncMode); } } return false; } replicateAllToServer(setting, showingNotice) { return this.openOneShotReplication( setting, showingNotice != null ? showingNotice : false, false, "pushOnly" ); } replicateAllFromServer(setting, showingNotice) { return this.openOneShotReplication(setting, showingNotice, false, "pullOnly"); } async checkReplicationConnectivity(setting, keepAlive, skipCheck, showResult) { if (setting.versionUpFlash != "") { Logger("Open settings and check message, please.", LOG_LEVEL.NOTICE); return false; } const uri = setting.couchDB_URI + (setting.couchDB_DBNAME == "" ? "" : "/" + setting.couchDB_DBNAME); if (this.controller != null) { Logger("Another replication running."); return false; } const dbRet = await this.connectRemoteCouchDBWithSetting(setting, this.env.getIsMobile()); if (typeof dbRet === "string") { Logger(`Could not connect to ${uri}: ${dbRet}`, showResult ? LOG_LEVEL.NOTICE : LOG_LEVEL.INFO); return false; } if (!skipCheck) { await putDesignDocuments(dbRet.db); if (!await checkRemoteVersion(dbRet.db, this.migrate.bind(this), VER)) { Logger("Remote database is newer or corrupted, make sure to latest version of self-hosted-livesync installed", LOG_LEVEL.NOTICE); return false; } this.remoteCleaned = false; this.remoteLocked = false; this.remoteLockedAndDeviceNotAccepted = false; const ensure = await ensureDatabaseIsCompatible(dbRet.db, setting, this.nodeid, currentVersionRange); if (ensure == "INCOMPATIBLE") { Logger("The remote database has no compatibility with the running version. Please upgrade the plugin.", LOG_LEVEL.NOTICE); return false; } else if (ensure == "NODE_LOCKED") { Logger("The remote database has been rebuilt or corrupted since we have synchronized last time. Fetch rebuilt DB, explicit unlocking or chunk clean-up is required.", LOG_LEVEL.NOTICE); this.remoteLockedAndDeviceNotAccepted = true; this.remoteLocked = true; return false; } else if (ensure == "LOCKED") { this.remoteLocked = true; } else if (ensure == "NODE_CLEANED") { Logger("The remote database has been cleaned up. Fetch rebuilt DB, explicit unlocking or chunk clean-up is required.", LOG_LEVEL.NOTICE); this.remoteLockedAndDeviceNotAccepted = true; this.remoteLocked = true; this.remoteCleaned = true; return false; } } const syncOptionBase = { batches_limit: setting.batches_limit, batch_size: setting.batch_size }; if (setting.readChunksOnline) { syncOptionBase.push = { filter: "replicate/push" }; syncOptionBase.pull = { filter: "replicate/pull" }; } const syncOption = keepAlive ? { live: true, retry: true, heartbeat: setting.useTimeouts ? false : 3e4, ...syncOptionBase } : { ...syncOptionBase }; return { db: dbRet.db, info: dbRet.info, syncOptionBase, syncOption }; } async openContinuousReplication(setting, showResult, retrying) { if (this.controller != null) { Logger("Replication is already in progress.", showResult ? LOG_LEVEL.NOTICE : LOG_LEVEL.INFO); return; } const localDB = this.env.getDatabase(); Logger("Before LiveSync, start OneShot once..."); if (await this.openOneShotReplication( setting, showResult, false, "pullOnly" )) { Logger("LiveSync begin..."); const ret = await this.checkReplicationConnectivity(setting, true, true, showResult); if (ret === false) { Logger("Could not connect to server.", showResult ? LOG_LEVEL.NOTICE : LOG_LEVEL.INFO); return false; } if (showResult) { Logger("Looking for the point last synchronized point.", LOG_LEVEL.NOTICE, "sync"); } const { db, syncOption } = ret; this.syncStatus = "STARTED"; this.maxPullSeq = Number(`${ret.info.update_seq}`.split("-")[0]); this.maxPushSeq = Number(`${(await localDB.info()).update_seq}`.split("-")[0]); this.updateInfo(); const docArrivedOnStart = this.docArrived; const docSentOnStart = this.docSent; if (!retrying) { this.originalSetting = setting; } this.terminateSync(); const syncHandler = localDB.sync(db, { ...syncOption, pull: { checkpoint: "target" }, push: { checkpoint: "source" } }); const syncMode = "sync"; const syncResult = await this.processSync(syncHandler, showResult, docSentOnStart, docArrivedOnStart, syncMode, retrying); if (syncResult == "DONE") { return true; } if (syncResult == "FAILED") { return false; } if (syncResult == "NEED_RESURRECT") { this.terminateSync(); return await this.openContinuousReplication(this.originalSetting, showResult, false); } if (syncResult == "NEED_RETRY") { const tempSetting = JSON.parse(JSON.stringify(setting)); tempSetting.batch_size = Math.ceil(tempSetting.batch_size / 2) + 2; tempSetting.batches_limit = Math.ceil(tempSetting.batches_limit / 2) + 2; if (tempSetting.batch_size <= 5 && tempSetting.batches_limit <= 5) { Logger("We can't replicate more lower value.", showResult ? LOG_LEVEL.NOTICE : LOG_LEVEL.INFO); return false; } else { Logger(`Retry with lower batch size:${tempSetting.batch_size}/${tempSetting.batches_limit}`, showResult ? LOG_LEVEL.NOTICE : LOG_LEVEL.INFO); return await this.openContinuousReplication(tempSetting, showResult, true); } } } } closeReplication() { if (!this.controller) { return; } this.controller.abort(); this.controller = null; this.syncStatus = "CLOSED"; Logger("Replication closed"); this.updateInfo(); } async tryResetRemoteDatabase(setting) { this.closeReplication(); const con = await this.connectRemoteCouchDBWithSetting(setting, this.env.getIsMobile()); if (typeof con == "string") return; try { await con.db.destroy(); Logger("Remote Database Destroyed", LOG_LEVEL.NOTICE); await this.tryCreateRemoteDatabase(setting); } catch (ex) { Logger("Something happened on Remote Database Destroy:", LOG_LEVEL.NOTICE); Logger(ex, LOG_LEVEL.NOTICE); } } async tryCreateRemoteDatabase(setting) { this.closeReplication(); const con2 = await this.connectRemoteCouchDBWithSetting(setting, this.env.getIsMobile()); if (typeof con2 === "string") return; Logger("Remote Database Created or Connected", LOG_LEVEL.NOTICE); } async markRemoteLocked(setting, locked, lockByClean) { const uri = setting.couchDB_URI + (setting.couchDB_DBNAME == "" ? "" : "/" + setting.couchDB_DBNAME); const dbRet = await this.connectRemoteCouchDBWithSetting(setting, this.env.getIsMobile()); if (typeof dbRet === "string") { Logger(`could not connect to ${uri}:${dbRet}`, LOG_LEVEL.NOTICE); return; } if (!await checkRemoteVersion(dbRet.db, this.migrate.bind(this), VER)) { Logger("Remote database is newer or corrupted, make sure to latest version of self-hosted-livesync installed", LOG_LEVEL.NOTICE); return; } const defInitPoint = { _id: MILSTONE_DOCID, type: "milestoneinfo", created: new Date() / 1, locked, cleaned: lockByClean, accepted_nodes: [this.nodeid], node_chunk_info: { [this.nodeid]: currentVersionRange } }; const remoteMilestone = { ...defInitPoint, ...await resolveWithIgnoreKnownError(dbRet.db.get(MILSTONE_DOCID), defInitPoint) }; remoteMilestone.node_chunk_info = { ...defInitPoint.node_chunk_info, ...remoteMilestone.node_chunk_info }; remoteMilestone.accepted_nodes = [this.nodeid]; remoteMilestone.locked = locked; remoteMilestone.cleaned = remoteMilestone.cleaned || lockByClean; if (locked) { Logger("Lock remote database to prevent data corruption", LOG_LEVEL.NOTICE); } else { Logger("Unlock remote database to prevent data corruption", LOG_LEVEL.NOTICE); } await dbRet.db.put(remoteMilestone); } async markRemoteResolved(setting) { const uri = setting.couchDB_URI + (setting.couchDB_DBNAME == "" ? "" : "/" + setting.couchDB_DBNAME); const dbRet = await this.connectRemoteCouchDBWithSetting(setting, this.env.getIsMobile()); if (typeof dbRet === "string") { Logger(`could not connect to ${uri}:${dbRet}`, LOG_LEVEL.NOTICE); return; } if (!await checkRemoteVersion(dbRet.db, this.migrate.bind(this), VER)) { Logger("Remote database is newer or corrupted, make sure to latest version of self-hosted-livesync installed", LOG_LEVEL.NOTICE); return; } const defInitPoint = { _id: MILSTONE_DOCID, type: "milestoneinfo", created: new Date() / 1, locked: false, accepted_nodes: [this.nodeid], node_chunk_info: { [this.nodeid]: currentVersionRange } }; const remoteMilestone = { ...defInitPoint, ...await resolveWithIgnoreKnownError(dbRet.db.get(MILSTONE_DOCID), defInitPoint) }; remoteMilestone.node_chunk_info = { ...defInitPoint.node_chunk_info, ...remoteMilestone.node_chunk_info }; remoteMilestone.accepted_nodes = Array.from(/* @__PURE__ */ new Set([...remoteMilestone.accepted_nodes, this.nodeid])); Logger("Mark this device as 'resolved'.", LOG_LEVEL.NOTICE); await dbRet.db.put(remoteMilestone); } connectRemoteCouchDBWithSetting(settings, isMobile) { if (settings.encrypt && settings.passphrase == "" && !settings.permitEmptyPassphrase) { return "Empty passphrases cannot be used without explicit permission"; } return this.env.connectRemoteCouchDB( settings.couchDB_URI + (settings.couchDB_DBNAME == "" ? "" : "/" + settings.couchDB_DBNAME), { username: settings.couchDB_USER, password: settings.couchDB_PASSWORD }, settings.disableRequestURI || isMobile, settings.encrypt ? settings.passphrase : settings.encrypt, settings.useDynamicIterationCount ); } async fetchRemoteChunks(missingChunks, showResult) { const ret = await this.connectRemoteCouchDBWithSetting(this.env.getSettings(), this.env.getIsMobile()); if (typeof ret === "string") { Logger(`Could not connect to server.${ret} `, showResult ? LOG_LEVEL.NOTICE : LOG_LEVEL.INFO, "fetch"); return false; } const remoteChunks = await ret.db.allDocs({ keys: missingChunks, include_docs: true }); if (remoteChunks.rows.some((e2) => "error" in e2)) { Logger(`Some chunks are not exists both on remote and local database.`, showResult ? LOG_LEVEL.NOTICE : LOG_LEVEL.INFO, "fetch"); return false; } const remoteChunkItems = remoteChunks.rows.map((e2) => e2.doc); return remoteChunkItems; } }; // node_modules/idb/build/wrap-idb-value.js var instanceOfAny = (object, constructors) => constructors.some((c) => object instanceof c); var idbProxyableTypes; var cursorAdvanceMethods; function getIdbProxyableTypes() { return idbProxyableTypes || (idbProxyableTypes = [ IDBDatabase, IDBObjectStore, IDBIndex, IDBCursor, IDBTransaction ]); } function getCursorAdvanceMethods() { return cursorAdvanceMethods || (cursorAdvanceMethods = [ IDBCursor.prototype.advance, IDBCursor.prototype.continue, IDBCursor.prototype.continuePrimaryKey ]); } var cursorRequestMap = /* @__PURE__ */ new WeakMap(); var transactionDoneMap = /* @__PURE__ */ new WeakMap(); var transactionStoreNamesMap = /* @__PURE__ */ new WeakMap(); var transformCache = /* @__PURE__ */ new WeakMap(); var reverseTransformCache = /* @__PURE__ */ new WeakMap(); function promisifyRequest(request) { const promise = new Promise((resolve, reject) => { const unlisten = () => { request.removeEventListener("success", success); request.removeEventListener("error", error); }; const success = () => { resolve(wrap(request.result)); unlisten(); }; const error = () => { reject(request.error); unlisten(); }; request.addEventListener("success", success); request.addEventListener("error", error); }); promise.then((value) => { if (value instanceof IDBCursor) { cursorRequestMap.set(value, request); } }).catch(() => { }); reverseTransformCache.set(promise, request); return promise; } function cacheDonePromiseForTransaction(tx) { if (transactionDoneMap.has(tx)) return; const done = new Promise((resolve, reject) => { const unlisten = () => { tx.removeEventListener("complete", complete); tx.removeEventListener("error", error); tx.removeEventListener("abort", error); }; const complete = () => { resolve(); unlisten(); }; const error = () => { reject(tx.error || new DOMException("AbortError", "AbortError")); unlisten(); }; tx.addEventListener("complete", complete); tx.addEventListener("error", error); tx.addEventListener("abort", error); }); transactionDoneMap.set(tx, done); } var idbProxyTraps = { get(target, prop, receiver) { if (target instanceof IDBTransaction) { if (prop === "done") return transactionDoneMap.get(target); if (prop === "objectStoreNames") { return target.objectStoreNames || transactionStoreNamesMap.get(target); } if (prop === "store") { return receiver.objectStoreNames[1] ? void 0 : receiver.objectStore(receiver.objectStoreNames[0]); } } return wrap(target[prop]); }, set(target, prop, value) { target[prop] = value; return true; }, has(target, prop) { if (target instanceof IDBTransaction && (prop === "done" || prop === "store")) { return true; } return prop in target; } }; function replaceTraps(callback) { idbProxyTraps = callback(idbProxyTraps); } function wrapFunction(func) { if (func === IDBDatabase.prototype.transaction && !("objectStoreNames" in IDBTransaction.prototype)) { return function(storeNames, ...args) { const tx = func.call(unwrap(this), storeNames, ...args); transactionStoreNamesMap.set(tx, storeNames.sort ? storeNames.sort() : [storeNames]); return wrap(tx); }; } if (getCursorAdvanceMethods().includes(func)) { return function(...args) { func.apply(unwrap(this), args); return wrap(cursorRequestMap.get(this)); }; } return function(...args) { return wrap(func.apply(unwrap(this), args)); }; } function transformCachableValue(value) { if (typeof value === "function") return wrapFunction(value); if (value instanceof IDBTransaction) cacheDonePromiseForTransaction(value); if (instanceOfAny(value, getIdbProxyableTypes())) return new Proxy(value, idbProxyTraps); return value; } function wrap(value) { if (value instanceof IDBRequest) return promisifyRequest(value); if (transformCache.has(value)) return transformCache.get(value); const newValue = transformCachableValue(value); if (newValue !== value) { transformCache.set(value, newValue); reverseTransformCache.set(newValue, value); } return newValue; } var unwrap = (value) => reverseTransformCache.get(value); // node_modules/idb/build/index.js function openDB(name, version2, { blocked, upgrade, blocking, terminated } = {}) { const request = indexedDB.open(name, version2); const openPromise = wrap(request); if (upgrade) { request.addEventListener("upgradeneeded", (event) => { upgrade(wrap(request.result), event.oldVersion, event.newVersion, wrap(request.transaction), event); }); } if (blocked) { request.addEventListener("blocked", (event) => blocked( event.oldVersion, event.newVersion, event )); } openPromise.then((db) => { if (terminated) db.addEventListener("close", () => terminated()); if (blocking) { db.addEventListener("versionchange", (event) => blocking(event.oldVersion, event.newVersion, event)); } }).catch(() => { }); return openPromise; } function deleteDB(name, { blocked } = {}) { const request = indexedDB.deleteDatabase(name); if (blocked) { request.addEventListener("blocked", (event) => blocked( event.oldVersion, event )); } return wrap(request).then(() => void 0); } var readMethods = ["get", "getKey", "getAll", "getAllKeys", "count"]; var writeMethods = ["put", "add", "delete", "clear"]; var cachedMethods = /* @__PURE__ */ new Map(); function getMethod(target, prop) { if (!(target instanceof IDBDatabase && !(prop in target) && typeof prop === "string")) { return; } if (cachedMethods.get(prop)) return cachedMethods.get(prop); const targetFuncName = prop.replace(/FromIndex$/, ""); const useIndex = prop !== targetFuncName; const isWrite = writeMethods.includes(targetFuncName); if (!(targetFuncName in (useIndex ? IDBIndex : IDBObjectStore).prototype) || !(isWrite || readMethods.includes(targetFuncName))) { return; } const method = async function(storeName, ...args) { const tx = this.transaction(storeName, isWrite ? "readwrite" : "readonly"); let target2 = tx.store; if (useIndex) target2 = target2.index(args.shift()); return (await Promise.all([ target2[targetFuncName](...args), isWrite && tx.done ]))[0]; }; cachedMethods.set(prop, method); return method; } replaceTraps((oldTraps) => ({ ...oldTraps, get: (target, prop, receiver) => getMethod(target, prop) || oldTraps.get(target, prop, receiver), has: (target, prop) => !!getMethod(target, prop) || oldTraps.has(target, prop) })); // src/KeyValueDB.ts var databaseCache = {}; var OpenKeyValueDatabase = async (dbKey) => { if (dbKey in databaseCache) { databaseCache[dbKey].close(); delete databaseCache[dbKey]; } const storeKey = dbKey; const dbPromise = openDB(dbKey, 1, { upgrade(db2) { db2.createObjectStore(storeKey); } }); let db = null; db = await dbPromise; databaseCache[dbKey] = db; return { get(key) { return db.get(storeKey, key); }, set(key, value) { return db.put(storeKey, value, key); }, del(key) { return db.delete(storeKey, key); }, clear() { return db.clear(storeKey); }, keys(query3, count) { return db.getAllKeys(storeKey, query3, count); }, close() { delete databaseCache[dbKey]; return db.close(); }, async destroy() { delete databaseCache[dbKey]; db.close(); await deleteDB(dbKey); } }; }; // src/JsonResolvePane.svelte var import_diff_match_patch3 = __toESM(require_diff_match_patch(), 1); function add_css2(target) { append_styles(target, "svelte-guf68w", ".deleted.svelte-guf68w{text-decoration:line-through}.svelte-guf68w{box-sizing:border-box}.scroller.svelte-guf68w{display:flex;flex-direction:column;overflow-y:scroll;max-height:60vh;user-select:text}.json-source.svelte-guf68w{white-space:pre;height:auto;overflow:auto;min-height:var(--font-ui-medium);flex-grow:1}"); } function get_each_context2(ctx, list, i) { const child_ctx = ctx.slice(); child_ctx[22] = list[i]; return child_ctx; } function get_each_context_12(ctx, list, i) { const child_ctx = ctx.slice(); child_ctx[25] = list[i]; return child_ctx; } function create_else_block2(ctx) { let div0; let t0; let t1; let div1; let t2; let t3_value = revStringToRevNumber(ctx[1]._rev) + ""; let t3; let t4; let t5_value = new Date(ctx[1].mtime).toLocaleString() + ""; let t5; let t6; let t7_value = ctx[3].length + ""; let t7; let t8; let t9; let div2; let t10; let t11_value = revStringToRevNumber(ctx[2]._rev) + ""; let t11; let t12; let t13_value = new Date(ctx[2].mtime).toLocaleString() + ""; let t13; let t14; let t15_value = ctx[4].length + ""; let t15; let t16; let t17; let div3; let button; let mounted; let dispose; let each_value_1 = ctx[9]; let each_blocks = []; for (let i = 0; i < each_value_1.length; i += 1) { each_blocks[i] = create_each_block_12(get_each_context_12(ctx, each_value_1, i)); } function select_block_type_1(ctx2, dirty) { if (ctx2[6] != false) return create_if_block_12; return create_else_block_12; } let current_block_type = select_block_type_1(ctx, -1); let if_block = current_block_type(ctx); return { c() { div0 = element("div"); for (let i = 0; i < each_blocks.length; i += 1) { each_blocks[i].c(); } t0 = space(); if_block.c(); t1 = space(); div1 = element("div"); t2 = text("A Rev:"); t3 = text(t3_value); t4 = text(" ,"); t5 = text(t5_value); t6 = space(); t7 = text(t7_value); t8 = text(" letters"); t9 = space(); div2 = element("div"); t10 = text("B Rev:"); t11 = text(t11_value); t12 = text(" ,"); t13 = text(t13_value); t14 = space(); t15 = text(t15_value); t16 = text(" letters"); t17 = space(); div3 = element("div"); button = element("button"); button.textContent = "Apply"; attr(div0, "class", "options svelte-guf68w"); attr(div1, "class", "svelte-guf68w"); attr(div2, "class", "svelte-guf68w"); attr(button, "class", "svelte-guf68w"); attr(div3, "class", "buttons svelte-guf68w"); }, m(target, anchor) { insert(target, div0, anchor); for (let i = 0; i < each_blocks.length; i += 1) { each_blocks[i].m(div0, null); } insert(target, t0, anchor); if_block.m(target, anchor); insert(target, t1, anchor); insert(target, div1, anchor); append(div1, t2); append(div1, t3); append(div1, t4); append(div1, t5); append(div1, t6); append(div1, t7); append(div1, t8); insert(target, t9, anchor); insert(target, div2, anchor); append(div2, t10); append(div2, t11); append(div2, t12); append(div2, t13); append(div2, t14); append(div2, t15); append(div2, t16); insert(target, t17, anchor); insert(target, div3, anchor); append(div3, button); if (!mounted) { dispose = listen(button, "click", ctx[10]); mounted = true; } }, p(ctx2, dirty) { if (dirty & 672) { each_value_1 = ctx2[9]; let i; for (i = 0; i < each_value_1.length; i += 1) { const child_ctx = get_each_context_12(ctx2, each_value_1, i); if (each_blocks[i]) { each_blocks[i].p(child_ctx, dirty); } else { each_blocks[i] = create_each_block_12(child_ctx); each_blocks[i].c(); each_blocks[i].m(div0, null); } } for (; i < each_blocks.length; i += 1) { each_blocks[i].d(1); } each_blocks.length = each_value_1.length; } if (current_block_type === (current_block_type = select_block_type_1(ctx2, dirty)) && if_block) { if_block.p(ctx2, dirty); } else { if_block.d(1); if_block = current_block_type(ctx2); if (if_block) { if_block.c(); if_block.m(t1.parentNode, t1); } } if (dirty & 2 && t3_value !== (t3_value = revStringToRevNumber(ctx2[1]._rev) + "")) set_data(t3, t3_value); if (dirty & 2 && t5_value !== (t5_value = new Date(ctx2[1].mtime).toLocaleString() + "")) set_data(t5, t5_value); if (dirty & 8 && t7_value !== (t7_value = ctx2[3].length + "")) set_data(t7, t7_value); if (dirty & 4 && t11_value !== (t11_value = revStringToRevNumber(ctx2[2]._rev) + "")) set_data(t11, t11_value); if (dirty & 4 && t13_value !== (t13_value = new Date(ctx2[2].mtime).toLocaleString() + "")) set_data(t13, t13_value); if (dirty & 16 && t15_value !== (t15_value = ctx2[4].length + "")) set_data(t15, t15_value); }, d(detaching) { if (detaching) detach(div0); destroy_each(each_blocks, detaching); if (detaching) detach(t0); if_block.d(detaching); if (detaching) detach(t1); if (detaching) detach(div1); if (detaching) detach(t9); if (detaching) detach(div2); if (detaching) detach(t17); if (detaching) detach(div3); mounted = false; dispose(); } }; } function create_if_block2(ctx) { let div0; let t1; let div1; let button; let mounted; let dispose; return { c() { div0 = element("div"); div0.textContent = "Just for a minute, please!"; t1 = space(); div1 = element("div"); button = element("button"); button.textContent = "Dismiss"; attr(div0, "class", "message svelte-guf68w"); attr(button, "class", "svelte-guf68w"); attr(div1, "class", "buttons svelte-guf68w"); }, m(target, anchor) { insert(target, div0, anchor); insert(target, t1, anchor); insert(target, div1, anchor); append(div1, button); if (!mounted) { dispose = listen(button, "click", ctx[10]); mounted = true; } }, p: noop, d(detaching) { if (detaching) detach(div0); if (detaching) detach(t1); if (detaching) detach(div1); mounted = false; dispose(); } }; } function create_if_block_22(ctx) { let label; let input; let input_value_value; let t0; let div; let t1_value = ctx[25][1] + ""; let t1; let label_class_value; let mounted; let dispose; return { c() { label = element("label"); input = element("input"); t0 = space(); div = element("div"); t1 = text(t1_value); attr(input, "type", "radio"); attr(input, "name", "disp"); input.__value = input_value_value = ctx[25][0]; input.value = input.__value; attr(input, "class", "sls-setting-tab svelte-guf68w"); ctx[18][0].push(input); attr(div, "class", "sls-setting-menu-btn svelte-guf68w"); attr(label, "class", label_class_value = null_to_empty(`sls-setting-label ${ctx[25][0] == ctx[5] ? "selected" : ""}`) + " svelte-guf68w"); }, m(target, anchor) { insert(target, label, anchor); append(label, input); input.checked = input.__value === ctx[5]; append(label, t0); append(label, div); append(div, t1); if (!mounted) { dispose = listen(input, "change", ctx[17]); mounted = true; } }, p(ctx2, dirty) { if (dirty & 32) { input.checked = input.__value === ctx2[5]; } if (dirty & 32 && label_class_value !== (label_class_value = null_to_empty(`sls-setting-label ${ctx2[25][0] == ctx2[5] ? "selected" : ""}`) + " svelte-guf68w")) { attr(label, "class", label_class_value); } }, d(detaching) { if (detaching) detach(label); ctx[18][0].splice(ctx[18][0].indexOf(input), 1); mounted = false; dispose(); } }; } function create_each_block_12(ctx) { let if_block_anchor; let if_block = (ctx[25][0] == "" || ctx[7][ctx[25][0]] != false) && create_if_block_22(ctx); return { c() { if (if_block) if_block.c(); if_block_anchor = empty(); }, m(target, anchor) { if (if_block) if_block.m(target, anchor); insert(target, if_block_anchor, anchor); }, p(ctx2, dirty) { if (ctx2[25][0] == "" || ctx2[7][ctx2[25][0]] != false) { if (if_block) { if_block.p(ctx2, dirty); } else { if_block = create_if_block_22(ctx2); if_block.c(); if_block.m(if_block_anchor.parentNode, if_block_anchor); } } else if (if_block) { if_block.d(1); if_block = null; } }, d(detaching) { if (if_block) if_block.d(detaching); if (detaching) detach(if_block_anchor); } }; } function create_else_block_12(ctx) { let t2; return { c() { t2 = text("NO PREVIEW"); }, m(target, anchor) { insert(target, t2, anchor); }, p: noop, d(detaching) { if (detaching) detach(t2); } }; } function create_if_block_12(ctx) { let div; let each_value = ctx[8]; let each_blocks = []; for (let i = 0; i < each_value.length; i += 1) { each_blocks[i] = create_each_block2(get_each_context2(ctx, each_value, i)); } return { c() { div = element("div"); for (let i = 0; i < each_blocks.length; i += 1) { each_blocks[i].c(); } attr(div, "class", "op-scrollable json-source svelte-guf68w"); }, m(target, anchor) { insert(target, div, anchor); for (let i = 0; i < each_blocks.length; i += 1) { each_blocks[i].m(div, null); } }, p(ctx2, dirty) { if (dirty & 256) { each_value = ctx2[8]; let i; for (i = 0; i < each_value.length; i += 1) { const child_ctx = get_each_context2(ctx2, each_value, i); if (each_blocks[i]) { each_blocks[i].p(child_ctx, dirty); } else { each_blocks[i] = create_each_block2(child_ctx); each_blocks[i].c(); each_blocks[i].m(div, null); } } for (; i < each_blocks.length; i += 1) { each_blocks[i].d(1); } each_blocks.length = each_value.length; } }, d(detaching) { if (detaching) detach(div); destroy_each(each_blocks, detaching); } }; } function create_each_block2(ctx) { let span; let t_value = ctx[22][1] + ""; let t2; let span_class_value; return { c() { span = element("span"); t2 = text(t_value); attr(span, "class", span_class_value = null_to_empty(ctx[22][0] == import_diff_match_patch3.DIFF_DELETE ? "deleted" : ctx[22][0] == import_diff_match_patch3.DIFF_INSERT ? "added" : "normal") + " svelte-guf68w"); }, m(target, anchor) { insert(target, span, anchor); append(span, t2); }, p(ctx2, dirty) { if (dirty & 256 && t_value !== (t_value = ctx2[22][1] + "")) set_data(t2, t_value); if (dirty & 256 && span_class_value !== (span_class_value = null_to_empty(ctx2[22][0] == import_diff_match_patch3.DIFF_DELETE ? "deleted" : ctx2[22][0] == import_diff_match_patch3.DIFF_INSERT ? "added" : "normal") + " svelte-guf68w")) { attr(span, "class", span_class_value); } }, d(detaching) { if (detaching) detach(span); } }; } function create_fragment2(ctx) { let h1; let t1; let div; let span; let t2; let t3; let if_block_anchor; function select_block_type(ctx2, dirty) { if (!ctx2[1] || !ctx2[2]) return create_if_block2; return create_else_block2; } let current_block_type = select_block_type(ctx, -1); let if_block = current_block_type(ctx); return { c() { h1 = element("h1"); h1.textContent = "Conflicted settings"; t1 = space(); div = element("div"); span = element("span"); t2 = text(ctx[0]); t3 = space(); if_block.c(); if_block_anchor = empty(); attr(h1, "class", "svelte-guf68w"); attr(span, "class", "svelte-guf68w"); attr(div, "class", "svelte-guf68w"); }, m(target, anchor) { insert(target, h1, anchor); insert(target, t1, anchor); insert(target, div, anchor); append(div, span); append(span, t2); insert(target, t3, anchor); if_block.m(target, anchor); insert(target, if_block_anchor, anchor); }, p(ctx2, [dirty]) { if (dirty & 1) set_data(t2, ctx2[0]); if (current_block_type === (current_block_type = select_block_type(ctx2, dirty)) && if_block) { if_block.p(ctx2, dirty); } else { if_block.d(1); if_block = current_block_type(ctx2); if (if_block) { if_block.c(); if_block.m(if_block_anchor.parentNode, if_block_anchor); } } }, i: noop, o: noop, d(detaching) { if (detaching) detach(h1); if (detaching) detach(t1); if (detaching) detach(div); if (detaching) detach(t3); if_block.d(detaching); if (detaching) detach(if_block_anchor); } }; } function revStringToRevNumber(rev2) { return rev2.split("-")[0]; } function instance2($$self, $$props, $$invalidate) { let mergedObjs; let selectedObj; let { docs = [] } = $$props; let { callback = async (_, __) => { Promise.resolve(); } } = $$props; let { filename = "" } = $$props; let docA = void 0; let docB = void 0; let docAContent = ""; let docBContent = ""; let objA = {}; let objB = {}; let objAB = {}; let objBA = {}; let diffs; const modes = [["", "Not now"], ["A", "A"], ["B", "B"], ["AB", "A + B"], ["BA", "B + A"]]; let mode = ""; function docToString(doc) { return doc.datatype == "plain" ? getDocData(doc.data) : base64ToString(doc.data); } function getDiff(left, right) { const dmp = new import_diff_match_patch3.diff_match_patch(); const mapLeft = dmp.diff_linesToChars_(left, right); const diffLeftSrc = dmp.diff_main(mapLeft.chars1, mapLeft.chars2, false); dmp.diff_charsToLines_(diffLeftSrc, mapLeft.lineArray); return diffLeftSrc; } function getJsonDiff(a2, b) { return getDiff(JSON.stringify(a2, null, 2), JSON.stringify(b, null, 2)); } function apply() { if (mode == "A") return callback(docA._rev, null); if (mode == "B") return callback(docB._rev, null); if (mode == "BA") return callback(null, JSON.stringify(objBA, null, 2)); if (mode == "AB") return callback(null, JSON.stringify(objAB, null, 2)); callback(null, null); } const $$binding_groups = [[]]; function input_change_handler() { mode = this.__value; $$invalidate(5, mode); } $$self.$$set = ($$props2) => { if ("docs" in $$props2) $$invalidate(11, docs = $$props2.docs); if ("callback" in $$props2) $$invalidate(12, callback = $$props2.callback); if ("filename" in $$props2) $$invalidate(0, filename = $$props2.filename); }; $$self.$$.update = () => { if ($$self.$$.dirty & 124958) { $: { if (docs && docs.length >= 1) { if (docs[0].mtime < docs[1].mtime) { $$invalidate(1, docA = docs[0]); $$invalidate(2, docB = docs[1]); } else { $$invalidate(1, docA = docs[1]); $$invalidate(2, docB = docs[0]); } $$invalidate(3, docAContent = docToString(docA)); $$invalidate(4, docBContent = docToString(docB)); try { $$invalidate(13, objA = false); $$invalidate(14, objB = false); $$invalidate(13, objA = JSON.parse(docAContent)); $$invalidate(14, objB = JSON.parse(docBContent)); $$invalidate(15, objAB = mergeObject(objA, objB)); $$invalidate(16, objBA = mergeObject(objB, objA)); if (JSON.stringify(objAB) == JSON.stringify(objBA)) { $$invalidate(16, objBA = false); } } catch (ex) { $$invalidate(16, objBA = false); $$invalidate(15, objAB = false); } } } } if ($$self.$$.dirty & 122880) { $: $$invalidate(7, mergedObjs = { "": false, A: objA, B: objB, AB: objAB, BA: objBA }); } if ($$self.$$.dirty & 160) { $: $$invalidate(6, selectedObj = mode in mergedObjs ? mergedObjs[mode] : {}); } if ($$self.$$.dirty & 8256) { $: { $$invalidate(8, diffs = getJsonDiff(objA, selectedObj)); console.dir(selectedObj); } } }; return [ filename, docA, docB, docAContent, docBContent, mode, selectedObj, mergedObjs, diffs, modes, apply, docs, callback, objA, objB, objAB, objBA, input_change_handler, $$binding_groups ]; } var JsonResolvePane = class extends SvelteComponent { constructor(options) { super(); init2(this, options, instance2, create_fragment2, safe_not_equal, { docs: 11, callback: 12, filename: 0 }, add_css2); } }; var JsonResolvePane_default = JsonResolvePane; // src/JsonResolveModal.ts var JsonResolveModal = class extends import_obsidian.Modal { constructor(app2, filename, docs, callback) { super(app2); this.callback = callback; this.filename = filename; this.docs = docs; } async UICallback(keepRev, mergedStr) { this.close(); await this.callback(keepRev, mergedStr); this.callback = null; } onOpen() { const { contentEl } = this; contentEl.empty(); if (this.component == null) { this.component = new JsonResolvePane_default({ target: contentEl, props: { docs: this.docs, filename: this.filename, callback: (keepRev, mergedStr) => this.UICallback(keepRev, mergedStr) } }); } return; } onClose() { const { contentEl } = this; contentEl.empty(); if (this.callback != null) { this.callback(null); } if (this.component != null) { this.component.$destroy(); this.component = null; } } }; // src/CmdHiddenFileSync.ts var HiddenFileSync = class extends LiveSyncCommands { constructor() { super(...arguments); this.periodicInternalFileScanProcessor = new PeriodicProcessor(this.plugin, async () => this.settings.syncInternalFiles && this.localDatabase.isReady && await this.syncInternalFilesAndDatabase("push", false)); this.confirmPopup = null; this.procInternalFiles = []; this.recentProcessedInternalFiles = []; } get kvDB() { return this.plugin.kvDB; } ensureDirectoryEx(fullPath) { return this.plugin.ensureDirectoryEx(fullPath); } getConflictedDoc(path, rev2) { return this.plugin.getConflictedDoc(path, rev2); } onunload() { var _a; (_a = this.periodicInternalFileScanProcessor) == null ? void 0 : _a.disable(); } onload() { this.plugin.addCommand({ id: "livesync-scaninternal", name: "Sync hidden files", callback: () => { this.syncInternalFilesAndDatabase("safe", true); } }); } async onInitializeDatabase(showNotice) { if (this.settings.syncInternalFiles) { try { Logger("Synchronizing hidden files..."); await this.syncInternalFilesAndDatabase("push", showNotice); Logger("Synchronizing hidden files done"); } catch (ex) { Logger("Synchronizing hidden files failed"); Logger(ex, LOG_LEVEL.VERBOSE); } } } async beforeReplicate(showNotice) { if (this.localDatabase.isReady && this.settings.syncInternalFiles && this.settings.syncInternalFilesBeforeReplication && !this.settings.watchInternalFileChanges) { await this.syncInternalFilesAndDatabase("push", showNotice); } } async onResume() { var _a; (_a = this.periodicInternalFileScanProcessor) == null ? void 0 : _a.disable(); if (this.plugin.suspended) return; if (this.settings.syncInternalFiles) { await this.syncInternalFilesAndDatabase("safe", false); } this.periodicInternalFileScanProcessor.enable(this.settings.syncInternalFiles && this.settings.syncInternalFilesInterval ? this.settings.syncInternalFilesInterval * 1e3 : 0); } parseReplicationResultItem(docs) { return false; } realizeSettingSyncMode() { var _a; (_a = this.periodicInternalFileScanProcessor) == null ? void 0 : _a.disable(); if (this.plugin.suspended) return; if (!this.plugin.isReady) return; this.periodicInternalFileScanProcessor.enable(this.settings.syncInternalFiles && this.settings.syncInternalFilesInterval ? this.settings.syncInternalFilesInterval * 1e3 : 0); return; } async execInternalFile() { await runWithLock("execinternal", false, async () => { const w = [...this.procInternalFiles]; this.procInternalFiles = []; Logger(`Applying hidden ${w.length} files change...`); await this.syncInternalFilesAndDatabase("pull", false, false, w); Logger(`Applying hidden ${w.length} files changed`); }); } procInternalFile(filename) { this.procInternalFiles.push(filename); scheduleTask("procInternal", 500, async () => { await this.execInternalFile(); }); } async watchVaultRawEventsAsync(path) { const stat = await this.app.vault.adapter.stat(path); if (stat && stat.type != "file") return; const storageMTime = ~~((stat && stat.mtime || 0) / 1e3); const key = `${path}-${storageMTime}`; if (this.recentProcessedInternalFiles.contains(key)) { return; } this.recentProcessedInternalFiles = [key, ...this.recentProcessedInternalFiles].slice(0, 100); const prefixedFileName = addPrefix(path, ICHeader); const filesOnDB = await this.localDatabase.getDBEntryMeta(prefixedFileName); const dbMTime = ~~((filesOnDB && filesOnDB.mtime || 0) / 1e3); if (dbMTime == storageMTime) { return; } if (storageMTime == 0) { await this.deleteInternalFileOnDatabase(path); } else { await this.storeInternalFileToDatabase({ path, ...stat }); const pluginDir = this.app.vault.configDir + "/plugins/"; const pluginFiles = ["manifest.json", "data.json", "style.css", "main.js"]; if (path.startsWith(pluginDir) && pluginFiles.some((e2) => path.endsWith(e2)) && this.settings.usePluginSync) { const pluginName = trimPrefix(path, pluginDir).split("/")[0]; await this.plugin.addOnPluginAndTheirSettings.sweepPlugin(false, pluginName); } } } async resolveConflictOnInternalFiles() { const conflicted = this.localDatabase.findEntries(ICHeader, ICHeaderEnd, { conflicts: true }); for await (const doc of conflicted) { if (!("_conflicts" in doc)) continue; if (isIdOfInternalMetadata(doc._id)) { await this.resolveConflictOnInternalFile(doc.path); } } } async resolveConflictOnInternalFile(path) { var _a, _b; try { const id = await this.path2id(path, ICHeader); const doc = await this.localDatabase.getRaw(id, { conflicts: true }); if (!("_conflicts" in doc)) return false; if (doc._conflicts.length == 0) return false; Logger(`Hidden file conflicted:${path}`); const conflicts = doc._conflicts.sort((a2, b) => Number(a2.split("-")[0]) - Number(b.split("-")[0])); const revA = doc._rev; const revB = conflicts[0]; if (path.endsWith(".json")) { const conflictedRev = conflicts[0]; const conflictedRevNo = Number(conflictedRev.split("-")[0]); const revFrom = await this.localDatabase.getRaw(id, { revs_info: true }); const commonBase = (_b = (_a = revFrom._revs_info.filter((e2) => e2.status == "available" && Number(e2.rev.split("-")[0]) < conflictedRevNo).first()) == null ? void 0 : _a.rev) != null ? _b : ""; const result = await this.plugin.mergeObject(path, commonBase, doc._rev, conflictedRev); if (result) { Logger(`Object merge:${path}`, LOG_LEVEL.INFO); const filename = stripAllPrefixes(path); const isExists = await this.app.vault.adapter.exists(filename); if (!isExists) { await this.ensureDirectoryEx(filename); } await this.app.vault.adapter.write(filename, result); const stat = await this.app.vault.adapter.stat(filename); await this.storeInternalFileToDatabase({ path: filename, ...stat }); await this.extractInternalFileFromDatabase(filename); await this.localDatabase.removeRaw(id, revB); return this.resolveConflictOnInternalFile(path); } else { Logger(`Object merge is not applicable.`, LOG_LEVEL.VERBOSE); } const docAMerge = await this.localDatabase.getDBEntry(path, { rev: revA }); const docBMerge = await this.localDatabase.getDBEntry(path, { rev: revB }); if (docAMerge != false && docBMerge != false) { if (await this.showJSONMergeDialogAndMerge(docAMerge, docBMerge)) { await delay(200); return this.resolveConflictOnInternalFile(path); } return false; } } const revBDoc = await this.localDatabase.getRaw(id, { rev: revB }); const mtimeA = "mtime" in doc && doc.mtime || 0; const mtimeB = "mtime" in revBDoc && revBDoc.mtime || 0; const delRev = mtimeA < mtimeB ? revA : revB; await this.localDatabase.removeRaw(id, delRev); Logger(`Older one has been deleted:${path}`); return this.resolveConflictOnInternalFile(path); } catch (ex) { Logger(`Failed to resolve conflict (Hidden): ${path}`); Logger(ex, LOG_LEVEL.VERBOSE); return false; } } async syncInternalFilesAndDatabase(direction, showMessage, files = false, targetFiles = false) { await this.resolveConflictOnInternalFiles(); const logLevel = showMessage ? LOG_LEVEL.NOTICE : LOG_LEVEL.INFO; Logger("Scanning hidden files.", logLevel, "sync_internal"); const ignorePatterns = this.settings.syncInternalFilesIgnorePatterns.replace(/\n| /g, "").split(",").filter((e2) => e2).map((e2) => new RegExp(e2, "i")); if (!files) files = await this.scanInternalFiles(); const filesOnDB = (await this.localDatabase.allDocsRaw({ startkey: ICHeader, endkey: ICHeaderEnd, include_docs: true })).rows.map((e2) => e2.doc).filter((e2) => !e2.deleted); const allFileNamesSrc = [.../* @__PURE__ */ new Set([...files.map((e2) => normalizePath(e2.path)), ...filesOnDB.map((e2) => stripAllPrefixes(this.getPath(e2)))])]; const allFileNames = allFileNamesSrc.filter((filename) => !targetFiles || targetFiles && targetFiles.indexOf(filename) !== -1); function compareMTime(a2, b) { const wa = ~~(a2 / 1e3); const wb = ~~(b / 1e3); const diff = wa - wb; return diff; } const fileCount = allFileNames.length; let processed = 0; let filesChanged = 0; const updatedFolders = {}; const countUpdatedFolder = (path) => { const pieces = path.split("/"); let c = pieces.shift(); let pathPieces = ""; filesChanged++; while (c) { pathPieces += (pathPieces != "" ? "/" : "") + c; pathPieces = normalizePath(pathPieces); if (!(pathPieces in updatedFolders)) { updatedFolders[pathPieces] = 0; } updatedFolders[pathPieces]++; c = pieces.shift(); } }; const p = []; const semaphore = Semaphore(10); let caches = {}; caches = await this.kvDB.get("diff-caches-internal") || {}; for (const filename of allFileNames) { if (!filename) continue; processed++; if (processed % 100 == 0) Logger(`Hidden file: ${processed}/${fileCount}`, logLevel, "sync_internal"); if (ignorePatterns.some((e2) => filename.match(e2))) continue; const fileOnStorage = files.find((e2) => e2.path == filename); const fileOnDatabase = filesOnDB.find((e2) => stripAllPrefixes(this.getPath(e2)) == filename); const addProc = async (p2) => { const releaser = await semaphore.acquire(1); try { return p2(); } catch (ex) { Logger("Some process failed", logLevel); Logger(ex); } finally { releaser(); } }; const cache = filename in caches ? caches[filename] : { storageMtime: 0, docMtime: 0 }; p.push(addProc(async () => { const xFileOnStorage = fileOnStorage; const xFileOnDatabase = fileOnDatabase; if (xFileOnStorage && xFileOnDatabase) { if (direction != "pullForce" && direction != "pushForce" && xFileOnDatabase.mtime == cache.docMtime && xFileOnStorage.mtime == cache.storageMtime) { return; } const nw = compareMTime(xFileOnStorage.mtime, xFileOnDatabase.mtime); if (nw > 0 || direction == "pushForce") { await this.storeInternalFileToDatabase(xFileOnStorage); } if (nw < 0 || direction == "pullForce") { if (!await this.extractInternalFileFromDatabase(filename)) return; } cache.docMtime = xFileOnDatabase.mtime; cache.storageMtime = xFileOnStorage.mtime; caches[filename] = cache; countUpdatedFolder(filename); } else if (!xFileOnStorage && xFileOnDatabase) { if (direction == "push" || direction == "pushForce") { if (xFileOnDatabase.deleted) return; await this.deleteInternalFileOnDatabase(filename, false); } else if (direction == "pull" || direction == "pullForce") { if (await this.extractInternalFileFromDatabase(filename)) { countUpdatedFolder(filename); } } else if (direction == "safe") { if (xFileOnDatabase.deleted) return; if (await this.extractInternalFileFromDatabase(filename)) { countUpdatedFolder(filename); } } } else if (xFileOnStorage && !xFileOnDatabase) { await this.storeInternalFileToDatabase(xFileOnStorage); } else { throw new Error("Invalid state on hidden file sync"); } })); } await Promise.all(p); await this.kvDB.set("diff-caches-internal", caches); if ((direction == "pull" || direction == "pullForce") && filesChanged != 0) { const configDir = normalizePath(this.app.vault.configDir); if (configDir in updatedFolders) { let updatedCount = updatedFolders[configDir]; try { const manifests = Object.values(this.app.plugins.manifests); const enabledPlugins = this.app.plugins.enabledPlugins; const enabledPluginManifests = manifests.filter((e2) => enabledPlugins.has(e2.id)); for (const manifest of enabledPluginManifests) { if (manifest.dir in updatedFolders) { updatedCount -= updatedFolders[manifest.dir]; const updatePluginId = manifest.id; const updatePluginName = manifest.name; const fragment = createFragment((doc) => { doc.createEl("span", null, (a2) => { a2.appendText(`Files in ${updatePluginName} has been updated, Press `); a2.appendChild(a2.createEl("a", null, (anchor) => { anchor.text = "HERE"; anchor.addEventListener("click", async () => { Logger(`Unloading plugin: ${updatePluginName}`, LOG_LEVEL.NOTICE, "plugin-reload-" + updatePluginId); await this.app.plugins.unloadPlugin(updatePluginId); await this.app.plugins.loadPlugin(updatePluginId); Logger(`Plugin reloaded: ${updatePluginName}`, LOG_LEVEL.NOTICE, "plugin-reload-" + updatePluginId); }); })); a2.appendText(` to reload ${updatePluginName}, or press elsewhere to dismiss this message.`); }); }); const updatedPluginKey = "popupUpdated-" + updatePluginId; scheduleTask(updatedPluginKey, 1e3, async () => { var _a; const popup = await memoIfNotExist(updatedPluginKey, () => new import_obsidian.Notice(fragment, 0)); const isShown = (_a = popup == null ? void 0 : popup.noticeEl) == null ? void 0 : _a.isShown(); if (!isShown) { memoObject(updatedPluginKey, new import_obsidian.Notice(fragment, 0)); } scheduleTask(updatedPluginKey + "-close", 2e4, () => { var _a2; const popup2 = retrieveMemoObject(updatedPluginKey); if (!popup2) return; if ((_a2 = popup2 == null ? void 0 : popup2.noticeEl) == null ? void 0 : _a2.isShown()) { popup2.hide(); } disposeMemoObject(updatedPluginKey); }); }); } } } catch (ex) { Logger("Error on checking plugin status."); Logger(ex, LOG_LEVEL.VERBOSE); } if (updatedCount != 0) { const fragment = createFragment((doc) => { doc.createEl("span", null, (a2) => { a2.appendText(`Hidden files have been synchronized, Press `); a2.appendChild(a2.createEl("a", null, (anchor) => { anchor.text = "HERE"; anchor.addEventListener("click", () => { this.app.commands.executeCommandById("app:reload"); }); })); a2.appendText(` to reload obsidian, or press elsewhere to dismiss this message.`); }); }); scheduleTask("popupUpdated-" + configDir, 1e3, () => { var _a, _b; const isShown = (_b = (_a = this.confirmPopup) == null ? void 0 : _a.noticeEl) == null ? void 0 : _b.isShown(); if (!isShown) { this.confirmPopup = new import_obsidian.Notice(fragment, 0); } scheduleTask("popupClose" + configDir, 2e4, () => { var _a2; (_a2 = this.confirmPopup) == null ? void 0 : _a2.hide(); this.confirmPopup = null; }); }); } } } Logger(`Hidden files scanned: ${filesChanged} files had been modified`, logLevel, "sync_internal"); } async storeInternalFileToDatabase(file, forceWrite = false) { const id = await this.path2id(file.path, ICHeader); const prefixedFileName = addPrefix(file.path, ICHeader); const contentBin = await this.app.vault.adapter.readBinary(file.path); let content; try { content = await arrayBufferToBase64(contentBin); } catch (ex) { Logger(`The file ${file.path} could not be encoded`); Logger(ex, LOG_LEVEL.VERBOSE); return false; } const mtime = file.mtime; return await runWithLock("file-" + prefixedFileName, false, async () => { try { const old = await this.localDatabase.getDBEntry(prefixedFileName, null, false, false); let saveData; if (old === false) { saveData = { _id: id, path: prefixedFileName, data: content, mtime, ctime: mtime, datatype: "newnote", size: file.size, children: [], deleted: false, type: "newnote" }; } else { if (isDocContentSame(old.data, content) && !forceWrite) { return; } saveData = { ...old, data: content, mtime, size: file.size, datatype: "newnote", children: [], deleted: false, type: "newnote" }; } const ret = await this.localDatabase.putDBEntry(saveData, true); Logger(`STORAGE --> DB:${file.path}: (hidden) Done`); return ret; } catch (ex) { Logger(`STORAGE --> DB:${file.path}: (hidden) Failed`); Logger(ex, LOG_LEVEL.VERBOSE); return false; } }); } async deleteInternalFileOnDatabase(filename, forceWrite = false) { const id = await this.path2id(filename, ICHeader); const prefixedFileName = addPrefix(filename, ICHeader); const mtime = new Date().getTime(); await runWithLock("file-" + prefixedFileName, false, async () => { try { const old = await this.localDatabase.getDBEntry(prefixedFileName, null, false, false); let saveData; if (old === false) { saveData = { _id: id, path: prefixedFileName, mtime, ctime: mtime, size: 0, children: [], deleted: true, type: "newnote" }; } else { if (old.deleted) { Logger(`STORAGE -x> DB:${filename}: (hidden) already deleted`); return; } saveData = { ...old, mtime, size: 0, children: [], deleted: true, type: "newnote" }; } await this.localDatabase.putRaw(saveData); Logger(`STORAGE -x> DB:${filename}: (hidden) Done`); } catch (ex) { Logger(`STORAGE -x> DB:${filename}: (hidden) Failed`); Logger(ex, LOG_LEVEL.VERBOSE); return false; } }); } async extractInternalFileFromDatabase(filename, force = false) { const isExists = await this.app.vault.adapter.exists(filename); const prefixedFileName = addPrefix(filename, ICHeader); return await runWithLock("file-" + prefixedFileName, false, async () => { var _a; try { const fileOnDB = await this.localDatabase.getDBEntry(prefixedFileName, { conflicts: true }, false, false); if (fileOnDB === false) throw new Error(`File not found on database.:${filename}`); if ((_a = fileOnDB == null ? void 0 : fileOnDB._conflicts) == null ? void 0 : _a.length) { Logger(`Hidden file ${filename} has conflicted revisions, to keep in safe, writing to storage has been prevented`, LOG_LEVEL.INFO); return; } const deleted = "deleted" in fileOnDB ? fileOnDB.deleted : false; if (deleted) { if (!isExists) { Logger(`STORAGE new Promise((res2) => { Logger("Opening data-merging dialog", LOG_LEVEL.VERBOSE); const docs = [docA, docB]; const path = stripAllPrefixes(docA.path); const modal = new JsonResolveModal(this.app, path, [docA, docB], async (keep, result) => { try { const filename = path; let needFlush = false; if (!result && !keep) { Logger(`Skipped merging: ${filename}`); res2(false); return; } if (result || keep) { for (const doc of docs) { if (doc._rev != keep) { if (await this.localDatabase.deleteDBEntry(this.getPath(doc), { rev: doc._rev })) { Logger(`Conflicted revision has been deleted: ${filename}`); needFlush = true; } } } } if (!keep && result) { const isExists = await this.app.vault.adapter.exists(filename); if (!isExists) { await this.ensureDirectoryEx(filename); } await this.app.vault.adapter.write(filename, result); const stat = await this.app.vault.adapter.stat(filename); await this.storeInternalFileToDatabase({ path: filename, ...stat }, true); try { await app.vault.adapter.reconcileInternalFile(filename); } catch (ex) { Logger("Failed to call internal API(reconcileInternalFile)", LOG_LEVEL.VERBOSE); Logger(ex, LOG_LEVEL.VERBOSE); } Logger(`STORAGE <-- DB:${filename}: written (hidden,merged)`); } if (needFlush) { await this.extractInternalFileFromDatabase(filename, false); Logger(`STORAGE --> DB:${filename}: extracted (hidden,merged)`); } res2(true); } catch (ex) { Logger("Could not merge conflicted json"); Logger(ex, LOG_LEVEL.VERBOSE); res2(false); } }); modal.open(); })); } async scanInternalFiles() { const ignoreFilter = this.settings.syncInternalFilesIgnorePatterns.replace(/\n| /g, "").split(",").filter((e2) => e2).map((e2) => new RegExp(e2, "i")); const root = this.app.vault.getRoot(); const findRoot = root.path; const filenames = (await this.getFiles(findRoot, [], null, ignoreFilter)).filter((e2) => e2.startsWith(".")).filter((e2) => !e2.startsWith(".trash")); const files = filenames.map(async (e2) => { return { path: e2, stat: await this.app.vault.adapter.stat(e2) }; }); const result = []; for (const f3 of files) { const w = await f3; result.push({ ...w, ...w.stat }); } return result; } async getFiles(path, ignoreList, filter2, ignoreFilter) { const w = await this.app.vault.adapter.list(path); let files = [ ...w.files.filter((e2) => !ignoreList.some((ee) => e2.endsWith(ee))).filter((e2) => !filter2 || filter2.some((ee) => e2.match(ee))).filter((e2) => !ignoreFilter || ignoreFilter.every((ee) => !e2.match(ee))) ]; L1: for (const v of w.folders) { for (const ignore of ignoreList) { if (v.endsWith(ignore)) { continue L1; } } if (ignoreFilter && ignoreFilter.some((e2) => v.match(e2))) { continue L1; } files = files.concat(await this.getFiles(v, ignoreList, filter2, ignoreFilter)); } return files; } }; // src/CmdSetupLiveSync.ts var SetupLiveSync = class extends LiveSyncCommands { onunload() { } onload() { this.plugin.registerObsidianProtocolHandler("setuplivesync", async (conf) => await this.setupWizard(conf.settings)); this.plugin.addCommand({ id: "livesync-copysetupuri", name: "Copy the setup URI", callback: this.command_copySetupURI.bind(this) }); this.plugin.addCommand({ id: "livesync-copysetupurifull", name: "Copy the setup URI (Full)", callback: this.command_copySetupURIFull.bind(this) }); this.plugin.addCommand({ id: "livesync-opensetupuri", name: "Open the setup URI", callback: this.command_openSetupURI.bind(this) }); } onInitializeDatabase(showNotice) { } beforeReplicate(showNotice) { } onResume() { } parseReplicationResultItem(docs) { return false; } async realizeSettingSyncMode() { } async command_copySetupURI() { const encryptingPassphrase = await askString(this.app, "Encrypt your settings", "The passphrase to encrypt the setup URI", ""); if (encryptingPassphrase === false) return; const setting = { ...this.settings, configPassphraseStore: "", encryptedCouchDBConnection: "", encryptedPassphrase: "" }; const keys2 = Object.keys(setting); for (const k of keys2) { if (JSON.stringify(k in setting ? setting[k] : "") == JSON.stringify(k in DEFAULT_SETTINGS ? DEFAULT_SETTINGS[k] : "*")) { delete setting[k]; } } const encryptedSetting = encodeURIComponent(await encrypt(JSON.stringify(setting), encryptingPassphrase, false)); const uri = `${configURIBase}${encryptedSetting}`; await navigator.clipboard.writeText(uri); Logger("Setup URI copied to clipboard", LOG_LEVEL.NOTICE); } async command_copySetupURIFull() { const encryptingPassphrase = await askString(this.app, "Encrypt your settings", "The passphrase to encrypt the setup URI", ""); if (encryptingPassphrase === false) return; const setting = { ...this.settings, configPassphraseStore: "", encryptedCouchDBConnection: "", encryptedPassphrase: "" }; const encryptedSetting = encodeURIComponent(await encrypt(JSON.stringify(setting), encryptingPassphrase, false)); const uri = `${configURIBase}${encryptedSetting}`; await navigator.clipboard.writeText(uri); Logger("Setup URI copied to clipboard", LOG_LEVEL.NOTICE); } async command_openSetupURI() { const setupURI = await askString(this.app, "Easy setup", "Set up URI", `${configURIBase}aaaaa`); if (setupURI === false) return; if (!setupURI.startsWith(`${configURIBase}`)) { Logger("Set up URI looks wrong.", LOG_LEVEL.NOTICE); return; } const config = decodeURIComponent(setupURI.substring(configURIBase.length)); console.dir(config); await this.setupWizard(config); } async setupWizard(confString) { try { const oldConf = JSON.parse(JSON.stringify(this.settings)); const encryptingPassphrase = await askString(this.app, "Passphrase", "The passphrase to decrypt your setup URI", ""); if (encryptingPassphrase === false) return; const newConf = await JSON.parse(await decrypt(confString, encryptingPassphrase, false)); if (newConf) { const result = await askYesNo(this.app, "Importing LiveSync's conf, OK?"); if (result == "yes") { const newSettingW = Object.assign({}, DEFAULT_SETTINGS, newConf); this.plugin.replicator.closeReplication(); this.settings.suspendFileWatching = true; console.dir(newSettingW); newSettingW.configPassphraseStore = ""; newSettingW.encryptedPassphrase = ""; newSettingW.encryptedCouchDBConnection = ""; const setupJustImport = "Just import setting"; const setupAsNew = "Set it up as secondary or subsequent device"; const setupAgain = "Reconfigure and reconstitute the data"; const setupManually = "Leave everything to me"; newSettingW.syncInternalFiles = false; newSettingW.usePluginSync = false; const setupType = await askSelectString(this.app, "How would you like to set it up?", [setupAsNew, setupAgain, setupJustImport, setupManually]); if (setupType == setupJustImport) { this.plugin.settings = newSettingW; this.plugin.usedPassphrase = ""; await this.plugin.saveSettings(); } else if (setupType == setupAsNew) { this.plugin.settings = newSettingW; this.plugin.usedPassphrase = ""; await this.fetchLocal(); } else if (setupType == setupAgain) { const confirm = "I know this operation will rebuild all my databases with files on this device, and files that are on the remote database and I didn't synchronize to any other devices will be lost and want to proceed indeed."; if (await askSelectString(this.app, "Do you really want to do this?", ["Cancel", confirm]) != confirm) { return; } this.plugin.settings = newSettingW; this.plugin.usedPassphrase = ""; await this.rebuildEverything(); } else if (setupType == setupManually) { const keepLocalDB = await askYesNo(this.app, "Keep local DB?"); const keepRemoteDB = await askYesNo(this.app, "Keep remote DB?"); if (keepLocalDB == "yes" && keepRemoteDB == "yes") { this.plugin.settings = newSettingW; this.plugin.usedPassphrase = ""; this.suspendAllSync(); this.suspendExtraSync(); await this.plugin.saveSettings(); const replicate2 = await askYesNo(this.app, "Unlock and replicate?"); if (replicate2 == "yes") { await this.plugin.replicate(true); await this.plugin.markRemoteUnlocked(); } Logger("Configuration loaded.", LOG_LEVEL.NOTICE); return; } if (keepLocalDB == "no" && keepRemoteDB == "no") { const reset = await askYesNo(this.app, "Drop everything?"); if (reset != "yes") { Logger("Cancelled", LOG_LEVEL.NOTICE); this.plugin.settings = oldConf; return; } } let initDB; this.plugin.settings = newSettingW; this.plugin.usedPassphrase = ""; await this.plugin.saveSettings(); if (keepLocalDB == "no") { await this.plugin.resetLocalDatabase(); await this.plugin.localDatabase.initializeDatabase(); const rebuild = await askYesNo(this.app, "Rebuild the database?"); if (rebuild == "yes") { initDB = this.plugin.initializeDatabase(true); } else { await this.plugin.markRemoteResolved(); } } if (keepRemoteDB == "no") { await this.plugin.tryResetRemoteDatabase(); await this.plugin.markRemoteLocked(); } if (keepLocalDB == "no" || keepRemoteDB == "no") { const replicate2 = await askYesNo(this.app, "Replicate once?"); if (replicate2 == "yes") { if (initDB != null) { await initDB; } await this.plugin.replicate(true); } } } } Logger("Configuration loaded.", LOG_LEVEL.NOTICE); } else { Logger("Cancelled.", LOG_LEVEL.NOTICE); } } catch (ex) { Logger("Couldn't parse or decrypt configuration uri.", LOG_LEVEL.NOTICE); } } suspendExtraSync() { Logger("Hidden files and plugin synchronization have been temporarily disabled. Please enable them after the fetching, if you need them.", LOG_LEVEL.NOTICE); this.plugin.settings.syncInternalFiles = false; this.plugin.settings.usePluginSync = false; this.plugin.settings.autoSweepPlugins = false; } async askHiddenFileConfiguration(opt) { this.plugin.addOnSetup.suspendExtraSync(); const message = `Would you like to enable \`Hidden File Synchronization\`? ${opt.enableFetch ? " - Fetch: Use files stored from other devices. \n" : ""}${opt.enableOverwrite ? "- Overwrite: Use files from this device. \n" : ""}- Keep it disabled: Do not use hidden file synchronization. Of course, we are able to disable this feature.`; const CHOICE_FETCH = "Fetch"; const CHOICE_OVERWRITE = "Overwrite"; const CHOICE_DISMISS = "keep it disabled"; const choices = []; if (opt == null ? void 0 : opt.enableFetch) { choices.push(CHOICE_FETCH); } if (opt == null ? void 0 : opt.enableOverwrite) { choices.push(CHOICE_OVERWRITE); } choices.push(CHOICE_DISMISS); const ret = await confirmWithMessage(this.plugin, "Hidden file sync", message, choices, CHOICE_DISMISS, 40); if (ret == CHOICE_FETCH) { await this.configureHiddenFileSync("FETCH"); } else if (ret == CHOICE_OVERWRITE) { await this.configureHiddenFileSync("OVERWRITE"); } else if (ret == CHOICE_DISMISS) { await this.configureHiddenFileSync("DISABLE"); } } async configureHiddenFileSync(mode) { this.plugin.addOnSetup.suspendExtraSync(); if (mode == "DISABLE") { this.plugin.settings.syncInternalFiles = false; await this.plugin.saveSettings(); return; } Logger("Gathering files for enabling Hidden File Sync", LOG_LEVEL.NOTICE); if (mode == "FETCH") { await this.plugin.addOnHiddenFileSync.syncInternalFilesAndDatabase("pullForce", true); } else if (mode == "OVERWRITE") { await this.plugin.addOnHiddenFileSync.syncInternalFilesAndDatabase("pushForce", true); } else if (mode == "MERGE") { await this.plugin.addOnHiddenFileSync.syncInternalFilesAndDatabase("safe", true); } this.plugin.settings.syncInternalFiles = true; await this.plugin.saveSettings(); Logger(`Done! Restarting the app is strongly recommended!`, LOG_LEVEL.NOTICE); } suspendAllSync() { this.plugin.settings.liveSync = false; this.plugin.settings.periodicReplication = false; this.plugin.settings.syncOnSave = false; this.plugin.settings.syncOnStart = false; this.plugin.settings.syncOnFileOpen = false; this.plugin.settings.syncAfterMerge = false; } async fetchLocal() { this.suspendExtraSync(); await this.plugin.realizeSettingSyncMode(); await this.plugin.resetLocalDatabase(); await delay(1e3); await this.plugin.markRemoteResolved(); await this.plugin.openDatabase(); this.plugin.isReady = true; await delay(500); await this.plugin.replicateAllFromServer(true); await delay(1e3); await this.plugin.replicateAllFromServer(true); await this.askHiddenFileConfiguration({ enableFetch: true }); } async rebuildRemote() { this.suspendExtraSync(); await this.plugin.realizeSettingSyncMode(); await this.plugin.markRemoteLocked(); await this.plugin.tryResetRemoteDatabase(); await this.plugin.markRemoteLocked(); await delay(500); await this.askHiddenFileConfiguration({ enableOverwrite: true }); await delay(1e3); await this.plugin.replicateAllToServer(true); await delay(1e3); await this.plugin.replicateAllToServer(true); } async rebuildEverything() { this.suspendExtraSync(); await this.plugin.realizeSettingSyncMode(); await this.plugin.resetLocalDatabase(); await delay(1e3); await this.plugin.initializeDatabase(true); await this.plugin.markRemoteLocked(); await this.plugin.tryResetRemoteDatabase(); await this.plugin.markRemoteLocked(); await delay(500); await this.askHiddenFileConfiguration({ enableOverwrite: true }); await delay(1e3); await this.plugin.replicateAllToServer(true); await delay(1e3); await this.plugin.replicateAllToServer(true); } }; // src/main.ts var isDebug = false; setNoticeClass(import_obsidian.Notice); var ObsidianLiveSyncPlugin = class extends import_obsidian.Plugin { constructor() { super(...arguments); this.isMobile = false; this.isReady = false; this.packageVersion = ""; this.manifestVersion = ""; this.addOnPluginAndTheirSettings = new PluginAndTheirSettings(this); this.addOnHiddenFileSync = new HiddenFileSync(this); this.addOnSetup = new SetupLiveSync(this); this.addOns = [this.addOnPluginAndTheirSettings, this.addOnHiddenFileSync, this.addOnSetup]; this.periodicSyncProcessor = new PeriodicProcessor(this, async () => await this.replicate()); this.last_successful_post = false; this.processReplication = (e2) => this.parseReplicationResult(e2); this.replicationStat = new ObservableStore({ sent: 0, arrived: 0, maxPullSeq: 0, maxPushSeq: 0, lastSyncPullSeq: 0, lastSyncPushSeq: 0, syncStatus: "CLOSED" }); this.usedPassphrase = ""; this.notifies = {}; this.lastLog = ""; this.queuedEntries = []; this.dbChangeProcRunning = false; this.queuedFiles = []; this.queuedFilesStore = getGlobalStore("queuedFiles", { queuedItems: [], fileEventItems: [] }); this.chunkWaitTimeout = 6e4; this.lastMessage = ""; this.logHideTimer = null; this.conflictedCheckFiles = []; } getLastPostFailedBySize() { return !this.last_successful_post; } async fetchByAPI(request) { var _a, _b; const ret = await (0, import_obsidian.requestUrl)(request); if (ret.status - ret.status % 100 !== 200) { const er = new Error(`Request Error:${ret.status}`); if (ret.json) { er.message = ret.json.reason; er.name = `${(_a = ret.json.error) != null ? _a : ""}:${(_b = ret.json.message) != null ? _b : ""}`; } er.status = ret.status; throw er; } return ret; } getDatabase() { return this.localDatabase.localDatabase; } getSettings() { return this.settings; } getIsMobile() { return this.isMobile; } async connectRemoteCouchDB(uri, auth, disableRequestURI, passphrase, useDynamicIterationCount) { if (!isValidRemoteCouchDBURI(uri)) return "Remote URI is not valid"; if (uri.toLowerCase() != uri) return "Remote URI and database name could not contain capital letters."; if (uri.indexOf(" ") !== -1) return "Remote URI and database name could not contain spaces."; let authHeader = ""; if (auth.username && auth.password) { const utf8str = String.fromCharCode.apply(null, new TextEncoder().encode(`${auth.username}:${auth.password}`)); const encoded = window.btoa(utf8str); authHeader = "Basic " + encoded; } else { authHeader = ""; } const conf = { adapter: "http", auth, fetch: async (url, opts) => { var _a, _b; let size = ""; const localURL = url.toString().substring(uri.length); const method = (_a = opts.method) != null ? _a : "GET"; if (opts.body) { const opts_length = opts.body.toString().length; if (opts_length > 1e3 * 1e3 * 10) { if (isCloudantURI(uri)) { this.last_successful_post = false; Logger("This request should fail on IBM Cloudant.", LOG_LEVEL.VERBOSE); throw new Error("This request should fail on IBM Cloudant."); } } size = ` (${opts_length})`; } if (!disableRequestURI && typeof url == "string" && typeof ((_b = opts.body) != null ? _b : "") == "string") { const body = opts.body; const transformedHeaders = { ...opts.headers }; if (authHeader != "") transformedHeaders["authorization"] = authHeader; delete transformedHeaders["host"]; delete transformedHeaders["Host"]; delete transformedHeaders["content-length"]; delete transformedHeaders["Content-Length"]; const requestParam = { url, method: opts.method, body, headers: transformedHeaders, contentType: "application/json" }; try { const r = await this.fetchByAPI(requestParam); if (method == "POST" || method == "PUT") { this.last_successful_post = r.status - r.status % 100 == 200; } else { this.last_successful_post = true; } Logger(`HTTP:${method}${size} to:${localURL} -> ${r.status}`, LOG_LEVEL.DEBUG); return new Response(r.arrayBuffer, { headers: r.headers, status: r.status, statusText: `${r.status}` }); } catch (ex) { Logger(`HTTP:${method}${size} to:${localURL} -> failed`, LOG_LEVEL.VERBOSE); if (url.toString().indexOf("_bulk_docs") !== -1) { this.last_successful_post = false; } Logger(ex); throw ex; } } try { const response = await fetch(url, opts); if (method == "POST" || method == "PUT") { this.last_successful_post = response.ok; } else { this.last_successful_post = true; } Logger(`HTTP:${method}${size} to:${localURL} -> ${response.status}`, LOG_LEVEL.DEBUG); return response; } catch (ex) { Logger(`HTTP:${method}${size} to:${localURL} -> failed`, LOG_LEVEL.VERBOSE); if (url.toString().indexOf("_bulk_docs") !== -1) { this.last_successful_post = false; } Logger(ex); throw ex; } } }; const db = new index_es_default(uri, conf); if (passphrase !== "false" && typeof passphrase === "string") { enableEncryption(db, passphrase, useDynamicIterationCount); } try { const info2 = await db.info(); return { db, info: info2 }; } catch (ex) { let msg = `${ex.name}:${ex.message}`; if (ex.name == "TypeError" && ex.message == "Failed to fetch") { msg += "\n**Note** This error caused by many reasons. The only sure thing is you didn't touch the server.\nTo check details, open inspector."; } Logger(ex, LOG_LEVEL.VERBOSE); return msg; } } id2path(id, entry, stripPrefix2) { const tempId = id2path(id, entry); if (stripPrefix2 && isIdOfInternalMetadata(tempId)) { const out = stripInternalMetadataPrefix(tempId); return out; } return tempId; } getPath(entry) { return getPath2(entry); } getPathWithoutPrefix(entry) { return getPathWithoutPrefix(entry); } async path2id(filename, prefix) { const destPath = addPrefix(filename, prefix); return await path2id(destPath, this.settings.usePathObfuscation ? this.settings.passphrase : ""); } createPouchDBInstance(name, options) { if (this.settings.useIndexedDBAdapter) { options.adapter = "indexeddb"; return new index_es_default(name + "-indexeddb", options); } return new index_es_default(name, options); } beforeOnUnload(db) { this.kvDB.close(); } onClose(db) { this.kvDB.close(); } async onInitializeDatabase(db) { this.kvDB = await OpenKeyValueDatabase(db.dbname + "-livesync-kv"); this.replicator = new LiveSyncDBReplicator(this); } async onResetDatabase(db) { await this.kvDB.destroy(); this.kvDB = await OpenKeyValueDatabase(db.dbname + "-livesync-kv"); this.replicator = new LiveSyncDBReplicator(this); } getReplicator() { return this.replicator; } getVaultName() { var _a; return this.app.vault.getName() + (((_a = this.settings) == null ? void 0 : _a.additionalSuffixOfDatabaseName) ? "-" + this.settings.additionalSuffixOfDatabaseName : ""); } setInterval(handler, timeout) { const timer = window.setInterval(handler, timeout); this.registerInterval(timer); return timer; } isRedFlagRaised() { const redflag = getAbstractFileByPath(normalizePath(FLAGMD_REDFLAG)); if (redflag != null) { return true; } return false; } isRedFlag2Raised() { const redflag = getAbstractFileByPath(normalizePath(FLAGMD_REDFLAG2)); if (redflag != null) { return true; } return false; } async deleteRedFlag2() { const redflag = getAbstractFileByPath(normalizePath(FLAGMD_REDFLAG2)); if (redflag != null) { await app.vault.delete(redflag, true); } } isRedFlag3Raised() { const redflag = getAbstractFileByPath(normalizePath(FLAGMD_REDFLAG3)); if (redflag != null) { return true; } return false; } async deleteRedFlag3() { const redflag = getAbstractFileByPath(normalizePath(FLAGMD_REDFLAG3)); if (redflag != null) { await app.vault.delete(redflag, true); } } showHistory(file, id) { new DocumentHistoryModal(this.app, this, file, id).open(); } async fileHistory() { const notes = []; for await (const doc of this.localDatabase.findAllDocs()) { notes.push({ id: doc._id, path: this.getPath(doc), dispPath: this.getPathWithoutPrefix(doc), mtime: doc.mtime }); } notes.sort((a2, b) => b.mtime - a2.mtime); const notesList = notes.map((e2) => e2.dispPath); const target = await askSelectString(this.app, "File to view History", notesList); if (target) { const targetId = notes.find((e2) => e2.dispPath == target); this.showHistory(targetId.path, void 0); } } async pickFileForResolve() { const notes = []; for await (const doc of this.localDatabase.findAllDocs({ conflicts: true })) { if (!("_conflicts" in doc)) continue; notes.push({ id: doc._id, path: this.getPath(doc), dispPath: this.getPathWithoutPrefix(doc), mtime: doc.mtime }); } notes.sort((a2, b) => b.mtime - a2.mtime); const notesList = notes.map((e2) => e2.dispPath); if (notesList.length == 0) { Logger("There are no conflicted documents", LOG_LEVEL.NOTICE); return false; } const target = await askSelectString(this.app, "File to view History", notesList); if (target) { const targetItem = notes.find((e2) => e2.dispPath == target); await this.resolveConflicted(targetItem.path); return true; } return false; } async resolveConflicted(target) { if (isIdOfInternalMetadata(target)) { await this.addOnHiddenFileSync.resolveConflictOnInternalFile(target); } else if (isPluginMetadata(target)) { await this.resolveConflictByNewerEntry(target); } else { await this.showIfConflicted(target); } } async collectDeletedFiles() { const limitDays = this.settings.automaticallyDeleteMetadataOfDeletedFiles; if (limitDays <= 0) return; Logger(`Checking expired file history`); const limit = Date.now() - 86400 * 1e3 * limitDays; const notes = []; for await (const doc of this.localDatabase.findAllDocs({ conflicts: true })) { if (doc.type == "newnote" || doc.type == "plain") { if (doc.deleted && doc.mtime - limit < 0) { notes.push({ path: this.getPath(doc), mtime: doc.mtime, ttl: (doc.mtime - limit) / 1e3 / 86400, doc }); } } } if (notes.length == 0) { Logger("There are no old documents"); Logger(`Checking expired file history done`); return; } for (const v of notes) { Logger(`Deletion history expired: ${v.path}`); const delDoc = v.doc; delDoc._deleted = true; await this.localDatabase.putRaw(delDoc); } Logger(`Checking expired file history done`); } async onLayoutReady() { this.registerFileWatchEvents(); if (!this.localDatabase.isReady) { Logger(`Something went wrong! The local database is not ready`, LOG_LEVEL.NOTICE); return; } try { if (this.isRedFlagRaised() || this.isRedFlag2Raised() || this.isRedFlag3Raised()) { this.settings.batchSave = false; this.addOnSetup.suspendAllSync(); this.addOnSetup.suspendExtraSync(); this.settings.suspendFileWatching = true; await this.saveSettings(); if (this.isRedFlag2Raised()) { Logger(`${FLAGMD_REDFLAG2} has been detected! Self-hosted LiveSync suspends all sync and rebuild everything.`, LOG_LEVEL.NOTICE); await this.addOnSetup.rebuildEverything(); await this.deleteRedFlag2(); if (await askYesNo(this.app, "Do you want to disable Suspend file watching and restart obsidian now?") == "yes") { this.settings.suspendFileWatching = false; await this.saveSettings(); this.app.commands.executeCommandById("app:reload"); } } else if (this.isRedFlag3Raised()) { Logger(`${FLAGMD_REDFLAG3} has been detected! Self-hosted LiveSync will discard the local database and fetch everything from the remote once again.`, LOG_LEVEL.NOTICE); await this.addOnSetup.fetchLocal(); await this.deleteRedFlag3(); if (await askYesNo(this.app, "Do you want to disable Suspend file watching and restart obsidian now?") == "yes") { this.settings.suspendFileWatching = false; await this.saveSettings(); this.app.commands.executeCommandById("app:reload"); } } else { this.settings.writeLogToTheFile = true; await this.openDatabase(); const warningMessage = "The red flag is raised! The whole initialize steps are skipped, and any file changes are not captured."; Logger(warningMessage, LOG_LEVEL.NOTICE); this.setStatusBarText(warningMessage); } } else { if (this.settings.suspendFileWatching) { Logger("'Suspend file watching' turned on. Are you sure this is what you intended? Every modification on the vault will be ignored.", LOG_LEVEL.NOTICE); } const isInitialized = await this.initializeDatabase(false, false); if (!isInitialized) { return false; } } await this.realizeSettingSyncMode(); this.registerWatchEvents(); if (this.settings.syncOnStart) { this.replicator.openReplication(this.settings, false, false); } this.scanStat(); } catch (ex) { Logger("Error while loading Self-hosted LiveSync", LOG_LEVEL.NOTICE); Logger(ex, LOG_LEVEL.VERBOSE); } } async scanStat() { const notes = []; Logger(`Additional safety scan..`, LOG_LEVEL.VERBOSE); for await (const doc of this.localDatabase.findAllDocs({ conflicts: true })) { if (!("_conflicts" in doc)) continue; notes.push({ path: this.getPath(doc), mtime: doc.mtime }); } if (notes.length > 0) { Logger(`Some files have been left conflicted! Please resolve them by "Pick a file to resolve conflict". The list is written in the log.`, LOG_LEVEL.NOTICE); for (const note of notes) { Logger(`Conflicted: ${note.path}`); } } else { Logger(`There are no conflicted files`, LOG_LEVEL.VERBOSE); } Logger(`Additional safety scan done`, LOG_LEVEL.VERBOSE); } async onload() { logStore.subscribe((e2) => this.addLog(e2.message, e2.level, e2.key)); Logger("loading plugin"); const manifestVersion = "0.18.6"; const packageVersion = "0.18.6"; this.manifestVersion = manifestVersion; this.packageVersion = packageVersion; Logger(`Self-hosted LiveSync v${manifestVersion} ${packageVersion} `); const lsKey = "obsidian-live-sync-ver" + this.getVaultName(); const last_version = localStorage.getItem(lsKey); await this.loadSettings(); const lastVersion = ~~(versionNumberString2Number(manifestVersion) / 1e3); if (lastVersion > this.settings.lastReadUpdates) { Logger("Self-hosted LiveSync has undergone a major upgrade. Please open the setting dialog, and check the information pane.", LOG_LEVEL.NOTICE); } if (this.app.isMobile) { this.isMobile = true; this.settings.disableRequestURI = true; } if (last_version && Number(last_version) < VER) { this.settings.liveSync = false; this.settings.syncOnSave = false; this.settings.syncOnStart = false; this.settings.syncOnFileOpen = false; this.settings.syncAfterMerge = false; this.settings.periodicReplication = false; this.settings.versionUpFlash = "Self-hosted LiveSync has been upgraded and some behaviors have changed incompatibly. All automatic synchronization is now disabled temporary. Ensure that other devices are also upgraded, and enable synchronization again."; this.saveSettings(); } localStorage.setItem(lsKey, `${VER}`); await this.openDatabase(); this.watchWorkspaceOpen = (0, import_obsidian.debounce)(this.watchWorkspaceOpen.bind(this), 1e3, false); this.watchWindowVisibility = (0, import_obsidian.debounce)(this.watchWindowVisibility.bind(this), 1e3, false); this.watchOnline = (0, import_obsidian.debounce)(this.watchOnline.bind(this), 500, false); this.parseReplicationResult = this.parseReplicationResult.bind(this); this.loadQueuedFiles = this.loadQueuedFiles.bind(this); this.triggerRealizeSettingSyncMode = (0, import_obsidian.debounce)(this.triggerRealizeSettingSyncMode.bind(this), 1e3); this.statusBar = this.addStatusBarItem(); this.statusBar.addClass("syncstatusbar"); (0, import_obsidian.addIcon)( "replicate", ` ` ); (0, import_obsidian.addIcon)( "view-log", ` ` ); await Promise.all(this.addOns.map((e2) => e2.onload())); this.addRibbonIcon("replicate", "Replicate", async () => { await this.replicate(true); }); this.addRibbonIcon("view-log", "Show log", () => { new LogDisplayModal(this.app, this).open(); }); this.addSettingTab(new ObsidianLiveSyncSettingTab(this.app, this)); this.app.workspace.onLayoutReady(this.onLayoutReady.bind(this)); this.addCommand({ id: "livesync-replicate", name: "Replicate now", callback: async () => { await this.replicate(); } }); this.addCommand({ id: "livesync-dump", name: "Dump information of this doc ", editorCallback: (editor, view) => { this.localDatabase.getDBEntry(getPathFromTFile(view.file), {}, true, false); } }); this.addCommand({ id: "livesync-checkdoc-conflicted", name: "Resolve if conflicted.", editorCallback: async (editor, view) => { await this.showIfConflicted(getPathFromTFile(view.file)); } }); this.addCommand({ id: "livesync-toggle", name: "Toggle LiveSync", callback: async () => { if (this.settings.liveSync) { this.settings.liveSync = false; Logger("LiveSync Disabled.", LOG_LEVEL.NOTICE); } else { this.settings.liveSync = true; Logger("LiveSync Enabled.", LOG_LEVEL.NOTICE); } await this.realizeSettingSyncMode(); this.saveSettings(); } }); this.addCommand({ id: "livesync-suspendall", name: "Toggle All Sync.", callback: async () => { if (this.suspended) { this.suspended = false; Logger("Self-hosted LiveSync resumed", LOG_LEVEL.NOTICE); } else { this.suspended = true; Logger("Self-hosted LiveSync suspended", LOG_LEVEL.NOTICE); } await this.realizeSettingSyncMode(); this.saveSettings(); } }); this.addCommand({ id: "livesync-history", name: "Show history", editorCallback: (editor, view) => { this.showHistory(view.file, null); } }); this.addCommand({ id: "livesync-scan-files", name: "Scan storage and database again", callback: async () => { await this.syncAllFiles(true); } }); this.triggerRealizeSettingSyncMode = (0, import_obsidian.debounce)(this.triggerRealizeSettingSyncMode.bind(this), 1e3); this.addCommand({ id: "livesync-filehistory", name: "Pick a file to show history", callback: () => { this.fileHistory(); } }); this.addCommand({ id: "livesync-conflictcheck", name: "Pick a file to resolve conflict", callback: () => { this.pickFileForResolve(); } }); this.addCommand({ id: "livesync-all-conflictcheck", name: "Resolve all conflicted files", callback: async () => { while (await this.pickFileForResolve()) ; } }); this.addCommand({ id: "livesync-runbatch", name: "Run pended batch processes", callback: async () => { await this.applyBatchChange(); } }); this.addCommand({ id: "livesync-abortsync", name: "Abort synchronization immediately", callback: () => { this.replicator.terminateSync(); } }); } onunload() { var _a; for (const addOn of this.addOns) { addOn.onunload(); } if (this.localDatabase != null) { this.localDatabase.onunload(); } (_a = this.periodicSyncProcessor) == null ? void 0 : _a.disable(); if (this.localDatabase != null) { this.replicator.closeReplication(); this.localDatabase.close(); } cancelAllPeriodicTask(); cancelAllTasks(); Logger("unloading plugin"); } async openDatabase() { if (this.localDatabase != null) { await this.localDatabase.close(); } const vaultName = this.getVaultName(); Logger("Waiting for ready..."); this.isMobile = this.app.isMobile; this.localDatabase = new LiveSyncLocalDB(vaultName, this); this.observeForLogs(); return await this.localDatabase.initializeDatabase(); } getPassphrase(settings) { const methods = { "": () => Promise.resolve("*"), "LOCALSTORAGE": () => { var _a; return Promise.resolve((_a = localStorage.getItem("ls-setting-passphrase")) != null ? _a : false); }, "ASK_AT_LAUNCH": () => askString(this.app, "Passphrase", "passphrase", "") }; const method = settings.configPassphraseStore; const methodFunc = method in methods ? methods[method] : methods[""]; return methodFunc(); } async decryptConfigurationItem(encrypted, passphrase) { const dec = await tryDecrypt(encrypted, passphrase + SALT_OF_PASSPHRASE, false); if (dec) { this.usedPassphrase = passphrase; return dec; } return false; } tryDecodeJson(encoded) { try { if (!encoded) return false; return JSON.parse(encoded); } catch (ex) { return false; } } async encryptConfigurationItem(src, settings) { if (this.usedPassphrase != "") { return await encrypt(src, this.usedPassphrase + SALT_OF_PASSPHRASE, false); } const passphrase = await this.getPassphrase(settings); if (passphrase === false) { Logger("Could not determine passphrase to save data.json! You probably make the configuration sure again!", LOG_LEVEL.URGENT); return ""; } const dec = await encrypt(src, passphrase + SALT_OF_PASSPHRASE, false); if (dec) { this.usedPassphrase = passphrase; return dec; } return ""; } async loadSettings() { const settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData()); const passphrase = await this.getPassphrase(settings); if (passphrase === false) { Logger("Could not determine passphrase for reading data.json! DO NOT synchronize with the remote before making sure your configuration is!", LOG_LEVEL.URGENT); } else { if (settings.encryptedCouchDBConnection) { const keys2 = ["couchDB_URI", "couchDB_USER", "couchDB_PASSWORD", "couchDB_DBNAME"]; const decrypted = this.tryDecodeJson(await this.decryptConfigurationItem(settings.encryptedCouchDBConnection, passphrase)); if (decrypted) { for (const key of keys2) { if (key in decrypted) { settings[key] = decrypted[key]; } } } else { Logger("Could not decrypt passphrase for reading data.json! DO NOT synchronize with the remote before making sure your configuration is!", LOG_LEVEL.URGENT); for (const key of keys2) { settings[key] = ""; } } } if (settings.encrypt && settings.encryptedPassphrase) { const encrypted = settings.encryptedPassphrase; const decrypted = await this.decryptConfigurationItem(encrypted, passphrase); if (decrypted) { settings.passphrase = decrypted; } else { Logger("Could not decrypt passphrase for reading data.json! DO NOT synchronize with the remote before making sure your configuration is!", LOG_LEVEL.URGENT); settings.passphrase = ""; } } } this.settings = settings; if ("workingEncrypt" in this.settings) delete this.settings.workingEncrypt; if ("workingPassphrase" in this.settings) delete this.settings.workingPassphrase; this.settings.disableRequestURI = true; this.settings.gcDelay = 0; this.settings.useHistory = true; const lsKey = "obsidian-live-sync-vaultanddevicename-" + this.getVaultName(); if (this.settings.deviceAndVaultName != "") { if (!localStorage.getItem(lsKey)) { this.deviceAndVaultName = this.settings.deviceAndVaultName; localStorage.setItem(lsKey, this.deviceAndVaultName); this.settings.deviceAndVaultName = ""; } } if (isCloudantURI(this.settings.couchDB_URI) && this.settings.customChunkSize != 0) { Logger("Configuration verification founds problems with your configuration. This has been fixed automatically. But you may already have data that cannot be synchronised. If this is the case, please rebuild everything.", LOG_LEVEL.NOTICE); this.settings.customChunkSize = 0; } this.deviceAndVaultName = localStorage.getItem(lsKey) || ""; } triggerRealizeSettingSyncMode() { (async () => await this.realizeSettingSyncMode())(); } async saveSettings() { const lsKey = "obsidian-live-sync-vaultanddevicename-" + this.getVaultName(); localStorage.setItem(lsKey, this.deviceAndVaultName || ""); const settings = { ...this.settings }; if (this.usedPassphrase == "" && !await this.getPassphrase(settings)) { Logger("Could not determine passphrase for saving data.json! Our data.json have insecure items!", LOG_LEVEL.NOTICE); } else { if (settings.couchDB_PASSWORD != "" || settings.couchDB_URI != "" || settings.couchDB_USER != "" || settings.couchDB_DBNAME) { const connectionSetting = { couchDB_DBNAME: settings.couchDB_DBNAME, couchDB_PASSWORD: settings.couchDB_PASSWORD, couchDB_URI: settings.couchDB_URI, couchDB_USER: settings.couchDB_USER }; settings.encryptedCouchDBConnection = await this.encryptConfigurationItem(JSON.stringify(connectionSetting), settings); settings.couchDB_PASSWORD = ""; settings.couchDB_DBNAME = ""; settings.couchDB_URI = ""; settings.couchDB_USER = ""; } if (settings.encrypt && settings.passphrase != "") { settings.encryptedPassphrase = await this.encryptConfigurationItem(settings.passphrase, settings); settings.passphrase = ""; } } await this.saveData(settings); this.localDatabase.settings = this.settings; this.triggerRealizeSettingSyncMode(); } registerFileWatchEvents() { this.vaultManager = new StorageEventManagerObsidian(this); } registerWatchEvents() { this.registerEvent(this.app.workspace.on("file-open", this.watchWorkspaceOpen)); this.registerDomEvent(document, "visibilitychange", this.watchWindowVisibility); this.registerDomEvent(window, "online", this.watchOnline); this.registerDomEvent(window, "offline", this.watchOnline); } watchOnline() { this.watchOnlineAsync(); } async watchOnlineAsync() { if (navigator.onLine && this.localDatabase.needScanning) { this.localDatabase.needScanning = false; await this.syncAllFiles(); } } watchWindowVisibility() { this.watchWindowVisibilityAsync(); } async watchWindowVisibilityAsync() { var _a; if (this.settings.suspendFileWatching) return; if (!this.isReady) return; const isHidden = document.hidden; await this.applyBatchChange(); if (isHidden) { this.replicator.closeReplication(); (_a = this.periodicSyncProcessor) == null ? void 0 : _a.disable(); } else { if (this.suspended) return; await Promise.all(this.addOns.map((e2) => e2.onResume())); if (this.settings.liveSync) { this.replicator.openReplication(this.settings, true, false); } if (this.settings.syncOnStart) { this.replicator.openReplication(this.settings, false, false); } this.periodicSyncProcessor.enable(this.settings.periodicReplication ? this.settings.periodicReplicationInterval * 1e3 : 0); } } async procFileEvent(applyBatch) { if (!this.isReady) return; if (this.settings.batchSave) { if (!applyBatch && this.vaultManager.getQueueLength() < FileWatchEventQueueMax) { scheduleTask("applyBatchAuto", 3e4, () => { this.procFileEvent(true); }); return; } } cancelTask("applyBatchAuto"); const ret = await runWithLock("procFiles", true, async () => { do { const queue2 = this.vaultManager.fetchEvent(); if (queue2 === false) break; if (queue2 === void 0) break; const file = queue2.args.file; const key = `file-last-proc-${queue2.type}-${file.path}`; const last = Number(await this.kvDB.get(key) || 0); let mtime = file.mtime; if (queue2.type == "DELETE") { await this.deleteFromDBbyPath(file.path); mtime = file.mtime - 1; const keyD1 = `file-last-proc-CREATE-${file.path}`; const keyD2 = `file-last-proc-CHANGED-${file.path}`; await this.kvDB.set(keyD1, mtime); await this.kvDB.set(keyD2, mtime); } else if (queue2.type == "INTERNAL") { await this.addOnHiddenFileSync.watchVaultRawEventsAsync(file.path); } else { const targetFile = this.app.vault.getAbstractFileByPath(file.path); if (!(targetFile instanceof import_obsidian.TFile)) { Logger(`Target file was not found: ${file.path}`, LOG_LEVEL.INFO); continue; } if (file.mtime == last) { Logger(`File has been already scanned on ${queue2.type}, skip: ${file.path}`, LOG_LEVEL.VERBOSE); continue; } const cache = queue2.args.cache; if (queue2.type == "CREATE" || queue2.type == "CHANGED") { const keyD1 = `file-last-proc-DELETED-${file.path}`; await this.kvDB.set(keyD1, mtime); if (!await this.updateIntoDB(targetFile, false, cache)) { Logger(`DB -> STORAGE: failed, cancel the relative operations: ${targetFile.path}`, LOG_LEVEL.INFO); this.vaultManager.cancelRelativeEvent(queue2); continue; } } if (queue2.type == "RENAME") { await this.watchVaultRenameAsync(targetFile, queue2.args.oldPath); } } await this.kvDB.set(key, mtime); } while (this.vaultManager.getQueueLength() > 0); return true; }); return ret; } watchWorkspaceOpen(file) { if (this.settings.suspendFileWatching) return; if (!this.isReady) return; this.watchWorkspaceOpenAsync(file); } async watchWorkspaceOpenAsync(file) { if (this.settings.suspendFileWatching) return; if (!this.isReady) return; await this.applyBatchChange(); if (file == null) { return; } if (this.settings.syncOnFileOpen && !this.suspended) { await this.replicate(); } await this.showIfConflicted(getPathFromTFile(file)); } async applyBatchChange() { if (this.settings.batchSave) { return await this.procFileEvent(true); } } getFilePath(file) { if (file instanceof import_obsidian.TFolder) { if (file.isRoot()) return ""; return this.getFilePath(file.parent) + "/" + file.name; } if (file instanceof import_obsidian.TFile) { return this.getFilePath(file.parent) + "/" + file.name; } return this.getFilePath(file.parent) + "/" + file.name; } async watchVaultRenameAsync(file, oldFile, cache) { Logger(`${oldFile} renamed to ${file.path}`, LOG_LEVEL.VERBOSE); if (file instanceof import_obsidian.TFile) { try { if (await this.updateIntoDB(file, false, cache)) { await this.deleteFromDBbyPath(oldFile); } else { Logger(`Could not save new file: ${file.path} `, LOG_LEVEL.NOTICE); } } catch (ex) { Logger(ex); } } } async addLog(message, level = LOG_LEVEL.INFO, key = "") { var _a, _b; if (level == LOG_LEVEL.DEBUG && !isDebug) { return; } if (level < LOG_LEVEL.INFO && this.settings && this.settings.lessInformationInLog) { return; } if (this.settings && !this.settings.showVerboseLog && level == LOG_LEVEL.VERBOSE) { return; } const vaultName = this.getVaultName(); const now = new Date(); const timestamp = now.toLocaleString(); const messageContent = typeof message == "string" ? message : message instanceof Error ? `${message.name}:${message.message}` : JSON.stringify(message, null, 2); if (message instanceof Error) { console.dir(message.stack); } const newMessage = timestamp + "->" + messageContent; console.log(vaultName + ":" + newMessage); if ((_a = this.settings) == null ? void 0 : _a.writeLogToTheFile) { const time = now.toISOString().split("T")[0]; const logDate = `${PREFIXMD_LOGFILE}${time}.md`; const file = this.app.vault.getAbstractFileByPath(normalizePath(logDate)); if (!file) { this.app.vault.adapter.append(normalizePath(logDate), "```\n"); } this.app.vault.adapter.append(normalizePath(logDate), vaultName + ":" + newMessage + "\n"); } logMessageStore.apply((e2) => [...e2, newMessage].slice(-100)); this.setStatusBarText(null, messageContent); if (level >= LOG_LEVEL.NOTICE) { if (!key) key = messageContent; if (key in this.notifies) { const isShown = (_b = this.notifies[key].notice.noticeEl) == null ? void 0 : _b.isShown(); if (!isShown) { this.notifies[key].notice = new import_obsidian.Notice(messageContent, 0); } clearTimeout(this.notifies[key].timer); if (key == messageContent) { this.notifies[key].count++; this.notifies[key].notice.setMessage(`(${this.notifies[key].count}):${messageContent}`); } else { this.notifies[key].notice.setMessage(`${messageContent}`); } this.notifies[key].timer = setTimeout(() => { const notify = this.notifies[key].notice; delete this.notifies[key]; try { notify.hide(); } catch (ex) { } }, 5e3); } else { const notify = new import_obsidian.Notice(messageContent, 0); this.notifies[key] = { count: 0, notice: notify, timer: setTimeout(() => { delete this.notifies[key]; notify.hide(); }, 5e3) }; } } } async ensureDirectory(fullPath) { const pathElements = fullPath.split("/"); pathElements.pop(); let c = ""; for (const v of pathElements) { c += v; try { await this.app.vault.createFolder(c); } catch (ex) { if (ex.message && ex.message == "Folder already exists.") { } else { Logger("Folder Create Error"); Logger(ex); } } c += "/"; } } async doc2storage(docEntry, file, force) { var _a; const mode = file == void 0 ? "create" : "modify"; const path = this.getPath(docEntry); if (shouldBeIgnored(path)) { return; } if (!this.isTargetFile(path)) return; if (docEntry._deleted || docEntry.deleted) { const lastDocs = await this.localDatabase.getDBEntry(path); if (path != file.path) { Logger(`delete skipped: ${file.path} :Not exactly matched`, LOG_LEVEL.VERBOSE); } if (lastDocs === false) { await this.deleteVaultItem(file); } else { await this.pullFile(path, null, true); Logger(`delete skipped:${file.path}`, LOG_LEVEL.VERBOSE); } return; } const localMtime = ~~((((_a = file == null ? void 0 : file.stat) == null ? void 0 : _a.mtime) || 0) / 1e3); const docMtime = ~~(docEntry.mtime / 1e3); const doc = await this.localDatabase.getDBEntry(path, { rev: docEntry._rev }); if (doc === false) return; const msg = `DB -> STORAGE (${mode}${force ? ",force" : ""},${doc.datatype}) `; if (doc.datatype != "newnote" && doc.datatype != "plain") { Logger(msg + "ERROR, Invalid datatype: " + path + "(" + doc.datatype + ")", LOG_LEVEL.NOTICE); return; } if (!force && localMtime >= docMtime) return; if (!isValidPath(path)) { Logger(msg + "ERROR, invalid path: " + path, LOG_LEVEL.NOTICE); return; } const writeData = doc.datatype == "newnote" ? base64ToArrayBuffer(doc.data) : getDocData(doc.data); await this.ensureDirectoryEx(path); try { let outFile; if (mode == "create") { outFile = await createFile(normalizePath(path), writeData, { ctime: doc.ctime, mtime: doc.mtime }); } else { await modifyFile(file, writeData, { ctime: doc.ctime, mtime: doc.mtime }); outFile = getAbstractFileByPath(getPathFromTFile(file)); } Logger(msg + path); touch(outFile); this.app.vault.trigger(mode, outFile); } catch (ex) { Logger(msg + "ERROR, Could not write: " + path, LOG_LEVEL.NOTICE); Logger(ex, LOG_LEVEL.VERBOSE); } } async deleteVaultItem(file) { if (file instanceof import_obsidian.TFile) { if (!this.isTargetFile(file)) return; } const dir = file.parent; if (this.settings.trashInsteadDelete) { await this.app.vault.trash(file, false); } else { await this.app.vault.delete(file); } Logger(`xxx <- STORAGE (deleted) ${file.path}`); Logger(`files: ${dir.children.length}`); if (dir.children.length == 0) { if (!this.settings.doNotDeleteFolder) { Logger(`All files under the parent directory (${dir}) have been deleted, so delete this one.`); await this.deleteVaultItem(dir); } } } handleDBChanged(change) { const af = app.workspace.getActiveFile(); if (af && af.path == this.getPath(change)) { this.queuedEntries = this.queuedEntries.filter((e2) => e2._id != change._id); return this.handleDBChangedAsync(change); } this.queuedEntries.push(change); this.execDBchanged(); } async execDBchanged() { if (this.dbChangeProcRunning) return false; this.dbChangeProcRunning = true; const semaphore = Semaphore(4); try { do { const entry = this.queuedEntries.shift(); if (this.queuedEntries.some((e2) => e2._id == entry._id)) continue; const path = getPath2(entry); try { const releaser = await semaphore.acquire(1); runWithLock(`dbchanged-${path}`, false, async () => { Logger(`Applying ${path} (${entry._id}: ${entry._rev}) change...`, LOG_LEVEL.VERBOSE); await this.handleDBChangedAsync(entry); Logger(`Applied ${path} (${entry._id}:${entry._rev}) change...`); }).finally(() => { releaser(); }); } catch (ex) { Logger(`Failed to apply the change of ${path} (${entry._id}:${entry._rev})`); } } while (this.queuedEntries.length > 0); } finally { this.dbChangeProcRunning = false; } } async handleDBChangedAsync(change) { const targetFile = getAbstractFileByPath(this.getPathWithoutPrefix(change)); if (targetFile == null) { if (change._deleted || change.deleted) { return; } const doc = change; await this.doc2storage(doc); } else if (targetFile instanceof import_obsidian.TFile) { const doc = change; const file = targetFile; const queueConflictCheck = () => { if (!this.settings.checkConflictOnlyOnOpen) { this.queueConflictedCheck(file); return true; } else { const af = app.workspace.getActiveFile(); if (af && af.path == file.path) { this.queueConflictedCheck(file); return true; } } return false; }; if (this.settings.writeDocumentsIfConflicted) { await this.doc2storage(doc, file); queueConflictCheck(); } else { const d = await this.localDatabase.getDBEntryMeta(this.getPath(change), { conflicts: true }, true); if (d && !d._conflicts) { await this.doc2storage(doc, file); } else { if (!queueConflictCheck()) { Logger(`${this.getPath(change)} is conflicted, write to the storage has been pended.`, LOG_LEVEL.NOTICE); } } } } else { Logger(`${this.getPath(change)} is already exist as the folder`); } } saveQueuedFiles() { const saveData = JSON.stringify(this.queuedFiles.filter((e2) => !e2.done).map((e2) => e2.entry._id)); const lsKey = "obsidian-livesync-queuefiles-" + this.getVaultName(); localStorage.setItem(lsKey, saveData); } async loadQueuedFiles() { const lsKey = "obsidian-livesync-queuefiles-" + this.getVaultName(); const ids = JSON.parse(localStorage.getItem(lsKey) || "[]"); const ret = await this.localDatabase.allDocsRaw({ keys: ids, include_docs: true }); for (const doc of ret.rows) { if (doc.doc && !this.queuedFiles.some((e2) => e2.entry._id == doc.doc._id)) { await this.parseIncomingDoc(doc.doc); } } } procQueuedFiles() { this.saveQueuedFiles(); for (const queue2 of this.queuedFiles) { if (queue2.done) continue; const now = new Date().getTime(); if (queue2.missingChildren.length == 0) { queue2.done = true; if (isIdOfInternalMetadata(queue2.entry._id)) { const filename = this.getPathWithoutPrefix(queue2.entry); this.addOnHiddenFileSync.procInternalFile(filename); } else if (isValidPath(this.getPath(queue2.entry))) { this.handleDBChanged(queue2.entry); } else { Logger(`Skipped: ${queue2.entry._id}`, LOG_LEVEL.VERBOSE); } } else if (now > queue2.timeout) { if (!queue2.warned) Logger(`Timed out: ${queue2.entry._id} could not collect ${queue2.missingChildren.length} chunks. plugin keeps watching, but you have to check the file after the replication.`, LOG_LEVEL.NOTICE); queue2.warned = true; continue; } } this.queuedFiles = this.queuedFiles.filter((e2) => !e2.done); this.queuedFilesStore.apply((value) => ({ ...value, queuedItems: this.queuedFiles })); this.saveQueuedFiles(); } parseIncomingChunk(chunk) { const now = new Date().getTime(); let isNewFileCompleted = false; for (const queue2 of this.queuedFiles) { if (queue2.done) continue; if (queue2.missingChildren.indexOf(chunk._id) !== -1) { queue2.missingChildren = queue2.missingChildren.filter((e2) => e2 != chunk._id); queue2.timeout = now + this.chunkWaitTimeout; } if (queue2.missingChildren.length == 0) { for (const e2 of this.queuedFiles) { if (e2.entry._id == queue2.entry._id && e2.entry.mtime < queue2.entry.mtime) { e2.done = true; } } isNewFileCompleted = true; } } if (isNewFileCompleted) this.procQueuedFiles(); } async parseIncomingDoc(doc) { const path = this.getPath(doc); if (!this.isTargetFile(path)) return; const skipOldFile = this.settings.skipOlderFilesOnSync && false; if (isIdOfInternalMetadata(doc._id) && !this.settings.syncInternalFiles) return; const ignoreFiles = [ "_design/replicate", FLAGMD_REDFLAG, FLAGMD_REDFLAG2, FLAGMD_REDFLAG3 ]; if (!isIdOfInternalMetadata(doc._id) && ignoreFiles.contains(path)) { return; } if (!isIdOfInternalMetadata(doc._id) && skipOldFile) { const info2 = getAbstractFileByPath(stripAllPrefixes(path)); if (info2 && info2 instanceof import_obsidian.TFile) { const localMtime = ~~(info2.stat.mtime / 1e3); const docMtime = ~~(doc.mtime / 1e3); if (localMtime >= docMtime) { Logger(`${doc._id} Skipped, older than storage.`, LOG_LEVEL.VERBOSE); return; } } } const now = new Date().getTime(); const newQueue = { entry: doc, missingChildren: [], timeout: now + this.chunkWaitTimeout }; if (!this.settings.readChunksOnline && "children" in doc) { const c = await this.localDatabase.allDocsRaw({ keys: doc.children, include_docs: false }); const missing = c.rows.filter((e2) => "error" in e2).map((e2) => e2.key); if (missing.length > 0) Logger(`${doc._id}(${doc._rev}) Queued (waiting ${missing.length} items)`, LOG_LEVEL.VERBOSE); newQueue.missingChildren = missing; this.queuedFiles.push(newQueue); } else { this.queuedFiles.push(newQueue); } this.saveQueuedFiles(); this.procQueuedFiles(); } async parseReplicationResult(docs) { const docsSorted = docs.sort((a2, b) => b.mtime - a2.mtime); L1: for (const change of docsSorted) { for (const proc of this.addOns) { if (await proc.parseReplicationResultItem(change)) { continue L1; } } if (isChunk(change._id)) { await this.parseIncomingChunk(change); continue; } if (change._id == SYNCINFO_ID) { continue; } if (change.type != "leaf" && change.type != "versioninfo" && change.type != "milestoneinfo" && change.type != "nodeinfo") { await this.parseIncomingDoc(change); continue; } if (change.type == "versioninfo") { if (change.version > VER) { this.replicator.closeReplication(); Logger(`Remote database updated to incompatible version. update your self-hosted-livesync plugin.`, LOG_LEVEL.NOTICE); } } } } async realizeSettingSyncMode() { var _a; this.replicator.closeReplication(); (_a = this.periodicSyncProcessor) == null ? void 0 : _a.disable(); this.localDatabase.refreshSettings(); await this.applyBatchChange(); await Promise.all(this.addOns.map((e2) => e2.realizeSettingSyncMode())); if (this.suspended) return; await Promise.all(this.addOns.map((e2) => e2.onResume())); if (this.settings.liveSync) { this.replicator.openReplication(this.settings, true, false); } this.periodicSyncProcessor.enable(this.settings.periodicReplication ? this.settings.periodicReplicationInterval * 1e3 : 0); } observeForLogs() { const observer__ = observeStores(this.queuedFilesStore, lockStore); const observer = observeStores(observer__, this.replicationStat); observer.observe((e2) => { const sent = e2.sent; const arrived = e2.arrived; const maxPullSeq = e2.maxPullSeq; const maxPushSeq = e2.maxPushSeq; const lastSyncPullSeq = e2.lastSyncPullSeq; const lastSyncPushSeq = e2.lastSyncPushSeq; let pushLast = ""; let pullLast = ""; let w = ""; switch (e2.syncStatus) { case "CLOSED": case "COMPLETED": case "NOT_CONNECTED": w = "\u23F9"; break; case "STARTED": w = "\u{1F300}"; break; case "PAUSED": w = "\u{1F4A4}"; break; case "CONNECTED": w = "\u26A1"; pushLast = lastSyncPushSeq == 0 ? "" : lastSyncPushSeq >= maxPushSeq ? " (LIVE)" : ` (${maxPushSeq - lastSyncPushSeq})`; pullLast = lastSyncPullSeq == 0 ? "" : lastSyncPullSeq >= maxPullSeq ? " (LIVE)" : ` (${maxPullSeq - lastSyncPullSeq})`; break; case "ERRORED": w = "\u26A0"; break; default: w = "?"; } this.statusBar.title = e2.syncStatus; let waiting = ""; if (this.settings.batchSave) { waiting = " " + "\u{1F6EB}".repeat(this.vaultManager.getQueueLength()); waiting = waiting.replace(/(🛫){10}/g, "\u{1F680}"); } let queued = ""; const queue2 = Object.entries(e2.queuedItems).filter((e3) => !e3[1].warned); const queuedCount = queue2.length; if (queuedCount) { const pieces = queue2.map((e3) => e3[1].missingChildren).reduce((prev, cur) => prev + cur.length, 0); queued = ` \u{1F9E9} ${queuedCount} (${pieces})`; } const processes = e2.count; const processesDisp = processes == 0 ? "" : ` \u23F3${processes}`; const message = `Sync: ${w} \u2191${sent}${pushLast} \u2193${arrived}${pullLast}${waiting}${processesDisp}${queued}`; function getProcKind(proc) { const p = proc.indexOf("-"); if (p == -1) { return proc; } return proc.substring(0, p); } const pendingTask = e2.pending.length ? "\nPending: " + Object.entries(e2.pending.reduce((p, c) => { var _a; return { ...p, [getProcKind(c)]: ((_a = p[getProcKind(c)]) != null ? _a : 0) + 1 }; }, {})).map((e3) => `${e3[0]}${e3[1] == 1 ? "" : `(${e3[1]})`}`).join(", ") : ""; const runningTask = e2.running.length ? "\nRunning: " + Object.entries(e2.running.reduce((p, c) => { var _a; return { ...p, [getProcKind(c)]: ((_a = p[getProcKind(c)]) != null ? _a : 0) + 1 }; }, {})).map((e3) => `${e3[0]}${e3[1] == 1 ? "" : `(${e3[1]})`}`).join(", ") : ""; this.setStatusBarText(message + pendingTask + runningTask); }); } refreshStatusText() { return; } setStatusBarText(message = null, log2 = null) { if (!this.statusBar) return; const newMsg = typeof message == "string" ? message : this.lastMessage; const newLog = typeof log2 == "string" ? log2 : this.lastLog; if (`${this.lastMessage}-${this.lastLog}` != `${newMsg}-${newLog}`) { this.statusBar.setText(newMsg.split("\n")[0]); if (this.settings.showStatusOnEditor) { const root = activeDocument.documentElement; const q = root.querySelectorAll(`.CodeMirror-wrap,.cm-s-obsidian>.cm-editor,.canvas-wrapper`); q.forEach((e2) => e2.setAttr("data-log", newMsg + "\n" + newLog)); } else { const root = activeDocument.documentElement; const q = root.querySelectorAll(`.CodeMirror-wrap,.cm-s-obsidian>.cm-editor,.canvas-wrapper`); q.forEach((e2) => e2.setAttr("data-log", "")); } if (this.logHideTimer != null) { clearTimeout(this.logHideTimer); } this.logHideTimer = setTimeout(() => this.setStatusBarText(null, ""), 3e3); this.lastMessage = newMsg; this.lastLog = newLog; } } updateStatusBarText() { } async replicate(showMessage) { if (!this.isReady) return; if (this.settings.versionUpFlash != "") { Logger("Open settings and check message, please.", LOG_LEVEL.NOTICE); return; } await this.applyBatchChange(); await Promise.all(this.addOns.map((e2) => e2.beforeReplicate(showMessage))); await this.loadQueuedFiles(); const ret = await this.replicator.openReplication(this.settings, false, showMessage); if (!ret) { if (this.replicator.remoteLockedAndDeviceNotAccepted) { if (this.replicator.remoteCleaned) { const message = ` The remote database has been cleaned up. To synchronize, this device must also be cleaned up or fetch everything again once. Fetching may takes some time. Cleaning up is not stable yet but fast. `; const CHOICE_CLEANUP = "Clean up"; const CHOICE_FETCH = "Fetch again"; const CHOICE_DISMISS = "Dismiss"; const ret2 = await confirmWithMessage(this, "Locked", message, [CHOICE_CLEANUP, CHOICE_FETCH, CHOICE_DISMISS], CHOICE_DISMISS, 10); if (ret2 == CHOICE_CLEANUP) { await localDatabaseCleanUp(this, true, false); await balanceChunks(this, false); } if (ret2 == CHOICE_FETCH) { await performRebuildDB(this, "localOnly"); } } else { const message = ` The remote database has been rebuilt. To synchronize, this device must fetch everything again once. Or if you are sure know what had been happened, we can unlock the database from the setting dialog. `; const CHOICE_FETCH = "Fetch again"; const CHOICE_DISMISS = "Dismiss"; const ret2 = await confirmWithMessage(this, "Locked", message, [CHOICE_FETCH, CHOICE_DISMISS], CHOICE_DISMISS, 10); if (ret2 == CHOICE_FETCH) { await performRebuildDB(this, "localOnly"); } } } } return ret; } async initializeDatabase(showingNotice, reopenDatabase = true) { this.isReady = false; if (!reopenDatabase || await this.openDatabase()) { if (this.localDatabase.isReady) { await this.syncAllFiles(showingNotice); } await Promise.all(this.addOns.map((e2) => e2.onInitializeDatabase(showingNotice))); this.isReady = true; await this.procFileEvent(true); return true; } else { this.isReady = false; return false; } } async replicateAllToServer(showingNotice) { if (!this.isReady) return false; await Promise.all(this.addOns.map((e2) => e2.beforeReplicate(showingNotice))); return await this.replicator.replicateAllToServer(this.settings, showingNotice); } async replicateAllFromServer(showingNotice) { if (!this.isReady) return false; return await this.replicator.replicateAllFromServer(this.settings, showingNotice); } async markRemoteLocked(lockByClean) { return await this.replicator.markRemoteLocked(this.settings, true, lockByClean); } async markRemoteUnlocked() { return await this.replicator.markRemoteLocked(this.settings, false, false); } async markRemoteResolved() { return await this.replicator.markRemoteResolved(this.settings); } async syncAllFiles(showingNotice) { let initialScan = false; if (showingNotice) { Logger("Initializing", LOG_LEVEL.NOTICE, "syncAll"); } Logger("Initialize and checking database files"); Logger("Checking deleted files"); await this.collectDeletedFiles(); Logger("Collecting local files on the storage", LOG_LEVEL.VERBOSE); const filesStorage = this.app.vault.getFiles().filter((e2) => this.isTargetFile(e2)); const filesStorageName = filesStorage.map((e2) => e2.path); Logger("Collecting local files on the DB", LOG_LEVEL.VERBOSE); const filesDatabase = []; for await (const doc of this.localDatabase.findAllNormalDocs()) { const path = getPath2(doc); if (isValidPath(path) && this.isTargetFile(path)) { filesDatabase.push(path); } } Logger("Opening the key-value database", LOG_LEVEL.VERBOSE); const isInitialized = await this.kvDB.get("initialized") || false; if (filesDatabase.length == 0 && !isInitialized) { initialScan = true; Logger("Database looks empty, save files as initial sync data"); } const onlyInStorage = filesStorage.filter((e2) => filesDatabase.indexOf(getPathFromTFile(e2)) == -1); const onlyInDatabase = filesDatabase.filter((e2) => filesStorageName.indexOf(e2) == -1); const onlyInStorageNames = onlyInStorage.map((e2) => e2.path); const syncFiles = filesStorage.filter((e2) => onlyInStorageNames.indexOf(e2.path) == -1); Logger("Updating database by new files"); this.setStatusBarText(`UPDATE DATABASE`); const runAll = async (procedureName, objects, callback) => { Logger(procedureName); const semaphore = Semaphore(25); if (!this.localDatabase.isReady) throw Error("Database is not ready!"); const processes = objects.map((e2) => (async (v) => { const releaser = await semaphore.acquire(1, procedureName); try { await callback(v); } catch (ex) { Logger(`Error while ${procedureName}`, LOG_LEVEL.NOTICE); Logger(ex); } finally { releaser(); } })(e2)); await Promise.all(processes); Logger(`${procedureName} done.`); }; await runAll("UPDATE DATABASE", onlyInStorage, async (e2) => { Logger(`UPDATE DATABASE ${e2.path}`); await this.updateIntoDB(e2, initialScan); }); if (!initialScan) { await runAll("UPDATE STORAGE", onlyInDatabase, async (e2) => { const w = await this.localDatabase.getDBEntryMeta(e2, {}, true); if (w && !(w.deleted || w._deleted)) { Logger(`Check or pull from db:${e2}`); await this.pullFile(e2, filesStorage, false, null, false); Logger(`Check or pull from db:${e2} OK`); } else if (w) { Logger(`Deletion history skipped: ${e2}`, LOG_LEVEL.VERBOSE); } else { Logger(`entry not found: ${e2}`); } }); } if (!initialScan) { let caches = {}; caches = await this.kvDB.get("diff-caches") || {}; const docsCount = syncFiles.length; do { const syncFilesXSrc = syncFiles.splice(0, 100); const syncFilesX = []; for (const file of syncFilesXSrc) { const id = await this.path2id(getPathFromTFile(file)); syncFilesX.push({ file, id }); } const docs = await this.localDatabase.allDocsRaw({ keys: syncFilesX.map((e2) => e2.id), include_docs: true }); const docsMap = docs.rows.reduce((p, c) => ({ ...p, [c.id]: c.doc }), {}); const syncFilesToSync = syncFilesX.map((e2) => ({ file: e2.file, doc: docsMap[e2.id] })); await runAll(`CHECK FILE STATUS:${syncFiles.length}/${docsCount}`, syncFilesToSync, async (e2) => { caches = await this.syncFileBetweenDBandStorage(e2.file, e2.doc, initialScan, caches); }); } while (syncFiles.length > 0); await this.kvDB.set("diff-caches", caches); } this.setStatusBarText(`NOW TRACKING!`); Logger("Initialized, NOW TRACKING!"); if (!isInitialized) { await this.kvDB.set("initialized", true); } if (showingNotice) { Logger("Initialize done!", LOG_LEVEL.NOTICE, "syncAll"); } } async getConflictedDoc(path, rev2) { try { const doc = await this.localDatabase.getDBEntry(path, { rev: rev2 }, false, false, true); if (doc === false) return false; let data = getDocData(doc.data); if (doc.datatype == "newnote") { data = base64ToString(data); } else if (doc.datatype == "plain") { } return { deleted: doc.deleted || doc._deleted, ctime: doc.ctime, mtime: doc.mtime, rev: rev2, data }; } catch (ex) { if (isErrorOfMissingDoc(ex)) { return false; } } return false; } async mergeSensibly(path, baseRev, currentRev, conflictedRev) { var _a, _b, _c, _d; const baseLeaf = await this.getConflictedDoc(path, baseRev); const leftLeaf = await this.getConflictedDoc(path, currentRev); const rightLeaf = await this.getConflictedDoc(path, conflictedRev); let autoMerge = false; if (baseLeaf == false || leftLeaf == false || rightLeaf == false) { return false; } const dmp = new import_diff_match_patch4.diff_match_patch(); const mapLeft = dmp.diff_linesToChars_(baseLeaf.data, leftLeaf.data); const diffLeftSrc = dmp.diff_main(mapLeft.chars1, mapLeft.chars2, false); dmp.diff_charsToLines_(diffLeftSrc, mapLeft.lineArray); const mapRight = dmp.diff_linesToChars_(baseLeaf.data, rightLeaf.data); const diffRightSrc = dmp.diff_main(mapRight.chars1, mapRight.chars2, false); dmp.diff_charsToLines_(diffRightSrc, mapRight.lineArray); function splitDiffPiece(src) { const ret = []; do { const d = src.shift(); const pieces = d[1].split(/([^\n]*\n)/).filter((f3) => f3 != ""); if (typeof d == "undefined") { break; } if (d[0] != import_diff_match_patch4.DIFF_DELETE) { ret.push(...pieces.map((e2) => [d[0], e2])); } if (d[0] == import_diff_match_patch4.DIFF_DELETE) { const nd = src.shift(); if (typeof nd != "undefined") { const piecesPair = nd[1].split(/([^\n]*\n)/).filter((f3) => f3 != ""); if (nd[0] == import_diff_match_patch4.DIFF_INSERT) { for (const pt of pieces) { ret.push([d[0], pt]); const pairP = piecesPair.shift(); if (typeof pairP != "undefined") ret.push([import_diff_match_patch4.DIFF_INSERT, pairP]); } ret.push(...piecesPair.map((e2) => [nd[0], e2])); } else { ret.push(...pieces.map((e2) => [d[0], e2])); ret.push(...piecesPair.map((e2) => [nd[0], e2])); } } else { ret.push(...pieces.map((e2) => [0, e2])); } } } while (src.length > 0); return ret; } const diffLeft = splitDiffPiece(diffLeftSrc); const diffRight = splitDiffPiece(diffRightSrc); let rightIdx = 0; let leftIdx = 0; const merged = []; autoMerge = true; LOOP_MERGE: do { if (leftIdx >= diffLeft.length && rightIdx >= diffRight.length) { break LOOP_MERGE; } const leftItem = (_a = diffLeft[leftIdx]) != null ? _a : [0, ""]; const rightItem = (_b = diffRight[rightIdx]) != null ? _b : [0, ""]; leftIdx++; rightIdx++; if (leftItem[0] == import_diff_match_patch4.DIFF_EQUAL && rightItem[0] == import_diff_match_patch4.DIFF_EQUAL && leftItem[1] == rightItem[1]) { merged.push(leftItem); continue; } if (leftItem[0] == import_diff_match_patch4.DIFF_DELETE && rightItem[0] == import_diff_match_patch4.DIFF_DELETE && leftItem[1] == rightItem[1]) { const nextLeftIdx = leftIdx; const nextRightIdx = rightIdx; const [nextLeftItem, nextRightItem] = [(_c = diffLeft[nextLeftIdx]) != null ? _c : [0, ""], (_d = diffRight[nextRightIdx]) != null ? _d : [0, ""]]; if (nextLeftItem[0] == import_diff_match_patch4.DIFF_INSERT && nextRightItem[0] == import_diff_match_patch4.DIFF_INSERT && nextLeftItem[1] != nextRightItem[1]) { autoMerge = false; break; } else { merged.push(leftItem); continue; } } if (leftItem[0] == import_diff_match_patch4.DIFF_INSERT && rightItem[0] == import_diff_match_patch4.DIFF_INSERT) { if (leftItem[1] == rightItem[1]) { merged.push(leftItem); continue; } else { if (leftLeaf.mtime <= rightLeaf.mtime) { merged.push(leftItem); merged.push(rightItem); continue; } else { merged.push(rightItem); merged.push(leftItem); continue; } } } if (leftItem[0] == import_diff_match_patch4.DIFF_INSERT) { rightIdx--; merged.push(leftItem); continue; } if (rightItem[0] == import_diff_match_patch4.DIFF_INSERT) { leftIdx--; merged.push(rightItem); continue; } if (rightItem[1] != leftItem[1]) { Logger(`MERGING PANIC:${leftItem[0]},${leftItem[1]} == ${rightItem[0]},${rightItem[1]}`, LOG_LEVEL.VERBOSE); autoMerge = false; break LOOP_MERGE; } if (leftItem[0] == import_diff_match_patch4.DIFF_DELETE) { if (rightItem[0] == import_diff_match_patch4.DIFF_EQUAL) { merged.push(leftItem); continue; } else { autoMerge = false; break LOOP_MERGE; } } if (rightItem[0] == import_diff_match_patch4.DIFF_DELETE) { if (leftItem[0] == import_diff_match_patch4.DIFF_EQUAL) { merged.push(rightItem); continue; } else { autoMerge = false; break LOOP_MERGE; } } Logger(`Weird condition:${leftItem[0]},${leftItem[1]} == ${rightItem[0]},${rightItem[1]}`, LOG_LEVEL.VERBOSE); break LOOP_MERGE; } while (leftIdx < diffLeft.length || rightIdx < diffRight.length); if (autoMerge) { Logger(`Sensibly merge available`, LOG_LEVEL.VERBOSE); return merged; } else { return false; } } async mergeObject(path, baseRev, currentRev, conflictedRev) { try { const baseLeaf = await this.getConflictedDoc(path, baseRev); const leftLeaf = await this.getConflictedDoc(path, currentRev); const rightLeaf = await this.getConflictedDoc(path, conflictedRev); if (baseLeaf == false || leftLeaf == false || rightLeaf == false) { return false; } const baseObj = { data: tryParseJSON(baseLeaf.data, {}) }; const leftObj = { data: tryParseJSON(leftLeaf.data, {}) }; const rightObj = { data: tryParseJSON(rightLeaf.data, {}) }; const diffLeft = generatePatchObj(baseObj, leftObj); const diffRight = generatePatchObj(baseObj, rightObj); const diffSetLeft = new Map(flattenObject(diffLeft)); const diffSetRight = new Map(flattenObject(diffRight)); for (const [key, value] of diffSetLeft) { if (diffSetRight.has(key)) { if (diffSetRight.get(key) == value) { diffSetRight.delete(key); } } } for (const [key, value] of diffSetRight) { if (diffSetLeft.has(key) && diffSetLeft.get(key) != value) { return false; } } const patches = [ { mtime: leftLeaf.mtime, patch: diffLeft }, { mtime: rightLeaf.mtime, patch: diffRight } ].sort((a2, b) => a2.mtime - b.mtime); let newObj = { ...baseObj }; for (const patch of patches) { newObj = applyPatch(newObj, patch.patch); } return JSON.stringify(newObj.data); } catch (ex) { Logger("Could not merge object"); Logger(ex, LOG_LEVEL.VERBOSE); return false; } } async getConflictedStatus(path) { var _a, _b; const test = await this.localDatabase.getDBEntry(path, { conflicts: true, revs_info: true }, false, false, true); if (test === false) return false; if (test == null) return false; if (!test._conflicts) return false; if (test._conflicts.length == 0) return false; const conflicts = test._conflicts.sort((a2, b) => Number(a2.split("-")[0]) - Number(b.split("-")[0])); if ((isSensibleMargeApplicable(path) || isObjectMargeApplicable(path)) && !this.settings.disableMarkdownAutoMerge) { const conflictedRev = conflicts[0]; const conflictedRevNo = Number(conflictedRev.split("-")[0]); const revFrom = await this.localDatabase.getRaw(await this.path2id(path), { revs_info: true }); const commonBase = (_b = (_a = revFrom._revs_info.filter((e2) => e2.status == "available" && Number(e2.rev.split("-")[0]) < conflictedRevNo).first()) == null ? void 0 : _a.rev) != null ? _b : ""; let p = void 0; if (commonBase) { if (isSensibleMargeApplicable(path)) { const result = await this.mergeSensibly(path, commonBase, test._rev, conflictedRev); if (result) { p = result.filter((e2) => e2[0] != import_diff_match_patch4.DIFF_DELETE).map((e2) => e2[1]).join(""); Logger(`Sensible merge:${path}`, LOG_LEVEL.INFO); } else { Logger(`Sensible merge is not applicable.`, LOG_LEVEL.VERBOSE); } } else if (isObjectMargeApplicable(path)) { const result = await this.mergeObject(path, commonBase, test._rev, conflictedRev); if (result) { Logger(`Object merge:${path}`, LOG_LEVEL.INFO); p = result; } else { Logger(`Object merge is not applicable.`, LOG_LEVEL.VERBOSE); } } if (p != void 0) { await this.localDatabase.deleteDBEntry(path, { rev: conflictedRev }); const file = getAbstractFileByPath(stripAllPrefixes(path)); if (file) { await this.app.vault.modify(file, p); await this.updateIntoDB(file); } else { const newFile = await this.app.vault.create(path, p); await this.updateIntoDB(newFile); } await this.pullFile(path); Logger(`Automatically merged (sensible) :${path}`, LOG_LEVEL.INFO); return true; } } } const leftLeaf = await this.getConflictedDoc(path, test._rev); const rightLeaf = await this.getConflictedDoc(path, conflicts[0]); if (leftLeaf == false) { Logger(`could not get current revisions:${path}`, LOG_LEVEL.NOTICE); return false; } if (rightLeaf == false) { await this.localDatabase.deleteDBEntry(path, { rev: conflicts[0] }); await this.pullFile(path, null, true); Logger(`could not get old revisions, automatically used newer one:${path}`, LOG_LEVEL.NOTICE); return true; } if (leftLeaf.data == rightLeaf.data && leftLeaf.deleted == rightLeaf.deleted) { let leaf = leftLeaf; if (leftLeaf.mtime > rightLeaf.mtime) { leaf = rightLeaf; } await this.localDatabase.deleteDBEntry(path, { rev: leaf.rev }); await this.pullFile(path, null, true); Logger(`automatically merged:${path}`); return true; } if (this.settings.resolveConflictsByNewerFile) { const lMtime = ~~(leftLeaf.mtime / 1e3); const rMtime = ~~(rightLeaf.mtime / 1e3); let loser = leftLeaf; if (lMtime > rMtime) { loser = rightLeaf; } await this.localDatabase.deleteDBEntry(path, { rev: loser.rev }); await this.pullFile(path, null, true); Logger(`Automatically merged (newerFileResolve) :${path}`, LOG_LEVEL.NOTICE); return true; } const dmp = new import_diff_match_patch4.diff_match_patch(); const diff = dmp.diff_main(leftLeaf.data, rightLeaf.data); dmp.diff_cleanupSemantic(diff); Logger(`conflict(s) found:${path}`); return { left: leftLeaf, right: rightLeaf, diff }; } showMergeDialog(filename, conflictCheckResult) { return runWithLock( "resolve-conflict:" + filename, false, () => new Promise((res2, rej) => { Logger("open conflict dialog", LOG_LEVEL.VERBOSE); new ConflictResolveModal(this.app, filename, conflictCheckResult, async (selected) => { const testDoc = await this.localDatabase.getDBEntry(filename, { conflicts: true }, false, false, true); if (testDoc === false) { Logger("Missing file..", LOG_LEVEL.VERBOSE); return res2(true); } if (!testDoc._conflicts) { Logger("Nothing have to do with this conflict", LOG_LEVEL.VERBOSE); return res2(true); } const toDelete = selected; const toKeep = conflictCheckResult.left.rev != toDelete ? conflictCheckResult.left.rev : conflictCheckResult.right.rev; if (toDelete == "") { const p = conflictCheckResult.diff.map((e2) => e2[1]).join(""); await this.localDatabase.deleteDBEntry(filename, { rev: testDoc._conflicts[0] }); const file = getAbstractFileByPath(stripAllPrefixes(filename)); if (file) { await this.app.vault.modify(file, p); await this.updateIntoDB(file); } else { const newFile = await this.app.vault.create(filename, p); await this.updateIntoDB(newFile); } await this.pullFile(filename); Logger("concat both file"); if (this.settings.syncAfterMerge && !this.suspended) { await this.replicate(); } setTimeout(() => { this.showIfConflicted(filename); }, 500); } else if (toDelete == null) { Logger("Leave it still conflicted"); } else { await this.localDatabase.deleteDBEntry(filename, { rev: toDelete }); await this.pullFile(filename, null, true, toKeep); Logger(`Conflict resolved:${filename}`); if (this.settings.syncAfterMerge && !this.suspended) { await this.replicate(); } setTimeout(() => { this.showIfConflicted(filename); }, 500); } return res2(true); }).open(); }) ); } queueConflictedCheck(file) { this.conflictedCheckFiles = this.conflictedCheckFiles.filter((e2) => e2 != file.path); this.conflictedCheckFiles.push(getPathFromTFile(file)); if (this.conflictedCheckTimer != null) { window.clearTimeout(this.conflictedCheckTimer); } this.conflictedCheckTimer = window.setTimeout(async () => { this.conflictedCheckTimer = null; const checkFiles = JSON.parse(JSON.stringify(this.conflictedCheckFiles)); for (const filename of checkFiles) { try { const file2 = getAbstractFileByPath(filename); if (file2 != null && file2 instanceof import_obsidian.TFile) { await this.showIfConflicted(getPathFromTFile(file2)); } } catch (ex) { Logger(ex); } } }, 100); } async showIfConflicted(filename) { await runWithLock("conflicted", false, async () => { const conflictCheckResult = await this.getConflictedStatus(filename); if (conflictCheckResult === false) { return; } if (conflictCheckResult === true) { if (this.settings.syncAfterMerge && !this.suspended) { await this.replicate(); } Logger("conflict:Automatically merged, but we have to check it again"); setTimeout(() => { this.showIfConflicted(filename); }, 500); return; } await this.showMergeDialog(filename, conflictCheckResult); }); } async pullFile(filename, fileList, force, rev2, waitForReady = true) { const targetFile = getAbstractFileByPath(stripAllPrefixes(filename)); if (!this.isTargetFile(filename)) return; if (targetFile == null) { const doc = await this.localDatabase.getDBEntry(filename, rev2 ? { rev: rev2 } : null, false, waitForReady); if (doc === false) { Logger(`${filename} Skipped`); return; } await this.doc2storage(doc, void 0, force); } else if (targetFile instanceof import_obsidian.TFile) { const file = targetFile; const doc = await this.localDatabase.getDBEntry(filename, rev2 ? { rev: rev2 } : null, false, waitForReady); if (doc === false) { Logger(`${filename} Skipped`); return; } await this.doc2storage(doc, file, force); } else { Logger(`target files:${filename} is exists as the folder`); } } async syncFileBetweenDBandStorage(file, doc, initialScan, caches) { if (!doc) { throw new Error(`Missing doc:${file.path}`); } if (!(file instanceof import_obsidian.TFile) && "path" in file) { const w = getAbstractFileByPath(file.path); if (w instanceof import_obsidian.TFile) { file = w; } else { throw new Error(`Missing file:${file.path}`); } } const storageMtime = ~~(file.stat.mtime / 1e3); const docMtime = ~~(doc.mtime / 1e3); const dK = `${file.path}-diff`; const isLastDiff = dK in caches ? caches[dK] : { storageMtime: 0, docMtime: 0 }; if (isLastDiff.docMtime == docMtime && isLastDiff.storageMtime == storageMtime) { Logger("STORAGE .. DB :" + file.path, LOG_LEVEL.VERBOSE); caches[dK] = { storageMtime, docMtime }; return caches; } if (storageMtime > docMtime) { Logger("STORAGE -> DB :" + file.path); Logger(`${storageMtime} > ${docMtime}`); await this.updateIntoDB(file, initialScan); caches[dK] = { storageMtime, docMtime }; return caches; } else if (storageMtime < docMtime) { Logger("STORAGE <- DB :" + file.path); Logger(`${storageMtime} < ${docMtime}`); const docx = await this.localDatabase.getDBEntry(getPathFromTFile(file), null, false, false); if (docx != false) { await this.doc2storage(docx, file); } else { Logger("STORAGE <- DB :" + file.path + " Skipped"); } caches[dK] = { storageMtime, docMtime }; return caches; } Logger("STORAGE == DB :" + file.path, LOG_LEVEL.VERBOSE); caches[dK] = { storageMtime, docMtime }; return caches; } async updateIntoDB(file, initialScan, cache, force) { if (!this.isTargetFile(file)) return true; if (shouldBeIgnored(file.path)) { return true; } let content; let datatype = "newnote"; if (!cache) { if (!isPlainText(file.name)) { Logger(`Reading : ${file.path}`, LOG_LEVEL.VERBOSE); const contentBin = await this.app.vault.readBinary(file); Logger(`Processing: ${file.path}`, LOG_LEVEL.VERBOSE); try { content = await arrayBufferToBase64(contentBin); } catch (ex) { Logger(`The file ${file.path} could not be encoded`); Logger(ex, LOG_LEVEL.VERBOSE); return false; } datatype = "newnote"; } else { content = await this.app.vault.read(file); datatype = "plain"; } } else { if (cache instanceof ArrayBuffer) { Logger(`Processing: ${file.path}`, LOG_LEVEL.VERBOSE); try { content = await arrayBufferToBase64(cache); } catch (ex) { Logger(`The file ${file.path} could not be encoded`); Logger(ex, LOG_LEVEL.VERBOSE); return false; } datatype = "newnote"; } else { content = cache; datatype = "plain"; } } const fullPath = getPathFromTFile(file); const id = await this.path2id(fullPath); const d = { _id: id, path: getPathFromTFile(file), data: content, ctime: file.stat.ctime, mtime: file.stat.mtime, size: file.stat.size, children: [], datatype, type: datatype }; const msg = `DB <- STORAGE (${datatype}) `; const isNotChanged = await runWithLock("file-" + fullPath, false, async () => { if (recentlyTouched(file)) { return true; } try { const old = await this.localDatabase.getDBEntry(fullPath, null, false, false); if (old !== false) { const oldData = { data: old.data, deleted: old._deleted || old.deleted }; const newData = { data: d.data, deleted: d._deleted || d.deleted }; if (oldData.deleted != newData.deleted) return false; if (!isDocContentSame(old.data, newData.data)) return false; Logger(msg + "Skipped (not changed) " + fullPath + (d._deleted || d.deleted ? " (deleted)" : ""), LOG_LEVEL.VERBOSE); return true; } } catch (ex) { if (force) { Logger(msg + "Error, Could not check the diff for the old one." + (force ? "force writing." : "") + fullPath + (d._deleted || d.deleted ? " (deleted)" : ""), LOG_LEVEL.VERBOSE); } else { Logger(msg + "Error, Could not check the diff for the old one." + fullPath + (d._deleted || d.deleted ? " (deleted)" : ""), LOG_LEVEL.VERBOSE); } return !force; } return false; }); if (isNotChanged) return true; const ret = await this.localDatabase.putDBEntry(d, initialScan); this.queuedFiles = this.queuedFiles.map((e2) => ({ ...e2, ...e2.entry._id == d._id ? { done: true } : {} })); Logger(msg + fullPath); if (this.settings.syncOnSave && !this.suspended) { await this.replicate(); } return ret != false; } async deleteFromDB(file) { if (!this.isTargetFile(file)) return; const fullPath = getPathFromTFile(file); Logger(`deleteDB By path:${fullPath}`); await this.deleteFromDBbyPath(fullPath); if (this.settings.syncOnSave && !this.suspended) { await this.replicate(); } } async deleteFromDBbyPath(fullPath) { await this.localDatabase.deleteDBEntry(fullPath); if (this.settings.syncOnSave && !this.suspended) { await this.replicate(); } } async resetLocalDatabase() { clearTouched(); await this.localDatabase.resetDatabase(); } async tryResetRemoteDatabase() { await this.replicator.tryResetRemoteDatabase(this.settings); } async tryCreateRemoteDatabase() { await this.replicator.tryCreateRemoteDatabase(this.settings); } async ensureDirectoryEx(fullPath) { const pathElements = fullPath.split("/"); pathElements.pop(); let c = ""; for (const v of pathElements) { c += v; try { await this.app.vault.adapter.mkdir(c); } catch (ex) { if (ex.message && ex.message == "Folder already exists.") { } else { Logger("Folder Create Error"); Logger(ex); } } c += "/"; } } filterTargetFiles(files, targetFiles = false) { const ignorePatterns = this.settings.syncInternalFilesIgnorePatterns.replace(/\n| /g, "").split(",").filter((e2) => e2).map((e2) => new RegExp(e2, "i")); return files.filter((file) => !ignorePatterns.some((e2) => file.path.match(e2))).filter((file) => !targetFiles || targetFiles && targetFiles.indexOf(file.path) !== -1); } async applyMTimeToFile(file) { await this.app.vault.adapter.append(file.path, "", { ctime: file.ctime, mtime: file.mtime }); } async resolveConflictByNewerEntry(path) { const id = await this.path2id(path); const doc = await this.localDatabase.getRaw(id, { conflicts: true }); if (!("_conflicts" in doc)) return false; if (doc._conflicts.length == 0) return false; Logger(`Hidden file conflicted:${this.getPath(doc)}`); const conflicts = doc._conflicts.sort((a2, b) => Number(a2.split("-")[0]) - Number(b.split("-")[0])); const revA = doc._rev; const revB = conflicts[0]; const revBDoc = await this.localDatabase.getRaw(id, { rev: revB }); const mtimeA = "mtime" in doc && doc.mtime || 0; const mtimeB = "mtime" in revBDoc && revBDoc.mtime || 0; const delRev = mtimeA < mtimeB ? revA : revB; await this.localDatabase.removeRaw(id, delRev); Logger(`Older one has been deleted:${this.getPath(doc)}`); return true; } isTargetFile(file) { if (file instanceof import_obsidian.TFile) { return this.localDatabase.isTargetFile(file.path); } else if (typeof file == "string") { return this.localDatabase.isTargetFile(file); } } };