Skip to content

Commit bb34542

Browse files
authored
ENG-1492 - fix(roam): harden setHintingShapes against atom reaction cycle errors (#837)
1 parent b56c402 commit bb34542

1 file changed

Lines changed: 59 additions & 0 deletions

File tree

apps/roam/src/components/canvas/Tldraw.tsx

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,64 @@ export const MAX_WIDTH = "400px";
134134

135135
const ICON_URL = `data:image/svg+xml;utf8,${encodeURIComponent(WHITE_LOGO_SVG)}`;
136136

137+
const isAtomReactionCycleError = (error: unknown): error is Error =>
138+
error instanceof Error &&
139+
/cannot change atoms during reaction cycle/i.test(error.message);
140+
141+
const installSafeHintingSetter = ({
142+
app,
143+
title,
144+
pageUid,
145+
}: {
146+
app: Editor;
147+
title?: string;
148+
pageUid?: string;
149+
}): void => {
150+
const originalSetHintingShapes = app.setHintingShapes.bind(app);
151+
152+
app.setHintingShapes = ((shapeIds: TLShapeId[]) => {
153+
try {
154+
return originalSetHintingShapes(shapeIds);
155+
} catch (error) {
156+
if (!isAtomReactionCycleError(error)) {
157+
throw error;
158+
}
159+
160+
internalError({
161+
error,
162+
type: "Canvas Atom Reaction Cycle Error",
163+
context: {
164+
phase: "setHintingShapes.sync",
165+
title,
166+
pageUid,
167+
},
168+
sendEmail: false,
169+
});
170+
171+
app.timers.setTimeout(() => {
172+
try {
173+
originalSetHintingShapes(shapeIds);
174+
} catch (deferredError) {
175+
if (isAtomReactionCycleError(deferredError)) {
176+
internalError({
177+
error: deferredError,
178+
type: "Canvas Atom Reaction Cycle Error",
179+
context: {
180+
phase: "setHintingShapes.deferred",
181+
title,
182+
pageUid,
183+
},
184+
sendEmail: false,
185+
});
186+
}
187+
}
188+
}, 0);
189+
190+
return app;
191+
}
192+
}) as Editor["setHintingShapes"];
193+
};
194+
137195
/** Valid file size for asset props; undefined when unknown (e.g. Roam/file API not a real File) to avoid persisting null. */
138196
const getValidFileSize = (file: { size?: number }): number | undefined =>
139197
typeof file.size === "number" && Number.isFinite(file.size) && file.size > 0
@@ -704,6 +762,7 @@ const TldrawCanvas = ({ title }: { title: string }) => {
704762
}
705763

706764
appRef.current = app;
765+
installSafeHintingSetter({ app, title, pageUid });
707766

708767
app.on("change", (entry) => {
709768
lastActionsRef.current.push(entry);

0 commit comments

Comments
 (0)