refactor: remove payload-level schema version

This commit is contained in:
Ryan Di
2026-03-23 17:30:11 +11:00
parent 11ba6784aa
commit 0e4ae079ac
12 changed files with 23 additions and 183 deletions
+2 -13
View File
@@ -35,8 +35,6 @@ import {
import { tryParseSpreadsheet, VALID_SPREADSHEET } from "./charts";
import { SCHEMA_VERSIONS } from "./data/schema";
import type { FileSystemHandle } from "./data/filesystem";
import type { Spreadsheet } from "./charts";
@@ -45,7 +43,6 @@ import type { BinaryFiles } from "./types";
type ElementsClipboard = {
type: typeof EXPORT_DATA_TYPES.excalidrawClipboard;
schemaVersion: number;
elements: readonly (NonDeletedExcalidrawElement & {
schemaVersion?: number;
})[];
@@ -58,7 +55,6 @@ export interface ClipboardData {
spreadsheet?: Spreadsheet;
elements?: readonly ExcalidrawElement[];
files?: BinaryFiles;
schemaVersion?: number;
text?: string;
mixedContent?: PastedMixedContent;
errorMessage?: string;
@@ -88,7 +84,6 @@ const clipboardContainsElements = (
): contents is {
elements: ExcalidrawElement[];
files?: BinaryFiles;
schemaVersion?: number;
} => {
if (
[
@@ -188,24 +183,19 @@ export const serializeAsClipboardJSON = ({
// select bound text elements when copying
const contents: ElementsClipboard = {
type: EXPORT_DATA_TYPES.excalidrawClipboard,
schemaVersion: SCHEMA_VERSIONS.latest,
elements: elements.map((element) => {
const elementWithSchema = {
...element,
schemaVersion: SCHEMA_VERSIONS.latest,
};
if (
getContainingFrame(element, elementsMap) &&
!framesToCopy.has(getContainingFrame(element, elementsMap)!)
) {
const copiedElement = deepCopyElement(elementWithSchema);
const copiedElement = deepCopyElement(element);
mutateElement(copiedElement, elementsMap, {
frameId: null,
});
return copiedElement;
}
return elementWithSchema;
return element;
}),
files: files ? _files : undefined,
};
@@ -587,7 +577,6 @@ export const parseClipboard = async (
return {
elements: systemClipboardData.elements,
files: systemClipboardData.files,
schemaVersion: systemClipboardData.schemaVersion,
text: isPlainPaste
? JSON.stringify(systemClipboardData.elements, null, 2)
: undefined,
+5 -48
View File
@@ -33,7 +33,6 @@ import {
ELEMENT_SHIFT_TRANSLATE_AMOUNT,
ELEMENT_TRANSLATE_AMOUNT,
EVENT,
EXPORT_DATA_TYPES,
FRAME_STYLE,
IMAGE_MIME_TYPES,
IMAGE_RENDER_TIMEOUT,
@@ -355,15 +354,6 @@ import {
import { exportCanvas, loadFromBlob } from "../data";
import Library, { distributeLibraryItemsOnSquareGrid } from "../data/library";
import { restoreAppState, restoreElements } from "../data/restore";
import {
migrateAPIElements,
migrateClipboardElements,
migrateLibraryElements,
migrateSceneElements,
SCHEMA_VERSIONS,
type SchemaVersionSource,
type SchemaMigrationScope,
} from "../data/schema";
import { getCenter, getDistance } from "../gesture";
import { History } from "../history";
import { defaultLang, getLanguage, languages, setLanguage, t } from "../i18n";
@@ -2335,8 +2325,6 @@ class App extends React.Component<AppProps, AppState> {
elements,
position: "center",
files: null,
schemaVersionSource: SCHEMA_VERSIONS.latest,
migrationScope: "api",
});
};
@@ -2817,21 +2805,10 @@ class App extends React.Component<AppProps, AppState> {
},
};
}
const initialDataSchemaFallback =
initialData?.type === EXPORT_DATA_TYPES.excalidraw
? SCHEMA_VERSIONS.initial
: SCHEMA_VERSIONS.latest;
const restoredElements = restoreElements(
migrateSceneElements(initialData?.elements, {
payloadSchemaVersion: initialData?.schemaVersion,
fallbackVersion: initialDataSchemaFallback,
}),
null,
{
repairBindings: true,
deleteInvisibleElements: true,
},
);
const restoredElements = restoreElements(initialData?.elements, null, {
repairBindings: true,
deleteInvisibleElements: true,
});
let restoredAppState = restoreAppState(initialData?.appState, null);
const activeTool = restoredAppState.activeTool;
@@ -3596,13 +3573,6 @@ class App extends React.Component<AppProps, AppState> {
this.addElementsFromPasteOrLibrary({
elements,
files: data.files || null,
schemaVersionSource: data.programmaticAPI
? SCHEMA_VERSIONS.latest
: {
payloadSchemaVersion: data.schemaVersion,
fallbackVersion: SCHEMA_VERSIONS.initial,
},
migrationScope: data.programmaticAPI ? "api" : "clipboard",
position:
this.editorInterface.formFactor === "desktop" ? "cursor" : "center",
retainSeed: isPlainPaste,
@@ -3629,8 +3599,6 @@ class App extends React.Component<AppProps, AppState> {
this.addElementsFromPasteOrLibrary({
elements,
files,
schemaVersionSource: SCHEMA_VERSIONS.latest,
migrationScope: "api",
position:
this.editorInterface.formFactor === "desktop" ? "cursor" : "center",
});
@@ -3748,20 +3716,11 @@ class App extends React.Component<AppProps, AppState> {
addElementsFromPasteOrLibrary = (opts: {
elements: readonly ExcalidrawElement[];
files: BinaryFiles | null;
schemaVersionSource: SchemaVersionSource;
migrationScope: SchemaMigrationScope;
position: { clientX: number; clientY: number } | "cursor" | "center";
retainSeed?: boolean;
fitToContent?: boolean;
}) => {
const migratedElements =
opts.migrationScope === "clipboard"
? migrateClipboardElements(opts.elements, opts.schemaVersionSource)
: opts.migrationScope === "library"
? migrateLibraryElements(opts.elements, opts.schemaVersionSource)
: migrateAPIElements(opts.elements, opts.schemaVersionSource);
const elements = restoreElements(migratedElements, null, {
const elements = restoreElements(opts.elements, null, {
deleteInvisibleElements: true,
});
const [minX, minY, maxX, maxY] = getCommonBounds(elements);
@@ -11532,8 +11491,6 @@ class App extends React.Component<AppProps, AppState> {
elements: distributeLibraryItemsOnSquareGrid(libraryItems),
position: event,
files: null,
schemaVersionSource: SCHEMA_VERSIONS.latest,
migrationScope: "library",
});
}
} catch (error: any) {
@@ -10,8 +10,6 @@ import {
getExportSource,
} from "@excalidraw/common";
import { SCHEMA_VERSIONS } from "../data/schema";
import { EditorLocalStorage } from "../data/EditorLocalStorage";
import { canvasToBlob, resizeImageFile } from "../data/blob";
import { t } from "../i18n";
@@ -282,7 +280,6 @@ const PublishLibrary = ({
const libContent: ExportedLibraryData = {
type: EXPORT_DATA_TYPES.excalidrawLibrary,
version: VERSIONS.excalidrawLibrary,
schemaVersion: SCHEMA_VERSIONS.latest,
source: getExportSource(),
libraryItems: clonedLibItems,
};
@@ -6,7 +6,6 @@ import type {
} from "@excalidraw/element/types";
import { EditorLocalStorage } from "../../data/EditorLocalStorage";
import { SCHEMA_VERSIONS } from "../../data/schema";
import {
convertToExcalidrawElements,
exportToCanvas,
@@ -149,8 +148,6 @@ export const insertToEditor = ({
app.addElementsFromPasteOrLibrary({
elements: newElements,
files,
schemaVersionSource: SCHEMA_VERSIONS.latest,
migrationScope: "api",
position: "center",
fitToContent: true,
});
+2 -10
View File
@@ -24,7 +24,6 @@ import {
restoreElements,
restoreLibraryItems,
} from "./restore";
import { migrateSceneElements, SCHEMA_VERSIONS } from "./schema";
import type { AppState, DataURL, LibraryItem } from "../types";
@@ -158,14 +157,10 @@ export const loadSceneOrLibraryFromBlob = async (
throw error;
}
if (isValidExcalidrawData(data)) {
const migratedElements = migrateSceneElements(data.elements, {
payloadSchemaVersion: data.schemaVersion,
fallbackVersion: SCHEMA_VERSIONS.initial,
});
return {
type: MIME_TYPES.excalidraw,
data: {
elements: restoreElements(migratedElements, localElements, {
elements: restoreElements(data.elements, localElements, {
repairBindings: true,
deleteInvisibleElements: true,
}),
@@ -227,10 +222,7 @@ export const parseLibraryJSON = (
throw new Error("Invalid library");
}
const libraryItems = data.libraryItems || data.library;
return restoreLibraryItems(libraryItems, defaultStatus, {
payloadSchemaVersion: data.schemaVersion,
fallbackVersion: SCHEMA_VERSIONS.initial,
});
return restoreLibraryItems(libraryItems, defaultStatus);
};
export const loadLibraryFromBlob = async (
-3
View File
@@ -12,7 +12,6 @@ import { cleanAppStateForExport, clearAppStateForDatabase } from "../appState";
import { isImageFileHandle, loadFromBlob } from "./blob";
import { fileOpen, fileSave } from "./filesystem";
import { SCHEMA_VERSIONS } from "./schema";
import type { AppState, BinaryFiles, LibraryItems } from "../types";
import type {
@@ -52,7 +51,6 @@ export const serializeAsJSON = (
const data: ExportedDataState = {
type: EXPORT_DATA_TYPES.excalidraw,
version: VERSIONS.excalidraw,
schemaVersion: SCHEMA_VERSIONS.latest,
source: getExportSource(),
elements,
appState:
@@ -131,7 +129,6 @@ export const serializeLibraryAsJSON = (libraryItems: LibraryItems) => {
const data: ExportedLibraryData = {
type: EXPORT_DATA_TYPES.excalidrawLibrary,
version: VERSIONS.excalidrawLibrary,
schemaVersion: SCHEMA_VERSIONS.latest,
source: getExportSource(),
libraryItems,
};
+3 -21
View File
@@ -33,7 +33,6 @@ import { t } from "../i18n";
import { loadLibraryFromBlob } from "./blob";
import { restoreLibraryItems } from "./restore";
import { SCHEMA_VERSIONS } from "./schema";
import type App from "../components/App";
@@ -68,7 +67,6 @@ type LibraryUpdate = {
export type LibraryPersistedData = {
libraryItems: LibraryItems;
schemaVersion?: number;
};
const onLibraryUpdateEmitter = new Emitter<
@@ -91,10 +89,7 @@ export interface LibraryPersistenceAdapter {
* purposes, in which case host app can implement more aggressive caching.
*/
source: LibraryAdatapterSource;
}): MaybePromise<{
libraryItems: LibraryItems_anyVersion;
schemaVersion?: number;
} | null>;
}): MaybePromise<{ libraryItems: LibraryItems_anyVersion } | null>;
/** Should persist to the database as is (do no change the data structure). */
save(libraryData: LibraryPersistedData): MaybePromise<void>;
}
@@ -106,7 +101,6 @@ export interface LibraryMigrationAdapter {
*/
load(): MaybePromise<{
libraryItems: LibraryItems_anyVersion;
schemaVersion?: number;
} | null>;
/** clears entire storage afterwards */
@@ -562,12 +556,7 @@ class AdapterTransaction {
new Promise<LibraryItems>(async (resolve, reject) => {
try {
const data = await adapter.load({ source });
resolve(
restoreLibraryItems(data?.libraryItems || [], "published", {
payloadSchemaVersion: data?.schemaVersion,
fallbackVersion: SCHEMA_VERSIONS.initial,
}),
);
resolve(restoreLibraryItems(data?.libraryItems || [], "published"));
} catch (error: any) {
reject(error);
}
@@ -675,10 +664,7 @@ const persistLibraryUpdate = async (
const version = getLibraryItemsHash(nextLibraryItems);
if (version !== lastSavedLibraryItemsHash) {
await adapter.save({
libraryItems: nextLibraryItems,
schemaVersion: SCHEMA_VERSIONS.latest,
});
await adapter.save({ libraryItems: nextLibraryItems });
}
lastSavedLibraryItemsHash = version;
@@ -878,10 +864,6 @@ export const useHandleLibrary = (
restoredData = restoreLibraryItems(
libraryData.libraryItems || [],
"published",
{
payloadSchemaVersion: libraryData.schemaVersion,
fallbackVersion: SCHEMA_VERSIONS.initial,
},
);
// we don't queue this operation because it's running inside