@graffy/common
Version:
Common libraries that used by various Graffy modules.
1,544 lines • 53.9 kB
JavaScript
"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