fix: preserve reconciliation authorities

This commit is contained in:
DongHyeonka
2026-08-02 03:15:22 +09:00
parent d9afccdd60
commit 184bd98d92
9 changed files with 287 additions and 22 deletions
@@ -38,6 +38,15 @@ export function createOptimisticLayerRuntime(queryClient: QueryClient) {
entry.disposeScopeListener = null;
}
function writeProjection(entry: EntryState, value: unknown): void {
writing = true;
try {
queryClient.setQueryData(entry.queryKey, value);
} finally {
writing = false;
}
}
queryClient.getQueryCache().subscribe((event) => {
if (
writing ||
@@ -70,12 +79,7 @@ export function createOptimisticLayerRuntime(queryClient: QueryClient) {
removeEntry(key, entry);
return;
}
writing = true;
try {
queryClient.setQueryData(entry.queryKey, value);
} finally {
writing = false;
}
writeProjection(entry, value);
}
function collapse(key: string, entry: EntryState): void {
@@ -132,15 +136,20 @@ export function createOptimisticLayerRuntime(queryClient: QueryClient) {
return null;
}
const layer: Layer = {
id: nextId++,
id: nextId,
status: "pending",
apply: (value) => update(value, input),
};
let projected: unknown;
try {
projected = update(entry.base, input);
projected = entry.base;
for (const existingLayer of entry.layers) {
projected = existingLayer.apply(projected);
}
projected = layer.apply(projected);
} catch (error) {
if (entry.layers.length === 0) removeEntry(key, entry);
if (entry.layers.length > 0) return null;
removeEntry(key, entry);
throw error;
}
if (
@@ -150,8 +159,9 @@ export function createOptimisticLayerRuntime(queryClient: QueryClient) {
if (entry.layers.length === 0) removeEntry(key, entry);
return null;
}
nextId += 1;
entry.layers.push(layer);
project(key, entry);
writeProjection(entry, projected);
let state: "pending" | "uncertain" | "settled" = "pending";
const selectedLayer = () => {
if (entries.get(key) !== entry) return undefined;
+24 -3
View File
@@ -64,6 +64,7 @@ export function useAppForm<
const [pending, setPending] = useState(false);
const [result, setResult] = useState<FormResultState>("idle");
const pendingRef = useRef<Promise<FormResult<Output>> | null>(null);
const unknownSubmissionRef = useRef<Values | null>(null);
const dirty = useMemo(
() => JSON.stringify(values) !== JSON.stringify(initialValues),
@@ -101,7 +102,9 @@ export function useAppForm<
return next;
});
setFormErrors([]);
setResult("idle");
setResult((current) =>
unknownSubmissionRef.current ? current : "idle",
);
},
[],
);
@@ -125,6 +128,7 @@ export function useAppForm<
const reset = useCallback(
(nextValues: Values = defaultValues) => {
unknownSubmissionRef.current = null;
setValues(nextValues);
setInitialValues(nextValues);
setTouched(new Set());
@@ -137,6 +141,7 @@ export function useAppForm<
const settleSuccessfulValues = useCallback(
(settledValues: Values) => {
unknownSubmissionRef.current = null;
setFieldErrors({} as FieldErrors<Values>);
setFormErrors([]);
setResult("success");
@@ -152,13 +157,24 @@ export function useAppForm<
);
const settleApplied = useCallback(() => {
settleSuccessfulValues(values);
}, [settleSuccessfulValues, values]);
const submittedValues = unknownSubmissionRef.current;
if (!submittedValues) return;
settleSuccessfulValues(submittedValues);
}, [settleSuccessfulValues]);
const settleNotApplied = useCallback(() => {
if (!unknownSubmissionRef.current) return;
unknownSubmissionRef.current = null;
setFieldErrors({} as FieldErrors<Values>);
setFormErrors([]);
setResult("idle");
}, []);
const submitForm = useCallback(
async (event?: FormEvent<HTMLFormElement>): Promise<FormResult<Output> | null> => {
event?.preventDefault();
if (pendingRef.current) return pendingRef.current;
if (unknownSubmissionRef.current) return null;
setFieldErrors({} as FieldErrors<Values>);
setFormErrors([]);
@@ -194,6 +210,7 @@ export function useAppForm<
return outcome;
}
if (outcome.error.kind === "VALIDATION_REJECTED") {
unknownSubmissionRef.current = null;
const mapped = mapValidationFailureToFields<Values>(
outcome.error,
allowedServerFields,
@@ -204,16 +221,19 @@ export function useAppForm<
setResult("validation-error");
focusFirstError(mapped.fieldErrors);
} else if (outcome.error.effect === "MAYBE_APPLIED") {
unknownSubmissionRef.current = parsed.data;
setFormErrors([]);
setResult("effect-unknown");
} else if (outcome.error.effect === "APPLIED_CONFIRMED") {
settleSuccessfulValues(parsed.data);
} else if (outcome.error.kind === "CONFLICT") {
unknownSubmissionRef.current = null;
setFormErrors([
message("form.conflict"),
]);
setResult("conflict");
} else {
unknownSubmissionRef.current = null;
setFormErrors([message("form.unavailable")]);
setResult("unavailable");
}
@@ -251,6 +271,7 @@ export function useAppForm<
submitForm,
reset,
settleApplied,
settleNotApplied,
});
}