mirror of
https://github.com/excalidraw/excalidraw.git
synced 2025-05-03 10:00:07 -04:00
chore: update firebase@8 to @11 (#9136)
This commit is contained in:
parent
f12b92ce9d
commit
16b86d7d16
4 changed files with 494 additions and 423 deletions
|
@ -25,6 +25,7 @@ import { MIME_TYPES } from "../../packages/excalidraw/constants";
|
|||
import { trackEvent } from "../../packages/excalidraw/analytics";
|
||||
import { getFrame } from "../../packages/excalidraw/utils";
|
||||
import { ExcalidrawLogo } from "../../packages/excalidraw/components/ExcalidrawLogo";
|
||||
import { uploadBytes, ref } from "firebase/storage";
|
||||
|
||||
export const exportToExcalidrawPlus = async (
|
||||
elements: readonly NonDeletedExcalidrawElement[],
|
||||
|
@ -32,7 +33,7 @@ export const exportToExcalidrawPlus = async (
|
|||
files: BinaryFiles,
|
||||
name: string,
|
||||
) => {
|
||||
const firebase = await loadFirebaseStorage();
|
||||
const storage = await loadFirebaseStorage();
|
||||
|
||||
const id = `${nanoid(12)}`;
|
||||
|
||||
|
@ -49,15 +50,13 @@ export const exportToExcalidrawPlus = async (
|
|||
},
|
||||
);
|
||||
|
||||
await firebase
|
||||
.storage()
|
||||
.ref(`/migrations/scenes/${id}`)
|
||||
.put(blob, {
|
||||
customMetadata: {
|
||||
data: JSON.stringify({ version: 2, name }),
|
||||
created: Date.now().toString(),
|
||||
},
|
||||
});
|
||||
const storageRef = ref(storage, `/migrations/scenes/${id}`);
|
||||
await uploadBytes(storageRef, blob, {
|
||||
customMetadata: {
|
||||
data: JSON.stringify({ version: 2, name }),
|
||||
created: Date.now().toString(),
|
||||
},
|
||||
});
|
||||
|
||||
const filesMap = new Map<FileId, BinaryFileData>();
|
||||
for (const element of elements) {
|
||||
|
|
|
@ -22,9 +22,17 @@ import {
|
|||
import { MIME_TYPES } from "../../packages/excalidraw/constants";
|
||||
import type { SyncableExcalidrawElement } from ".";
|
||||
import { getSyncableElements } from ".";
|
||||
import type { ResolutionType } from "../../packages/excalidraw/utility-types";
|
||||
import type { Socket } from "socket.io-client";
|
||||
import type { RemoteExcalidrawElement } from "../../packages/excalidraw/data/reconcile";
|
||||
import { initializeApp } from "firebase/app";
|
||||
import {
|
||||
getFirestore,
|
||||
doc,
|
||||
getDoc,
|
||||
runTransaction,
|
||||
Bytes,
|
||||
} from "firebase/firestore";
|
||||
import { getStorage, ref, uploadBytes } from "firebase/storage";
|
||||
|
||||
// private
|
||||
// -----------------------------------------------------------------------------
|
||||
|
@ -41,80 +49,42 @@ try {
|
|||
FIREBASE_CONFIG = {};
|
||||
}
|
||||
|
||||
let firebasePromise: Promise<typeof import("firebase/app").default> | null =
|
||||
null;
|
||||
let firestorePromise: Promise<any> | null | true = null;
|
||||
let firebaseStoragePromise: Promise<any> | null | true = null;
|
||||
let firebaseApp: ReturnType<typeof initializeApp> | null = null;
|
||||
let firestore: ReturnType<typeof getFirestore> | null = null;
|
||||
let firebaseStorage: ReturnType<typeof getStorage> | null = null;
|
||||
|
||||
let isFirebaseInitialized = false;
|
||||
|
||||
const _loadFirebase = async () => {
|
||||
const firebase = (
|
||||
await import(/* webpackChunkName: "firebase" */ "firebase/app")
|
||||
).default;
|
||||
|
||||
if (!isFirebaseInitialized) {
|
||||
try {
|
||||
firebase.initializeApp(FIREBASE_CONFIG);
|
||||
} catch (error: any) {
|
||||
// trying initialize again throws. Usually this is harmless, and happens
|
||||
// mainly in dev (HMR)
|
||||
if (error.code === "app/duplicate-app") {
|
||||
console.warn(error.name, error.code);
|
||||
} else {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
isFirebaseInitialized = true;
|
||||
const _initializeFirebase = () => {
|
||||
if (!firebaseApp) {
|
||||
firebaseApp = initializeApp(FIREBASE_CONFIG);
|
||||
}
|
||||
|
||||
return firebase;
|
||||
return firebaseApp;
|
||||
};
|
||||
|
||||
const _getFirebase = async (): Promise<
|
||||
typeof import("firebase/app").default
|
||||
> => {
|
||||
if (!firebasePromise) {
|
||||
firebasePromise = _loadFirebase();
|
||||
const _getFirestore = () => {
|
||||
if (!firestore) {
|
||||
firestore = getFirestore(_initializeFirebase());
|
||||
}
|
||||
return firebasePromise;
|
||||
return firestore;
|
||||
};
|
||||
|
||||
const _getStorage = () => {
|
||||
if (!firebaseStorage) {
|
||||
firebaseStorage = getStorage(_initializeFirebase());
|
||||
}
|
||||
return firebaseStorage;
|
||||
};
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
const loadFirestore = async () => {
|
||||
const firebase = await _getFirebase();
|
||||
if (!firestorePromise) {
|
||||
firestorePromise = import(
|
||||
/* webpackChunkName: "firestore" */ "firebase/firestore"
|
||||
);
|
||||
}
|
||||
if (firestorePromise !== true) {
|
||||
await firestorePromise;
|
||||
firestorePromise = true;
|
||||
}
|
||||
return firebase;
|
||||
};
|
||||
|
||||
export const loadFirebaseStorage = async () => {
|
||||
const firebase = await _getFirebase();
|
||||
if (!firebaseStoragePromise) {
|
||||
firebaseStoragePromise = import(
|
||||
/* webpackChunkName: "storage" */ "firebase/storage"
|
||||
);
|
||||
}
|
||||
if (firebaseStoragePromise !== true) {
|
||||
await firebaseStoragePromise;
|
||||
firebaseStoragePromise = true;
|
||||
}
|
||||
return firebase;
|
||||
return _getStorage();
|
||||
};
|
||||
|
||||
interface FirebaseStoredScene {
|
||||
type FirebaseStoredScene = {
|
||||
sceneVersion: number;
|
||||
iv: firebase.default.firestore.Blob;
|
||||
ciphertext: firebase.default.firestore.Blob;
|
||||
}
|
||||
iv: Bytes;
|
||||
ciphertext: Bytes;
|
||||
};
|
||||
|
||||
const encryptElements = async (
|
||||
key: string,
|
||||
|
@ -175,7 +145,7 @@ export const saveFilesToFirebase = async ({
|
|||
prefix: string;
|
||||
files: { id: FileId; buffer: Uint8Array }[];
|
||||
}) => {
|
||||
const firebase = await loadFirebaseStorage();
|
||||
const storage = await loadFirebaseStorage();
|
||||
|
||||
const erroredFiles: FileId[] = [];
|
||||
const savedFiles: FileId[] = [];
|
||||
|
@ -183,17 +153,10 @@ export const saveFilesToFirebase = async ({
|
|||
await Promise.all(
|
||||
files.map(async ({ id, buffer }) => {
|
||||
try {
|
||||
await firebase
|
||||
.storage()
|
||||
.ref(`${prefix}/${id}`)
|
||||
.put(
|
||||
new Blob([buffer], {
|
||||
type: MIME_TYPES.binary,
|
||||
}),
|
||||
{
|
||||
cacheControl: `public, max-age=${FILE_CACHE_MAX_AGE_SEC}`,
|
||||
},
|
||||
);
|
||||
const storageRef = ref(storage, `${prefix}/${id}`);
|
||||
await uploadBytes(storageRef, buffer, {
|
||||
cacheControl: `public, max-age=${FILE_CACHE_MAX_AGE_SEC}`,
|
||||
});
|
||||
savedFiles.push(id);
|
||||
} catch (error: any) {
|
||||
erroredFiles.push(id);
|
||||
|
@ -205,7 +168,6 @@ export const saveFilesToFirebase = async ({
|
|||
};
|
||||
|
||||
const createFirebaseSceneDocument = async (
|
||||
firebase: ResolutionType<typeof loadFirestore>,
|
||||
elements: readonly SyncableExcalidrawElement[],
|
||||
roomKey: string,
|
||||
) => {
|
||||
|
@ -213,10 +175,8 @@ const createFirebaseSceneDocument = async (
|
|||
const { ciphertext, iv } = await encryptElements(roomKey, elements);
|
||||
return {
|
||||
sceneVersion,
|
||||
ciphertext: firebase.firestore.Blob.fromUint8Array(
|
||||
new Uint8Array(ciphertext),
|
||||
),
|
||||
iv: firebase.firestore.Blob.fromUint8Array(iv),
|
||||
ciphertext: Bytes.fromUint8Array(new Uint8Array(ciphertext)),
|
||||
iv: Bytes.fromUint8Array(iv),
|
||||
} as FirebaseStoredScene;
|
||||
};
|
||||
|
||||
|
@ -236,20 +196,14 @@ export const saveToFirebase = async (
|
|||
return null;
|
||||
}
|
||||
|
||||
const firebase = await loadFirestore();
|
||||
const firestore = firebase.firestore();
|
||||
const firestore = _getFirestore();
|
||||
const docRef = doc(firestore, "scenes", roomId);
|
||||
|
||||
const docRef = firestore.collection("scenes").doc(roomId);
|
||||
|
||||
const storedScene = await firestore.runTransaction(async (transaction) => {
|
||||
const storedScene = await runTransaction(firestore, async (transaction) => {
|
||||
const snapshot = await transaction.get(docRef);
|
||||
|
||||
if (!snapshot.exists) {
|
||||
const storedScene = await createFirebaseSceneDocument(
|
||||
firebase,
|
||||
elements,
|
||||
roomKey,
|
||||
);
|
||||
if (!snapshot.exists()) {
|
||||
const storedScene = await createFirebaseSceneDocument(elements, roomKey);
|
||||
|
||||
transaction.set(docRef, storedScene);
|
||||
|
||||
|
@ -269,7 +223,6 @@ export const saveToFirebase = async (
|
|||
);
|
||||
|
||||
const storedScene = await createFirebaseSceneDocument(
|
||||
firebase,
|
||||
reconciledElements,
|
||||
roomKey,
|
||||
);
|
||||
|
@ -294,15 +247,13 @@ export const loadFromFirebase = async (
|
|||
roomKey: string,
|
||||
socket: Socket | null,
|
||||
): Promise<readonly SyncableExcalidrawElement[] | null> => {
|
||||
const firebase = await loadFirestore();
|
||||
const db = firebase.firestore();
|
||||
|
||||
const docRef = db.collection("scenes").doc(roomId);
|
||||
const doc = await docRef.get();
|
||||
if (!doc.exists) {
|
||||
const firestore = _getFirestore();
|
||||
const docRef = doc(firestore, "scenes", roomId);
|
||||
const docSnap = await getDoc(docRef);
|
||||
if (!docSnap.exists()) {
|
||||
return null;
|
||||
}
|
||||
const storedScene = doc.data() as FirebaseStoredScene;
|
||||
const storedScene = docSnap.data() as FirebaseStoredScene;
|
||||
const elements = getSyncableElements(
|
||||
restoreElements(await decryptElements(storedScene, roomKey), null),
|
||||
);
|
||||
|
|
|
@ -29,7 +29,7 @@
|
|||
"@excalidraw/random-username": "1.0.0",
|
||||
"@sentry/browser": "9.0.1",
|
||||
"callsites": "4.2.0",
|
||||
"firebase": "8.3.3",
|
||||
"firebase": "11.3.1",
|
||||
"i18next-browser-languagedetector": "6.1.4",
|
||||
"idb-keyval": "6.0.3",
|
||||
"jotai": "2.11.0",
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue