Socket
Socket
Sign inDemoInstall

@solid-primitives/storage

Package Overview
Dependencies
Maintainers
0
Versions
45
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@solid-primitives/storage - npm Package Compare versions

Comparing version 3.8.0 to 4.0.0

dist/persisted-7aCRLS7M.d.cts

207

dist/index/index.d.ts

@@ -1,103 +0,10 @@

import { S as StringStorageProps, a as StorageWithOptions, b as StorageObject, c as StorageSetter, d as StorageActions, A as AnyStorageProps, e as AsyncStorage, f as AsyncStorageWithOptions, g as AsyncStorageObject, h as AsyncStorageSetter, i as AsyncStorageActions, j as StorageSignalProps, k as StorageProps } from '../types-C92rHTXK.js';
export { l as StorageDeserializer, m as StorageSerializer } from '../types-C92rHTXK.js';
import { Accessor, Setter, Signal } from 'solid-js';
import { Store, SetStoreFunction } from 'solid-js/store';
import { S as SyncStorageWithOptions, a as SyncStorage, A as AsyncStorageWithOptions, b as AsyncStorage } from '../persisted-7aCRLS7M.js';
export { P as PersistenceOptions, e as PersistenceSyncAPI, c as PersistenceSyncCallback, d as PersistenceSyncData, m as makePersisted, g as messageSync, f as multiplexSync, s as storageSync, w as wsSync } from '../persisted-7aCRLS7M.js';
import 'solid-js';
import 'solid-js/store';
/**
* like createStore, but bound to a localStorage-like API
* ```typescript
* type StorageWithOptions<O> = Storage; // but with options added to setItem
* type StorageProps<T extends string, O> = {
* api?: Storage | StorageWithOptions;
* // or an array thereof, default will be localStorage
* deserializer?: (value: string, key: string, options?: O) => T;
* serializer?: (value: T, key: string, options?: O) => string;
* options?: O; // options
* prefix?: string // will be prefixed to the key
* };
* createStorage(props?: StorageProps) => [
* store: StorageObject<T>, // basically like `Store<T>`
* setter: StorageSetter<T>, // like `setStoreFunction<T>`
* actions: {
* remove: (key: string) => void;
* clear: () => void;
* toJSON: () => { [key: string]: T };
* }
* ]
* ```
* @deprecated in favor of makePersisted
*/
declare function createStorage<O>(props?: StringStorageProps<Storage | StorageWithOptions<O>, O>): [
store: StorageObject<string>,
setter: StorageSetter<string, O>,
actions: StorageActions<string>
];
declare function createStorage<O, T>(props?: AnyStorageProps<Storage | StorageWithOptions<O>, O, T>): [store: StorageObject<T>, setter: StorageSetter<T, O>, actions: StorageActions<T>];
/**
* like createStore, but bound to an asynchronous localStorage-like API
* ```typescript
* type AsyncStorage = Storage // but returns everything wrapped in Promises
* type AsyncStorageWithOptions<O> = Storage; // but with options added to setItem
* type AsyncStorageProps<T extends string, O> = {
* api?: AsyncStorage | AsyncStorageWithOptions;
* // or an array thereof, default will be localStorage
* deserializer?: (value: string, key: string, options?: O) => T;
* serializer?: (value: T, key: string, options?: O) => string;
* options?: O; // options
* prefix?: string // will be prefixed to the key
* };
* createStorage(props?: AsyncStorageProps) => [
* store: AsyncStorageObject<T>, // basically like `Store<T>`
* setter: AsyncStorageSetter<T>, // like `setStoreFunction<T>`
* actions: {
* remove: (key: string) => Promise<void>;
* clear: () => Promise<void>;
* toJSON: () => Promise<{ [key: string]: T }>;
* }
* ]
* ```
* @deprecated in favor of makePersisted
*/
declare function createAsyncStorage<O>(props?: StringStorageProps<AsyncStorage | AsyncStorageWithOptions<O>, O>): [
store: AsyncStorageObject<string>,
setter: AsyncStorageSetter<string, O>,
actions: AsyncStorageActions<string>
];
declare function createAsyncStorage<O, T>(props?: AnyStorageProps<T, AsyncStorage | AsyncStorageWithOptions<O>, O>): [
store: AsyncStorageObject<T>,
setter: AsyncStorageSetter<T, O>,
actions: AsyncStorageActions<T>
];
/**
* like createSignal, but bound to a localStorage-like API
* ```typescript
* type StorageWithOptions<O> = Storage; // but with options added to setItem
* type StorageProps<T extends string, O> = {
* api?: Storage | StorageWithOptions;
* // or an array thereof, default will be localStorage
* deserializer?: (value: string, key: string, options?: O) => T;
* serializer?: (value: T, key: string, options?: O) => string;
* options?: O; // options
* prefix?: string // will be prefixed to the key
* };
* createStorage<T extends string>(key: string, props?: StorageProps<T>) => [
* accessor: Accessor<T> &
* { error: () => Error | undefined },
* // basically like `value()`
* setter: Setter<T>, // like `setValue()`
* refetch: () => void // reloads from storage
* ]
* ```
* @deprecated in favor of makePersisted
*/
declare function createStorageSignal<T, O = {}>(key: string, initialValue?: T, props?: StorageSignalProps<T, Storage | StorageWithOptions<O>, O>): [accessor: Accessor<T | null>, setter: Setter<T | null>, refetch: () => void];
/** @deprecated in favor of makePersistent */
declare const createLocalStorage: typeof createStorage;
/** @deprecated in favor of makePersistent */
declare const createSessionStorage: <T, O = {}>(props: StorageProps<T, Storage, O>) => [store: StorageObject<string>, setter: StorageSetter<string, unknown>, actions: StorageActions<string>];
type CookieOptions = CookieProperties & {
type CookieOptions = (CookieProperties & {
getRequestHeaders?: () => Headers;
getResponseHeaders?: () => Headers;
};
}) | undefined;
type CookiePropertyTypes = {

@@ -134,8 +41,3 @@ domain?: string;

*/
declare const cookieStorage: StorageWithOptions<CookieOptions>;
/**
* creates a reactive store but bound to document.cookie
* @deprecated in favor of makePersisted
*/
declare const createCookieStorage: <T, O = CookieOptions, A = StorageWithOptions<CookieOptions>>(props?: Omit<StorageProps<T, A, O>, "api"> | undefined) => [store: StorageObject<T>, setter: StorageSetter<T, O>, actions: StorageActions<T>];
declare const cookieStorage: SyncStorageWithOptions<CookieOptions>;

@@ -145,12 +47,19 @@ /**

*/
declare const addClearMethod: <S extends Storage | StorageWithOptions<any>>(storage: Omit<S, "clear"> & {
declare const addClearMethod: <S extends SyncStorage | {
[key: string]: any;
getItem: (key: string, options?: any) => string | null;
setItem: (key: string, value: string, options?: any) => void;
removeItem: (key: string, options?: any) => void;
}, R extends S & {
clear: () => void;
}>(storage: Omit<S, "clear"> & {
clear?: (() => void) | undefined;
}) => S;
}) => R;
/**
* adds a `.withOptions` method that wraps the storage to apply options
*/
declare const addWithOptionsMethod: <O, S extends StorageWithOptions<O> | AsyncStorageWithOptions<O>, W extends Storage | AsyncStorage = S extends AsyncStorageWithOptions<O> ? AsyncStorage : Storage>(storage: S) => S & {
declare const addWithOptionsMethod: <O, S extends SyncStorageWithOptions<O> | AsyncStorageWithOptions<O>, W extends SyncStorage | AsyncStorage = S extends AsyncStorageWithOptions<O> ? AsyncStorage : SyncStorage>(storage: S) => S & {
withOptions: (options: O) => W;
};
type StorageMultiplexer = <S extends any[]>(...storages: S) => AsyncStorage extends S[number] ? AsyncStorage : Storage;
type StorageMultiplexer = <S extends any[]>(...storages: S) => AsyncStorage extends S[number] ? AsyncStorage : SyncStorage;
/**

@@ -160,72 +69,16 @@ * combines multiple storages to a single storage

declare const multiplexStorage: StorageMultiplexer;
type PersistenceSyncData = {
key: string;
newValue: string | null | undefined;
timeStamp: number;
url?: string;
};
type PersistenceSyncCallback = (data: PersistenceSyncData) => void;
type PersistenceSyncAPI = [
/** subscribes to sync */
subscribe: (subscriber: PersistenceSyncCallback) => void,
update: (key: string, value: string | null | undefined) => void
];
type PersistenceOptions<T, O extends Record<string, any> | undefined> = {
name?: string;
serialize?: (data: T) => string;
deserialize?: (data: string) => T;
sync?: PersistenceSyncAPI;
} & (undefined extends O ? {
storage?: Storage | AsyncStorage;
} : {
storage: StorageWithOptions<O> | AsyncStorageWithOptions<O>;
storageOptions?: O;
});
type SignalType<S extends Signal<any> | [Store<any>, SetStoreFunction<any>]> = S extends Signal<infer T> ? T : S extends [Store<infer T>, SetStoreFunction<infer T>] ? T : never;
/**
* Persists a signal, store or similar API
* ```ts
* const [getter, setter] = makePersisted(createSignal("data"), options);
* const options = {
* storage: cookieStorage, // can be any synchronous or asynchronous storage
* storageOptions: { ... }, // for storages with options, otherwise not needed
* name: "solid-data", // optional
* serialize: (value: string) => value, // optional
* deserialize: (data: string) => data, // optional
* };
* ```
* Can be used with `createSignal` or `createStore`. The initial value from the storage will overwrite the initial
* value of the signal or store unless overwritten. Overwriting a signal with `null` or `undefined` will remove the
* item from the storage.
*
* @param {Signal<T> | [get: Store<T>, set: SetStoreFunction<T>]} signal - The signal or store to be persisted.
* @param {PersistenceOptions<T, O>} options - The options for persistence.
* @returns {Signal<T> | [get: Store<T>, set: SetStoreFunction<T>]} - The persisted signal or store.
* Provides a minimal Storage API wrapper for an object
*/
declare function makePersisted<S extends Signal<any> | [Store<any>, SetStoreFunction<any>]>(signal: S, options?: PersistenceOptions<SignalType<S>, undefined>): S;
declare function makePersisted<S extends Signal<any> | [Store<any>, SetStoreFunction<any>], O extends Record<string, any>>(signal: S, options: PersistenceOptions<SignalType<S>, O>): S;
/**
* storageSync - synchronize localStorage
* This does only work for { storage: localStorage }.
* If you wish to use e.g. cookieStorage, you may use a different sync method
*/
declare const storageSync: PersistenceSyncAPI;
/**
* messageSync - synchronize over post message or broadcast channel API
*/
declare const messageSync: (channel?: Window | BroadcastChannel) => PersistenceSyncAPI;
/**
* wsSync - syncronize persisted storage via web socket
*/
declare const wsSync: (ws: WebSocket, warnOnError?: boolean) => PersistenceSyncAPI;
/**
* multiplex arbitrary sync APIs
*
* ```ts
* makePersisted(createSignal(0), { sync: multiplexSync(messageSync(bc), wsSync(ws)) })
* ```
*/
declare const multiplexSync: (...syncAPIs: PersistenceSyncAPI[]) => PersistenceSyncAPI;
declare const makeObjectStorage: (object: {
[key: string]: string;
}) => {
getItem: (key: string) => string | null;
setItem: (key: string, value: string) => void;
removeItem: (key: string) => void;
key: (index: number) => string | undefined;
readonly length: number;
clear: () => void;
};
export { AnyStorageProps, AsyncStorage, AsyncStorageObject, AsyncStorageSetter, AsyncStorageWithOptions, type CookieOptions, type PersistenceOptions, type PersistenceSyncAPI, type PersistenceSyncCallback, type PersistenceSyncData, StorageObject, StorageProps, StorageSetter, StorageSignalProps, StorageWithOptions, StringStorageProps, addClearMethod, addWithOptionsMethod, cookieStorage, createAsyncStorage, createCookieStorage, createLocalStorage, createSessionStorage, createStorage, createStorageSignal, makePersisted, messageSync, multiplexStorage, multiplexSync, storageSync, wsSync };
export { AsyncStorage, AsyncStorageWithOptions, type CookieOptions, SyncStorage, SyncStorageWithOptions, addClearMethod, addWithOptionsMethod, cookieStorage, makeObjectStorage, multiplexStorage };

@@ -1,383 +0,6 @@

import { createHydratableSignal } from '@solid-primitives/utils';
import { createSignal, onMount, onCleanup, createEffect, createUniqueId, untrack } from 'solid-js';
import { isServer, getRequestEvent, isDev } from 'solid-js/web';
import { createUniqueId, untrack } from 'solid-js';
import { reconcile } from 'solid-js/store';
// src/storage.ts
function createStorage(props) {
const [error, setError] = createSignal();
const handleError = props?.throw ? (err, fallback) => {
setError(err instanceof Error ? err : new Error(fallback));
throw err;
} : (err, fallback) => {
setError(err instanceof Error ? err : new Error(fallback));
};
const apis = props?.api ? Array.isArray(props.api) ? props.api : [props.api] : [globalThis.localStorage].filter(Boolean);
const prefix = props?.prefix ? `${props.prefix}.` : "";
const signals = /* @__PURE__ */ new Map();
const store = new Proxy(
{},
{
get(_, key) {
let node = signals.get(key);
if (!node) {
node = createSignal(void 0, { equals: false });
signals.set(key, node);
}
node[0]();
const value = apis.reduce(
(result, api) => {
if (result !== null || !api) {
return result;
}
try {
return api.getItem(`${prefix}${key}`);
} catch (err) {
handleError(err, `Error reading ${prefix}${key} from ${api["name"]}`);
return null;
}
},
null
);
if (value !== null && props?.deserializer) {
return props.deserializer(value, key, props.options);
}
return value;
}
}
);
const setter = (key, value, options) => {
const filteredValue = props?.serializer ? props.serializer(value, key, options ?? props.options) : value;
const apiKey = `${prefix}${key}`;
apis.forEach((api) => {
try {
api.getItem(apiKey) !== filteredValue && api.setItem(apiKey, filteredValue);
} catch (err) {
handleError(err, `Error setting ${prefix}${key} to ${filteredValue} in ${api.name}`);
}
});
const node = signals.get(key);
node && node[1]();
};
const remove = (key) => apis.forEach((api) => {
try {
api.removeItem(`${prefix}${key}`);
} catch (err) {
handleError(err, `Error removing ${prefix}${key} from ${api.name}`);
}
});
const clear = () => apis.forEach((api) => {
try {
api.clear();
} catch (err) {
handleError(err, `Error clearing ${api.name}`);
}
});
const toJSON = () => {
const result = {};
const addValue = (key, value) => {
if (!result.hasOwnProperty(key)) {
const filteredValue = value && props?.deserializer ? props.deserializer(value, key, props.options) : value;
if (filteredValue) {
result[key] = filteredValue;
}
}
};
apis.forEach((api) => {
if (typeof api.getAll === "function") {
let values;
try {
values = api.getAll();
} catch (err) {
handleError(err, `Error getting all values from in ${api.name}`);
}
for (const key of values) {
addValue(key, values[key]);
}
} else {
let index = 0, key;
try {
while (key = api.key(index++)) {
if (!result.hasOwnProperty(key)) {
addValue(key, api.getItem(key));
}
}
} catch (err) {
handleError(err, `Error getting all values from ${api.name}`);
}
}
});
return result;
};
props?.sync !== false && onMount(() => {
const listener = (ev) => {
let changed = false;
apis.forEach((api) => {
try {
if (api !== ev.storageArea && ev.key && ev.newValue !== api.getItem(ev.key)) {
ev.newValue ? api.setItem(ev.key, ev.newValue) : api.removeItem(ev.key);
changed = true;
}
} catch (err) {
handleError(
err,
`Error synching api ${api.name} from storage event (${ev.key}=${ev.newValue})`
);
}
});
changed && ev.key && signals.get(ev.key)?.[1]();
};
if ("addEventListener" in globalThis) {
globalThis.addEventListener("storage", listener);
onCleanup(() => globalThis.removeEventListener("storage", listener));
} else {
apis.forEach((api) => api.addEventListener?.("storage", listener));
onCleanup(() => apis.forEach((api) => api.removeEventListener?.("storage", listener)));
}
});
return [
store,
setter,
{
clear,
error,
remove,
toJSON
}
];
}
function createAsyncStorage(props) {
const [error, setError] = createSignal();
const handleError = props?.throw ? (err, fallback) => {
setError(err instanceof Error ? err : new Error(fallback));
throw err;
} : (err, fallback) => {
setError(err instanceof Error ? err : new Error(fallback));
};
const apis = props?.api ? Array.isArray(props.api) ? props.api : [props.api] : [];
const prefix = props?.prefix ? `${props.prefix}.` : "";
const signals = /* @__PURE__ */ new Map();
const store = new Proxy({}, {
get(_, key) {
let node = signals.get(key);
if (!node) {
node = createSignal(void 0, { equals: false });
signals.set(key, node);
}
node[0]();
return apis.reduce((result, api) => {
if (result !== null || !api) {
return result;
}
let value;
try {
value = api.getItem(`${prefix}${key}`);
} catch (err) {
handleError(err, `Error getting ${prefix}${key} from ${api.name}`);
}
if (value instanceof Promise) {
return value.then(
(newValue) => newValue && props?.deserializer ? props.deserializer(newValue, key, props.options) : newValue
);
}
return value !== null && props?.deserializer ? Promise.resolve(props.deserializer(value, key, props.options)) : Promise.resolve(value);
}, null);
}
});
const setter = (key, value, options) => {
const filteredValue = props?.serializer ? props.serializer(value, key, options ?? props.options) : value;
return Promise.all(
apis.map((api) => {
try {
api.setItem(`${prefix}${key}`, filteredValue, options ?? props?.options);
} catch (err) {
handleError(err, `Error setting ${prefix}${key} to ${filteredValue} in ${api.name}`);
}
})
).then(() => {
const node = signals.get(key);
node && node[1]();
});
};
const remove = (key) => {
Promise.all(
apis.map((api) => {
try {
api.removeItem(`${prefix}${key}`);
} catch (err) {
handleError(err, `Error removing ${prefix}${key} from ${api.name}`);
}
})
).then(() => {
const node = signals.get(key);
node && node[1]();
});
};
const clear = () => Promise.all(
apis.map(async (api) => {
let index = 0, key;
while (key = await api.key(index++)) {
try {
await api.removeItem(key);
} catch (err) {
handleError(err, `Error removing ${key} from ${api.name} during clear()`);
}
}
})
).then(() => {
return;
});
const toJSON = async () => {
const result = {};
const addValue = (key, value) => {
if (!result.hasOwnProperty(key)) {
const filteredValue = value && props?.deserializer ? props.deserializer(value, key, props.options) : value;
if (filteredValue) {
result[key] = filteredValue;
}
}
};
await Promise.all(
apis.map(async (api) => {
if (typeof api.getAll === "function") {
try {
const values = await api.getAll();
for (const key of values) {
addValue(key, values[key]);
}
} catch (err) {
handleError(err, `Error attempting to get all keys from ${api.name}`);
}
} else {
let index = 0, key;
try {
while (key = await api.key(index++)) {
addValue(key, await api.getItem(key));
}
} catch (err) {
handleError(err, `Error attempting to get all keys from ${api.name}`);
}
}
})
);
return result;
};
props?.sync !== false && onMount(() => {
const listener = (ev) => {
let changed = false;
apis.forEach(async (api) => {
try {
if (api !== ev.storageArea && ev.key && ev.newValue !== await api.getItem(ev.key)) {
ev.newValue ? api.setItem(ev.key, ev.newValue) : api.removeItem(ev.key);
changed = true;
}
} catch (err) {
handleError(err, "Error attempting to sync on event");
}
});
changed && ev.key && signals.get(ev.key)?.[1]();
};
if ("addEventListener" in globalThis) {
globalThis.addEventListener("storage", listener);
onCleanup(() => globalThis.removeEventListener("storage", listener));
} else {
apis.forEach((api) => api.addEventListener?.("storage", listener));
onCleanup(() => apis.forEach((api) => api.removeEventListener?.("storage", listener)));
}
});
return [
store,
setter,
{
remove,
clear,
error,
toJSON
}
];
}
function createStorageSignal(key, initialValue, props) {
const [error, setError] = createSignal();
const apis = props?.api ? Array.isArray(props.api) ? props.api : [props.api] : [globalThis.localStorage].filter(Boolean);
const prefix = props?.prefix ? `${props.prefix}.` : "";
const read = () => apis.reduce((result, api) => {
if (result !== null || !api) {
return result;
}
let value = null;
try {
value = api.getItem(`${prefix}${key}`);
} catch (err) {
setError(
err instanceof Error ? err : new Error(`Error reading ${prefix}${key} from ${api.name}`)
);
if (props?.throw) {
throw err;
}
}
if (value !== null && props?.deserializer) {
return props.deserializer(value + "", key, props.options);
}
return value;
}, null);
const [accessor, setter] = createHydratableSignal(
initialValue,
() => read() ?? initialValue,
props
);
createEffect(() => {
const value = accessor();
const filteredValue = props?.serializer ? props.serializer(value, key, props.options) : value + "";
const apiKey = `${prefix}${key}`;
try {
if (value === null) {
apis.forEach((api) => api.getItem(apiKey) !== null && api.removeItem(apiKey));
} else {
apis.forEach(
(api) => api.getItem(apiKey) !== filteredValue && api.setItem(apiKey, filteredValue, props?.options)
);
}
} catch (err) {
setError(
err instanceof Error ? err : new Error(`Error ${value === null ? "removing" : "writing"} value`)
);
if (props?.throw) {
throw err;
}
}
});
const refetch = () => {
const value = read();
setter(value);
};
props?.sync !== false && onMount(() => {
const listener = (ev) => {
let changed = false;
try {
apis.forEach((api) => {
if (api !== ev.storageArea && ev.key && ev.newValue !== api.getItem(ev.key)) {
ev.newValue ? api.setItem(ev.key, ev.newValue) : api.removeItem(ev.key);
changed = true;
}
});
} catch (err) {
setError(err instanceof Error ? err : new Error("Error synching api after event"));
if (props?.throw) {
throw err;
}
}
changed && refetch();
};
if ("addEventListener" in globalThis) {
globalThis.addEventListener("storage", listener);
onCleanup(() => globalThis.removeEventListener("storage", listener));
} else {
apis.forEach((api) => api.addEventListener?.("storage", listener));
onCleanup(() => apis.forEach((api) => api.removeEventListener?.("storage", listener)));
}
});
return [Object.assign(accessor, { error }), setter, refetch];
}
var createLocalStorage = createStorage;
var createSessionStorage = (props) => createStorage({ ...props, api: globalThis.sessionStorage });
// src/cookies.ts

@@ -442,2 +65,18 @@ // src/tools.ts

});
var makeObjectStorage = (object) => ({
getItem: (key) => Object.hasOwn(object, key) && object[key] || null,
setItem: (key, value) => {
object[key] = value;
},
removeItem: (key) => {
delete object[key];
},
key: (index) => Object.keys(object)[index],
get length() {
return Object.keys(object).length;
},
clear: () => Object.keys(object).forEach((key) => {
delete object[key];
})
});

