@nemigo/storage 1.5.0 → 1.7.0

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.
@@ -0,0 +1,12 @@
1
+ import { RuntimeStorage } from "./runtime.js";
2
+ import type { IStorageSetOptions } from "./types.js";
3
+ export interface ConstructCapacityStorage {
4
+ capacity: number;
5
+ ttl_seconds?: number;
6
+ }
7
+ export declare class CapacityStorage extends RuntimeStorage {
8
+ capacity: number;
9
+ constructor({ capacity, ttl_seconds }: ConstructCapacityStorage);
10
+ get<T = any>(key: string): T | undefined;
11
+ set(key: string, value: any, options?: IStorageSetOptions): void;
12
+ }
@@ -0,0 +1,39 @@
1
+ import { RuntimeStorage } from "./runtime.js";
2
+ export class CapacityStorage extends RuntimeStorage {
3
+ capacity;
4
+ constructor({ capacity, ttl_seconds }) {
5
+ super(ttl_seconds);
6
+ this.capacity = capacity;
7
+ }
8
+ get(key) {
9
+ const entry = super.__get(key);
10
+ if (!entry)
11
+ return;
12
+ // Обновляем порядок использования, чтобы сохранить от LRU-удаления
13
+ this.__storage.delete(key);
14
+ this.__storage.set(key, entry);
15
+ return entry.value;
16
+ }
17
+ set(key, value, options) {
18
+ this.__storage.delete(key);
19
+ if (this.__storage.size >= this.capacity) {
20
+ // Удаляем устаревшие элементы
21
+ for (const existingKey of this.__storage.keys()) {
22
+ const entry = this.__storage.get(existingKey);
23
+ if (!entry || this.__isExpired(entry)) {
24
+ this.__storage.delete(existingKey);
25
+ }
26
+ if (this.__storage.size < this.capacity)
27
+ break;
28
+ }
29
+ // Если всё ещё переполнен — удаляем LRU
30
+ if (this.__storage.size >= this.capacity) {
31
+ const firstKey = this.__storage.keys().next().value;
32
+ if (firstKey !== undefined) {
33
+ this.__storage.delete(firstKey);
34
+ }
35
+ }
36
+ }
37
+ super.set(key, value, options);
38
+ }
39
+ }
package/dist/cookie.d.ts CHANGED
@@ -1,48 +1,42 @@
1
- import { VeilPrefixStorage } from "./internal/veil.js";
2
- import type { IStorage, IStorageValue, SetIStorageOptions } from "./types.js";
1
+ import type { ConstructVeilPrefixStorage } from "./internal/veil-prefix.js";
2
+ import { VeilPrefixStorage } from "./internal/veil-prefix.js";
3
+ import type { IStorage, IStorageValue, IStorageSetOptions } from "./types.js";
3
4
  import type { SetDocumentCookieOptions } from "@nemigo/helpers/html/cookie";
4
- /**
5
- * Серверные readonly-куки для {@link CookieStorage}
6
- */
7
- export interface ServerCookie {
8
- name: string;
9
- value: string;
10
- }
11
5
  /**
12
6
  * Опции для {@link CookieStorage.set}
13
7
  */
