export const unknownFieldClock = () => ({ kind: "unknown" }); export const revisionFieldClock = (revision) => { if (typeof revision === "bigint") { return { kind: "revision", revision }; } if (typeof revision === "number" && Number.isInteger(revision) && revision >= 0) { return { kind: "revision", revision: BigInt(revision) }; } if (typeof revision === "string" && /^\d+$/.test(revision)) { return { kind: "revision", revision: BigInt(revision) }; } return unknownFieldClock(); }; export const fieldClockToRevisionString = (clock) => clock.kind === "revision" ? clock.revision.toString() : ""; export const compareFieldClocks = (left, right) => { if (left.kind === "revision" && right.kind === "revision") { if (left.revision < right.revision) { return "older"; } if (left.revision > right.revision) { return "newer"; } return "same"; } if (left.kind === "unknown" && right.kind === "unknown") { return "same"; } return "unknown"; }; export const sameFieldClock = (left, right) => compareFieldClocks(left, right) === "same"; const shouldAcceptCanonical = (incoming, current) => { const order = compareFieldClocks(incoming, current); if (order === "older") { return false; } if (order === "unknown" && current.kind !== "unknown") { return false; } return true; }; const latestPendingValue = (state) => state.pending.at(-1)?.value; const recomputeVisible = (state) => { const pendingValue = latestPendingValue(state); return pendingValue === undefined ? state.canonical.value : pendingValue; }; export const createRegisterFieldState = (initial) => ({ canonical: initial, visible: initial.value, pending: [], nextPendingSequence: 1, }); export const applyCanonicalFieldValue = (state, incoming, clientMutationId) => { const visibleBefore = state.visible; const pendingBefore = state.pending.length; if (!shouldAcceptCanonical(incoming.clock, state.canonical.clock)) { return { accepted: false, canonicalChanged: false, pendingChanged: false, visibleChanged: false, }; } const canonicalChanged = !Object.is(state.canonical.value, incoming.value) || !sameFieldClock(state.canonical.clock, incoming.clock); state.canonical = incoming; if (clientMutationId) { state.pending = state.pending.filter((entry) => entry.clientMutationId !== clientMutationId); } state.visible = recomputeVisible(state); return { accepted: true, canonicalChanged, pendingChanged: state.pending.length !== pendingBefore, visibleChanged: !Object.is(state.visible, visibleBefore), }; }; export const beginLocalFieldWrite = (state, clientMutationId, value) => { const visibleBefore = state.visible; state.pending.push({ clientMutationId, sequence: state.nextPendingSequence++, value, }); state.visible = value; return { accepted: true, canonicalChanged: false, pendingChanged: true, visibleChanged: !Object.is(state.visible, visibleBefore), }; }; export const failLocalFieldWrite = (state, clientMutationId) => { const visibleBefore = state.visible; const pendingBefore = state.pending.length; state.pending = state.pending.filter((entry) => entry.clientMutationId !== clientMutationId); state.visible = recomputeVisible(state); return { accepted: true, canonicalChanged: false, pendingChanged: state.pending.length !== pendingBefore, visibleChanged: !Object.is(state.visible, visibleBefore), }; }; //# sourceMappingURL=field-semantics.js.map