UNPKG

@graffy/common

Version:

Common libraries that used by various Graffy modules.

1,544 lines 53.9 kB
"use strict"; Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" }); const debug = require("debug"); const isEqual = require("lodash/isEqual.js"); const mergeIterators = require("merge-async-iterators"); const stream = require("@graffy/stream"); const isDebugMode = debug("graffy*").enabled; const MIN_KEY = new Uint8Array(); const MAX_KEY = new Uint8Array([255]); function isMinKey(key) { return key.length === 0; } function isMaxKey(key) { return key.length === 1 && key[0] === 255; } function err(message, { cause = null, ...args } = {}) { const e = new Error(message + (args ? ` ${JSON.stringify(args)}` : "")); e.cause = cause; throw e; } function errIf(message, condition, args) { if (condition) err(message, args); } function isEmpty(object) { for (const _ in object) return false; return true; } function isDef(value) { return typeof value !== "undefined"; } function isPlainObject(arg) { return typeof arg === "object" && arg && !Array.isArray(arg) && !ArrayBuffer.isView(arg); } function clone$1(obj) { if (Array.isArray(obj)) { return obj.slice(0); } return { ...obj }; } function cmp(a, b) { const l = a.length < b.length ? a.length : b.length; for (let i = 0; i < l; i++) { if (a[i] < b[i]) return -1; if (a[i] > b[i]) return 1; } if (a.length < b.length) return -1; if (a.length > b.length) return 1; return 0; } function find(items, compare2, first = 0, last = items.length) { let currentFirst = first; let currentLast = last; while (currentFirst < currentLast) { const ix = (currentFirst + currentLast) / 2 | 0; const d = compare2(items[ix]); if (d < 0) { currentFirst = ix + 1; } else if (d > 0) { currentLast = ix; } else { return ix; } } return currentFirst; } function stringify() { var _a; if ((this == null ? void 0 : this.length) === 0) return "·"; let str = ""; let bull = false; (_a = this == null ? void 0 : this.forEach) == null ? void 0 : _a.call(this, (value, i) => { if (value >= 32 && value <= 126) { str += String.fromCharCode(value); bull = true; } else { str += (bull ? "·" : "") + `0${value.toString(16)}`.slice(-2) + (i < this.length - 1 ? "·" : ""); bull = false; } }); return str; } const inspectSymbol = Symbol.for("nodejs.util.inspect.custom"); function addStringify(buffer) { if (!isDebugMode) return buffer; if ("toJSON" in buffer || inspectSymbol in buffer) return buffer; buffer.toJSON = stringify; buffer.toString = stringify; buffer[inspectSymbol] = stringify; return buffer; } addStringify(MIN_KEY); addStringify(MAX_KEY); function TwosComplement(view) { const lo = -view.getUint32(4) >>> 0; const carry = lo ? 0 : -1; const hi = ~view.getUint32(0) + carry >>> 0; view.setUint32(0, hi); view.setUint32(4, lo); } function encode$6(number) { const buffer = new ArrayBuffer(8); const view = new DataView(buffer); view.setFloat64(0, number); if (number < 0) { TwosComplement(view); } else { view.setUint8(0, view.getUint8(0) | 128); } return new Uint8Array(buffer); } function decode$6(u8Arr) { const copy = new Uint8Array(8); copy.set(u8Arr, 0); const { buffer, byteOffset, byteLength } = copy; const view = new DataView(buffer, byteOffset, byteLength); const high = view.getUint8(0); if (high & 128) { view.setUint8(0, high & 127); } else { TwosComplement(view); } return view.getFloat64(0); } const textEncoder = new TextEncoder(); const textDecoder = new TextDecoder("utf-8"); function encode$5(string) { return textEncoder.encode(string); } function decode$5(u8Arr) { return textDecoder.decode(u8Arr); } const END = 0; const NULL = 1; const FALSE = 2; const TRUE = 3; const NUM = 4; const STR = 5; const ARR = 6; const OBJ = 7; const EOK = 127; function encodeArray(array) { return [ARR, ...array.flatMap((value) => encodeParts(value)), END]; } function encodeObject(object) { const keys = Object.keys(object).sort(); return [ OBJ, ...keys.flatMap((key) => [ STR, encode$5(key), END, ...encodeParts(object[key]) ]), END ]; } function encodeParts(value) { if (value === null) return [NULL]; if (value === false) return [FALSE]; if (value === true) return [TRUE]; if (typeof value === "number") return [NUM, encode$6(value)]; if (typeof value === "string") return [STR, encode$5(value), END]; if (Array.isArray(value)) return encodeArray(value); if (typeof value === "object") return encodeObject(value); return [NULL]; } function encode$4(value) { const parts = encodeParts(value); while (parts[parts.length - 1] === END) parts.pop(); const lastPart = parts[parts.length - 1]; if (typeof lastPart !== "number") { let end = lastPart.length - 1; while (end >= 0 && !lastPart[end]) end--; if (lastPart[end] !== 255) { parts[parts.length - 1] = lastPart.slice(0, end + 1); } else { parts.push(EOK); } } const length = parts.reduce( (sum, part) => sum + (typeof part === "number" ? 1 : part.length), 0 ); const buffer = new Uint8Array(length); let i = 0; for (const part of parts) { if (typeof part === "number") { buffer[i] = part; i++; } else { buffer.set(part, i); i += part.length; } } addStringify(buffer); return buffer; } const nextKey = /* @__PURE__ */ new WeakMap(); function decode$4(buffer) { let i = 0; const stack = [[]]; function readString() { const start = i; while (i < buffer.length && buffer[i] !== END) i++; const str = decode$5(buffer.subarray(start, i)); i++; return str; } function pushToken(type, value) { const current = stack[stack.length - 1]; if (type === ARR || type === OBJ) stack.push(value); if (!current) return; if (Array.isArray(current)) { current.push(value); } else { if (nextKey.has(current)) { current[nextKey.get(current)] = value; nextKey.delete(current); } else { nextKey.set(current, value); } } } function popToken() { stack.pop(); } while (i < buffer.length) { const type = buffer[i]; const start = ++i; switch (type) { case EOK: return stack[0][0]; case END: popToken(); break; case NULL: pushToken(type, null); break; case FALSE: pushToken(type, false); break; case TRUE: pushToken(type, true); break; case NUM: i += 8; pushToken(type, decode$6(buffer.subarray(start, i))); break; case STR: pushToken(type, readString()); break; case ARR: pushToken(type, []); break; case OBJ: pushToken(type, {}); break; default: throw new Error(`Invalid byte ${type} at ${start}`); } } return stack[0][0]; } function keyStep(key) { if (isMinKey(key)) return { key, step: 1 }; if (isMaxKey(key)) return { key, step: -1 }; const l = key.length - 1; let newKey; let step; switch (key[l]) { case 0: newKey = key.slice(0, l); addStringify(newKey); step = 1; break; case 255: newKey = key.slice(0, l); addStringify(newKey); newKey[l - 1]++; step = -1; break; default: newKey = key; step = 0; } return { key: newKey, step }; } function keyBefore(key) { if (isMinKey(key) || isMaxKey(key)) return key; const l = key.length - 1; let newKey; if (key[l] === 0) { newKey = key.slice(0, l); } else { newKey = new Uint8Array(l + 2); newKey.set(key, 0); newKey[l]--; newKey[l + 1] = 255; } addStringify(newKey); return newKey; } function keyAfter(key) { if (isMaxKey(key)) return key; const l = key.length - 1; let newKey; if (key[l] === 255) { newKey = key.slice(0, l); newKey[l - 1]++; } else { newKey = new Uint8Array(l + 2); newKey.set(key, 0); newKey[l + 1] = 0; } addStringify(newKey); return newKey; } function decodeBound(bound) { const { key, step } = keyStep(bound); if (isMinKey(key) || isMaxKey(key)) return { step }; const value = decode$4(key); return { key: value, step }; } const pageProps = { $all: 1, $first: 1, $last: 1, $after: 1, $before: 1, $since: 1, $until: 1, $cursor: 1 }; function splitArgs(arg) { const page = {}; const filter = {}; for (const p in arg) (p in pageProps ? page : filter)[p] = arg[p]; return [ isEmpty(page) ? void 0 : page, isEmpty(filter) ? void 0 : filter ]; } function encode$3(arg) { if (!isPlainObject(arg)) return { key: encode$4(arg) }; const [page, filter] = splitArgs(arg); errIf("page_and_filter", page && filter, arg); if (!page) return { key: encode$4(filter || {}) }; const { $cursor, ...range } = page; const { $first, $all, $last, $after, $before, $since, $until } = range; const hasRange = !isEmpty(range); errIf("first_and_last", isDef($first) && isDef($last), arg); errIf("all_and_last", isDef($all) && isDef($last), arg); errIf("all_and_first", isDef($first) && isDef($all), arg); errIf("after_and_since", isDef($after) && isDef($since), arg); errIf("before_and_until", isDef($before) && isDef($until), arg); errIf("cursor_and_range_arg", isDef($cursor) && hasRange, arg); let [key, end] = hasRange ? [MIN_KEY, MAX_KEY] : []; if (isDef($cursor)) key = encode$4($cursor); if (isDef($after)) key = keyAfter(encode$4($after)); if (isDef($before)) end = keyBefore(encode$4($before)); if (isDef($since)) key = encode$4($since); if (isDef($until)) end = encode$4($until); if (isDef($last)) [key, end] = [end, key]; const node = { key }; if (isDef(end)) node.end = end; if ($first || $last) node.limit = $first || $last; return node; } function decode$3(node) { const { key, end, limit } = node; errIf("no_key", !isDef(key)); errIf("limit_without_end", isDef(limit) && !isDef(end)); const kParts = decodeBound(key); if (!isDef(end) || cmp(key, end) === 0) return kParts.key; const eParts = decodeBound(end); const reverse = cmp(key, end) > 0; const [lower, upper] = reverse ? [eParts, kParts] : [kParts, eParts]; const args = {}; if (limit) { args[reverse ? "$last" : "$first"] = limit; } else if (isMinKey(key) && isMaxKey(end) || isMinKey(end) && isMaxKey(key)) { args.$all = true; } if (isDef(lower.key) && !isMinKey(lower.key)) { args[lower.step === 1 ? "$after" : "$since"] = lower.key; } if (isDef(upper.key) && !isMaxKey(upper.key)) { args[upper.step === -1 ? "$before" : "$until"] = upper.key; } return args; } const PATH_SEPARATOR = "."; function encode$2(path) { if (typeof path === "string") { if (!path.length || path === PATH_SEPARATOR) return []; path = path.split(PATH_SEPARATOR); } if (!Array.isArray(path)) { throw Error(`encodePath.invalid:${JSON.stringify(path)}`); } function encodeSegment(seg) { if (ArrayBuffer.isView(seg)) return seg; const node = encode$3(seg); if (node.end) return node; return node.key; } if (isPlainObject(path[path.length - 1])) { const [page, filter] = splitArgs(path[path.length - 1]); if (page) path = path.slice(0, -1).concat([filter || MIN_KEY]); } return path.map(encodeSegment); } function decode$2(path) { if (!Array.isArray(path)) { throw Error(`decodePath.invalid:${JSON.stringify(path)}`); } return path.map((key) => decode$3({ key })); } function splitRef($ref) { if (!Array.isArray($ref)) return []; const tail = $ref[$ref.length - 1]; if (!isPlainObject(tail)) return []; return splitArgs(tail); } let customAlphabet = (alphabet, defaultSize = 21) => { return (size = defaultSize) => { let id2 = ""; let i = size | 0; while (i--) { id2 += alphabet[Math.random() * alphabet.length | 0]; } return id2; }; }; const alpha = "-0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz"; const id = customAlphabet(alpha, 20); function findFirst(children, target, first, last) { return find( children, ({ key, end }) => { const keyCmp = cmp(key, target); const endCmp = end && cmp(end, target); if (end && keyCmp < 0 && endCmp >= 0) return 0; return keyCmp; }, first, last ); } function findLast(children, end, first, last) { const ix = findFirst(children, end, first, last); return children[ix] && cmp(children[ix].key, end) <= 0 ? ix + 1 : ix; } function isRange(node) { return node && typeof node.end !== "undefined"; } function isBranch(node) { return node && typeof node.children !== "undefined"; } function isPrefix(node) { return node == null ? void 0 : node.prefix; } function isLink(node) { return node && typeof node.path !== "undefined"; } function isOlder(node, version) { return typeof node.version !== "undefined" && node.version < version; } function isNewer(node, version) { return typeof node.version !== "undefined" && node.version > version; } function add(base, diff) { let changed = false; let index = 0; for (const node of diff) { const cmp2 = compare(node); const nodeIsBranch = isBranch(node); index = find(base, cmp2, index); const item = base[index]; const itemIsBranch = isBranch(item); if (!item || cmp2(item)) { base.splice(index, 0, clone(node)); changed = true; continue; } if (nodeIsBranch && itemIsBranch) { changed = add(item.children, node.children) || changed; } else if (nodeIsBranch) { continue; } else if (itemIsBranch) { item.value = node.value; changed = true; } else { item.value += node.value; } const size = itemIsBranch ? item.children.length : item.value; if (!size) { base.splice(index, 1); changed = true; } } return changed; } function compare(node) { return (item) => { const v = cmp(item.key, node.key) || compareValue(!!item.end, !!node.end) || item.end && cmp(item.end, node.end) || compareValue(item.limit, node.limit); return v; }; } function compareValue(a, b) { if (a === b) return 0; return a < b ? -1 : 1; } function clone(node) { const copy = { ...node }; if (node.children) copy.children = node.children.map((child) => clone(child)); return copy; } function merge(current, changes) { let index = 0; if (typeof changes === "undefined") return current; for (const change of changes) { index = isRange(change) ? insertRange$1(current, change, index) : insertNode$1(current, change, index); } return current; } function insertRange$1(current, change, start = 0) { const { key, end } = change; const keyIx = findFirst(current, key, start); const endIx = findLast(current, end, keyIx); const insertions = [change]; for (let i = keyIx; i < endIx; i++) { const node = current[i]; if (isRange(node)) { insertions.push(...mergeRanges$1(insertions.pop(), node)); } else { insertNode$1(insertions, node, insertions.length - 1); } } current.splice(keyIx, endIx - keyIx, ...insertions); return keyIx + insertions.length - 1; } function mergeRanges$1(base, node) { if (node.version < base.version) [node, base] = [base, node]; return [ cmp(base.key, node.key) < 0 && { ...base, end: keyBefore(node.key) }, node, cmp(base.end, node.end) > 0 && { ...base, key: keyAfter(node.end) } ].filter(Boolean); } function insertNode$1(current, change, start = 0) { if (!current) throw new Error(`merge.insertNode: ${current}`); const key = change.key; const index = findFirst(current, key, start); const node = current[index]; if (node && cmp(node.key, key) <= 0) { return isRange(node) ? insertNodeIntoRange$1(current, index, change) : updateNode$1(current, index, change); } current.splice(index, 0, change); return index + 1; } function insertNodeIntoRange$1(current, index, change) { const key = change.key; const range = current[index]; const newChange = getNewer(change, range); if (!newChange) return; const insertions = [ cmp(range.key, key) < 0 && { ...range, end: keyBefore(key) }, newChange, cmp(range.end, key) > 0 && { ...range, key: keyAfter(key) } ].filter(Boolean); current.splice(index, 1, ...insertions); return index + insertions.length - 1; } function updateNode$1(current, index, change) { const node = current[index]; if (isBranch(change) && isBranch(node)) { merge(node.children, change.children); } else if (isBranch(node)) { const newNode = getNewer(node, change); current[index] = newNode || change; } else { const newChange = getNewer(change, node); if (newChange) current[index] = newChange; } if (change.prefix) current[index].prefix = true; return index + 1; } function getNewer(node, base) { const { version } = base; if (isBranch(node)) { const children = [{ key: MIN_KEY, end: MAX_KEY, version }]; merge(children, node.children); return children.length === 1 ? null : { ...node, children }; } return node.version >= version ? node : null; } const IS_VAL = Symbol("IS_VAL"); function makeNode(seg, props2) { if (ArrayBuffer.isView(seg)) return { key: seg, ...props2 }; return { ...seg, ...props2 }; } function wrapValue(value, path, version = 0) { const node = makeNode(path[path.length - 1], { value, version }); return wrap([node], path.slice(0, -1), version); } function wrap(children, path, version = 0, prefix = false) { if (!Array.isArray(path)) throw Error(`wrap.path_not_array ${path}`); if (!path.length) return children; let i = path.length - 1; if (!Array.isArray(children)) { children = [makeNode(path[i--], { value: children, version })]; } else { if (!children.length) return; children = [makeNode(path[i--], { children, version })]; } if (prefix) children[0].prefix = true; while (i >= 0) children = [makeNode(path[i--], { children, version })]; return children; } function unwrap(tree, path) { if (!Array.isArray(path)) throw Error(`unwrap.path_not_array ${path}`); let children = tree; let node = { children }; for (let i = 0; i < path.length; i++) { const key = path[i]; if (!ArrayBuffer.isView(key)) throw Error("unwrap.ranges_unsupported"); children = node.children; if (!children) return null; node = children[findFirst(children, key)]; if (!node || cmp(node.key, key) > 0) return void 0; if (isRange(node)) return null; if (node.path) return unwrap(tree, node.path.concat(path.slice(i + 1))); } return getNodeValue(node); } function getNodeValue(node) { if (node.children) return node.children; if (node.value && typeof node.value === "object") { node.value[IS_VAL] = true; } return node.value; } function remove(children, path) { if (!Array.isArray(path)) throw Error(`del.path_not_array ${path}`); if (!children) return null; if (!path.length) return []; const key = path[0]; const ix = findFirst(children, key); const node = children[ix]; if (!node || cmp(node.key, key) > 0 || isRange(node)) return children; if (path.length === 1) { return children.slice(0, ix).concat(children.slice(ix + 1)); } if (!isBranch(node)) return children; const filteredChildren = remove(node.children, path.slice(1)); if (filteredChildren === children) return children; const filteredNode = filteredChildren.length ? { ...node, children: filteredChildren } : []; return children.slice(0, ix).concat(filteredNode, children.slice(ix + 1)); } class Result { constructor(root) { this.root = root || this; } addKnown(node) { this.known = this.known || []; merge(this.known, [node]); } addUnknown(node) { this.unknown = this.unknown || []; this.unknown.push(node); } addLinked(children) { if (this.root !== this) return this.root.addLinked(children); this.linked = this.linked || []; add(this.linked, children); } } function slice(graph, query, root) { const result = new Result(root); let currentQuery = query; while (currentQuery) { let index = 0; for (const queryNode of currentQuery) { if (isRange(queryNode)) { sliceRange(graph, queryNode, result); } else { const key = queryNode.key; index = findFirst(graph, key); sliceNode(graph[index], queryNode, result); } } currentQuery = root ? void 0 : result.linked; delete result.linked; } delete result.root; return result; } function sliceNode(graph, query, result) { const { key, version } = query; const { root } = result; if (!graph || cmp(graph.key, key) > 0 || isOlder(graph, version)) { result.addUnknown(query); } else if (isRange(graph)) { if (isBranch(query)) { const { known } = slice( [{ key: MIN_KEY, end: MAX_KEY, version: graph.version }], query.children ); result.addKnown({ key, version: graph.version, children: known }); } else { result.addKnown({ key, end: key, version: graph.version }); } } else if (isBranch(graph) && isBranch(query)) { const { known, unknown } = slice(graph.children, query.children, root); if (known) result.addKnown({ ...graph, children: known }); if (unknown) result.addUnknown({ ...query, children: unknown }); } else if (isLink(graph)) { result.addKnown(graph); if (graph.prefix && isRange(query)) { result.addLinked(wrap([query], graph.path, version, true)); } else { result.addLinked( wrap( query.children || query.value, graph.path, version, graph.prefix || query.prefix ) ); } } else if (isBranch(graph)) { result.addKnown(graph); } else if (isBranch(query)) { const { known } = slice( [{ key: MIN_KEY, end: MAX_KEY, version: graph.version }], query.children ); result.addKnown({ key, version: graph.version, children: known }); } else { result.addKnown(graph); } } function sliceRange(graph, query, result) { let { key, end, limit = Number.POSITIVE_INFINITY, version } = query; const step = cmp(key, end) < 0 ? 1 : -1; if (isMinKey(graph[0].key) && graph[0].prefix && graph[0].children) { const { known, unknown } = slice(graph[0].children, [query], result.root); if (known) result.addKnown({ ...graph[0], children: known }); if (unknown) result.addUnknown({ ...query[0], children: unknown }); return; } if (cmp(key, end) < 0) { for (let i = findFirst(graph, key); cmp(key, end) <= 0 && limit > 0; i++) { const node = graph[i]; if (!node || cmp(key, node.key) < 0 || isOlder(node, version)) break; if (isRange(node)) { result.addKnown(getOverlap(node, key, end)); } else { sliceNode(node, { ...query, key }, result); limit--; } key = keyAfter(node.end || node.key); } } else { for (let i = findLast(graph, key) - 1; cmp(key, end) >= 0 && limit > 0; i--) { const node = graph[i]; if (!node || cmp(key, node.end || node.key) > 0 || isOlder(node, version)) break; if (isRange(node)) { result.addKnown(getOverlap(node, end, key)); } else { sliceNode(node, { ...query, key }, result); limit--; } key = keyBefore(node.key); } } if (limit && (step < 0 ? cmp(key, end) > 0 : cmp(key, end) < 0)) { const unknown = { ...query, key, end, limit }; result.addUnknown(unknown); } } function getOverlap(node, key, end) { if (cmp(node.key, key) >= 0 && cmp(node.end, end) <= 0) return node; return { ...node, key: cmp(node.key, key) > 0 ? node.key : key, end: cmp(node.end, end) < 0 ? node.end : end }; } function sieve(current, changes, result = []) { let index = 0; for (const change of changes) { index = isRange(change) ? insertRange(current, change, result, index) : insertNode(current, change, result, index); } return result; } function insertRange(current, change, result, start = 0) { const { key, end } = change; const keyIx = findFirst(current, key, start); const endIx = findLast(current, end, keyIx); if (keyIx === endIx && !(current[keyIx] && cmp(current[keyIx].key, end) <= 0 && cmp(current[keyIx].end || current[keyIx].key, key) >= 0)) { return keyIx; } const appliedChange = []; let currentKey = change.key; for (let i = keyIx; i < endIx; i++) { const node = current[i]; if (isRange(node) && node.version >= 0) { if (cmp(node.key, currentKey) > 0) { appliedChange.push({ key: currentKey, end: keyBefore(node.key), version: change.version }); } currentKey = keyAfter(node.end); } else { if (getNewerChange(node, change)) { appliedChange.push({ key: currentKey, end: keyBefore(node.key), version: change.version }); currentKey = keyAfter(node.key); } } if (cmp(currentKey, change.end) >= 0) { break; } } if (cmp(currentKey, change.end) <= 0) { appliedChange.push({ key: currentKey, end: change.end, version: change.version }); } if (appliedChange.length) result.push(...appliedChange); const insertions = [change]; for (let i = keyIx; i < endIx; i++) { const node = current[i]; if (isRange(node)) { insertions.push(...mergeRanges(insertions.pop(), node)); } else { insertNode(insertions, node, [], insertions.length - 1); } } current.splice(keyIx, endIx - keyIx, ...insertions); return keyIx + insertions.length - 1; } function mergeRanges(base, node) { if (node.version < base.version) [node, base] = [base, node]; return [ cmp(base.key, node.key) < 0 && { ...base, end: keyBefore(node.key) }, node, cmp(base.end, node.end) > 0 && { ...base, key: keyAfter(node.end) } ].filter(Boolean); } function insertNode(current, change, result, start = 0) { const key = change.key; const index = findFirst(current, key, start); const node = current[index]; if (node && cmp(node.key, key) <= 0) { return isRange(node) ? insertNodeIntoRange(current, index, change, result) : updateNode(current, index, change, result); } return index; } function insertNodeIntoRange(current, index, change, result) { const key = change.key; const range = current[index]; const newChange = getNewerChange(change, range); const newNode = getNewerNode(change, range); if (!newChange) return; result.push(newChange); const insertions = [ cmp(range.key, key) < 0 && { ...range, end: keyBefore(key) }, newNode, cmp(range.end, key) > 0 && { ...range, key: keyAfter(key) } ].filter(Boolean); current.splice(index, 1, ...insertions); return index + insertions.length - 1; } function updateNode(current, index, change, result) { const node = current[index]; if (isBranch(change) && isBranch(node)) { const nextResult = []; node.version = change.version; sieve(node.children, change.children, nextResult); if (nextResult.length) result.push({ ...change, children: nextResult }); } else if (isBranch(node)) { const newNode = getNewerNode(node, change); current[index] = newNode || change; if (!newNode) result.push(change); } else { const newChange = getNewerChange(change, node); const newNode = getNewerNode(change, node); if (newNode) current[index] = newNode; if (newChange && (change.value !== node.value || !isPathEqual(change.path, node.path))) { result.push(newChange); } } return index + 1; } function isPathEqual(first, second) { if (!(first || second)) return true; if (!(first && second)) return false; if (first.length !== second.length) return false; for (let i = 0; i < first.length; i++) { if (first[i] !== second[i]) return false; } return true; } function getNewerNode(node, base) { if (isBranch(node)) { const emptyNode = { key: MIN_KEY, end: MAX_KEY, version: base.version }; const children = [emptyNode]; sieve(children, node.children); return children.length === 1 && children[0] === emptyNode ? null : { ...node, children }; } return node.version >= base.version ? node : null; } function getNewerChange(node, base) { if (isBranch(node)) { const children = node.children.filter( (child) => getNewerChange(child, base) ); return children.length && { ...node, children }; } return node.version >= base.version ? node : null; } function setVersion(graph, version, onlyIfZero = false) { for (const node of graph) { if (!(onlyIfZero && node.version)) node.version = version; if (node.children) setVersion(node.children, version, onlyIfZero); } return graph; } function getKnown(graph, version = 0) { const query = []; for (const { key, end, children } of graph) { const node = { key, version }; if (end) { if (cmp(end, key) !== 0) node.end = end; node.value = 1; } if (children) { node.children = getKnown(children); } else { node.value = 1; } query.push(node); } return query; } function finalize(graph, query, version = Date.now()) { let result = [{ key: MIN_KEY, end: MAX_KEY, version: 0 }]; merge(result, graph); if (query) result = slice(result, query).known || []; if (version !== false) result = setVersion(result, version, true); return result; } const PRE_CHI_PUT = Symbol("PREFIX_CHILDREN_$PUT"); function decode$1(nodes = [], { isGraph } = {}) { function decodeChildren(nodes2) { let result = []; let allStrs = true; let allNums = true; function pushResult(...objects) { for (const object of objects) { if (isDef(object) && !Number.isInteger(object.$key)) allNums = false; if (isDef(object) && typeof object.$key !== "string") allStrs = false; } result.push(...objects); } const putRanges = []; const prefixChildPuts = []; let lastNode = null; function addPutRange({ key, end }) { if (lastNode) { if (lastNode.end) { if (cmp(key, keyAfter(lastNode.end)) === 0) { lastNode.end = end || key; return end && cmp(end, key) !== 0; } } else { if (cmp(key, keyAfter(lastNode.key)) === 0) { key = lastNode.key; } } } if (end && cmp(key, end) !== 0) { lastNode = { key, end }; putRanges.push(lastNode); return true; } lastNode = { key }; return false; } for (const node of nodes2) { if (isGraph && addPutRange(node)) continue; if (isPrefix(node)) { const decodedChildren = decodePrefixNode(node); if (PRE_CHI_PUT in decodedChildren) { prefixChildPuts.push(...decodedChildren[PRE_CHI_PUT]); } pushResult(...decodedChildren); } else if (isGraph && isRange(node)) pushResult(decodeRangeNode(node)); else if (isBranch(node)) pushResult(decodeBranchNode(node)); else if (isLink(node)) pushResult(decodeLinkNode(node)); else pushResult(decodeLeafNode(node)); } if (allStrs || allNums && putRanges.length === 1 && cmp(putRanges[0].key, 0) === 0 && cmp(putRanges[0].end, Number.POSITIVE_INFINITY) === 0) { result = result.reduce( (collection, item) => { if (Array.isArray(item)) { collection[item.$key] = item; delete item.$key; return collection; } let { $key, $val } = item; delete item.$key; delete item.$val; if ($val === null) { $val = { $val }; } else if (typeof $val === "object") { $val = clone$1($val); Object.defineProperty($val, "$val", { value: true }); } collection[$key] = isDef($val) ? $val : !isEmpty(item) || item.$ref || item.$put ? item : isGraph ? null : true; return collection; }, allStrs ? {} : [] ); } if (isGraph && putRanges.length) { if (isMinKey(putRanges[0].key) && isMaxKey(putRanges[0].end)) { Object.defineProperty(result, "$put", { value: true }); } else { Object.defineProperty(result, "$put", { value: putRanges.map((rNode) => decode$3(rNode)).concat(prefixChildPuts) }); } } else if (prefixChildPuts.length) { Object.defineProperty(result, "$put", { value: prefixChildPuts }); } return result; } function decodePrefixNode(node) { let args = decode$3(node); if (!args) args = {}; if (typeof args === "string") { throw Error(`decode.unencoded_prefix: ${args}`); } if (isLink(node)) { args.$all = true; const $ref = decode$2(node.path); const lastKey = $ref[$ref.length - 1]; if (typeof lastKey === "string") { throw Error(`decode.unencoded_prefix_ref: ${node.path}`); } lastKey.$all = true; const linkObject = { $key: args }; Object.defineProperty(linkObject, "$ref", { value: $ref }); return [linkObject]; } const children = decodeChildren(node.children); if (!Array.isArray(children)) { throw Error(`decode.prefix_without_encoded_child_keys:${node.key}`); } for (const child of children) { if (typeof child.$key === "string") { throw Error(`decode.prefix_with_unencoded_child_key:${child.$key}`); } if (!splitArgs(child.$key)[0]) { child.$key = { $cursor: child.$key }; } child.$key = { ...args, ...child.$key }; } if (children.$put === true) { children[PRE_CHI_PUT] = [{ ...args, $all: true }]; } else if (Array.isArray(children.$put)) { children[PRE_CHI_PUT] = children.$put.map((rarg) => ({ ...args, ...rarg })); } else if (isDef(children.$put)) { children[PRE_CHI_PUT] = [{ ...args, ...children.$put }]; } return children; } function decodeBranchNode(node) { const child = decodeChildren(node.children); child.$key = decode$3(node); return child; } function decodeLeafNode(node) { const child = isGraph ? { $val: node.value } : {}; child.$key = decode$3(node); return child; } function decodeRangeNode(node) { if (cmp(node.key, node.end) === 0) { return { $key: decode$3({ key: node.key }) }; } } function decodeLinkNode(node) { const linkObject = { $key: decode$3(node) }; Object.defineProperty(linkObject, "$ref", { value: decode$2(node.path) }); return linkObject; } return decodeChildren(nodes); } function decodeGraph(graph) { return decode$1(graph, { isGraph: true }); } function decodeQuery(query) { return decode$1(query, { isGraph: false }); } const REF = Symbol(); const PRE = Symbol(); function decorate(rootGraph, rootQuery) { function construct(plumGraph, query) { if (plumGraph === null) return null; if (!isDef(plumGraph)) plumGraph = []; if (query.$key) query = [query]; let graph; if (query.$ref) { const { $ref, ...props2 } = query; const [range, filter] = splitRef($ref); const path = encode$2($ref); const targetPlumGraph = unwrap(rootGraph, path); if (targetPlumGraph) { if (range) targetPlumGraph[PRE] = filter; graph = construct( targetPlumGraph, range ? { $key: range, ...props2 } : props2 ); Object.defineProperty(graph, "$ref", { value: $ref }); } } else if (Array.isArray(query)) { let pageKey; graph = query.flatMap((item, i) => { if (!(item == null ? void 0 : item.$key)) { return construct(descend(plumGraph, i), item); } const { $key, $chi, ...props2 } = item; const subQuery = $chi || (isEmpty(props2) ? 1 : props2); if (!(isPlainObject($key) && splitArgs($key)[0])) { return construct(descend(plumGraph, $key), subQuery); } if (pageKey) { throw Error( `decorate.multi_range_query:${JSON.stringify({ $key, pageKey })}` ); } pageKey = $key; const children = slice2(plumGraph, $key); return children.filter((node) => !isRange(node)).map((node) => { const $key2 = decode$3(node); const subResult = construct(getValue(node), subQuery); if (typeof subResult === "object" && subResult) { subResult.$key = children[PRE] && !isMinKey(children[PRE]) ? { ...children[PRE], $cursor: $key2 } : $key2; } return subResult; }); }); if (pageKey) addPageMeta(graph, pageKey); } else if (typeof query === "object") { graph = {}; for (const prop in query) { graph[prop] = construct(descend(plumGraph, prop), query[prop]); } } else if (query) { if (Array.isArray(plumGraph) && !plumGraph.length) { graph = void 0; } else if (typeof plumGraph !== "object" || !plumGraph) { graph = plumGraph; } else if (plumGraph[IS_VAL]) { graph = Array.isArray(plumGraph) ? plumGraph.slice(0) : { ...plumGraph }; graph.$val = true; } else if (Array.isArray(plumGraph)) { graph = deValNull(decodeGraph(plumGraph)); } else { throw Error("decorate.unexpected_graph"); } } if (plumGraph[REF]) { Object.defineProperty(graph, "$ref", { value: decode$2(plumGraph[REF]) }); } return graph; } function descend(children, $key) { const key = ArrayBuffer.isView($key) ? $key : encode$3($key).key; if (!Array.isArray(children)) return null; const ix = findFirst(children, key); const node = children[ix]; if (!node) return; if (isRange(node) && node.end >= key) return null; if (cmp(node.key, key) !== 0) return; const result2 = getValue(node); if (node.prefix) result2[PRE] = $key; return result2; } function getValue(node) { let result2; if (node.path) { result2 = unwrap(rootGraph, node.path); if (typeof result2 === "object" && result2) result2[REF] = node.path; } else { result2 = getNodeValue(node); } return result2; } function slice2(children, $key) { const [range, filter] = splitArgs($key); if (isDef(filter)) { children = descend(children, filter); } else if (isMinKey(children[0].key) && children[0].prefix) { children = descend(children, MIN_KEY); } const { key, end, limit = Number.POSITIVE_INFINITY } = encode$3(range); const ix = findFirst(children, key); let i = ix; let result2; if (cmp(key, end) < 0) { for (let n = 0; i < children.length && n < limit; i++) { if (!isRange(children[i])) n++; } result2 = children.slice(ix, i); } else { for (let n = 0; i >= 0 && n < limit; i--) { if (!isRange(children[i])) n++; } result2 = children.slice(i + 1, ix + 1); } if (children[REF]) result2[REF] = children[REF]; if (children[PRE]) result2[PRE] = children[PRE]; return result2; } const result = construct(rootGraph, rootQuery); return result; } function deValNull(graph) { if (typeof graph !== "object" || !graph) return graph; if ("$val" in graph && graph.$val !== true) return graph.$val; for (const prop in graph) graph[prop] = deValNull(graph[prop]); return graph; } function addPageMeta(graph, args) { if (args.$all) { Object.assign(graph, { $page: args, $prev: null, $next: null }); return; } const [{ $first, $last, ...bounds }, filter] = splitArgs(args); const count = $first || $last; const $page = { ...filter, ...bounds, $all: true }; if (graph.length === count) { if ($first) { const boundKey = graph[graph.length - 1].$key; $page.$until = isDef(boundKey == null ? void 0 : boundKey.$cursor) ? boundKey.$cursor : boundKey; delete $page.$before; } else { const boundKey = graph[0].$key; $page.$since = isDef(boundKey == null ? void 0 : boundKey.$cursor) ? boundKey.$cursor : boundKey; delete $page.$after; } } const $prev = isDef($page.$after) ? { ...filter, $last: count, $until: $page.$after } : isDef($page.$since) ? { ...filter, $last: count, $before: $page.$since } : null; const $next = isDef($page.$before) ? { ...filter, $first: count, $since: $page.$before } : isDef($page.$until) ? { ...filter, $first: count, $after: $page.$until } : null; Object.assign(graph, { $page, $next, $prev }); } function getByte(view, offset) { return offset < view.byteLength ? view.getUint8(offset) : 0; } function getChar(string, offset) { return offset < string.length ? alpha.indexOf(string[offset]) : 0; } function encode$1(u8Arr) { const { buffer, byteOffset, byteLength } = u8Arr; const view = new DataView(buffer, byteOffset, byteLength); let str = ""; for (let i = 0; i < view.byteLength; i += 3) { let value = (getByte(view, i) << 16) + (getByte(view, i + 1) << 8) + getByte(view, i + 2); let gstr = ""; for (let j = 0; j < 4; j++) { gstr = alpha[value & 63] + gstr; value = value >> 6 | 0; } str += gstr; } return str.substring(0, Math.ceil(view.byteLength * 4 / 3)); } function decode(string, start = 0) { const buffer = new ArrayBuffer(Math.floor((string.length - start) * 3 / 4)); const view = new DataView(buffer); for (let i = start; i < string.length; i += 4) { let value = (getChar(string, i) << 18) + (getChar(string, i + 1) << 12) + (getChar(string, i + 2) << 6) + getChar(string, i + 3); for (let j = i * 3 / 4 + 2; j >= i * 3 / 4; j--) { if (j < view.byteLength) view.setUint8(j, value & 255); value = value >> 8 | 0; } } return addStringify(new Uint8Array(buffer)); } const props = [ "end", "version", "limit", "value", "path", "prefix", "children" ]; function serializeKey(key) { if (key[0] === STR) { const last = key[key.length - 1]; if (last !== 0 && last !== 255) { return decode$4(key); } } return `\0${encode$1(key)}`; } function deserializeKey(key) { if (key[0] === "\0") return decode(key.slice(1)); return encode$4(key); } function pack(children, parentVersion) { if (!Array.isArray(children)) return children; const array = children.map( (node) => props.reduce( (array2, prop, i) => { if (!(prop in node)) return array2; let value = node[prop]; if (prop === "version" && value === parentVersion) return array2; if (prop === "children") value = pack(value, node.version); if (prop === "end") value = serializeKey(value); if (prop === "path") value = value.map(serializeKey); array2[1] |= 1 << i; array2.push(value); return array2; }, [serializeKey(node.key), 0] ) ); return array; } function unpack(children, parentVersion) { if (!Array.isArray(children)) return children; const node = children.map( ([key, type, ...values]) => props.reduce( (node2, prop, i) => { if (!(type & 1 << i)) return node2; let value = values.shift(); if (prop === "children") value = unpack(value, node2.version); if (prop === "end") value = deserializeKey(value); if (prop === "path") value = value.map(deserializeKey); node2[prop] = value; return node2; }, { key: deserializeKey(key), version: parentVersion } ) ); return node; } const ROOT_KEY = Symbol(); function encode(value, { version, isGraph } = {}) { var _a; const links = []; function pushLink($ref, $ver, props2, $val, $chi) { const [range, _] = splitRef($ref); const node = !isEmpty(props2) ? makeNode2(range ? [{ $key: range, ...props2 }] : props2, void 0, $ver) : isDef($chi) ? makeNode2(range ? [{ $key: range, $chi }] : $chi, void 0, $ver) : null; const children = node ? node.children : isDef($val) ? $val : isGraph ? void 0 : 1; if (children) { links.push(wrap(children, encode$2($ref), $ver, !!range)[0]); } } const combine = isGraph ? merge : add; function makeNode2(object, key, ver, parentPuts = []) { var _a2; if (!isDef(object)) return; const { $key, $ver, $ref, $val, $chi, $put, ...props2 } = object || {}; if (typeof object === "object" && object && !Array.isArray(object)) { object = { ...Object.fromEntries( Object.entries({ $key, $ver, $ref, $val, $chi, $put }).filter(([_, val]) => isDef(val)) ), ...props2 }; } if (typeof object === "object" && object && isEmpty(object)) return; if (isDef($ver)) ver = $ver; if (isPlainObject($key)) { const [page, filter] = splitArgs($key); if (page) { const foundPuts = parentPuts.filter(([_, putFilter]) => isEqual(filter, putFilter)).map(([range]) => range); if (isGraph && !isDef(page.$cursor) && ($ref || $val || $chi || $put || !isEmpty(props2))) { object.$key = filter || {}; object.$put = foundPuts; const node2 = makeNode2(object, key, ver); if (!filter) node2.key = MIN_KEY; node2.prefix = true; return node2; } if ((!isDef(key) || Number.isInteger(key)) && (filter || isDef(page.$cursor))) { object.$key = isDef(page.$cursor) ? page.$cursor : page; const wrapper = { $key: filter || {}, $chi: [object] }; if (isGraph) wrapper.$put = foundPuts; const node2 = makeNode2(wrapper, key, ver); if (!filter) node2.key = MIN_KEY; node2.prefix = true; return node2; } } } let putRange = []; const prefixPuts = []; if (Array.isArray(object) && !isDef($put) && !isDef($val) && !object.some((it) => isDef(it == null ? void 0 : it.$key))) { putRange = [encode$3({ $since: 0, $until: Number.POSITIVE_INFINITY })]; } function classifyPut(put) { const [range, filter] = splitArgs(put); if (filter) { prefixPuts.push([range, filter]); } else { putRange.push(encode$3(put)); } } if ($put === true) { putRange = [{ key: MIN_KEY, end: MAX_KEY }]; } else if (Array.isArray($put)) { $put.forEach(classifyPut); } else if (isDef($put)) { classifyPut($put); } if (isDef($key) && (Number.isInteger(key) || !isDef(key))) key = $key; const node = key === ROOT_KEY || !isDef(key) ? {} : encode$3(key); node.version = ver; if (object === null) { node.end = node.key; } else if (isDef($key) && isDef(key) && key !== $key) { node.children = [makeNode2(object, void 0, ver, prefixPuts)].filter( Boolean ); return node; } else if ($ref) { pushLink($ref, node.version, props2, $val, $chi); if (!isGraph) return; node.path = encode$2($ref); } else if ($val === true) { node.value = Array.isArray(object) ? clone$1(object) : props2; } else if (isDef($val)) { node.value = $val; } else if (typeof object !== "object") { node.value = isGraph || typeof object === "number" ? object : 1; } else if (isDef($chi)) { const children = $chi.map((obj) => makeNode2(obj, void 0, ver, prefixPuts)).filter(Boolean).sort((a, b) => cmp(a.key, b.key)); if (children.length) { node.children = children; } } else if (Array.isArray(object)) { const children = object.map((obj, i) => makeNode2(obj, i, ver, prefixPuts)).filter(Boolean).reduce((acc, it) => { combine(acc, [it]); return acc; }, []); if (children.length) { node.children = children; } } else { const children = Object.keys(props2).sort().map((key2) => makeNode2(object[key2], key2, ver)).filter(Boolean); if (children.length) { node.children = children; } else if (putRange.length) ; else if (isGraph) { if (!(isDef($key) || isDef($put))) return; if (node.key && !node.end) node.end = node.key; } else { if (!isDef($key)) return; node.value = 1; } } if (isGraph && putRange.length && !isDef(node.path) && !isDef(node.value)) { const putRangeClone = putRange.map(({ key: key2, end }) => ({ key: key2, end, version: 0 })); node.children = merge(putRangeClone, node.children || []); } if ( // (key === ROOT_KEY || isDef(node.key)) && ((_a2 = node.children) == null ? void 0 : _a2.length) || isDef(node.end) || isDef(node.value) || isDef(node.path) ) { return node; } } if (value == null ? void 0 : value.$key) value = [value]; const result = ((_a = makeNode2(value, ROOT_KEY, version)) == null ? void 0 : _a.children) || []; while (links.length) { combine(result, [links.pop()]); } return result; } function encodeGraph(obj, version = Date.now()) { const encoded = encode(obj, { version, isGraph: true }); const versioned = setVersion(encoded, version, true); return versioned; } function encodeQuery(obj, version = 0) { return encode(obj, { version, isGraph: false }); } async function* mergeStreams(...streams) { const firstValues = (await Promise.all(streams.map((stream2) => stream2.next()))).map((iter) => iter.value); if (firstValues.some((value) => typeof value === "undefined")) { yield void 0; for (const value of firstValues) { if (typeof value !== "undefined") yield value; } } else { const merged = []; for (const value of firstValues) merge(merged, value); yield merged; } yield* mergeIterators(streams); } function makeWatcher() { const listeners = /* @__PURE__ */ new Set(); function write(change) { for (const push of listeners) push(change); } function watch(...args) { return stream.makeStream((push, _end) => { listeners.add(push); if (args.length) Pr