14
- export interface SetCookieStorageOptions extends SetDocumentCookieOptions, SetIStorageOptions {
8
+ export interface CookieStorageSetOptions extends SetDocumentCookieOptions, IStorageSetOptions {
15
9
  prefix?: string;
16
10
  }
17
11
  /**
18
12
  * Опции для {@link CookieStorage.delete}
19
13
  */
20
- export interface DeleteCookieStorageOptions {
14
+ export interface CookieStorageDeleteOptions {
21
15
  Path?: string;
22
16
  prefix?: string;
23
17
  }
24
- export declare class CookieStorage extends VeilPrefixStorage implements IStorage {
18
+ /**
19
+ * Серверные readonly-куки для {@link CookieStorage}
20
+ */
21
+ export interface ServerCookie {
22
+ name: string;
23
+ value: string;
24
+ }
25
+ export interface ConstructCookieStorage extends ConstructVeilPrefixStorage {
26
+ cookies?: ServerCookie[];
27
+ }
28
+ export declare class CookieStorage extends VeilPrefixStorage implements IStorage<void> {
25
29
  __server: Map<string, string>;
26
- /**
27
- * TTL (time-to-live) хранилища
28
- */
29
- ttl_seconds?: number | null;
30
- /**
31
- * @remarks `options.ttl_seconds === null` делает хранение сессионным!
32
- */
33
- constructor({ cookies, prefix, ttl_seconds }: {
34
- cookies?: ServerCookie[];
35
- prefix?: string;
36
- ttl_seconds?: number | null;
37
- });
30
+ constructor(ctx?: ConstructCookieStorage);
38
31
  fill(cookies?: ServerCookie[]): void;
39
32
  __unveil<T>(value?: string | null): T | undefined;
33
+ has(name: string): boolean;
40
34
  get<T extends IStorageValue>(name: string, prefix?: string): T | undefined;
41
35
  /**
42
- * @remarks `options.ttl_seconds === null` делает хранение сессионным!
36
+ * @remarks `options.ttl_seconds === undefined` делает хранение сессионным!
43
37
  */
44
- set(name: string, value: IStorageValue, options?: SetCookieStorageOptions): void;
45
- delete(name: string, options?: DeleteCookieStorageOptions): void;
38
+ set(name: string, value: IStorageValue, options?: CookieStorageSetOptions): void;
39
+ delete(name: string, options?: CookieStorageDeleteOptions): void;
46
40
  /**
47
41
  * Очистка серверных кук
48
42
  */
package/dist/cookie.js CHANGED
@@ -1,20 +1,12 @@
1
- import { VeilPrefixStorage } from "./internal/veil.js";
1
+ import { VeilPrefixStorage } from "./internal/veil-prefix.js";
2
2
  import { isSSR } from "@nemigo/helpers/html";
3
3
  import { deleteDocumentCookie, getDocumentCookie, setDocumentCookie } from "@nemigo/helpers/html/cookie";
4
4
  import { unveil, veil } from "@nemigo/helpers/veil";
5
5
  export class CookieStorage extends VeilPrefixStorage {
6
6
  __server = new Map();
7
- /**
8
- * TTL (time-to-live) хранилища
9
- */
10
- ttl_seconds;
11
- /**
12
- * @remarks `options.ttl_seconds === null` делает хранение сессионным!
13
- */
14
- constructor({ cookies, prefix, ttl_seconds }) {
15
- super(prefix);
16
- this.fill(cookies);
17
- this.ttl_seconds = ttl_seconds;
7
+ constructor(ctx = {}) {
8
+ super(ctx);
9
+ this.fill(ctx.cookies);
18
10
  }
19
11
  fill(cookies = []) {
20
12
  for (const item of cookies)
@@ -24,19 +16,19 @@ export class CookieStorage extends VeilPrefixStorage {
24
16
  __unveil(value) {
25
17
  return value ? unveil(value) : undefined;
26
18
  }
19
+ has(name) {
20
+ return this.get(name) !== undefined;
21
+ }
27
22
  get(name, prefix) {
28
23
  const key = this.__toKey(name, prefix);
29
24
  return this.__unveil(isSSR ? this.__server.get(key) : getDocumentCookie(key));
30
25
  }
31
- //...
32
26
  /**
33
- * @remarks `options.ttl_seconds === null` делает хранение сессионным!
27
+ * @remarks `options.ttl_seconds === undefined` делает хранение сессионным!
34
28
  */
35
29
  set(name, value, options = {}) {
36
- if (isSSR)
37
- return;
38
- const MaxAge = options.ttl_seconds !== undefined ? options.ttl_seconds : this.ttl_seconds;
39
- setDocumentCookie(this.__toKey(name, options.prefix), veil(value), { ...options, MaxAge });
30
+ if (!isSSR)
31
+ setDocumentCookie(this.__toKey(name, options.prefix), veil(value), { ...options, MaxAge: options.ttl_seconds });
40
32
  }
41
33
  delete(name, options = {}) {
42
34
  if (!isSSR)
@@ -0,0 +1,66 @@
1
+ import type { CanBePromise } from "@nemigo/helpers/types";
2
+ import type { IStorage } from "@nemigo/storage/types";
3
+ export interface VaultItem<PayloadData> {
4
+ /**
5
+ * Полезная нагрузка
6
+ */
7
+ pld: PayloadData;
8
+ /**
9
+ * Время создания (timestamp в секундах)
10
+ */
11
+ iat: number;
12
+ /**
13
+ * Абсолютное время истечения (timestamp в секундах). Если не задано — не устаревает
14
+ */
15
+ exp?: number;
16
+ /**
17
+ * Абсолютное время, до которого нельзя обновлять (timestamp в секундах)
18
+ */
19
+ upd?: number;
20
+ }
21
+ export interface VaultTimings {
22
+ /**
23
+ * Срок действия данных (в секундах). Если не задано — данные не устаревают
24
+ */
25
+ exp?: number;
26
+ /**
27
+ * Минимальный интервал до следующего обновления (в секундах).
28
+ * Если не задано — обновление разрешено в любой момент
29
+ */
30
+ upd?: number;
31
+ }
32
+ export interface VaultRunOptions<PayloadData> extends VaultTimings {
33
+ /**
34
+ * Использовать иные данные вместо генерации
35
+ */
36
+ overload?: PayloadData;
37
+ /**
38
+ * Принудительно перегенерировать, игнорируя тайминги
39
+ */
40
+ force?: boolean;
41
+ /**
42
+ * TTL в хранилище (в секундах, дельта от текущего момента)
43
+ */
44
+ ttl_seconds?: number;
45
+ }
46
+ export interface ConstructVault<PayloadData> extends VaultTimings {
47
+ /**
48
+ * Функция генерации полезной нагрузки
49
+ */
50
+ generate: (delta: VaultTimings, now_seconds: number) => CanBePromise<PayloadData>;
51
+ /**
52
+ * Функция сравнения двух полезных нагрузок на эквивалентность
53
+ */
54
+ equal: (a: PayloadData, b: PayloadData) => CanBePromise<boolean>;
55
+ }
56
+ export declare class Vault<PayloadData, Storage extends IStorage = IStorage> {
57
+ storage: Storage;
58
+ ctx: ConstructVault<PayloadData>;
59
+ constructor(storage: Storage, ctx: ConstructVault<PayloadData>);
60
+ find(key: string): CanBePromise<VaultItem<PayloadData> | undefined>;
61
+ check(key: string, pld: PayloadData): Promise<boolean>;
62
+ run(key: string, options?: VaultRunOptions<PayloadData>): Promise<{
63
+ generate: boolean;
64
+ item: VaultItem<PayloadData>;
65
+ }>;
66
+ }
@@ -0,0 +1,41 @@
1
+ export class Vault {
2
+ storage;
3
+ ctx;
4
+ constructor(storage, ctx) {
5
+ this.storage = storage;
6
+ this.ctx = ctx;
7
+ }
8
+ find(key) {
9
+ return this.storage.get(key);
10
+ }
11
+ async check(key, pld) {
12
+ const existed = await this.find(key);
13
+ if (!existed)
14
+ return false;
15
+ return this.ctx.equal(existed.pld, pld);
16
+ }
17
+ async run(key, options = {}) {
18
+ const { ttl_seconds, exp = this.ctx.exp, upd = this.ctx.upd, force = false, overload } = options;
19
+ // работаем в секундах
20
+ const nowSec = Math.floor(Date.now() / 1000);
21
+ const existed = await this.find(key);
22
+ if (existed && !force) {
23
+ const expired = existed.exp !== undefined && nowSec > existed.exp;
24
+ const tooEarlyToUpdate = existed.upd !== undefined && nowSec < existed.upd;
25
+ if (!expired && !tooEarlyToUpdate) {
26
+ return { generate: false, item: existed };
27
+ }
28
+ }
29
+ // Вычисляем абсолютные времена для сохранения
30
+ const newExp = exp !== undefined ? nowSec + exp : undefined;
31
+ const newUpd = upd !== undefined ? nowSec + upd : undefined;
32
+ const item = {
33
+ pld: overload ?? (await this.ctx.generate({ exp, upd }, nowSec)),
34
+ iat: nowSec,
35
+ exp: newExp,
36
+ upd: newUpd,
37
+ };
38
+ await this.storage.set(key, item, { ttl_seconds });
39
+ return { generate: true, item };
40
+ }
41
+ }
@@ -0,0 +1,13 @@
1
+ export interface ConstructVeilPrefixStorage {
2
+ prefix?: string;
3
+ ttl_seconds?: number;
4
+ }
5
+ export declare abstract class VeilPrefixStorage {
6
+ /**
7
+ * TTL хранилища для быстрого использования
8
+ */
9
+ ttl_seconds?: number;
10
+ prefix: string;
11
+ constructor({ ttl_seconds, prefix }?: ConstructVeilPrefixStorage);
12
+ __toKey(name: string, prefix?: string): string;
13
+ }
@@ -0,0 +1,16 @@
1
+ import { veil } from "@nemigo/helpers/veil";
2
+ export class VeilPrefixStorage {
3
+ /**
4
+ * TTL хранилища для быстрого использования
5
+ */
6
+ ttl_seconds;
7
+ prefix;
8
+ // noinspection TypeScriptAbstractClassConstructorCanBeMadeProtected
9
+ constructor({ ttl_seconds, prefix = "" } = {}) {
10
+ this.prefix = prefix;
11
+ this.ttl_seconds = ttl_seconds;
12
+ }
13
+ __toKey(name, prefix = this.prefix) {
14
+ return prefix + veil(name);
15
+ }
16
+ }
package/dist/runtime.d.ts CHANGED
@@ -1,59 +1,20 @@
1
- import type { IStorage, IStorageValue, SetIStorageOptions } from "./types.js";
1
+ import type { IStorage, IStorageValue, IStorageSetOptions } from "./types.js";
2
2
  import type { Timestamp } from "@nemigo/helpers/types";
3
- interface InternalValue {
3
+ export interface EntryValue {
4
4
  value: IStorageValue;
5
5
  expired?: Timestamp;
6
6
  }
7
- /**
8
- * LRU (Least Recently Used) runtime-хранилище данных, имплементирующее интерфейс {@link IStorage}
9
- *
10
- * - Значения удаляются при превышении максимального размера или по истечении заданного TTL
11
- * - TTL для каждого значения используется из хранилища (если задано), но можно указать и индивидуальное
12
- *
13
- * @example
14
- * ```typescript
15
- * const storage = new RuntimeStorage({ max: 2, ttl_minutes: 5 });
16
- * storage.set('one', 1);
17
- * storage.set('two', 2);
18
- * storage.set('three', 3); // Если хранилище переполнено, удалится наименее недавно использованное или устаревшее значение
19
- * console.log(storage.get('one')); // undefined, если значение устарело или удалено
20
- * console.log(storage.get('two')); // 2
21
- * ```
22
- */
23
- export declare class RuntimeStorage implements IStorage {
24
- __storage: Map<string, InternalValue>;
7
+ export declare class RuntimeStorage implements IStorage<boolean> {
8
+ __storage: Map<string, EntryValue>;
25
9
  /**
26
- * Максимальное количество значений в хранилище
10
+ * TTL хранилища для быстрого использования
27
11
  */
28
- max: number;
29
- /**
30
- * TTL (time-to-live) хранилища в миллисекундах
31
- */
32
- ttl?: number | null;
33
- /**
34
- * @param options - Настройки хранилища
35
- * @param [options.max=200] - Максимальное количество значений в хранилище
36
- * @param [options.ttl_seconds] - TTL (time-to-live) хранилища в **секундах**
37
- */
38
- constructor({ max, ttl_seconds }?: {
39
- max?: number;
40
- ttl_seconds?: number | null;
41
- });
42
- __isExpired(entry: InternalValue): boolean;
12
+ ttl_seconds?: number;
13
+ constructor(ttl_seconds?: number);
14
+ __isExpired(entry: EntryValue): boolean;
15
+ __get(key: string): EntryValue | undefined;
16
+ has(key: string): boolean;
43
17
  get<T = any>(key: string): T | undefined;
44
- /**
45
- * Устанавливает значение в кэш
46
- *
47
- * - Если индивидуальный TTL в **секундах** не указан, используется TTL хранилища (если задано)
48
- * - Если ключ уже существует, его значение обновляется и перемещается в конец
49
- * - Если размер хранимых значений превышает максимальное значение, производится очистка устаревших
50
- * - Если после очистки хранилище всё ещё переполнено, удаляется наименее недавно использованное значение
51
- */
52
- set(key: string, value: any, options?: SetIStorageOptions): void;
53
- size(): number;
54
- shake(): void;
18
+ set(key: string, value: any, options?: IStorageSetOptions): void;
55
19
  delete(key: string): boolean;
56
- clear(): void;
57
- has(key: string): boolean;
58
20
  }
59
- export {};
package/dist/runtime.js CHANGED
@@ -1,116 +1,37 @@
1
- import { getTTL } from "./internal/index.js";
2
- /**
3
- * LRU (Least Recently Used) runtime-хранилище данных, имплементирующее интерфейс {@link IStorage}
4
- *
5
- * - Значения удаляются при превышении максимального размера или по истечении заданного TTL
6
- * - TTL для каждого значения используется из хранилища (если задано), но можно указать и индивидуальное
7
- *
8
- * @example
9
- * ```typescript
10
- * const storage = new RuntimeStorage({ max: 2, ttl_minutes: 5 });
11
- * storage.set('one', 1);
12
- * storage.set('two', 2);
13
- * storage.set('three', 3); // Если хранилище переполнено, удалится наименее недавно использованное или устаревшее значение
14
- * console.log(storage.get('one')); // undefined, если значение устарело или удалено
15
- * console.log(storage.get('two')); // 2
16
- * ```
17
- */
18
1
  export class RuntimeStorage {
19
2
  __storage;
20
3
  /**
21
- * Максимальное количество значений в хранилище
4
+ * TTL хранилища для быстрого использования
22
5
  */
23
- max;
24
- /**
25
- * TTL (time-to-live) хранилища в миллисекундах
26
- */
27
- ttl;
28
- /**
29
- * @param options - Настройки хранилища
30
- * @param [options.max=200] - Максимальное количество значений в хранилище
31
- * @param [options.ttl_seconds] - TTL (time-to-live) хранилища в **секундах**
32
- */
33
- constructor({ max = 200, ttl_seconds } = {}) {
34
- this.max = max;
35
- this.ttl = ttl_seconds ? ttl_seconds * 1000 : ttl_seconds;
6
+ ttl_seconds;
7
+ constructor(ttl_seconds) {
36
8
  this.__storage = new Map();
9
+ this.ttl_seconds = ttl_seconds;
37
10
  }
38
11
  __isExpired(entry) {
39
12
  return Boolean(entry.expired && Date.now() > entry.expired);
40
13
  }
41
- get(key) {
14
+ __get(key) {
42
15
  const entry = this.__storage.get(key);
43
16
  if (!entry)
44
- return undefined;
17
+ return;
45
18
  if (this.__isExpired(entry)) {
46
19
  this.__storage.delete(key);
47
- return undefined;
48
- }
49
- // Обновляем порядок использования, чтобы сохранить от LRU-удаления
50
- this.__storage.delete(key);
51
- this.__storage.set(key, entry);
52
- return entry.value;
53
- }
54
- /**
55
- * Устанавливает значение в кэш
56
- *
57
- * - Если индивидуальный TTL в **секундах** не указан, используется TTL хранилища (если задано)
58
- * - Если ключ уже существует, его значение обновляется и перемещается в конец
59
- * - Если размер хранимых значений превышает максимальное значение, производится очистка устаревших
60
- * - Если после очистки хранилище всё ещё переполнено, удаляется наименее недавно использованное значение
61
- */
62
- set(key, value, options) {
63
- if (this.__storage.has(key)) {
64
- this.__storage.delete(key);
65
20
  }
66
21
  else {
67
- if (this.__storage.size >= this.max) {
68
- // Удаляем устаревшие элементы
69
- for (const existingKey of this.__storage.keys()) {
70
- const entry = this.__storage.get(existingKey);
71
- if (!entry || this.__isExpired(entry)) {
72
- this.__storage.delete(existingKey);
73
- }
74
- if (this.__storage.size < this.max)
75
- break;
76
- }
77
- // Если всё ещё переполнен — удаляем LRU
78
- if (this.__storage.size >= this.max) {
79
- const firstKey = this.__storage.keys().next().value;
80
- if (firstKey !== undefined) {
81
- this.__storage.delete(firstKey);
82
- }
83
- }
84
- }
22
+ return entry;
85
23
  }
86
- const expired = getTTL(options?.ttl_seconds, this.ttl);
87
- this.__storage.set(key, expired ? { value, expired } : { value });
88
24
  }
89
- size() {
90
- return this.__storage.size;
25
+ has(key) {
26
+ return Boolean(this.__get(key));
27
+ }
28
+ get(key) {
29
+ return this.__get(key)?.value;
91
30
  }
92
- shake() {
93
- for (const existingKey of this.__storage.keys()) {
94
- const entry = this.__storage.get(existingKey);
95
- if (!entry || this.__isExpired(entry)) {
96
- this.__storage.delete(existingKey);
97
- }
98
- }
31
+ set(key, value, options) {
32
+ this.__storage.set(key, options?.ttl_seconds ? { value, expired: options.ttl_seconds * 1000 } : { value });
99
33
  }
100
34
  delete(key) {
101
35
  return this.__storage.delete(key);
102
36
  }
103
- clear() {
104
- this.__storage.clear();
105
- }
106
- has(key) {
107
- const entry = this.__storage.get(key);
108
- if (!entry)
109
- return false;
110
- if (this.__isExpired(entry)) {
111
- this.__storage.delete(key);
112
- return false;
113
- }
114
- return true;
115
- }
116
37
  }
package/dist/types.d.ts CHANGED
@@ -6,33 +6,53 @@ export type IStorageValue = object | string | boolean | number | null;
6
6
  /**
7
7
  * Опции для {@link IStorage.set}
8
8
  */
9
- export interface SetIStorageOptions {
9
+ export interface IStorageSetOptions {
10
10
  /**
11
- * @remarks `null` поведение может отличаться у разных имплементаций!
11
+ * @remarks `undefined` поведение может быть особым у разных имплементаций!
12
12
  */
13
- ttl_seconds?: number | null;
13
+ ttl_seconds?: number;
14
14
  }
15
15
  /**
16
16
  * Интерфейс для синхронных хранилищ данных для полиморфизма
17
17
  *
18
18
  * Используется только там, где нельзя использовать {@link IStorage}
19
19
  */
20
- export interface ISyncStorage {
21
- get<T extends IStorageValue>(key: string): T | undefined;
22
- set(key: string, value: IStorageValue, options?: SetIStorageOptions): void;
20
+ export interface ISyncStorage<Delete extends boolean | void = boolean | void> {
21
+ get<T extends IStorageValue>(name: string): T | undefined;
22
+ set(name: string, value: IStorageValue, options?: IStorageSetOptions): void;
23
23
  /**
24
- * @return `true`, если оно существовало. Допускаются имплементации без проверки
24
+ * @return `true`, если оно существовало. Допускаются имплементации без этого
25
25
  */
26
- delete(key: string): boolean | void;
26
+ delete(name: string): Delete;
27
+ /**
28
+ * Обычно просто `Boolean(this.get(name))`, но могут быть более производительные способы
29
+ */
30
+ has(name: string): boolean;
27
31
  }
28
32
  /**
29
33
  * Интерфейс для всех хранилищ данных для полиморфизма
30
34
  */
31
- export interface IStorage {
32
- get<T extends IStorageValue>(key: string): CanBePromise<T | undefined>;
33
- set(key: string, value: IStorageValue, options?: SetIStorageOptions): CanBePromise;
35
+ export interface IStorage<Delete extends boolean | void = boolean | void> {
36
+ get<T extends IStorageValue>(name: string): CanBePromise<T | undefined>;
37
+ set(name: string, value: IStorageValue, options?: IStorageSetOptions): CanBePromise;
38
+ /**
39
+ * @return `true`, если оно существовало. Допускаются имплементации без этого
40
+ */
41
+ delete(name: string): CanBePromise<Delete>;
34
42
  /**
35
- * @return `true`, если оно существовало. Допускаются имплементации без проверки
43
+ * Обычно просто `Boolean(this.get(name))`, но могут быть более производительные способы
36
44
  */
37
- delete(key: string): CanBePromise<boolean | void>;
45
+ has(name: string): CanBePromise<boolean>;
46
+ }
47
+ export interface ISyncStoragePanic<Delete extends boolean | void = boolean | void> {
48
+ onhas?(err: unknown): boolean | never;
49
+ onget?<V extends IStorageValue = IStorageValue>(err: unknown): V | undefined | never;
50
+ ondelete?(err: unknown): Delete | never;
51
+ onset?(err: unknown): undefined | never;
52
+ }
53
+ export interface IStoragePanic<Delete extends boolean | void = boolean | void> {
54
+ onhas?(err: unknown): CanBePromise<boolean | never>;
55
+ onget?<V extends IStorageValue = IStorageValue>(err: unknown): CanBePromise<V | undefined | never>;
56
+ ondelete?(err: unknown): CanBePromise<Delete | never>;
57
+ onset?(err: unknown): CanBePromise<undefined | never>;
38
58
  }
package/dist/web.d.ts CHANGED
@@ -1,28 +1,20 @@
1
- import { VeilPrefixStorage } from "./internal/veil.js";
2
- import type { IStorage, IStorageValue, SetIStorageOptions } from "./types.js";
1
+ import { VeilPrefixStorage } from "./internal/veil-prefix.js";
2
+ import type { IStorage, IStorageValue, IStorageSetOptions } from "./types.js";
3
+ import type { Timestamp } from "@nemigo/helpers/types";
3
4
  export type WebStorageType = "local" | "session";
4
5
  export interface WebStorageOptions {
5
6
  type?: WebStorageType;
6
7
  prefix?: string;
7
8
  }
8
- export declare class WebStorage extends VeilPrefixStorage implements IStorage {
9
- /**
10
- * TTL (time-to-live) хранилища в миллисекундах
11
- */
12
- ttl?: number | null;
13
- /**
14
- * @param options - Настройки хранилища
15
- * @param [options.ttl_seconds] - TTL (time-to-live) хранилища в **секундах**
16
- */
17
- constructor({ ttl_seconds, prefix }?: {
18
- prefix?: string;
19
- ttl_seconds?: number | null;
20
- });
9
+ export interface EntryValue {
10
+ value: IStorageValue;
11
+ expired?: Timestamp;
12
+ }
13
+ export declare class WebStorage extends VeilPrefixStorage implements IStorage<void> {
14
+ __isExpired(entry: EntryValue): boolean;
21
15
  __get<T>(storage: Storage, key: string): T | undefined;
16
+ has(name: string, options?: WebStorageOptions): boolean;
22
17
  get<T extends IStorageValue>(name: string, options?: WebStorageOptions): T | undefined;
23
- set(name: string, value: IStorageValue, options?: SetIStorageOptions & WebStorageOptions): void;
24
- delete(name: string, options?: {
25
- type?: WebStorageType;
26
- prefix?: string;
27
- }): boolean | void;
18
+ set(name: string, value: IStorageValue, options?: IStorageSetOptions & WebStorageOptions): void;
19
+ delete(name: string, options?: WebStorageOptions): void;
28
20
  }
package/dist/web.js CHANGED
@@ -1,32 +1,25 @@
1
- import { getTTL } from "./internal/index.js";
2
- import { VeilPrefixStorage } from "./internal/veil.js";
1
+ import { VeilPrefixStorage } from "./internal/veil-prefix.js";
3
2
  import { isSSR } from "@nemigo/helpers/html";
4
3
  import { unveil, veil } from "@nemigo/helpers/veil";
5
4
  export class WebStorage extends VeilPrefixStorage {
6
- /**
7
- * TTL (time-to-live) хранилища в миллисекундах
8
- */
9
- ttl;
10
- /**
11
- * @param options - Настройки хранилища
12
- * @param [options.ttl_seconds] - TTL (time-to-live) хранилища в **секундах**
13
- */
14
- constructor({ ttl_seconds, prefix } = {}) {
15
- super(prefix);
16
- this.ttl = ttl_seconds ? ttl_seconds * 1000 : ttl_seconds;
5
+ __isExpired(entry) {
6
+ return Boolean(entry.expired && Date.now() > entry.expired);
17
7
  }
18
8
  __get(storage, key) {
19
9
  const entry = storage.getItem(key);
20
10
  if (!entry)
21
11
  return;
22
- const encoded = unveil(entry);
23
- if (encoded.expired && Date.now() > encoded.expired) {
12
+ const unveiled = unveil(entry);
13
+ if (this.__isExpired(unveiled)) {
24
14
  storage.removeItem(key);
25
15
  }
26
16
  else {
27
- return encoded.value;
17
+ return unveiled.value;
28
18
  }
29
19
  }
20
+ has(name, options) {
21
+ return Boolean(this.get(name, options));
22
+ }
30
23
  get(name, options = {}) {
31
24
  if (isSSR)
32
25
  return;
@@ -44,13 +37,11 @@ export class WebStorage extends VeilPrefixStorage {
44
37
  if (isSSR)
45
38
  return;
46
39
  const key = this.__toKey(name, options.prefix);
47
- const expired = getTTL(options.ttl_seconds, this.ttl);
48
- const internalValue = expired ? { value, expired } : { value };
49
- const _value = veil(internalValue);
40
+ const veiled = veil(options.ttl_seconds ? { value, expired: options.ttl_seconds * 1000 } : { value });
50
41
  if (options.type === "session")
51
- sessionStorage.setItem(key, _value);
42
+ sessionStorage.setItem(key, veiled);
52
43
  else
53
- localStorage.setItem(key, _value);
44
+ localStorage.setItem(key, veiled);
54
45
  }
55
46
  delete(name, options = {}) {
56
47
  if (isSSR)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nemigo/storage",
3
- "version": "1.5.0",
3
+ "version": "1.7.0",
4
4
  "private": false,
5
5
  "author": {
6
6
  "name": "Vlad Logvin",
@@ -18,17 +18,21 @@
18
18
  "format": "prettier --write ./"
19
19
  },
20
20
  "exports": {
21
+ "./capacity": {
22
+ "types": "./dist/capacity.d.ts",
23
+ "default": "./dist/capacity.js"
24
+ },
21
25
  "./cookie": {
22
26
  "types": "./dist/cookie.d.ts",
23
27
  "default": "./dist/cookie.js"
24
28
  },
25
- "./internal": {
26
- "types": "./dist/internal/index.d.ts",
27
- "default": "./dist/internal/index.js"
29
+ "./derived/vault": {
30
+ "types": "./dist/derived/vault.d.ts",
31
+ "default": "./dist/derived/vault.js"
28
32
  },
29
- "./internal/veil": {
30
- "types": "./dist/internal/veil.d.ts",
31
- "default": "./dist/internal/veil.js"
33
+ "./internal/veil-prefix": {
34
+ "types": "./dist/internal/veil-prefix.d.ts",
35
+ "default": "./dist/internal/veil-prefix.js"
32
36
  },
33
37
  "./runtime": {
34
38
  "types": "./dist/runtime.d.ts",
@@ -44,7 +48,7 @@
44
48
  }
45
49
  },
46
50
  "peerDependencies": {
47
- "@nemigo/helpers": ">=1.5.0"
51
+ "@nemigo/helpers": ">=1.6.0"
48
52
  },
49
53
  "devDependencies": {
50
54
  "@nemigo/configs": "workspace:*",
@@ -1 +0,0 @@
1
- export declare const getTTL: (entry_in_seconds?: number | null, storage?: number | null) => number | null | undefined;
@@ -1,10 +0,0 @@
1
- export const getTTL = (entry_in_seconds, storage) => {
2
- if (entry_in_seconds)
3
- return Date.now() + entry_in_seconds * 1000;
4
- if (entry_in_seconds === null)
5
- return null;
6
- if (storage)
7
- return Date.now() + storage;
8
- if (storage === null)
9
- return null;
10
- };
@@ -1,5 +0,0 @@
1
- export declare abstract class VeilPrefixStorage {
2
- prefix: string;
3
- protected constructor(prefix?: string);
4
- __toKey(name: string, prefix: string | undefined): string;
5
- }
@@ -1,10 +0,0 @@
1
- import { veil } from "@nemigo/helpers/veil";
2
- export class VeilPrefixStorage {
3
- prefix;
4
- constructor(prefix = "") {
5
- this.prefix = prefix;
6
- }
7
- __toKey(name, prefix) {
8
- return (prefix === undefined ? this.prefix : prefix) + veil(name);
9
- }
10
- }