@nemigo/storage 1.6.0 → 1.7.1

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.
@@ -1,12 +1,12 @@
1
1
  import { RuntimeStorage } from "./runtime.js";
2
- import type { SetIStorageOptions } from "./types.js";
3
- export interface ConstructorCapacityStorage {
2
+ import type { IStorageSetOptions } from "./types.js";
3
+ export interface ConstructCapacityStorage {
4
4
  capacity: number;
5
5
  ttl_seconds?: number;
6
6
  }
7
7
  export declare class CapacityStorage extends RuntimeStorage {
8
8
  capacity: number;
9
- constructor({ capacity, ttl_seconds }: ConstructorCapacityStorage);
9
+ constructor({ capacity, ttl_seconds }: ConstructCapacityStorage);
10
10
  get<T = any>(key: string): T | undefined;
11
- set(key: string, value: any, options?: SetIStorageOptions): void;
11
+ set(key: string, value: any, options?: IStorageSetOptions): void;
12
12
  }
package/dist/cookie.d.ts CHANGED
@@ -1,17 +1,17 @@
1
1
  import type { ConstructVeilPrefixStorage } from "./internal/veil-prefix.js";
2
2
  import { VeilPrefixStorage } from "./internal/veil-prefix.js";
3
- import type { IStorage, IStorageValue, SetIStorageOptions } from "./types.js";
3
+ import type { IStorage, IStorageValue, IStorageSetOptions } from "./types.js";
4
4
  import type { SetDocumentCookieOptions } from "@nemigo/helpers/html/cookie";
5
5
  /**
6
6
  * Опции для {@link CookieStorage.set}
7
7
  */
8
- export interface SetCookieStorageOptions extends SetDocumentCookieOptions, SetIStorageOptions {
8
+ export interface CookieStorageSetOptions extends SetDocumentCookieOptions, IStorageSetOptions {
9
9
  prefix?: string;
10
10
  }
11
11
  /**
12
12
  * Опции для {@link CookieStorage.delete}
13
13
  */
14
- export interface DeleteCookieStorageOptions {
14
+ export interface CookieStorageDeleteOptions {
15
15
  Path?: string;
16
16
  prefix?: string;
17
17
  }
@@ -25,7 +25,7 @@ export interface ServerCookie {
25
25
  export interface ConstructCookieStorage extends ConstructVeilPrefixStorage {
26
26
  cookies?: ServerCookie[];
27
27
  }
28
- export declare class CookieStorage extends VeilPrefixStorage implements IStorage {
28
+ export declare class CookieStorage extends VeilPrefixStorage implements IStorage<void> {
29
29
  __server: Map<string, string>;
30
30
  constructor(ctx?: ConstructCookieStorage);
31
31
  fill(cookies?: ServerCookie[]): void;
@@ -35,8 +35,8 @@ export declare class CookieStorage extends VeilPrefixStorage implements IStorage
35
35
  /**
36
36
  * @remarks `options.ttl_seconds === undefined` делает хранение сессионным!
37
37
  */
38
- set(name: string, value: IStorageValue, options?: SetCookieStorageOptions): void;
39
- delete(name: string, options?: DeleteCookieStorageOptions): void;
38
+ set(name: string, value: IStorageValue, options?: CookieStorageSetOptions): void;
39
+ delete(name: string, options?: CookieStorageDeleteOptions): void;
40
40
  /**
41
41
  * Очистка серверных кук
42
42
  */
@@ -0,0 +1,80 @@
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
+ * TTL в хранилище (в секундах, дельта от текущего момента)
33
+ */
34
+ ttl?: number;
35
+ }
36
+ export interface VaultRunOptions<PayloadData> extends VaultTimings {
37
+ /**
38
+ * Использовать иные данные вместо генерации
39
+ */
40
+ overload?: PayloadData;
41
+ /**
42
+ * Принудительно перегенерировать, игнорируя тайминги
43
+ */
44
+ force?: boolean;
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
+ /**
57
+ * @example
58
+ * ```typescript
59
+ * export const codeVault = new Vault<string, RedisStorage>(redisStorage, {
60
+ * generate: () => rand(),
61
+ * equal: (a, b) => a === b,
62
+ * exp: 60 * 10,
63
+ * ttl: 60 * 10,
64
+ * upd: 60,
65
+ * });
66
+ *
67
+ * const result = await codeVault.run("some:key")
68
+ * ```
69
+ */
70
+ export declare class Vault<PayloadData, Storage extends IStorage = IStorage> {
71
+ storage: Storage;
72
+ ctx: ConstructVault<PayloadData>;
73
+ constructor(storage: Storage, ctx: ConstructVault<PayloadData>);
74
+ find(key: string): CanBePromise<VaultItem<PayloadData> | undefined>;
75
+ check(key: string, pld: PayloadData): Promise<boolean>;
76
+ run(key: string, options?: VaultRunOptions<PayloadData>): Promise<{
77
+ generate: boolean;
78
+ item: VaultItem<PayloadData>;
79
+ }>;
80
+ }
@@ -0,0 +1,55 @@
1
+ /**
2
+ * @example
3
+ * ```typescript
4
+ * export const codeVault = new Vault<string, RedisStorage>(redisStorage, {
5
+ * generate: () => rand(),
6
+ * equal: (a, b) => a === b,
7
+ * exp: 60 * 10,
8
+ * ttl: 60 * 10,
9
+ * upd: 60,
10
+ * });
11
+ *
12
+ * const result = await codeVault.run("some:key")
13
+ * ```
14
+ */
15
+ export class Vault {
16
+ storage;
17
+ ctx;
18
+ constructor(storage, ctx) {
19
+ this.storage = storage;
20
+ this.ctx = ctx;
21
+ }
22
+ find(key) {
23
+ return this.storage.get(key);
24
+ }
25
+ async check(key, pld) {
26
+ const existed = await this.find(key);
27
+ if (!existed)
28
+ return false;
29
+ return this.ctx.equal(existed.pld, pld);
30
+ }
31
+ async run(key, options = {}) {
32
+ const { ttl = this.ctx.ttl, exp = this.ctx.exp, upd = this.ctx.upd, force = false, overload } = options;
33
+ // работаем в секундах
34
+ const nowSec = Math.floor(Date.now() / 1000);
35
+ const existed = await this.find(key);
36
+ if (existed && !force) {
37
+ const expired = existed.exp !== undefined && nowSec > existed.exp;
38
+ const tooEarlyToUpdate = existed.upd !== undefined && nowSec < existed.upd;
39
+ if (!expired && !tooEarlyToUpdate) {
40
+ return { generate: false, item: existed };
41
+ }
42
+ }
43
+ // Вычисляем абсолютные времена для сохранения
44
+ const newExp = exp !== undefined ? nowSec + exp : undefined;
45
+ const newUpd = upd !== undefined ? nowSec + upd : undefined;
46
+ const item = {
47
+ pld: overload ?? (await this.ctx.generate({ exp, upd }, nowSec)),
48
+ iat: nowSec,
49
+ exp: newExp,
50
+ upd: newUpd,
51
+ };
52
+ await this.storage.set(key, item, { ttl_seconds: ttl });
53
+ return { generate: true, item };
54
+ }
55
+ }
package/dist/runtime.d.ts CHANGED
@@ -1,10 +1,10 @@
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
3
  export interface EntryValue {
4
4
  value: IStorageValue;
5
5
  expired?: Timestamp;
6
6
  }
7
- export declare class RuntimeStorage implements IStorage {
7
+ export declare class RuntimeStorage implements IStorage<boolean> {
8
8
  __storage: Map<string, EntryValue>;
9
9
  /**
10
10
  * TTL хранилища для быстрого использования
@@ -15,6 +15,6 @@ export declare class RuntimeStorage implements IStorage {
15
15
  __get(key: string): EntryValue | undefined;
16
16
  has(key: string): boolean;
17
17
  get<T = any>(key: string): T | undefined;
18
- set(key: string, value: any, options?: SetIStorageOptions): void;
18
+ set(key: string, value: any, options?: IStorageSetOptions): void;
19
19
  delete(key: string): boolean;
20
20
  }
package/dist/types.d.ts CHANGED
@@ -6,7 +6,7 @@ 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
11
  * @remarks `undefined` поведение может быть особым у разных имплементаций!
12
12
  */
@@ -17,13 +17,13 @@ export interface SetIStorageOptions {
17
17
  *
18
18
  * Используется только там, где нельзя использовать {@link IStorage}
19
19
  */
20
- export interface ISyncStorage {
20
+ export interface ISyncStorage<Delete extends boolean | void = boolean | void> {
21
21
  get<T extends IStorageValue>(name: string): T | undefined;
22
- set(name: string, value: IStorageValue, options?: SetIStorageOptions): void;
22
+ set(name: string, value: IStorageValue, options?: IStorageSetOptions): void;
23
23
  /**
24
- * @return `true`, если оно существовало. Допускаются имплементации без проверки
24
+ * @return `true`, если оно существовало. Допускаются имплементации без этого
25
25
  */
26
- delete(name: string): boolean | void;
26
+ delete(name: string): Delete;
27
27
  /**
28
28
  * Обычно просто `Boolean(this.get(name))`, но могут быть более производительные способы
29
29
  */
@@ -32,15 +32,27 @@ export interface ISyncStorage {
32
32
  /**
33
33
  * Интерфейс для всех хранилищ данных для полиморфизма
34
34
  */
35
- export interface IStorage {
35
+ export interface IStorage<Delete extends boolean | void = boolean | void> {
36
36
  get<T extends IStorageValue>(name: string): CanBePromise<T | undefined>;
37
- set(name: string, value: IStorageValue, options?: SetIStorageOptions): CanBePromise;
37
+ set(name: string, value: IStorageValue, options?: IStorageSetOptions): CanBePromise;
38
38
  /**
39
- * @return `true`, если оно существовало. Допускаются имплементации без проверки
39
+ * @return `true`, если оно существовало. Допускаются имплементации без этого
40
40
  */
41
- delete(name: string): CanBePromise<boolean | void>;
41
+ delete(name: string): CanBePromise<Delete>;
42
42
  /**
43
43
  * Обычно просто `Boolean(this.get(name))`, но могут быть более производительные способы
44
44
  */
45
45
  has(name: string): CanBePromise<boolean>;
46
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>;
58
+ }
package/dist/web.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { VeilPrefixStorage } from "./internal/veil-prefix.js";
2
- import type { IStorage, IStorageValue, SetIStorageOptions } from "./types.js";
2
+ import type { IStorage, IStorageValue, IStorageSetOptions } from "./types.js";
3
3
  import type { Timestamp } from "@nemigo/helpers/types";
4
4
  export type WebStorageType = "local" | "session";
5
5
  export interface WebStorageOptions {
@@ -10,11 +10,11 @@ export interface EntryValue {
10
10
  value: IStorageValue;
11
11
  expired?: Timestamp;
12
12
  }
13
- export declare class WebStorage extends VeilPrefixStorage implements IStorage {
13
+ export declare class WebStorage extends VeilPrefixStorage implements IStorage<void> {
14
14
  __isExpired(entry: EntryValue): boolean;
15
15
  __get<T>(storage: Storage, key: string): T | undefined;
16
16
  has(name: string, options?: WebStorageOptions): boolean;
17
17
  get<T extends IStorageValue>(name: string, options?: WebStorageOptions): T | undefined;
18
- set(name: string, value: IStorageValue, options?: SetIStorageOptions & WebStorageOptions): void;
19
- delete(name: string, options?: WebStorageOptions): boolean | void;
18
+ set(name: string, value: IStorageValue, options?: IStorageSetOptions & WebStorageOptions): void;
19
+ delete(name: string, options?: WebStorageOptions): void;
20
20
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nemigo/storage",
3
- "version": "1.6.0",
3
+ "version": "1.7.1",
4
4
  "private": false,
5
5
  "author": {
6
6
  "name": "Vlad Logvin",
@@ -26,6 +26,10 @@
26
26
  "types": "./dist/cookie.d.ts",
27
27
  "default": "./dist/cookie.js"
28
28
  },
29
+ "./derived/vault": {
30
+ "types": "./dist/derived/vault.d.ts",
31
+ "default": "./dist/derived/vault.js"
32
+ },
29
33
  "./internal/veil-prefix": {
30
34
  "types": "./dist/internal/veil-prefix.d.ts",
31
35
  "default": "./dist/internal/veil-prefix.js"