Files
rrweb/packages/web-extension/src/utils/storage.ts
Yun Feng 282c8fa415 rrweb extension implementation (#1044)
* feat: add rrweb web-extension package

* refactor: make the extension suitable for manifest v3

* update tsconfig.json

* use version_name rather than recorder_version in manifest.json

* update manifest.json

* enable to keep recording after changing tabs

* enable to record between tabs and urls

* fix CI error

* try to fix CI error

* feat: add pause and resume buttons

* feat: add a link to new session after recording

* improve session list

* refactor: migrate session storage from chrome local storage to indexedDB

* feat: add pagination to session list

* fix: multiple recorders are started after pausing and resuming process

* fix: can't stop recording on firefox browser

* update type import of 'eventWithTime'

* fix CI error

* doc: add readme

* Apply suggestions from Justin's code review

Co-authored-by: Justin Halsall <Juice10@users.noreply.github.com>

* refactor: make use of webNavigation API to implement recording consistent during page navigation

* fix firefox compatibility issue and add title to pages

* add mouseleave listener to enhance the recording liability

* fix firefox compatibility issue and improve the experience of recording resume after closing tabs

* update tsconfig

* upgrade vite-plugin-web-extension config to fix some bugs on facebook web page

* update import links

* refactor: cross tab recording mechanism

apply Justin's suggestion

* refactor: slipt util/index.ts into multiple files

* implement cross-origin iframe recording

* fix: regression of issue: ShadowHost can't be a string (issue 941)

* refactor shadow dom recording to make tests cover key code

* Apply formatting changes

* increase the node memory limitation to avoid CI failure

* Create lovely-pears-cross.md

* Apply formatting changes

* Update packages/web-extension/package.json

* Update .changeset/lovely-pears-cross.md

* update change logs

* delete duplicated property

---------

Co-authored-by: Justin Halsall <Juice10@users.noreply.github.com>
2023-02-14 07:15:34 +08:00

91 lines
2.6 KiB
TypeScript

import { openDB } from 'idb';
import { eventWithTime } from '@rrweb/types';
import { Session } from '~/types';
/**
* Storage related functions with indexedDB.
*/
const EventStoreName = 'events';
type EventData = {
id: string;
events: eventWithTime[];
};
export async function getEventStore() {
return openDB<EventData>(EventStoreName, 1, {
upgrade(db) {
db.createObjectStore(EventStoreName, {
keyPath: 'id',
autoIncrement: false,
});
},
});
}
export async function getEvents(id: string) {
const db = await getEventStore();
const data = (await db.get(EventStoreName, id)) as EventData;
return data.events;
}
const SessionStoreName = 'sessions';
export async function getSessionStore() {
return openDB<Session>(SessionStoreName, 1, {
upgrade(db) {
// Create a store of objects
db.createObjectStore(SessionStoreName, {
// The 'id' property of the object will be the key.
keyPath: 'id',
// If it isn't explicitly set, create a value by auto incrementing.
autoIncrement: false,
});
},
});
}
export async function saveSession(session: Session, events: eventWithTime[]) {
const eventStore = await getEventStore();
await eventStore.put(EventStoreName, { id: session.id, events });
const store = await getSessionStore();
await store.add(SessionStoreName, session);
}
export async function getSession(id: string) {
const store = await getSessionStore();
return store.get(SessionStoreName, id) as Promise<Session>;
}
export async function getAllSessions() {
const store = await getSessionStore();
const sessions = (await store.getAll(SessionStoreName)) as Session[];
return sessions.sort((a, b) => b.createTimestamp - a.createTimestamp);
}
export async function deleteSession(id: string) {
const eventStore = await getEventStore();
const sessionStore = await getSessionStore();
await Promise.all([
eventStore.delete(EventStoreName, id),
sessionStore.delete(SessionStoreName, id),
]);
}
export async function deleteSessions(ids: string[]) {
const eventStore = await getEventStore();
const sessionStore = await getSessionStore();
const eventTransition = eventStore.transaction(EventStoreName, 'readwrite');
const sessionTransition = sessionStore.transaction(
SessionStoreName,
'readwrite',
);
const promises = [];
for (const id of ids) {
promises.push(eventTransition.store.delete(id));
promises.push(sessionTransition.store.delete(id));
}
await Promise.all(promises).then(() => {
return Promise.all([eventTransition.done, sessionTransition.done]);
});
}