Files
camino-datatypes/dist/src/crdt-automerge.js
T
2026-07-12 21:04:20 -07:00

84 lines
3.0 KiB
JavaScript

import * as Automerge from "@automerge/automerge";
const bytesToBase64 = (value) => {
if (typeof Buffer !== "undefined") {
return Buffer.from(value).toString("base64");
}
let binary = "";
for (const byte of value) {
binary += String.fromCharCode(byte);
}
return btoa(binary);
};
const base64ToBytes = (value) => {
if (typeof Buffer !== "undefined") {
return Buffer.from(value, "base64");
}
const binary = atob(value);
const bytes = new Uint8Array(binary.length);
for (let index = 0; index < binary.length; index += 1) {
bytes[index] = binary.charCodeAt(index);
}
return bytes;
};
export const isCaminoCrdtEnvelope = (value) => Boolean(value) &&
typeof value === "object" &&
!Array.isArray(value) &&
typeof value.$caminoCrdtType ===
"string" &&
typeof value.$caminoCrdtPayload ===
"string" &&
(value.$caminoCrdtEncoding ===
undefined ||
value.$caminoCrdtEncoding ===
"base64");
const assertEnvelopeType = (value, type) => {
if (value.$caminoCrdtType !== type) {
throw new Error(`CRDT type mismatch: expected ${type}, got ${value.$caminoCrdtType}`);
}
};
export const loadAutomergeFieldDoc = (value, type) => {
assertEnvelopeType(value, type);
return Automerge.load(base64ToBytes(value.$caminoCrdtPayload));
};
export const saveAutomergeFieldDoc = (doc, type) => ({
$caminoCrdtType: type,
$caminoCrdtEncoding: "base64",
$caminoCrdtPayload: bytesToBase64(Automerge.save(doc)),
});
export const createAutomergeFieldValue = (value, type) => saveAutomergeFieldDoc(Automerge.from({ value }), type);
export const isAutomergeFieldDoc = (value) => {
if (!value || typeof value !== "object") {
return false;
}
try {
Automerge.getHeads(value);
return true;
}
catch {
return false;
}
};
export const encodeAutomergeFieldWrite = (value, type) => {
if (isCaminoCrdtEnvelope(value)) {
return saveAutomergeFieldDoc(loadAutomergeFieldDoc(value, type), type);
}
if (isAutomergeFieldDoc(value)) {
return saveAutomergeFieldDoc(value, type);
}
throw new Error("CRDT field writes must use an Automerge document or Camino CRDT envelope");
};
export const normalizeAutomergeFieldValue = (value, type) => encodeAutomergeFieldWrite(value, type);
export const materializeAutomergeFieldValue = (value, type) => loadAutomergeFieldDoc(value, type).value;
export const mergeAutomergeFieldValues = ({ existing, incoming, type, }) => {
const incomingDoc = loadAutomergeFieldDoc(normalizeAutomergeFieldValue(incoming, type), type);
const mergedDoc = existing === undefined || existing === null
? incomingDoc
: Automerge.merge(loadAutomergeFieldDoc(normalizeAutomergeFieldValue(existing, type), type), incomingDoc);
const stored = saveAutomergeFieldDoc(mergedDoc, type);
return {
stored,
materialized: mergedDoc.value,
};
};
//# sourceMappingURL=crdt-automerge.js.map