diff --git a/packages/core/src/router.ts b/packages/core/src/router.ts index 96691077c..215fe3083 100644 --- a/packages/core/src/router.ts +++ b/packages/core/src/router.ts @@ -47,6 +47,7 @@ export class Router { protected navigationType?: string protected activeVisit?: ActiveVisit protected visitId: VisitId = null + protected sessionSize: number = 0; public init({ initialPage, @@ -509,25 +510,43 @@ export class Router { private _pushState(page: Page): void { const uniqueId = this.getStateId(); - window.sessionStorage.setItem(uniqueId, JSON.stringify(page)); + this.dropOldestStateItemToPreventQuotaExceeded(); + const serializedPage = JSON.stringify(page); + window.sessionStorage.setItem(uniqueId, serializedPage); window.history.pushState({_id: uniqueId}, '', page.url); + this.sessionSize += (new Blob([serializedPage])).size; } - protected getAllStates(): string[] { + protected getAllStateIds(): string[] { return JSON.parse(window.sessionStorage.getItem(allStateIdsSessionStorageKey) ?? '[]'); } + protected dropOldestStateItemToPreventQuotaExceeded() { + // Ensures inertia uses at most ~1M (+/- size of 1 Page) of session storage for history state + if (this.sessionSize > 1000000) { + const allStateIds = this.getAllStateIds(); + const oldestStateId = allStateIds.shift(); + if (oldestStateId) { + const sizeOfStateItem = new Blob([window.sessionStorage.getItem(oldestStateId) ?? '']).size; + window.sessionStorage.removeItem(oldestStateId); + window.sessionStorage.setItem(allStateIdsSessionStorageKey, JSON.stringify(allStateIds)); + this.sessionSize -= sizeOfStateItem; + } + } + } + private getStateId() { const newId = `inertia_${Date.now() + Math.floor(Math.random() * 1000)}`; - window.sessionStorage.setItem(allStateIdsSessionStorageKey, JSON.stringify([...this.getAllStates(), newId])); + window.sessionStorage.setItem(allStateIdsSessionStorageKey, JSON.stringify([...this.getAllStateIds(), newId])); return newId; } public clearHistory(): void { - this.getAllStates().forEach((id) => { + this.getAllStateIds().forEach((id) => { window.sessionStorage.removeItem(id); }); window.sessionStorage.removeItem(allStateIdsSessionStorageKey); + this.sessionSize = 0; } protected pushState(page: Page): void { @@ -543,8 +562,11 @@ export class Router { private _replaceState(page: Page): void { const currentId = window.history.state?._id ?? this.getStateId(); - window.sessionStorage.setItem(currentId, JSON.stringify(page)); + const serializedPage = JSON.stringify(page); + this.sessionSize -= (new Blob([window.sessionStorage.getItem(currentId) ?? ''])).size; + window.sessionStorage.setItem(currentId, serializedPage); window.history.replaceState({_id: currentId}, '', page.url); + this.sessionSize += (new Blob([serializedPage])).size; } protected replaceState(page: Page): void {