@take-out/helpers 0.0.31 → 0.0.33
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/async/useAsync.native.js +1 -1
- package/dist/cjs/async/useAsyncEffect.js.map +1 -1
- package/dist/cjs/async/useLazyMount.js.map +1 -1
- package/dist/cjs/async/useLazyValue.js.map +1 -1
- package/dist/cjs/emitter.cjs +1 -1
- package/dist/cjs/emitter.js +1 -1
- package/dist/cjs/emitter.js.map +1 -1
- package/dist/cjs/emitter.native.js +1 -1
- package/dist/cjs/emitter.native.js.map +1 -1
- package/dist/cjs/index.cjs +1 -2
- package/dist/cjs/index.js +1 -2
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/index.native.js +2 -4
- package/dist/cjs/index.native.js.map +1 -1
- package/dist/cjs/react/createGlobalContext.js.map +1 -1
- package/dist/cjs/server/ensureEnv.cjs +1 -1
- package/dist/cjs/server/ensureEnv.js +1 -1
- package/dist/cjs/server/ensureEnv.js.map +1 -1
- package/dist/cjs/server/ensureEnv.native.js +1 -1
- package/dist/cjs/server/ensureEnv.native.js.map +1 -1
- package/dist/cjs/storage/createStorage.cjs +83 -0
- package/dist/cjs/storage/createStorage.js +81 -0
- package/dist/cjs/storage/createStorage.js.map +6 -0
- package/dist/cjs/storage/createStorage.native.js +118 -0
- package/dist/cjs/storage/createStorage.native.js.map +6 -0
- package/dist/cjs/storage/driver.cjs +38 -0
- package/dist/cjs/storage/driver.js +33 -0
- package/dist/cjs/storage/driver.js.map +6 -0
- package/dist/cjs/storage/driver.native.js +47 -0
- package/dist/cjs/storage/driver.native.js.map +6 -0
- package/dist/cjs/storage/index.cjs +30 -0
- package/dist/cjs/storage/index.js +24 -0
- package/dist/cjs/storage/index.js.map +6 -0
- package/dist/cjs/storage/index.native.js +32 -0
- package/dist/cjs/storage/index.native.js.map +6 -0
- package/dist/cjs/storage/types.cjs +16 -0
- package/dist/cjs/storage/types.js +14 -0
- package/dist/cjs/storage/types.js.map +6 -0
- package/dist/cjs/storage/types.native.js +15 -0
- package/dist/cjs/storage/types.native.js.map +6 -0
- package/dist/esm/async/useAsync.native.js +1 -1
- package/dist/esm/async/useAsyncEffect.js.map +1 -1
- package/dist/esm/async/useAsyncEffect.mjs.map +1 -1
- package/dist/esm/async/useAsyncEffect.native.js.map +1 -1
- package/dist/esm/async/useLazyMount.js.map +1 -1
- package/dist/esm/async/useLazyMount.mjs.map +1 -1
- package/dist/esm/async/useLazyMount.native.js.map +1 -1
- package/dist/esm/async/useLazyValue.js.map +1 -1
- package/dist/esm/async/useLazyValue.mjs.map +1 -1
- package/dist/esm/async/useLazyValue.native.js.map +1 -1
- package/dist/esm/emitter.js +1 -1
- package/dist/esm/emitter.js.map +1 -1
- package/dist/esm/emitter.mjs +1 -1
- package/dist/esm/emitter.mjs.map +1 -1
- package/dist/esm/emitter.native.js +1 -1
- package/dist/esm/emitter.native.js.map +1 -1
- package/dist/esm/index.js +1 -2
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/index.mjs +1 -2
- package/dist/esm/index.mjs.map +1 -1
- package/dist/esm/index.native.js +1 -2
- package/dist/esm/index.native.js.map +1 -1
- package/dist/esm/react/createGlobalContext.js.map +1 -1
- package/dist/esm/react/createGlobalContext.mjs.map +1 -1
- package/dist/esm/react/createGlobalContext.native.js.map +1 -1
- package/dist/esm/server/ensureEnv.js +1 -1
- package/dist/esm/server/ensureEnv.js.map +1 -1
- package/dist/esm/server/ensureEnv.mjs +1 -1
- package/dist/esm/server/ensureEnv.mjs.map +1 -1
- package/dist/esm/server/ensureEnv.native.js +1 -1
- package/dist/esm/server/ensureEnv.native.js.map +1 -1
- package/dist/esm/storage/createStorage.js +65 -0
- package/dist/esm/storage/createStorage.js.map +6 -0
- package/dist/esm/storage/createStorage.mjs +59 -0
- package/dist/esm/storage/createStorage.mjs.map +1 -0
- package/dist/esm/storage/createStorage.native.js +94 -0
- package/dist/esm/storage/createStorage.native.js.map +1 -0
- package/dist/esm/storage/driver.js +17 -0
- package/dist/esm/storage/driver.js.map +6 -0
- package/dist/esm/storage/driver.mjs +14 -0
- package/dist/esm/storage/driver.mjs.map +1 -0
- package/dist/esm/storage/driver.native.js +22 -0
- package/dist/esm/storage/driver.native.js.map +1 -0
- package/dist/esm/storage/index.js +9 -0
- package/dist/esm/storage/index.js.map +6 -0
- package/dist/esm/storage/index.mjs +4 -0
- package/dist/esm/storage/index.mjs.map +1 -0
- package/dist/esm/storage/index.native.js +4 -0
- package/dist/esm/storage/index.native.js.map +1 -0
- package/dist/esm/storage/types.js +1 -0
- package/dist/esm/storage/types.js.map +6 -0
- package/dist/esm/storage/types.mjs +2 -0
- package/dist/esm/storage/types.mjs.map +1 -0
- package/dist/esm/storage/types.native.js +2 -0
- package/dist/esm/storage/types.native.js.map +1 -0
- package/package.json +6 -6
- package/src/async/asyncContext.ts +2 -2
- package/src/async/useAsync.ts +1 -1
- package/src/async/useAsyncEffect.ts +3 -2
- package/src/async/useLazyMount.ts +3 -1
- package/src/async/useLazyValue.ts +1 -0
- package/src/emitter.tsx +8 -7
- package/src/index.ts +3 -2
- package/src/object/object.ts +1 -1
- package/src/react/createGlobalContext.ts +1 -0
- package/src/server/ensureEnv.ts +1 -1
- package/src/storage/createStorage.ts +141 -0
- package/src/storage/driver.ts +20 -0
- package/src/storage/index.ts +4 -0
- package/src/storage/types.ts +6 -0
- package/types/async/asyncContext.d.ts.map +1 -1
- package/types/async/useAsync.d.ts.map +1 -1
- package/types/async/useAsyncEffect.d.ts.map +2 -2
- package/types/async/useLazyMount.d.ts +1 -1
- package/types/async/useLazyMount.d.ts.map +2 -2
- package/types/async/useLazyValue.d.ts.map +2 -2
- package/types/emitter.d.ts.map +2 -2
- package/types/index.d.ts +2 -2
- package/types/index.d.ts.map +2 -2
- package/types/object/object.d.ts +1 -1
- package/types/object/object.d.ts.map +2 -2
- package/types/react/createGlobalContext.d.ts.map +2 -2
- package/types/server/ensureEnv.d.ts.map +1 -1
- package/types/storage/createStorage.d.ts +65 -0
- package/types/storage/createStorage.d.ts.map +18 -0
- package/types/storage/driver.d.ts +5 -0
- package/types/storage/driver.d.ts.map +13 -0
- package/types/storage/index.d.ts +6 -0
- package/types/storage/index.d.ts.map +11 -0
- package/types/storage/types.d.ts +8 -0
- package/types/storage/types.d.ts.map +14 -0
- package/src/array/fuzzy.ts +0 -39
- package/src/browser/localStorage.ts +0 -311
- package/types/ensure/catchEnsureErrors.d.ts +0 -3
- package/types/ensure/catchEnsureErrors.d.ts.map +0 -13
- package/types/ensure/ensureSingleton.d.ts +0 -7
- package/types/ensure/ensureSingleton.d.ts.map +0 -14
- package/types/files/download.d.ts +0 -4
- package/types/files/download.d.ts.map +0 -16
- package/types/global/globalContext.d.ts +0 -6
- package/types/global/globalContext.d.ts.map +0 -14
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* namespaced storage interface with JSON serialization
|
|
3
|
+
* @template K - key type (string literal union for type-safe keys)
|
|
4
|
+
* @template V - value type (automatically JSON serialized/deserialized)
|
|
5
|
+
*/
|
|
6
|
+
export interface Storage<
|
|
7
|
+
K extends string = string,
|
|
8
|
+
V = unknown
|
|
9
|
+
> {
|
|
10
|
+
/** get a JSON-parsed value by key */
|
|
11
|
+
get(key: K): V | undefined;
|
|
12
|
+
/** set a value (JSON serialized) */
|
|
13
|
+
set(key: K, value: V): void;
|
|
14
|
+
/** remove a key */
|
|
15
|
+
remove(key: K): void;
|
|
16
|
+
/** check if key exists */
|
|
17
|
+
has(key: K): boolean;
|
|
18
|
+
/** get all keys in this namespace */
|
|
19
|
+
keys(): K[];
|
|
20
|
+
/** remove all keys in this namespace */
|
|
21
|
+
clear(): void;
|
|
22
|
+
/** get raw string value (no JSON parsing) - localStorage compatible */
|
|
23
|
+
getItem(key: K): string | null;
|
|
24
|
+
/** set raw string value (no JSON serialization) - localStorage compatible */
|
|
25
|
+
setItem(key: K, value: string): void;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* create a namespaced storage instance
|
|
29
|
+
* @param namespace - unique prefix for all keys (throws if already used)
|
|
30
|
+
* @returns storage instance with get/set (JSON) and getItem/setItem (raw) methods
|
|
31
|
+
* @example
|
|
32
|
+
* const store = createStorage<'token' | 'user', string>('auth')
|
|
33
|
+
* store.set('token', 'abc123')
|
|
34
|
+
* store.get('token') // 'abc123'
|
|
35
|
+
*/
|
|
36
|
+
export declare function createStorage<
|
|
37
|
+
K extends string,
|
|
38
|
+
V
|
|
39
|
+
>(namespace: string): Storage<K, V>;
|
|
40
|
+
/**
|
|
41
|
+
* single-value storage interface
|
|
42
|
+
* @template T - value type (automatically JSON serialized/deserialized)
|
|
43
|
+
*/
|
|
44
|
+
export interface StorageValue<T> {
|
|
45
|
+
/** get the stored value */
|
|
46
|
+
get(): T | undefined;
|
|
47
|
+
/** set the value */
|
|
48
|
+
set(value: T): void;
|
|
49
|
+
/** remove the value */
|
|
50
|
+
remove(): void;
|
|
51
|
+
/** check if value exists */
|
|
52
|
+
has(): boolean;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* create a single-value storage (wrapper around createStorage)
|
|
56
|
+
* @param key - unique storage key
|
|
57
|
+
* @returns storage value instance
|
|
58
|
+
* @example
|
|
59
|
+
* const token = createStorageValue<string>('auth-token')
|
|
60
|
+
* token.set('abc123')
|
|
61
|
+
* token.get() // 'abc123'
|
|
62
|
+
*/
|
|
63
|
+
export declare function createStorageValue<T>(key: string): StorageValue<T>;
|
|
64
|
+
|
|
65
|
+
//# sourceMappingURL=createStorage.d.ts.map
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"mappings": ";;;;;AASA,iBAAiB;CAAQ;CAA2B;EAAa;;CAE/D,IAAIA,KAAK,IAAI;;CAEb,IAAIA,KAAK,GAAGC,OAAO;;CAEnB,OAAOD,KAAK;;CAEZ,IAAIA,KAAK;;CAET,QAAQ;;CAER;;CAEA,QAAQA,KAAK;;CAEb,QAAQA,KAAK,GAAGE;AACjB;;;;;;;;;;AAWD,OAAO,iBAAS;CAAc;CAAkB;EAAGC,oBAAoB,QAAQ,GAAG;;;;;AA2ElF,iBAAiB,aAAa,GAAG;;CAE/B,OAAO;;CAEP,IAAIC,OAAO;;CAEX;;CAEA;AACD;;;;;;;;;;AAWD,OAAO,iBAAS,mBAAmB,GAAGC,cAAc,aAAa",
|
|
3
|
+
"names": [
|
|
4
|
+
"key: K",
|
|
5
|
+
"value: V",
|
|
6
|
+
"value: string",
|
|
7
|
+
"namespace: string",
|
|
8
|
+
"value: T",
|
|
9
|
+
"key: string"
|
|
10
|
+
],
|
|
11
|
+
"sources": [
|
|
12
|
+
"src/storage/createStorage.ts"
|
|
13
|
+
],
|
|
14
|
+
"sourcesContent": [
|
|
15
|
+
"import { getStorageDriver } from './driver'\n\nconst namespaces = new Set<string>()\n\n/**\n * namespaced storage interface with JSON serialization\n * @template K - key type (string literal union for type-safe keys)\n * @template V - value type (automatically JSON serialized/deserialized)\n */\nexport interface Storage<K extends string = string, V = unknown> {\n /** get a JSON-parsed value by key */\n get(key: K): V | undefined\n /** set a value (JSON serialized) */\n set(key: K, value: V): void\n /** remove a key */\n remove(key: K): void\n /** check if key exists */\n has(key: K): boolean\n /** get all keys in this namespace */\n keys(): K[]\n /** remove all keys in this namespace */\n clear(): void\n /** get raw string value (no JSON parsing) - localStorage compatible */\n getItem(key: K): string | null\n /** set raw string value (no JSON serialization) - localStorage compatible */\n setItem(key: K, value: string): void\n}\n\n/**\n * create a namespaced storage instance\n * @param namespace - unique prefix for all keys (throws if already used)\n * @returns storage instance with get/set (JSON) and getItem/setItem (raw) methods\n * @example\n * const store = createStorage<'token' | 'user', string>('auth')\n * store.set('token', 'abc123')\n * store.get('token') // 'abc123'\n */\nexport function createStorage<K extends string, V>(namespace: string): Storage<K, V> {\n if (namespaces.has(namespace)) {\n throw new Error(`storage namespace already exists: ${namespace}`)\n }\n namespaces.add(namespace)\n\n const prefix = `${namespace}:`\n const prefixKey = (key: string) => `${prefix}${key}`\n\n return {\n get(key: K): V | undefined {\n const driver = getStorageDriver()\n if (!driver) return undefined\n const raw = driver.getItem(prefixKey(key))\n if (raw == null) return undefined\n try {\n return JSON.parse(raw)\n } catch {\n return undefined\n }\n },\n\n set(key: K, value: V): void {\n const driver = getStorageDriver()\n if (!driver) return\n driver.setItem(prefixKey(key), JSON.stringify(value))\n },\n\n remove(key: K): void {\n const driver = getStorageDriver()\n if (!driver) return\n driver.removeItem(prefixKey(key))\n },\n\n has(key: K): boolean {\n const driver = getStorageDriver()\n if (!driver) return false\n return driver.getItem(prefixKey(key)) != null\n },\n\n keys(): K[] {\n const driver = getStorageDriver()\n if (!driver) return []\n return driver\n .getAllKeys()\n .filter((k) => k.startsWith(prefix))\n .map((k) => k.slice(prefix.length) as K)\n },\n\n clear(): void {\n const driver = getStorageDriver()\n if (!driver) return\n for (const key of this.keys()) {\n driver.removeItem(prefixKey(key))\n }\n },\n\n getItem(key: K): string | null {\n const driver = getStorageDriver()\n if (!driver) return null\n return driver.getItem(prefixKey(key)) ?? null\n },\n\n setItem(key: K, value: string): void {\n const driver = getStorageDriver()\n if (!driver) return\n driver.setItem(prefixKey(key), value)\n },\n }\n}\n\n/**\n * single-value storage interface\n * @template T - value type (automatically JSON serialized/deserialized)\n */\nexport interface StorageValue<T> {\n /** get the stored value */\n get(): T | undefined\n /** set the value */\n set(value: T): void\n /** remove the value */\n remove(): void\n /** check if value exists */\n has(): boolean\n}\n\n/**\n * create a single-value storage (wrapper around createStorage)\n * @param key - unique storage key\n * @returns storage value instance\n * @example\n * const token = createStorageValue<string>('auth-token')\n * token.set('abc123')\n * token.get() // 'abc123'\n */\nexport function createStorageValue<T>(key: string): StorageValue<T> {\n const storage = createStorage<'value', T>(`_v:${key}`)\n return {\n get: (): T | undefined => storage.get('value'),\n set: (value: T): void => storage.set('value', value),\n remove: (): void => storage.remove('value'),\n has: (): boolean => storage.has('value'),\n }\n}\n"
|
|
16
|
+
],
|
|
17
|
+
"version": 3
|
|
18
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
{
|
|
2
|
+
"mappings": "AAAA,cAAc,qBAAqB,SAAS;AAI5C,OAAO,iBAAS,iBAAiBA,GAAG;AAIpC,OAAO,iBAAS,oBAAoB",
|
|
3
|
+
"names": [
|
|
4
|
+
"d: StorageDriver"
|
|
5
|
+
],
|
|
6
|
+
"sources": [
|
|
7
|
+
"src/storage/driver.ts"
|
|
8
|
+
],
|
|
9
|
+
"sourcesContent": [
|
|
10
|
+
"import type { StorageDriver } from './types'\n\nlet driver: StorageDriver | null = null\n\nexport function setStorageDriver(d: StorageDriver): void {\n driver = d\n}\n\nexport function getStorageDriver(): StorageDriver | null {\n if (driver) return driver\n if (typeof localStorage !== 'undefined') {\n return {\n getItem: (key) => localStorage.getItem(key),\n setItem: (key, value) => localStorage.setItem(key, value),\n removeItem: (key) => localStorage.removeItem(key),\n getAllKeys: () => Object.keys(localStorage),\n }\n }\n return null\n}\n"
|
|
11
|
+
],
|
|
12
|
+
"version": 3
|
|
13
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { createStorage, createStorageValue } from "./createStorage";
|
|
2
|
+
export type { Storage, StorageValue } from "./createStorage";
|
|
3
|
+
export { getStorageDriver, setStorageDriver } from "./driver";
|
|
4
|
+
export type { StorageDriver } from "./types";
|
|
5
|
+
|
|
6
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
{
|
|
2
|
+
"mappings": "AAAA,SAAS,eAAe,0BAA0B;AAClD,cAAc,SAAS,oBAAoB;AAC3C,SAAS,kBAAkB,wBAAwB;AACnD,cAAc,qBAAqB",
|
|
3
|
+
"names": [],
|
|
4
|
+
"sources": [
|
|
5
|
+
"src/storage/index.ts"
|
|
6
|
+
],
|
|
7
|
+
"sourcesContent": [
|
|
8
|
+
"export { createStorage, createStorageValue } from './createStorage'\nexport type { Storage, StorageValue } from './createStorage'\nexport { getStorageDriver, setStorageDriver } from './driver'\nexport type { StorageDriver } from './types'\n"
|
|
9
|
+
],
|
|
10
|
+
"version": 3
|
|
11
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"mappings": "AAAA,iBAAiB,cAAc;CAC7B,QAAQA;CACR,QAAQA,aAAaC;CACrB,WAAWD;CACX;AACD",
|
|
3
|
+
"names": [
|
|
4
|
+
"key: string",
|
|
5
|
+
"value: string"
|
|
6
|
+
],
|
|
7
|
+
"sources": [
|
|
8
|
+
"src/storage/types.ts"
|
|
9
|
+
],
|
|
10
|
+
"sourcesContent": [
|
|
11
|
+
"export interface StorageDriver {\n getItem(key: string): string | null | undefined\n setItem(key: string, value: string): void\n removeItem(key: string): void\n getAllKeys(): string[]\n}\n"
|
|
12
|
+
],
|
|
13
|
+
"version": 3
|
|
14
|
+
}
|
package/src/array/fuzzy.ts
DELETED
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
import Fuse, { type FuseSearchOptions, type IFuseOptions } from 'fuse.js'
|
|
2
|
-
|
|
3
|
-
export type FuzzyOptions = IFuseOptions<unknown>
|
|
4
|
-
|
|
5
|
-
// fuse does some insane staleness in getFn that doesn't make sense so pulled it all the way out here
|
|
6
|
-
let lastSearch = ''
|
|
7
|
-
|
|
8
|
-
export function createFuzzy<
|
|
9
|
-
A extends Record<string, any>,
|
|
10
|
-
Results extends A[] | readonly A[],
|
|
11
|
-
>(
|
|
12
|
-
items: Results,
|
|
13
|
-
options?: IFuseOptions<A>
|
|
14
|
-
): {
|
|
15
|
-
search: (val: string, options?: FuseSearchOptions) => Results
|
|
16
|
-
} {
|
|
17
|
-
const fuse = new Fuse(items, {
|
|
18
|
-
isCaseSensitive: false,
|
|
19
|
-
threshold: 0.5,
|
|
20
|
-
...options,
|
|
21
|
-
getFn(obj, path, ...rest) {
|
|
22
|
-
if (obj.skipFuzzy) {
|
|
23
|
-
return lastSearch
|
|
24
|
-
}
|
|
25
|
-
return Fuse.config.getFn(obj, path)
|
|
26
|
-
},
|
|
27
|
-
})
|
|
28
|
-
|
|
29
|
-
return {
|
|
30
|
-
search: (val: string, options?: FuseSearchOptions): Results => {
|
|
31
|
-
if (!val) {
|
|
32
|
-
return items
|
|
33
|
-
}
|
|
34
|
-
lastSearch = val
|
|
35
|
-
const results = fuse.search(val, options).map((result) => result.item)
|
|
36
|
-
return results as Results
|
|
37
|
-
},
|
|
38
|
-
}
|
|
39
|
-
}
|
|
@@ -1,311 +0,0 @@
|
|
|
1
|
-
const created = new Set<string>()
|
|
2
|
-
|
|
3
|
-
const STORAGE_TRACKING_KEY = '__localStorage_tracking__'
|
|
4
|
-
const STORAGE_ORDER_KEY = '__localStorage_order__'
|
|
5
|
-
|
|
6
|
-
interface StorageTracking {
|
|
7
|
-
[key: string]: number // key -> size in bytes
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
interface LocalStorageOptions {
|
|
11
|
-
synced?: boolean
|
|
12
|
-
disableSetOnBlur?: boolean
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* Limit in kB
|
|
16
|
-
*/
|
|
17
|
-
storageLimit?: number
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
export function createLocalStorage<K extends string, V>(
|
|
21
|
-
name: string,
|
|
22
|
-
{ synced = false, disableSetOnBlur = false, storageLimit }: LocalStorageOptions = {}
|
|
23
|
-
) {
|
|
24
|
-
if (created.has(name)) {
|
|
25
|
-
throw new Error(`Already defined this localStorage namespace: ${name}`)
|
|
26
|
-
}
|
|
27
|
-
created.add(name)
|
|
28
|
-
|
|
29
|
-
let isWindowActive = true
|
|
30
|
-
if (typeof window !== 'undefined' && disableSetOnBlur) {
|
|
31
|
-
const handleFocus = () => {
|
|
32
|
-
isWindowActive = true
|
|
33
|
-
}
|
|
34
|
-
const handleBlur = () => {
|
|
35
|
-
isWindowActive = false
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
window.addEventListener('focus', handleFocus)
|
|
39
|
-
window.addEventListener('blur', handleBlur)
|
|
40
|
-
|
|
41
|
-
isWindowActive = document.hasFocus()
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
const listeners = new Map<string, Set<(value: any) => void>>()
|
|
45
|
-
|
|
46
|
-
if (synced && typeof window !== 'undefined') {
|
|
47
|
-
const handleStorageChange = (event: StorageEvent) => {
|
|
48
|
-
if (event.key?.startsWith(`${name}:`) && event.storageArea === localStorage) {
|
|
49
|
-
const key = event.key.slice(name.length + 1)
|
|
50
|
-
const newValue = event.newValue ? JSON.parse(event.newValue) : undefined
|
|
51
|
-
const keyListeners = listeners.get(key)
|
|
52
|
-
if (keyListeners) {
|
|
53
|
-
keyListeners.forEach((listener) => listener(newValue))
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
window.addEventListener('storage', handleStorageChange)
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
const getFullKey = (key: string) => `${name}:${key}`
|
|
62
|
-
|
|
63
|
-
return {
|
|
64
|
-
get: (key: K): V | undefined => {
|
|
65
|
-
if (typeof localStorage === 'undefined') {
|
|
66
|
-
console.warn(`No localStorage`)
|
|
67
|
-
return
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
const fullKey = getFullKey(key)
|
|
71
|
-
const item = localStorage.getItem(fullKey)
|
|
72
|
-
if (item && storageLimit) {
|
|
73
|
-
updateKeyAccess(fullKey)
|
|
74
|
-
}
|
|
75
|
-
return item ? JSON.parse(item) : undefined
|
|
76
|
-
},
|
|
77
|
-
|
|
78
|
-
set: (key: K, value: V): void => {
|
|
79
|
-
if (typeof localStorage === 'undefined') {
|
|
80
|
-
console.warn(`No localStorage`)
|
|
81
|
-
return
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
if (disableSetOnBlur && !isWindowActive) {
|
|
85
|
-
return
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
const fullKey = getFullKey(key)
|
|
89
|
-
const serializedValue = JSON.stringify(value)
|
|
90
|
-
|
|
91
|
-
if (storageLimit) {
|
|
92
|
-
const newSize = getStringSizeInBytes(serializedValue)
|
|
93
|
-
enforceStorageLimit(fullKey, newSize, storageLimit)
|
|
94
|
-
const tracking = getStorageTracking()
|
|
95
|
-
tracking[fullKey] = newSize
|
|
96
|
-
setStorageTracking(tracking)
|
|
97
|
-
updateKeyAccess(fullKey)
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
localStorage.setItem(fullKey, serializedValue)
|
|
101
|
-
},
|
|
102
|
-
|
|
103
|
-
remove: (key: K): void => {
|
|
104
|
-
if (typeof localStorage === 'undefined') {
|
|
105
|
-
console.warn(`No localStorage`)
|
|
106
|
-
return
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
// don't remove if window is not active and disablesetonblur is true
|
|
110
|
-
if (disableSetOnBlur && !isWindowActive) {
|
|
111
|
-
return
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
const fullKey = getFullKey(key)
|
|
115
|
-
localStorage.removeItem(fullKey)
|
|
116
|
-
|
|
117
|
-
// clean up tracking data if storage limit is enabled
|
|
118
|
-
if (storageLimit) {
|
|
119
|
-
const tracking = getStorageTracking()
|
|
120
|
-
delete tracking[fullKey]
|
|
121
|
-
setStorageTracking(tracking)
|
|
122
|
-
|
|
123
|
-
const order = getStorageOrder()
|
|
124
|
-
const index = order.indexOf(fullKey)
|
|
125
|
-
if (index > -1) {
|
|
126
|
-
order.splice(index, 1)
|
|
127
|
-
setStorageOrder(order)
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
},
|
|
131
|
-
|
|
132
|
-
exists: (key: K): boolean => {
|
|
133
|
-
const fullKey = getFullKey(key)
|
|
134
|
-
return localStorage.getItem(fullKey) != null
|
|
135
|
-
},
|
|
136
|
-
|
|
137
|
-
clear: (): void => {
|
|
138
|
-
if (typeof localStorage === 'undefined') {
|
|
139
|
-
console.warn(`No localStorage`)
|
|
140
|
-
return
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
// Remove all keys with this namespace
|
|
144
|
-
const keysToRemove: string[] = []
|
|
145
|
-
for (let i = 0; i < localStorage.length; i++) {
|
|
146
|
-
const key = localStorage.key(i)
|
|
147
|
-
if (key?.startsWith(`${name}:`)) {
|
|
148
|
-
keysToRemove.push(key)
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
keysToRemove.forEach((key) => localStorage.removeItem(key))
|
|
153
|
-
|
|
154
|
-
// Clean up tracking data
|
|
155
|
-
if (storageLimit) {
|
|
156
|
-
const tracking = getStorageTracking()
|
|
157
|
-
const order = getStorageOrder()
|
|
158
|
-
|
|
159
|
-
keysToRemove.forEach((key) => {
|
|
160
|
-
delete tracking[key]
|
|
161
|
-
const index = order.indexOf(key)
|
|
162
|
-
if (index > -1) {
|
|
163
|
-
order.splice(index, 1)
|
|
164
|
-
}
|
|
165
|
-
})
|
|
166
|
-
|
|
167
|
-
setStorageTracking(tracking)
|
|
168
|
-
setStorageOrder(order)
|
|
169
|
-
}
|
|
170
|
-
},
|
|
171
|
-
|
|
172
|
-
subscribe: (key: string, listener: (value: V | undefined) => void): (() => void) => {
|
|
173
|
-
if (!synced) {
|
|
174
|
-
console.warn(`Subscribe only works when synced option is enabled`)
|
|
175
|
-
return () => {}
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
if (!listeners.has(key)) {
|
|
179
|
-
listeners.set(key, new Set())
|
|
180
|
-
}
|
|
181
|
-
const keyListeners = listeners.get(key)!
|
|
182
|
-
keyListeners.add(listener)
|
|
183
|
-
|
|
184
|
-
return () => {
|
|
185
|
-
keyListeners.delete(listener)
|
|
186
|
-
if (keyListeners.size === 0) {
|
|
187
|
-
listeners.delete(key)
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
},
|
|
191
|
-
|
|
192
|
-
keys: (): string[] => {
|
|
193
|
-
if (typeof localStorage === 'undefined') {
|
|
194
|
-
return []
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
const keys: string[] = []
|
|
198
|
-
const prefix = `${name}:`
|
|
199
|
-
|
|
200
|
-
for (let i = 0; i < localStorage.length; i++) {
|
|
201
|
-
const key = localStorage.key(i)
|
|
202
|
-
if (key?.startsWith(prefix)) {
|
|
203
|
-
keys.push(key.slice(prefix.length))
|
|
204
|
-
}
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
return keys
|
|
208
|
-
},
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
export function createLocalStorageValue<T>(
|
|
213
|
-
key: string,
|
|
214
|
-
options: LocalStorageOptions = {}
|
|
215
|
-
) {
|
|
216
|
-
const storage = createLocalStorage<string, T>(`single:${key}`, options)
|
|
217
|
-
const storageKey = 'value'
|
|
218
|
-
|
|
219
|
-
return {
|
|
220
|
-
get: (): T | undefined => {
|
|
221
|
-
return storage.get(storageKey)
|
|
222
|
-
},
|
|
223
|
-
|
|
224
|
-
set: (value: T): void => {
|
|
225
|
-
storage.set(storageKey, value)
|
|
226
|
-
},
|
|
227
|
-
|
|
228
|
-
remove: (): void => {
|
|
229
|
-
storage.remove(storageKey)
|
|
230
|
-
},
|
|
231
|
-
|
|
232
|
-
exists: (): boolean => {
|
|
233
|
-
return storage.exists(storageKey)
|
|
234
|
-
},
|
|
235
|
-
|
|
236
|
-
clear: (): void => {
|
|
237
|
-
storage.clear()
|
|
238
|
-
},
|
|
239
|
-
|
|
240
|
-
subscribe: (listener: (value: T | undefined) => void): (() => void) => {
|
|
241
|
-
return storage.subscribe(storageKey, listener)
|
|
242
|
-
},
|
|
243
|
-
}
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
function getStorageTracking(): StorageTracking {
|
|
247
|
-
if (typeof localStorage === 'undefined') return {}
|
|
248
|
-
const tracking = localStorage.getItem(STORAGE_TRACKING_KEY)
|
|
249
|
-
return tracking ? JSON.parse(tracking) : {}
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
function setStorageTracking(tracking: StorageTracking): void {
|
|
253
|
-
if (typeof localStorage === 'undefined') return
|
|
254
|
-
localStorage.setItem(STORAGE_TRACKING_KEY, JSON.stringify(tracking))
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
function getStorageOrder(): string[] {
|
|
258
|
-
if (typeof localStorage === 'undefined') return []
|
|
259
|
-
const order = localStorage.getItem(STORAGE_ORDER_KEY)
|
|
260
|
-
return order ? JSON.parse(order) : []
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
function setStorageOrder(order: string[]): void {
|
|
264
|
-
if (typeof localStorage === 'undefined') return
|
|
265
|
-
localStorage.setItem(STORAGE_ORDER_KEY, JSON.stringify(order))
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
function getStringSizeInBytes(str: string): number {
|
|
269
|
-
return new Blob([str]).size
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
function updateKeyAccess(key: string): void {
|
|
273
|
-
const order = getStorageOrder()
|
|
274
|
-
const index = order.indexOf(key)
|
|
275
|
-
if (index > -1) {
|
|
276
|
-
order.splice(index, 1)
|
|
277
|
-
}
|
|
278
|
-
order.push(key) // move to end (most recent)
|
|
279
|
-
setStorageOrder(order)
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
function enforceStorageLimit(newKey: string, newSize: number, limitKB: number): void {
|
|
283
|
-
const tracking = getStorageTracking()
|
|
284
|
-
const order = getStorageOrder()
|
|
285
|
-
|
|
286
|
-
let totalSize = Object.values(tracking).reduce((sum, size) => sum + size, 0)
|
|
287
|
-
totalSize += newSize // add the new item size
|
|
288
|
-
|
|
289
|
-
const limitBytes = limitKB * 1024
|
|
290
|
-
|
|
291
|
-
while (totalSize > limitBytes && order.length > 0) {
|
|
292
|
-
const oldestKey = order.shift()!
|
|
293
|
-
|
|
294
|
-
if (
|
|
295
|
-
oldestKey === newKey ||
|
|
296
|
-
oldestKey === STORAGE_TRACKING_KEY ||
|
|
297
|
-
oldestKey === STORAGE_ORDER_KEY
|
|
298
|
-
) {
|
|
299
|
-
continue
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
const oldSize = tracking[oldestKey] || 0
|
|
303
|
-
totalSize -= oldSize
|
|
304
|
-
|
|
305
|
-
localStorage.removeItem(oldestKey)
|
|
306
|
-
delete tracking[oldestKey]
|
|
307
|
-
}
|
|
308
|
-
|
|
309
|
-
setStorageTracking(tracking)
|
|
310
|
-
setStorageOrder(order)
|
|
311
|
-
}
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"mappings": "AAEA,OAAO,iBAAS,kBAAkB,UAAU,UAAUA,IAAI,IAAI",
|
|
3
|
-
"names": [
|
|
4
|
-
"fn: T"
|
|
5
|
-
],
|
|
6
|
-
"sources": [
|
|
7
|
-
"src/ensure/catchEnsureErrors.ts"
|
|
8
|
-
],
|
|
9
|
-
"sourcesContent": [
|
|
10
|
-
"import { EnsureError } from '../error/errors'\n\nexport function catchEnsureErrors<T extends Function>(fn: T): T {\n return ((...args: any[]) => {\n try {\n return fn(...args)\n } catch (error) {\n if (error instanceof EnsureError) {\n console.error(`EnsureError: ${error.message}`)\n return\n }\n throw error\n }\n }) as unknown as T\n}\n"
|
|
11
|
-
],
|
|
12
|
-
"version": 3
|
|
13
|
-
}
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
// Ensures a singleton value is stored on `globalThis` using a symbol key.
|
|
2
|
-
// This creates a stable singleton that survives hot-reloads during development.
|
|
3
|
-
// We store values on globalThis using `Symbol.for` keys to avoid collisions
|
|
4
|
-
// across independently bundled modules.
|
|
5
|
-
export declare function ensureSingleton<T>(key: string, factory: () => T): T;
|
|
6
|
-
|
|
7
|
-
//# sourceMappingURL=ensureSingleton.d.ts.map
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"mappings": ";;;;AAMA,OAAO,iBAAS,gBAAgB,GAAGA,aAAaC,eAAe,IAAI",
|
|
3
|
-
"names": [
|
|
4
|
-
"key: string",
|
|
5
|
-
"factory: () => T"
|
|
6
|
-
],
|
|
7
|
-
"sources": [
|
|
8
|
-
"src/ensure/ensureSingleton.ts"
|
|
9
|
-
],
|
|
10
|
-
"sourcesContent": [
|
|
11
|
-
"// Ensures a singleton value is stored on `globalThis` using a symbol key.\n// This creates a stable singleton that survives hot-reloads during development.\n\n// We store values on globalThis using `Symbol.for` keys to avoid collisions\n// across independently bundled modules.\n\nexport function ensureSingleton<T>(key: string, factory: () => T): T {\n const symbolKey = Symbol.for(key)\n const g = globalThis as Record<symbol, unknown>\n\n if (!g[symbolKey]) {\n g[symbolKey] = factory()\n }\n\n return g[symbolKey] as T\n}\n"
|
|
12
|
-
],
|
|
13
|
-
"version": 3
|
|
14
|
-
}
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"mappings": "AAuCA,OAAO,iBAAe,aACpBA,cACAC,kBACA;AAYF,OAAO,iBAAe,gBAAgBC,aAAaC",
|
|
3
|
-
"names": [
|
|
4
|
-
"data: string",
|
|
5
|
-
"filename: string",
|
|
6
|
-
"url: string",
|
|
7
|
-
"filename?: string"
|
|
8
|
-
],
|
|
9
|
-
"sources": [
|
|
10
|
-
"src/files/download.ts"
|
|
11
|
-
],
|
|
12
|
-
"sourcesContent": [
|
|
13
|
-
"import { isTauri } from '../constants'\n\nasync function saveInTauri(data: string | Blob, filename: string) {\n // @ts-ignore - tauri plugins only available in tauri environment\n const { save } = await import('@tauri-apps/plugin-dialog')\n // @ts-ignore - tauri plugins only available in tauri environment\n const { writeTextFile, writeBinaryFile } = await import('@tauri-apps/plugin-fs')\n\n const extension = filename.split('.').pop() || ''\n const filePath = await save({\n defaultPath: filename,\n filters: [\n {\n name: `${extension.toUpperCase()} files`,\n extensions: [extension],\n },\n ],\n })\n\n if (filePath) {\n if (typeof data === 'string') {\n await writeTextFile(filePath, data)\n } else {\n const arrayBuffer = await data.arrayBuffer()\n await writeBinaryFile(filePath, new Uint8Array(arrayBuffer))\n }\n }\n}\n\nfunction downloadInBrowser(url: string, filename: string) {\n const a = document.createElement('a')\n a.href = url\n a.download = filename\n a.target = '_blank'\n document.body.appendChild(a)\n a.click()\n document.body.removeChild(a)\n}\n\nexport async function downloadFile(\n data: string,\n filename: string,\n mimeType = 'application/json'\n) {\n if (isTauri) {\n await saveInTauri(data, filename)\n } else {\n const blob = new Blob([data], { type: mimeType })\n const url = URL.createObjectURL(blob)\n downloadInBrowser(url, filename)\n URL.revokeObjectURL(url)\n }\n}\n\nexport async function downloadFromUrl(url: string, filename?: string) {\n const resolvedFilename = filename || url.split('/').pop() || 'download'\n\n if (isTauri) {\n try {\n const response = await fetch(url)\n const blob = await response.blob()\n await saveInTauri(blob, resolvedFilename)\n } catch (error) {\n console.error('Failed to download file:', error)\n downloadInBrowser(url, resolvedFilename)\n }\n } else {\n downloadInBrowser(url, resolvedFilename)\n }\n}\n"
|
|
14
|
-
],
|
|
15
|
-
"version": 3
|
|
16
|
-
}
|
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
import { type Context } from "react";
|
|
2
|
-
// create or retrieve a React context that is stored on `globalThis`.
|
|
3
|
-
// this ensures a stable singleton that survives hot-reloads during development.
|
|
4
|
-
export declare function createGlobalContext<T>(key: string, defaultValue: T): Context<T>;
|
|
5
|
-
|
|
6
|
-
//# sourceMappingURL=globalContext.d.ts.map
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"mappings": "AAAA,cAAc,eAA8B,OAAO;;;AAMnD,OAAO,iBAAS,oBAAoB,GAAGA,aAAaC,cAAc,IAAI,QAAQ",
|
|
3
|
-
"names": [
|
|
4
|
-
"key: string",
|
|
5
|
-
"defaultValue: T"
|
|
6
|
-
],
|
|
7
|
-
"sources": [
|
|
8
|
-
"src/global/globalContext.ts"
|
|
9
|
-
],
|
|
10
|
-
"sourcesContent": [
|
|
11
|
-
"import { type Context, createContext } from 'react'\nimport { ensureSingleton } from '../ensure/ensureSingleton'\n\n// create or retrieve a React context that is stored on `globalThis`.\n// this ensures a stable singleton that survives hot-reloads during development.\n\nexport function createGlobalContext<T>(key: string, defaultValue: T): Context<T> {\n return ensureSingleton(key, () => createContext<T>(defaultValue))\n}\n"
|
|
12
|
-
],
|
|
13
|
-
"version": 3
|
|
14
|
-
}
|