@@ -455,12 +94,8 @@ // src/cookies.ts

function serializeCookieOptions(options) {
if (!options)
return "";
if (!options) return "";
const result = Object.entries(options).map(([key, value]) => {
const serializedKey = cookiePropertyMap[key];
if (!serializedKey)
return void 0;
if (value instanceof Date)
return `${serializedKey}=${value.toUTCString()}`;
if (typeof value === "boolean")
return value ? `${serializedKey}` : void 0;
if (!serializedKey) return void 0;
if (value instanceof Date) return `${serializedKey}=${value.toUTCString()}`;
if (typeof value === "boolean") return value ? `${serializedKey}` : void 0;
return `${serializedKey}=${value}`;

@@ -531,3 +166,2 @@ }).filter((v) => !!v);

);
var createCookieStorage = (props) => createStorage({ ...props, api: cookieStorage });
function makePersisted(signal, options = {}) {

@@ -548,4 +182,3 @@ const storage = options.storage || globalThis.localStorage;

} catch (e) {
if (isDev)
console.warn(e);
if (isDev) console.warn(e);
}

@@ -557,11 +190,8 @@ } : (data) => {

} catch (e) {
if (isDev)
console.warn(e);
if (isDev) console.warn(e);
}
};
let unchanged = true;
if (init instanceof Promise)
init.then((data) => unchanged && data && set(data));
else if (init)
set(init);
if (init instanceof Promise) init.then((data) => unchanged && data && set(data));
else if (init) set(init);
if (typeof options.sync?.[0] === "function") {

@@ -582,6 +212,4 @@ const get = typeof signal[0] === "function" ? signal[0] : () => signal[0];

options.sync?.[1](name, serialized);
if (value != null)
storage.setItem(name, serialized, storageOptions);
else
storage.removeItem(name, storageOptions);
if (value != null) storage.setItem(name, serialized, storageOptions);
else storage.removeItem(name, storageOptions);
unchanged = false;

@@ -620,4 +248,3 @@ return output;

} catch (e) {
if (warnOnError)
console.warn(e);
if (warnOnError) console.warn(e);
}

