Revert "Protect local storage calls (#3043)" (#3063)

This reverts commit 2f28d7c6f8.

### Change Type

- [x] `patch` — Bug fix
This commit is contained in:
alex 2024-03-04 15:48:31 +00:00 committed by GitHub
parent 15c760f7ea
commit 8adaaf8e22
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
18 changed files with 52 additions and 625 deletions

View file

@ -14,7 +14,6 @@ module.exports = {
'@next/next', '@next/next',
'react-hooks', 'react-hooks',
'deprecation', 'deprecation',
'no-storage',
], ],
settings: { settings: {
next: { next: {
@ -22,7 +21,6 @@ module.exports = {
}, },
}, },
rules: { rules: {
'no-storage/no-browser-storage': 2,
'deprecation/deprecation': 'error', 'deprecation/deprecation': 'error',
'@next/next/no-html-link-for-pages': 'off', '@next/next/no-html-link-for-pages': 'off',
'react/jsx-key': 'off', 'react/jsx-key': 'off',

View file

@ -1,15 +1,17 @@
// What is going on in this file? /**
// We had some bad early assumptions about how we would store documents. * What is going on in this file?
// Which ended up with us generating random persistenceKey strings for the *
// 'scratch' document for each user (i.e. each browser context), and storing it in localStorage. * We had some bad early assumptions about how we would store documents.
// Many users still have that random string in their localStorage so we need to load it. But for new * Which ended up with us generating random persistenceKey strings for the
// users it does not need to be unique and we can just use a constant. * 'scratch' document for each user (i.e. each browser context), and storing it in localStorage.
*
import { getFromLocalStorage, setInLocalStorage } from 'tldraw' * Many users still have that random string in their localStorage so we need to load it. But for new
* users it does not need to be unique and we can just use a constant.
*/
// DO NOT CHANGE THESE WITHOUT ADDING MIGRATION LOGIC. DOING SO WOULD WIPE ALL EXISTING LOCAL DATA. // DO NOT CHANGE THESE WITHOUT ADDING MIGRATION LOGIC. DOING SO WOULD WIPE ALL EXISTING LOCAL DATA.
const defaultDocumentKey = 'TLDRAW_DEFAULT_DOCUMENT_NAME_v2' const defaultDocumentKey = 'TLDRAW_DEFAULT_DOCUMENT_NAME_v2'
const w = typeof window === 'undefined' ? undefined : window
export const SCRATCH_PERSISTENCE_KEY = export const SCRATCH_PERSISTENCE_KEY =
(getFromLocalStorage(defaultDocumentKey) as any) ?? 'tldraw_document_v3' (w?.localStorage.getItem(defaultDocumentKey) as any) ?? 'tldraw_document_v3'
setInLocalStorage(defaultDocumentKey, SCRATCH_PERSISTENCE_KEY) w?.localStorage.setItem(defaultDocumentKey, SCRATCH_PERSISTENCE_KEY)

View file

@ -1,4 +1,4 @@
import { T, atom, getFromLocalStorage, setInLocalStorage } from 'tldraw' import { T, atom } from 'tldraw'
const channel = const channel =
typeof BroadcastChannel !== 'undefined' ? new BroadcastChannel('tldrawUserPreferences') : null typeof BroadcastChannel !== 'undefined' ? new BroadcastChannel('tldrawUserPreferences') : null
@ -37,7 +37,9 @@ function createPreference<Type>(key: string, validator: T.Validator<Type>, defau
} }
function loadItemFromStorage<Type>(key: string, validator: T.Validator<Type>): Type | null { function loadItemFromStorage<Type>(key: string, validator: T.Validator<Type>): Type | null {
const item = getFromLocalStorage(`tldrawUserPreferences.${key}`, null) if (typeof localStorage === 'undefined' || !localStorage) return null
const item = localStorage.getItem(`tldrawUserPreferences.${key}`)
if (item == null) return null if (item == null) return null
try { try {
return validator.validate(JSON.parse(item)) return validator.validate(JSON.parse(item))
@ -47,5 +49,11 @@ function loadItemFromStorage<Type>(key: string, validator: T.Validator<Type>): T
} }
function saveItemToStorage(key: string, value: unknown): void { function saveItemToStorage(key: string, value: unknown): void {
setInLocalStorage(`tldrawUserPreferences.${key}`, JSON.stringify(value)) if (typeof localStorage === 'undefined' || !localStorage) return
try {
localStorage.setItem(`tldrawUserPreferences.${key}`, JSON.stringify(value))
} catch (e) {
// not a big deal
}
} }

View file

@ -1,12 +1,5 @@
import { useLayoutEffect, useState } from 'react' import { useLayoutEffect, useState } from 'react'
import { import { Tldraw, createTLStore, defaultShapeUtils, throttle } from 'tldraw'
Tldraw,
createTLStore,
defaultShapeUtils,
getFromLocalStorage,
setInLocalStorage,
throttle,
} from 'tldraw'
import 'tldraw/tldraw.css' import 'tldraw/tldraw.css'
// There's a guide at the bottom of this file! // There's a guide at the bottom of this file!
@ -27,7 +20,7 @@ export default function PersistenceExample() {
setLoadingState({ status: 'loading' }) setLoadingState({ status: 'loading' })
// Get persisted data from local storage // Get persisted data from local storage
const persistedSnapshot = getFromLocalStorage(PERSISTENCE_KEY) const persistedSnapshot = localStorage.getItem(PERSISTENCE_KEY)
if (persistedSnapshot) { if (persistedSnapshot) {
try { try {
@ -45,7 +38,7 @@ export default function PersistenceExample() {
const cleanupFn = store.listen( const cleanupFn = store.listen(
throttle(() => { throttle(() => {
const snapshot = store.getSnapshot() const snapshot = store.getSnapshot()
setInLocalStorage(PERSISTENCE_KEY, JSON.stringify(snapshot)) localStorage.setItem(PERSISTENCE_KEY, JSON.stringify(snapshot))
}, 500) }, 500)
) )

View file

@ -112,7 +112,6 @@
"@sentry/cli": "^2.25.0", "@sentry/cli": "^2.25.0",
"@yarnpkg/types": "^4.0.0", "@yarnpkg/types": "^4.0.0",
"cross-env": "^7.0.3", "cross-env": "^7.0.3",
"eslint-plugin-no-storage": "^1.0.2",
"purgecss": "^5.0.0", "purgecss": "^5.0.0",
"svgo": "^3.0.2" "svgo": "^3.0.2"
} }

View file

@ -17,12 +17,7 @@ import {
pageIdValidator, pageIdValidator,
shapeIdValidator, shapeIdValidator,
} from '@tldraw/tlschema' } from '@tldraw/tlschema'
import { import { objectMapFromEntries } from '@tldraw/utils'
deleteFromSessionStorage,
getFromSessionStorage,
objectMapFromEntries,
setInSessionStorage,
} from '@tldraw/utils'
import { T } from '@tldraw/validate' import { T } from '@tldraw/validate'
import { uniqueId } from '../utils/uniqueId' import { uniqueId } from '../utils/uniqueId'
@ -31,9 +26,7 @@ const tabIdKey = 'TLDRAW_TAB_ID_v2' as const
const window = globalThis.window as const window = globalThis.window as
| { | {
navigator: Window['navigator'] navigator: Window['navigator']
// eslint-disable-next-line no-storage/no-browser-storage
localStorage: Window['localStorage'] localStorage: Window['localStorage']
// eslint-disable-next-line no-storage/no-browser-storage
sessionStorage: Window['sessionStorage'] sessionStorage: Window['sessionStorage']
addEventListener: Window['addEventListener'] addEventListener: Window['addEventListener']
TLDRAW_TAB_ID_v2?: string TLDRAW_TAB_ID_v2?: string
@ -58,7 +51,7 @@ function iOS() {
* @public * @public
*/ */
export const TAB_ID: string = window export const TAB_ID: string = window
? window[tabIdKey] ?? getFromSessionStorage(tabIdKey) ?? `TLDRAW_INSTANCE_STATE_V1_` + uniqueId() ? window[tabIdKey] ?? window.sessionStorage[tabIdKey] ?? `TLDRAW_INSTANCE_STATE_V1_` + uniqueId()
: '<error>' : '<error>'
if (window) { if (window) {
window[tabIdKey] = TAB_ID window[tabIdKey] = TAB_ID
@ -69,14 +62,14 @@ if (window) {
// in which case they'll have two tabs with the same UI state. // in which case they'll have two tabs with the same UI state.
// It's not a big deal, but it's not ideal. // It's not a big deal, but it's not ideal.
// And anyway I can't see a way to duplicate a tab in iOS Safari. // And anyway I can't see a way to duplicate a tab in iOS Safari.
setInSessionStorage(tabIdKey, TAB_ID) window.sessionStorage[tabIdKey] = TAB_ID
} else { } else {
deleteFromSessionStorage(tabIdKey) delete window.sessionStorage[tabIdKey]
} }
} }
window?.addEventListener('beforeunload', () => { window?.addEventListener('beforeunload', () => {
setInSessionStorage(tabIdKey, TAB_ID) window.sessionStorage[tabIdKey] = TAB_ID
}) })
const Versions = { const Versions = {

View file

@ -1,7 +1,6 @@
import { atom } from '@tldraw/state' import { atom } from '@tldraw/state'
import { defineMigrations, migrate } from '@tldraw/store' import { defineMigrations, migrate } from '@tldraw/store'
import { getDefaultTranslationLocale } from '@tldraw/tlschema' import { getDefaultTranslationLocale } from '@tldraw/tlschema'
import { getFromLocalStorage, setInLocalStorage } from '@tldraw/utils'
import { T } from '@tldraw/validate' import { T } from '@tldraw/validate'
import { uniqueId } from '../utils/uniqueId' import { uniqueId } from '../utils/uniqueId'
@ -204,7 +203,7 @@ function loadUserPreferences(): TLUserPreferences {
const userData = const userData =
typeof window === 'undefined' typeof window === 'undefined'
? null ? null
: ((JSON.parse(getFromLocalStorage(USER_DATA_KEY) || 'null') ?? : ((JSON.parse(window?.localStorage?.getItem(USER_DATA_KEY) || 'null') ??
null) as null | UserDataSnapshot) null) as null | UserDataSnapshot)
return migrateUserPreferences(userData) return migrateUserPreferences(userData)
@ -213,7 +212,8 @@ function loadUserPreferences(): TLUserPreferences {
const globalUserPreferences = atom<TLUserPreferences | null>('globalUserData', null) const globalUserPreferences = atom<TLUserPreferences | null>('globalUserData', null)
function storeUserPreferences() { function storeUserPreferences() {
setInLocalStorage( if (typeof window !== 'undefined' && window.localStorage) {
window.localStorage.setItem(
USER_DATA_KEY, USER_DATA_KEY,
JSON.stringify({ JSON.stringify({
version: userMigrations.currentVersion, version: userMigrations.currentVersion,
@ -221,6 +221,7 @@ function storeUserPreferences() {
}) })
) )
} }
}
/** @public */ /** @public */
export function setUserPreferences(user: TLUserPreferences) { export function setUserPreferences(user: TLUserPreferences) {

View file

@ -1,5 +1,4 @@
import { Atom, atom, react } from '@tldraw/state' import { Atom, atom, react } from '@tldraw/state'
import { deleteFromSessionStorage, getFromSessionStorage, setInSessionStorage } from '@tldraw/utils'
// --- 1. DEFINE --- // --- 1. DEFINE ---
// //
@ -129,9 +128,9 @@ function createDebugValueBase<T>(def: DebugFlagDef<T>): DebugFlag<T> {
const currentValue = valueAtom.get() const currentValue = valueAtom.get()
try { try {
if (currentValue === defaultValue) { if (currentValue === defaultValue) {
deleteFromSessionStorage(`tldraw_debug:${def.name}`) window.sessionStorage.removeItem(`tldraw_debug:${def.name}`)
} else { } else {
setInSessionStorage(`tldraw_debug:${def.name}`, JSON.stringify(currentValue)) window.sessionStorage.setItem(`tldraw_debug:${def.name}`, JSON.stringify(currentValue))
} }
} catch { } catch {
// not a big deal // not a big deal
@ -155,7 +154,7 @@ function createDebugValueBase<T>(def: DebugFlagDef<T>): DebugFlag<T> {
function getStoredInitialValue(name: string) { function getStoredInitialValue(name: string) {
try { try {
return JSON.parse(getFromSessionStorage(`tldraw_debug:${name}`) ?? 'null') return JSON.parse(window?.sessionStorage.getItem(`tldraw_debug:${name}`) ?? 'null')
} catch (err) { } catch (err) {
return null return null
} }

View file

@ -1,4 +1,3 @@
import { clearLocalStorage } from '@tldraw/utils'
import { deleteDB } from 'idb' import { deleteDB } from 'idb'
import { getAllIndexDbNames } from './indexedDb' import { getAllIndexDbNames } from './indexedDb'
@ -7,17 +6,15 @@ import { getAllIndexDbNames } from './indexedDb'
* *
* @public */ * @public */
export async function hardReset({ shouldReload = true } = {}) { export async function hardReset({ shouldReload = true } = {}) {
clearLocalStorage() sessionStorage.clear()
await Promise.all(getAllIndexDbNames().map((db) => deleteDB(db))) await Promise.all(getAllIndexDbNames().map((db) => deleteDB(db)))
clearLocalStorage() localStorage.clear()
if (shouldReload) { if (shouldReload) {
if (typeof window !== 'undefined') {
window.location.reload() window.location.reload()
} }
} }
}
if (typeof window !== 'undefined') { if (typeof window !== 'undefined') {
if (process.env.NODE_ENV === 'development') { if (process.env.NODE_ENV === 'development') {

View file

@ -9,7 +9,6 @@ import {
const clearAll = async () => { const clearAll = async () => {
const dbs = (indexedDB as any)._databases as Map<any, any> const dbs = (indexedDB as any)._databases as Map<any, any>
dbs.clear() dbs.clear()
// eslint-disable-next-line no-storage/no-browser-storage
localStorage.clear() localStorage.clear()
} }

View file

@ -1,6 +1,5 @@
import { RecordsDiff, SerializedSchema, SerializedStore } from '@tldraw/store' import { RecordsDiff, SerializedSchema, SerializedStore } from '@tldraw/store'
import { TLRecord, TLStoreSchema } from '@tldraw/tlschema' import { TLRecord, TLStoreSchema } from '@tldraw/tlschema'
import { getFromLocalStorage, setInLocalStorage } from '@tldraw/utils'
import { IDBPDatabase, openDB } from 'idb' import { IDBPDatabase, openDB } from 'idb'
import { TLSessionStateSnapshot } from '../../config/TLSessionStateSnapshot' import { TLSessionStateSnapshot } from '../../config/TLSessionStateSnapshot'
@ -222,7 +221,7 @@ async function pruneSessionState({
/** @internal */ /** @internal */
export function getAllIndexDbNames(): string[] { export function getAllIndexDbNames(): string[] {
const result = JSON.parse(getFromLocalStorage(dbNameIndexKey) || '[]') ?? [] const result = JSON.parse(window?.localStorage.getItem(dbNameIndexKey) || '[]') ?? []
if (!Array.isArray(result)) { if (!Array.isArray(result)) {
return [] return []
} }
@ -232,5 +231,5 @@ export function getAllIndexDbNames(): string[] {
function addDbName(name: string) { function addDbName(name: string) {
const all = new Set(getAllIndexDbNames()) const all = new Set(getAllIndexDbNames())
all.add(name) all.add(name)
setInLocalStorage(dbNameIndexKey, JSON.stringify([...all])) window?.localStorage.setItem(dbNameIndexKey, JSON.stringify([...all]))
} }

View file

@ -1,4 +1,3 @@
import { getFromLocalStorage, setInLocalStorage } from '@tldraw/editor'
import React from 'react' import React from 'react'
/** @public */ /** @public */
@ -6,7 +5,7 @@ export function useLocalStorageState<T = any>(key: string, defaultValue: T) {
const [state, setState] = React.useState(defaultValue) const [state, setState] = React.useState(defaultValue)
React.useLayoutEffect(() => { React.useLayoutEffect(() => {
const value = getFromLocalStorage(key) const value = localStorage.getItem(key)
if (value) { if (value) {
try { try {
setState(JSON.parse(value)) setState(JSON.parse(value))
@ -20,7 +19,7 @@ export function useLocalStorageState<T = any>(key: string, defaultValue: T) {
(setter: T | ((value: T) => T)) => { (setter: T | ((value: T) => T)) => {
setState((s) => { setState((s) => {
const value = typeof setter === 'function' ? (setter as any)(s) : setter const value = typeof setter === 'function' ? (setter as any)(s) : setter
setInLocalStorage(key, JSON.stringify(value)) localStorage.setItem(key, JSON.stringify(value))
return value return value
}) })
}, },

View file

@ -19,12 +19,6 @@ export const assert: (value: unknown, message?: string) => asserts value;
// @internal (undocumented) // @internal (undocumented)
export const assertExists: <T>(value: T, message?: string | undefined) => NonNullable<T>; export const assertExists: <T>(value: T, message?: string | undefined) => NonNullable<T>;
// @public
export function clearLocalStorage(): void;
// @public
export function clearSessionStorage(): void;
// @internal (undocumented) // @internal (undocumented)
export function compact<T>(arr: T[]): NonNullable<T>[]; export function compact<T>(arr: T[]): NonNullable<T>[];
@ -40,12 +34,6 @@ export function dedupe<T>(input: T[], equals?: (a: any, b: any) => boolean): T[]
// @public // @public
export function deepCopy<T = unknown>(obj: T): T; export function deepCopy<T = unknown>(obj: T): T;
// @public
export function deleteFromLocalStorage(key: string): void;
// @public
export function deleteFromSessionStorage(key: string): void;
// @public (undocumented) // @public (undocumented)
export type ErrorResult<E> = { export type ErrorResult<E> = {
readonly ok: false; readonly ok: false;
@ -80,12 +68,6 @@ export function getErrorAnnotations(error: Error): ErrorAnnotations;
// @public // @public
export function getFirstFromIterable<T = unknown>(set: Map<any, T> | Set<T>): T; export function getFirstFromIterable<T = unknown>(set: Map<any, T> | Set<T>): T;
// @public
export function getFromLocalStorage(key: string, defaultValue?: null): any;
// @public
export function getFromSessionStorage(key: string, defaultValue?: null): any;
// @public // @public
export function getHashForBuffer(buffer: ArrayBuffer): string; export function getHashForBuffer(buffer: ArrayBuffer): string;
@ -291,12 +273,6 @@ export function rng(seed?: string): () => number;
// @public // @public
export function rotateArray<T>(arr: T[], offset: number): T[]; export function rotateArray<T>(arr: T[], offset: number): T[];
// @public
export function setInLocalStorage(key: string, value: any): void;
// @public
export function setInSessionStorage(key: string, value: any): void;
// @public (undocumented) // @public (undocumented)
export function sortById<T extends { export function sortById<T extends {
id: any; id: any;

View file

@ -172,62 +172,6 @@
"name": "", "name": "",
"preserveMemberOrder": false, "preserveMemberOrder": false,
"members": [ "members": [
{
"kind": "Function",
"canonicalReference": "@tldraw/utils!clearLocalStorage:function(1)",
"docComment": "/**\n * Clear all values from local storage. Will not throw an error if localStorage is not available.\n *\n * @public\n */\n",
"excerptTokens": [
{
"kind": "Content",
"text": "export declare function clearLocalStorage(): "
},
{
"kind": "Content",
"text": "void"
},
{
"kind": "Content",
"text": ";"
}
],
"fileUrlPath": "packages/utils/src/lib/local-storage.ts",
"returnTypeTokenRange": {
"startIndex": 1,
"endIndex": 2
},
"releaseTag": "Public",
"overloadIndex": 1,
"parameters": [],
"name": "clearLocalStorage"
},
{
"kind": "Function",
"canonicalReference": "@tldraw/utils!clearSessionStorage:function(1)",
"docComment": "/**\n * Clear all values from session storage. Will not throw an error if sessionStorage is not available.\n *\n * @public\n */\n",
"excerptTokens": [
{
"kind": "Content",
"text": "export declare function clearSessionStorage(): "
},
{
"kind": "Content",
"text": "void"
},
{
"kind": "Content",
"text": ";"
}
],
"fileUrlPath": "packages/utils/src/lib/session-storage.ts",
"returnTypeTokenRange": {
"startIndex": 1,
"endIndex": 2
},
"releaseTag": "Public",
"overloadIndex": 1,
"parameters": [],
"name": "clearSessionStorage"
},
{ {
"kind": "Function", "kind": "Function",
"canonicalReference": "@tldraw/utils!debounce:function(1)", "canonicalReference": "@tldraw/utils!debounce:function(1)",
@ -479,96 +423,6 @@
], ],
"name": "deepCopy" "name": "deepCopy"
}, },
{
"kind": "Function",
"canonicalReference": "@tldraw/utils!deleteFromLocalStorage:function(1)",
"docComment": "/**\n * Remove a value from local storage. Will not throw an error if localStorage is not available.\n *\n * @param key - The key to set.\n *\n * @public\n */\n",
"excerptTokens": [
{
"kind": "Content",
"text": "export declare function deleteFromLocalStorage(key: "
},
{
"kind": "Content",
"text": "string"
},
{
"kind": "Content",
"text": "): "
},
{
"kind": "Content",
"text": "void"
},
{
"kind": "Content",
"text": ";"
}
],
"fileUrlPath": "packages/utils/src/lib/local-storage.ts",
"returnTypeTokenRange": {
"startIndex": 3,
"endIndex": 4
},
"releaseTag": "Public",
"overloadIndex": 1,
"parameters": [
{
"parameterName": "key",
"parameterTypeTokenRange": {
"startIndex": 1,
"endIndex": 2
},
"isOptional": false
}
],
"name": "deleteFromLocalStorage"
},
{
"kind": "Function",
"canonicalReference": "@tldraw/utils!deleteFromSessionStorage:function(1)",
"docComment": "/**\n * Remove a value from session storage. Will not throw an error if sessionStorage is not available.\n *\n * @param key - The key to set.\n *\n * @public\n */\n",
"excerptTokens": [
{
"kind": "Content",
"text": "export declare function deleteFromSessionStorage(key: "
},
{
"kind": "Content",
"text": "string"
},
{
"kind": "Content",
"text": "): "
},
{
"kind": "Content",
"text": "void"
},
{
"kind": "Content",
"text": ";"
}
],
"fileUrlPath": "packages/utils/src/lib/session-storage.ts",
"returnTypeTokenRange": {
"startIndex": 3,
"endIndex": 4
},
"releaseTag": "Public",
"overloadIndex": 1,
"parameters": [
{
"parameterName": "key",
"parameterTypeTokenRange": {
"startIndex": 1,
"endIndex": 2
},
"isOptional": false
}
],
"name": "deleteFromSessionStorage"
},
{ {
"kind": "TypeAlias", "kind": "TypeAlias",
"canonicalReference": "@tldraw/utils!ErrorResult:type", "canonicalReference": "@tldraw/utils!ErrorResult:type",
@ -800,128 +654,6 @@
], ],
"name": "getFirstFromIterable" "name": "getFirstFromIterable"
}, },
{
"kind": "Function",
"canonicalReference": "@tldraw/utils!getFromLocalStorage:function(1)",
"docComment": "/**\n * Get a value from local storage.\n *\n * @param key - The key to get.\n *\n * @param defaultValue - The default value to return if the key is not found or if local storage is not available.\n *\n * @public\n */\n",
"excerptTokens": [
{
"kind": "Content",
"text": "export declare function getFromLocalStorage(key: "
},
{
"kind": "Content",
"text": "string"
},
{
"kind": "Content",
"text": ", defaultValue?: "
},
{
"kind": "Content",
"text": "null"
},
{
"kind": "Content",
"text": "): "
},
{
"kind": "Content",
"text": "any"
},
{
"kind": "Content",
"text": ";"
}
],
"fileUrlPath": "packages/utils/src/lib/local-storage.ts",
"returnTypeTokenRange": {
"startIndex": 5,
"endIndex": 6
},
"releaseTag": "Public",
"overloadIndex": 1,
"parameters": [
{
"parameterName": "key",
"parameterTypeTokenRange": {
"startIndex": 1,
"endIndex": 2
},
"isOptional": false
},
{
"parameterName": "defaultValue",
"parameterTypeTokenRange": {
"startIndex": 3,
"endIndex": 4
},
"isOptional": true
}
],
"name": "getFromLocalStorage"
},
{
"kind": "Function",
"canonicalReference": "@tldraw/utils!getFromSessionStorage:function(1)",
"docComment": "/**\n * Get a value from session storage.\n *\n * @param key - The key to get.\n *\n * @param defaultValue - The default value to return if the key is not found or if session storage is not available.\n *\n * @public\n */\n",
"excerptTokens": [
{
"kind": "Content",
"text": "export declare function getFromSessionStorage(key: "
},
{
"kind": "Content",
"text": "string"
},
{
"kind": "Content",
"text": ", defaultValue?: "
},
{
"kind": "Content",
"text": "null"
},
{
"kind": "Content",
"text": "): "
},
{
"kind": "Content",
"text": "any"
},
{
"kind": "Content",
"text": ";"
}
],
"fileUrlPath": "packages/utils/src/lib/session-storage.ts",
"returnTypeTokenRange": {
"startIndex": 5,
"endIndex": 6
},
"releaseTag": "Public",
"overloadIndex": 1,
"parameters": [
{
"parameterName": "key",
"parameterTypeTokenRange": {
"startIndex": 1,
"endIndex": 2
},
"isOptional": false
},
{
"parameterName": "defaultValue",
"parameterTypeTokenRange": {
"startIndex": 3,
"endIndex": 4
},
"isOptional": true
}
],
"name": "getFromSessionStorage"
},
{ {
"kind": "Function", "kind": "Function",
"canonicalReference": "@tldraw/utils!getHashForBuffer:function(1)", "canonicalReference": "@tldraw/utils!getHashForBuffer:function(1)",
@ -3329,128 +3061,6 @@
], ],
"name": "rotateArray" "name": "rotateArray"
}, },
{
"kind": "Function",
"canonicalReference": "@tldraw/utils!setInLocalStorage:function(1)",
"docComment": "/**\n * Set a value in local storage. Will not throw an error if localStorage is not available.\n *\n * @param key - The key to set.\n *\n * @param value - The value to set.\n *\n * @public\n */\n",
"excerptTokens": [
{
"kind": "Content",
"text": "export declare function setInLocalStorage(key: "
},
{
"kind": "Content",
"text": "string"
},
{
"kind": "Content",
"text": ", value: "
},
{
"kind": "Content",
"text": "any"
},
{
"kind": "Content",
"text": "): "
},
{
"kind": "Content",
"text": "void"
},
{
"kind": "Content",
"text": ";"
}
],
"fileUrlPath": "packages/utils/src/lib/local-storage.ts",
"returnTypeTokenRange": {
"startIndex": 5,
"endIndex": 6
},
"releaseTag": "Public",
"overloadIndex": 1,
"parameters": [
{
"parameterName": "key",
"parameterTypeTokenRange": {
"startIndex": 1,
"endIndex": 2
},
"isOptional": false
},
{
"parameterName": "value",
"parameterTypeTokenRange": {
"startIndex": 3,
"endIndex": 4
},
"isOptional": false
}
],
"name": "setInLocalStorage"
},
{
"kind": "Function",
"canonicalReference": "@tldraw/utils!setInSessionStorage:function(1)",
"docComment": "/**\n * Set a value in session storage. Will not throw an error if sessionStorage is not available.\n *\n * @param key - The key to set.\n *\n * @param value - The value to set.\n *\n * @public\n */\n",
"excerptTokens": [
{
"kind": "Content",
"text": "export declare function setInSessionStorage(key: "
},
{
"kind": "Content",
"text": "string"
},
{
"kind": "Content",
"text": ", value: "
},
{
"kind": "Content",
"text": "any"
},
{
"kind": "Content",
"text": "): "
},
{
"kind": "Content",
"text": "void"
},
{
"kind": "Content",
"text": ";"
}
],
"fileUrlPath": "packages/utils/src/lib/session-storage.ts",
"returnTypeTokenRange": {
"startIndex": 5,
"endIndex": 6
},
"releaseTag": "Public",
"overloadIndex": 1,
"parameters": [
{
"parameterName": "key",
"parameterTypeTokenRange": {
"startIndex": 1,
"endIndex": 2
},
"isOptional": false
},
{
"parameterName": "value",
"parameterTypeTokenRange": {
"startIndex": 3,
"endIndex": 4
},
"isOptional": false
}
],
"name": "setInSessionStorage"
},
{ {
"kind": "Function", "kind": "Function",
"canonicalReference": "@tldraw/utils!sortById:function(1)", "canonicalReference": "@tldraw/utils!sortById:function(1)",

View file

@ -23,12 +23,6 @@ export { noop, omitFromStackTrace, throttle } from './lib/function'
export { getHashForBuffer, getHashForObject, getHashForString, lns } from './lib/hash' export { getHashForBuffer, getHashForObject, getHashForString, lns } from './lib/hash'
export { getFirstFromIterable } from './lib/iterable' export { getFirstFromIterable } from './lib/iterable'
export type { JsonArray, JsonObject, JsonPrimitive, JsonValue } from './lib/json-value' export type { JsonArray, JsonObject, JsonPrimitive, JsonValue } from './lib/json-value'
export {
clearLocalStorage,
deleteFromLocalStorage,
getFromLocalStorage,
setInLocalStorage,
} from './lib/local-storage'
export { MediaHelpers } from './lib/media' export { MediaHelpers } from './lib/media'
export { invLerp, lerp, modulate, rng } from './lib/number' export { invLerp, lerp, modulate, rng } from './lib/number'
export { export {
@ -58,12 +52,6 @@ export {
sortByIndex, sortByIndex,
validateIndexKey, validateIndexKey,
} from './lib/reordering/reordering' } from './lib/reordering/reordering'
export {
clearSessionStorage,
deleteFromSessionStorage,
getFromSessionStorage,
setInSessionStorage,
} from './lib/session-storage'
export { sortById } from './lib/sort' export { sortById } from './lib/sort'
export type { Expand, RecursivePartial, Required } from './lib/types' export type { Expand, RecursivePartial, Required } from './lib/types'
export { isDefined, isNonNull, isNonNullish, structuredClone } from './lib/value' export { isDefined, isNonNull, isNonNullish, structuredClone } from './lib/value'

View file

@ -1,63 +0,0 @@
/* eslint-disable no-storage/no-browser-storage */
/**
* Get a value from local storage.
*
* @param key - The key to get.
* @param defaultValue - The default value to return if the key is not found or if local storage is not available.
*
* @public
*/
export function getFromLocalStorage(key: string, defaultValue = null) {
try {
const value = localStorage.getItem(key)
if (value === null) return defaultValue
return JSON.parse(value)
} catch {
return defaultValue
}
}
/**
* Set a value in local storage. Will not throw an error if localStorage is not available.
*
* @param key - The key to set.
* @param value - The value to set.
*
* @public
*/
export function setInLocalStorage(key: string, value: any) {
try {
localStorage.setItem(key, JSON.stringify(value))
} catch {
// noop
}
}
/**
* Remove a value from local storage. Will not throw an error if localStorage is not available.
*
* @param key - The key to set.
*
* @public
*/
export function deleteFromLocalStorage(key: string) {
try {
localStorage.removeItem(key)
} catch {
// noop
}
}
/**
* Clear all values from local storage. Will not throw an error if localStorage is not available.
*
* @public
*/
export function clearLocalStorage() {
try {
localStorage.clear()
} catch {
// noop
}
}

View file

@ -1,63 +0,0 @@
/* eslint-disable no-storage/no-browser-storage */
/**
* Get a value from session storage.
*
* @param key - The key to get.
* @param defaultValue - The default value to return if the key is not found or if session storage is not available.
*
* @public
*/
export function getFromSessionStorage(key: string, defaultValue = null) {
try {
const value = sessionStorage.getItem(key)
if (value === null) return defaultValue
return JSON.parse(value)
} catch {
return defaultValue
}
}
/**
* Set a value in session storage. Will not throw an error if sessionStorage is not available.
*
* @param key - The key to set.
* @param value - The value to set.
*
* @public
*/
export function setInSessionStorage(key: string, value: any) {
try {
sessionStorage.setItem(key, JSON.stringify(value))
} catch {
// noop
}
}
/**
* Remove a value from session storage. Will not throw an error if sessionStorage is not available.
*
* @param key - The key to set.
*
* @public
*/
export function deleteFromSessionStorage(key: string) {
try {
sessionStorage.removeItem(key)
} catch {
// noop
}
}
/**
* Clear all values from session storage. Will not throw an error if sessionStorage is not available.
*
* @public
*/
export function clearSessionStorage() {
try {
sessionStorage.clear()
} catch {
// noop
}
}

View file

@ -7299,7 +7299,6 @@ __metadata:
eslint-plugin-import: "npm:^2.27.5" eslint-plugin-import: "npm:^2.27.5"
eslint-plugin-local: "npm:^1.0.0" eslint-plugin-local: "npm:^1.0.0"
eslint-plugin-no-only-tests: "npm:^3.1.0" eslint-plugin-no-only-tests: "npm:^3.1.0"
eslint-plugin-no-storage: "npm:^1.0.2"
eslint-plugin-react: "npm:^7.32.2" eslint-plugin-react: "npm:^7.32.2"
eslint-plugin-react-hooks: "npm:^4.6.0" eslint-plugin-react-hooks: "npm:^4.6.0"
fs-extra: "npm:^11.1.0" fs-extra: "npm:^11.1.0"
@ -12903,13 +12902,6 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"eslint-plugin-no-storage@npm:^1.0.2":
version: 1.0.2
resolution: "eslint-plugin-no-storage@npm:1.0.2"
checksum: 971323b852846a3eb1558ff68aa51e36ff6671cf99f261410768a3c4c2baebc1702decee3afbc16128d12d965ea00b574adf2ee35fc4b68b58d74810e6bcb37b
languageName: node
linkType: hard
"eslint-plugin-react-hooks@npm:^4.5.0, eslint-plugin-react-hooks@npm:^4.6.0": "eslint-plugin-react-hooks@npm:^4.5.0, eslint-plugin-react-hooks@npm:^4.6.0":
version: 4.6.0 version: 4.6.0
resolution: "eslint-plugin-react-hooks@npm:4.6.0" resolution: "eslint-plugin-react-hooks@npm:4.6.0"