import murmurhash from "murmurhash";
import { fileDesc, messageDesc } from "@bufbuild/protobuf/codegenv2";
import { create, fromBinary, toBinary } from "@bufbuild/protobuf";
//#region \0rolldown/runtime.js
var __defProp = Object.defineProperty;
var __exportAll = (all, no_symbols) => {
	let target = {};
	for (var name in all) __defProp(target, name, {
		get: all[name],
		enumerable: true
	});
	if (!no_symbols) __defProp(target, Symbol.toStringTag, { value: "Module" });
	return target;
};
//#endregion
//#region src/crdt/merkle.ts
var merkle_exports = /* @__PURE__ */ __exportAll({
	build: () => build,
	debug: () => debug,
	diff: () => diff,
	emptyTrie: () => emptyTrie,
	getKeys: () => getKeys,
	insert: () => insert,
	keyToTimestamp: () => keyToTimestamp,
	prune: () => prune
});
function emptyTrie() {
	return { hash: 0 };
}
function isNumberTrieNodeKey(input) {
	return [
		"0",
		"1",
		"2"
	].includes(input);
}
function getKeys(trie) {
	return Object.keys(trie).filter(isNumberTrieNodeKey);
}
function keyToTimestamp(key) {
	const fullkey = key + "0".repeat(16 - key.length);
	return parseInt(fullkey, 3) * 1e3 * 60;
}
/**
* Mutates `trie` to insert a node at `timestamp`
*/
function insert(trie, timestamp) {
	const hash = timestamp.hash();
	const key = Number(Math.floor(timestamp.millis() / 1e3 / 60)).toString(3);
	trie = Object.assign({}, trie, { hash: (trie.hash || 0) ^ hash });
	return insertKey(trie, key, hash);
}
function insertKey(trie, key, hash) {
	if (key.length === 0) return trie;
	const c = key[0];
	const n = (isNumberTrieNodeKey(c) ? trie[c] : void 0) || {};
	return Object.assign({}, trie, { [c]: Object.assign({}, n, insertKey(n, key.slice(1), hash), { hash: (n.hash || 0) ^ hash }) });
}
function build(timestamps) {
	const trie = emptyTrie();
	for (const timestamp of timestamps) insert(trie, timestamp);
	return trie;
}
function diff(trie1, trie2) {
	if (trie1.hash === trie2.hash) return null;
	let node1 = trie1;
	let node2 = trie2;
	let k = "";
	while (true) {
		const keys = [...new Set([...getKeys(node1), ...getKeys(node2)]).values()];
		keys.sort((a, b) => a.localeCompare(b));
		let diffkey = null;
		for (let i = 0; i < keys.length; i++) {
			const key = keys[i];
			const next1 = node1[key];
			const next2 = node2[key];
			if (!next1 || !next2) break;
			if (next1.hash !== next2.hash) {
				diffkey = key;
				break;
			}
		}
		if (!diffkey) return keyToTimestamp(k);
		k += diffkey;
		node1 = node1[diffkey] || emptyTrie();
		node2 = node2[diffkey] || emptyTrie();
	}
	return null;
}
function prune(trie, n = 2) {
	if (!trie.hash) return trie;
	const keys = getKeys(trie);
	keys.sort((a, b) => a.localeCompare(b));
	const next = { hash: trie.hash };
	for (const k of keys.slice(-n)) {
		const node = trie[k];
		if (!node) throw new Error(`TrieNode for key ${k} could not be found`);
		next[k] = prune(node, n);
	}
	return next;
}
function debug(trie, k = "", indent = 0) {
	return " ".repeat(indent) + (k !== "" ? `k: ${k} ` : "") + `hash: ${trie.hash || "(empty)"}\n` + getKeys(trie).map((key) => {
		const node = trie[key];
		if (!node) return "";
		return debug(node, key, indent + 2);
	}).join("");
}
//#endregion
//#region ../../node_modules/uuid/dist-node/stringify.js
var byteToHex = [];
for (let i = 0; i < 256; ++i) byteToHex.push((i + 256).toString(16).slice(1));
function unsafeStringify(arr, offset = 0) {
	return (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();
}
//#endregion
//#region ../../node_modules/uuid/dist-node/rng.js
var rnds8 = new Uint8Array(16);
function rng() {
	return crypto.getRandomValues(rnds8);
}
//#endregion
//#region ../../node_modules/uuid/dist-node/v4.js
function v4(options, buf, offset) {
	if (!buf && !options && crypto.randomUUID) return crypto.randomUUID();
	return _v4(options, buf, offset);
}
function _v4(options, buf, offset) {
	options = options || {};
	const rnds = options.random ?? options.rng?.() ?? rng();
	if (rnds.length < 16) throw new Error("Random bytes length must be >= 16");
	rnds[6] = rnds[6] & 15 | 64;
	rnds[8] = rnds[8] & 63 | 128;
	if (buf) {
		offset = offset || 0;
		if (offset < 0 || offset + 16 > buf.length) throw new RangeError(`UUID byte range ${offset}:${offset + 15} is out of buffer bounds`);
		for (let i = 0; i < 16; ++i) buf[offset + i] = rnds[i];
		return buf;
	}
	return unsafeStringify(rnds);
}
//#endregion
//#region src/crdt/timestamp.ts
var clock;
function setClock(clock_) {
	clock = clock_;
}
function getClock() {
	return clock;
}
function makeClock(timestamp, merkle = {}) {
	return {
		timestamp: MutableTimestamp.from(timestamp),
		merkle
	};
}
function serializeClock(clock) {
	return JSON.stringify({
		timestamp: clock.timestamp.toString(),
		merkle: clock.merkle
	});
}
function deserializeClock(clock) {
	let data;
	try {
		data = JSON.parse(clock);
	} catch {
		data = {
			timestamp: "1970-01-01T00:00:00.000Z-0000-" + makeClientId(),
			merkle: {}
		};
	}
	const ts = Timestamp.parse(data.timestamp);
	if (!ts) throw new Timestamp.InvalidError(data.timestamp);
	return {
		timestamp: MutableTimestamp.from(ts),
		merkle: data.merkle
	};
}
function makeClientId() {
	return v4().replace(/-/g, "").slice(-16);
}
var config = { maxDrift: 300 * 1e3 };
var MAX_COUNTER = parseInt("0xFFFF");
var MAX_NODE_LENGTH = 16;
/**
* timestamp instance class
*/
var Timestamp = class Timestamp {
	constructor(millis, counter, node) {
		this._state = {
			millis,
			counter,
			node
		};
	}
	valueOf() {
		return this.toString();
	}
	toString() {
		return [
			new Date(this.millis()).toISOString(),
			("0000" + this.counter().toString(16).toUpperCase()).slice(-4),
			("0000000000000000" + this.node()).slice(-16)
		].join("-");
	}
	millis() {
		return this._state.millis;
	}
	counter() {
		return this._state.counter;
	}
	node() {
		return this._state.node;
	}
	hash() {
		return murmurhash.v3(this.toString());
	}
	static init(options = {}) {
		if (options.maxDrift) config.maxDrift = options.maxDrift;
		setClock(makeClock(new Timestamp(0, 0, options.node ? ("0000000000000000" + options.node).toString().slice(-16) : "")));
	}
	static {
		this.max = Timestamp.parse("9999-12-31T23:59:59.999Z-FFFF-FFFFFFFFFFFFFFFF");
	}
	/**
	* timestamp parsing
	* converts a fixed-length string timestamp to the structured value
	*/
	static parse(timestamp) {
		if (timestamp instanceof Timestamp) return timestamp;
		if (typeof timestamp === "string") {
			const parts = timestamp.split("-");
			if (parts && parts.length === 5) {
				const millis = Date.parse(parts.slice(0, 3).join("-")).valueOf();
				const counter = parseInt(parts[3], 16);
				const node = parts[4];
				if (!isNaN(millis) && millis >= 0 && !isNaN(counter) && counter <= MAX_COUNTER && typeof node === "string" && node.length <= MAX_NODE_LENGTH) return new Timestamp(millis, counter, node);
			}
		}
		return null;
	}
	/**
	* Timestamp send. Generates a unique, monotonic timestamp suitable
	* for transmission to another system in string format
	*/
	static send() {
		if (!clock) return null;
		const phys = Date.now();
		const lOld = clock.timestamp.millis();
		const cOld = clock.timestamp.counter();
		const lNew = Math.max(lOld, phys);
		const cNew = lOld === lNew ? cOld + 1 : 0;
		if (lNew - phys > config.maxDrift) throw new Timestamp.ClockDriftError(lNew, phys, config.maxDrift);
		if (cNew > MAX_COUNTER) throw new Timestamp.OverflowError();
		clock.timestamp.setMillis(lNew);
		clock.timestamp.setCounter(cNew);
		return new Timestamp(clock.timestamp.millis(), clock.timestamp.counter(), clock.timestamp.node());
	}
	static recv(msg) {
		if (!clock) return null;
		const phys = Date.now();
		const lMsg = msg.millis();
		const cMsg = msg.counter();
		if (lMsg - phys > config.maxDrift) throw new Timestamp.ClockDriftError();
		const lOld = clock.timestamp.millis();
		const cOld = clock.timestamp.counter();
		const lNew = Math.max(Math.max(lOld, phys), lMsg);
		const cNew = lNew === lOld && lNew === lMsg ? Math.max(cOld, cMsg) + 1 : lNew === lOld ? cOld + 1 : lNew === lMsg ? cMsg + 1 : 0;
		if (lNew - phys > config.maxDrift) throw new Timestamp.ClockDriftError();
		if (cNew > MAX_COUNTER) throw new Timestamp.OverflowError();
		clock.timestamp.setMillis(lNew);
		clock.timestamp.setCounter(cNew);
		return new Timestamp(clock.timestamp.millis(), clock.timestamp.counter(), clock.timestamp.node());
	}
	static {
		this.zero = Timestamp.parse("1970-01-01T00:00:00.000Z-0000-0000000000000000");
	}
	static {
		this.since = (isoString) => isoString + "-0000-0000000000000000";
	}
	static {
		this.DuplicateNodeError = class DuplicateNodeError extends Error {
			constructor(node) {
				super("duplicate node identifier " + node);
				this.name = "DuplicateNodeError";
			}
		};
	}
	static {
		this.ClockDriftError = class ClockDriftError extends Error {
			constructor(...args) {
				super(["maximum clock drift exceeded", ...args.map(String)].join(" "));
				this.name = "ClockDriftError";
			}
		};
	}
	static {
		this.OverflowError = class OverflowError extends Error {
			constructor() {
				super("timestamp counter overflow");
				this.name = "OverflowError";
			}
		};
	}
	static {
		this.InvalidError = class InvalidError extends Error {
			constructor(...args) {
				super(["timestamp is not valid"].concat(args.map(String)).join(" "));
				this.name = "InvalidError";
			}
		};
	}
};
var MutableTimestamp = class MutableTimestamp extends Timestamp {
	static from(timestamp) {
		return new MutableTimestamp(timestamp.millis(), timestamp.counter(), timestamp.node());
	}
	setMillis(n) {
		this._state.millis = n;
	}
	setCounter(n) {
		this._state.counter = n;
	}
	setNode(n) {
		this._state.node = n;
	}
};
//#endregion
//#region src/proto/sync_pb.ts
/**
* Describes the file sync.proto.
*/
var file_sync = fileDesc("CgpzeW5jLnByb3RvIjoKDUVuY3J5cHRlZERhdGESCgoCaXYYASABKAwSDwoHYXV0aFRhZxgCIAEoDBIMCgRkYXRhGAMgASgMIkYKB01lc3NhZ2USDwoHZGF0YXNldBgBIAEoCRILCgNyb3cYAiABKAkSDgoGY29sdW1uGAMgASgJEg0KBXZhbHVlGAQgASgJIkoKD01lc3NhZ2VFbnZlbG9wZRIRCgl0aW1lc3RhbXAYASABKAkSEwoLaXNFbmNyeXB0ZWQYAiABKAgSDwoHY29udGVudBgDIAEoDCJ2CgtTeW5jUmVxdWVzdBIiCghtZXNzYWdlcxgBIAMoCzIQLk1lc3NhZ2VFbnZlbG9wZRIOCgZmaWxlSWQYAiABKAkSDwoHZ3JvdXBJZBgDIAEoCRINCgVrZXlJZBgFIAEoCRINCgVzaW5jZRgGIAEoCUoECAQQBSJCCgxTeW5jUmVzcG9uc2USIgoIbWVzc2FnZXMYASADKAsyEC5NZXNzYWdlRW52ZWxvcGUSDgoGbWVya2xlGAIgASgJYgZwcm90bzM");
/**
* Describes the message EncryptedData.
* Use `create(EncryptedDataSchema)` to create a new message.
*/
var EncryptedDataSchema = messageDesc(file_sync, 0);
/**
* Describes the message Message.
* Use `create(MessageSchema)` to create a new message.
*/
var MessageSchema = messageDesc(file_sync, 1);
/**
* Describes the message MessageEnvelope.
* Use `create(MessageEnvelopeSchema)` to create a new message.
*/
var MessageEnvelopeSchema = messageDesc(file_sync, 2);
/**
* Describes the message SyncRequest.
* Use `create(SyncRequestSchema)` to create a new message.
*/
var SyncRequestSchema = messageDesc(file_sync, 3);
/**
* Describes the message SyncResponse.
* Use `create(SyncResponseSchema)` to create a new message.
*/
var SyncResponseSchema = messageDesc(file_sync, 4);
//#endregion
export { EncryptedDataSchema, MessageEnvelopeSchema, MessageSchema, SyncRequestSchema, SyncResponseSchema, Timestamp, create, deserializeClock, fromBinary, getClock, makeClientId, makeClock, merkle_exports as merkle, serializeClock, setClock, toBinary };

//# sourceMappingURL=index.js.map