@@ -639,2 +266,2 @@ }),

export { addClearMethod, addWithOptionsMethod, cookieStorage, createAsyncStorage, createCookieStorage, createLocalStorage, createSessionStorage, createStorage, createStorageSignal, makePersisted, messageSync, multiplexStorage, multiplexSync, storageSync, wsSync };
export { addClearMethod, addWithOptionsMethod, cookieStorage, makeObjectStorage, makePersisted, messageSync, multiplexStorage, multiplexSync, storageSync, wsSync };

@@ -1,2 +0,4 @@

import { e as AsyncStorage } from '../types-C92rHTXK.js';
import { b as AsyncStorage } from '../persisted-7aCRLS7M.js';
import 'solid-js';
import 'solid-js/store';

@@ -3,0 +5,0 @@ /**

{
"name": "@solid-primitives/storage",
"version": "3.8.0",
"version": "4.0.0",
"description": "Primitive that provides reactive wrappers for storage access",

@@ -28,3 +28,4 @@ "author": "Alex Lohr <alex.lohr@logmein.com>",

"addClearMethod",
"addWithOptionsMethod"
"addWithOptionsMethod",
"makeObjectStorage"
],

@@ -83,4 +84,4 @@ "category": "Browser APIs"

"peerDependencies": {
"solid-js": "^1.6.12",
"@tauri-apps/plugin-store": "*"
"@tauri-apps/plugin-store": "*",
"solid-js": "^1.6.12"
},

@@ -87,0 +88,0 @@ "peerDependenciesMeta": {

@@ -32,3 +32,3 @@ <p>

// localStorage is default
storage?: Storage | StorageWithOptions | AsyncStorage | AsyncStorageWithOptions,
storage?: Storage | StorageWithOptions | AsyncStorage | AsyncStorageWithOptions | LocalForage,
// only required for storage APIs with options

@@ -103,2 +103,18 @@ storageOptions?: StorageOptions,

#### LocalForage
LocalForage uses indexedDB or WebSQL if available to greatly increase the size of what can be stored. Just drop it in as a storage (only supported in the client):
```ts
import { isServer } from "solid-js/web";
import { makePersisted } from "@solid-primtives/storage";
import localforage from "localforage";
const [state, setState] = makePersisted(createSignal(), {
storage: !isServer ? localforage : undefined,
});
```
Keep in mind that it will only run on the client, so unless you have
#### TauriStorage

@@ -148,8 +164,12 @@

#### IndexedDB, WebSQL
#### Object storage
There is also [`localForage`](https://localforage.github.io/localForage/), which uses `IndexedDB`, `WebSQL`
or `localStorage` to provide an asynchronous Storage API that can ideally store much more than the few Megabytes that
are available in most browsers.
This package also provides a way to create a storage API wrapper for an object called `makeObjectStorage(object)`. This is especially useful as a server fallback if you want to store the data in your user session or database object:
```ts
const [state, setState] = createPersisted(createSignal(), {
storage: globalThis.localStorage ?? makeObjectStorage(session.userState),
});
```
#### Multiplexed storages

@@ -256,175 +276,2 @@

---
### Deprecated primitives:
The previous implementation proved to be confusing and cumbersome for most people who just wanted to persist their
signals and stores, so they are now deprecated and will soon be removed from this package.
`createStorage` is meant to wrap any `localStorage`-like API to be as accessible as
a [Solid Store](https://www.solidjs.com/docs/latest/api#createstore). The main differences are
- that this store is persisted in whatever API is used,
- that you can only use the topmost layer of the object and
- that you have additional methods in an object as the third part of the returned tuple:
```ts
const [store, setStore, {
remove: (key: string) => void;
clear: () => void;
toJSON: () => ({[key: string]: string });
}]
= createStorage({api: sessionStorage, prefix: 'my-app'});
setStore('key', 'value');
store.key; // 'value'
```
The props object support the following parameters:
`api`
: An array of or a single `localStorage`-like storage API; default will be `localStorage` if it exists; an empty array
or no API will not throw an error, but only ever get `null` and not actually persist anything
`prefix`
: A string that will be prefixed every key inside the API on set and get operations
`serializer / deserializer`
: A set of function to filter the input and output; the `serializer` takes an arbitrary object and returns a string,
e.g. `JSON.stringify`, whereas the `deserializer` takes a string and returns the requested object again.
`options`
: For APIs that support options as third argument in the `getItem` and `setItem` method (see helper
type `StorageWithOptions<O>`), you can add options they will receive on every operation.
---
There are a number of convenience Methods primed with common storage APIs and our own version to use cookies:
```ts
createLocalStorage();
createSessionStorage();
createCookieStorage();
```
---
#### Asynchronous storage APIs
In case you have APIs that persist data on the server or via `ServiceWorker` in
a [`CookieStore`](https://wicg.github.io/cookie-store/#CookieStore), you can wrap them into an asynchronous
storage (`AsyncStorage` or `AsyncStorageWithOptions` API) and use them with `createAsyncStorage`:
```ts
type CookieStoreOptions = {
path: string;
domain: string;
expires: DOMTimeStamp;
sameSite: "None" | "Lax" | "Strict"
}
const CookieStoreAPI: AsyncStorageWithOptions<CookieStoreOptions> = {
getItem: (key) => cookieStore.get(key),
getAll: () => cookieStore.getAll(),
setItem: (key: string, value: string, options: CookieStoreOptions = {}) => cookieStore.set({
...options, name, value
}),
removeItem: (key) => cookieStore.delete(key),
clear: async () => {
const all = await cookieStore.getAll();
for (const key of all) {
await cookieStore.delete(key);
}
},
key: async (index: number) => {
const all = await cookieStore.getAll();
return Object.keys(all)[index];
}
}
)
;
const [cookies, setCookie, {
remove: (key: string) => void;
clear: () => void;
toJSON: () => ({[key: string]: string
})
;
}]
= createAsyncStorage({api: CookieStoreAPI, prefix: 'my-app', sync: false});
await setStore('key', 'value');
await store.key; // 'value'
```
It works exactly like a synchronous storage, with the exception that you have to `await` every single return value. Once
the `CookieStore` API becomes more prevalent, we will integrate support out of the box.
If you cannot use `document.cookie`, you can overwrite the entry point using the following tuple:
```ts
import {cookieStorage} from '@solid-primitives/storage';
cookieStorage._cookies = [object
:
{
[name
:
string
]:
CookieProxy
}
,
name: string
]
;
```
If you need to abstract an API yourself, you can use a getter and a setter:
```ts
const CookieAbstraction = {
get cookie() {
return myCookieJar.toString()
}
set cookie(cookie) {
const data = {};
cookie.replace(/([^=]+)=(?:([^;]+);?)/g, (_, key, value) => {
data[key] = value
});
myCookieJar.set(data);
}
}
cookieStorage._cookies = [CookieAbstraction, 'cookie'];
```
---
`createStorageSignal` is meant for those cases when you only need to conveniently access a single value instead of full
access to the storage API:
```ts
const [value, setValue] = createStorageSignal("value", { api: cookieStorage });
setValue("value");
value(); // 'value'
```
As a convenient additional method, you can also use `createCookieStorageSignal(key, initialValue, options)`.
---
### Options
The properties of your `createStorage`/`createAsyncStorage`/`createStorageSignal` props are:
- `api`: the (synchronous or
asynchronous) [Storage-like API](https://developer.mozilla.org/de/docs/Web/API/Web_Storage_API), default
is `localStorage`
- `deserializer` (optional): a `deserializer` or parser for the stored data
- `serializer` (optional): a `serializer` or string converter for the stored data
- `options` (optional): default options for the set-call of Storage-like API, if supported
- `prefix` (optional): a prefix for the Storage keys
- `sync` (optional): if set to
false, [event synchronization](https://developer.mozilla.org/en-US/docs/Web/API/StorageEvent) is disabled
## Demo

@@ -431,0 +278,0 @@

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc