@dxtmisha/wiki 0.39.6 → 0.39.8
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/defineProperty-Bjg6wMoX.js +39 -0
- package/dist/library.d.ts +0 -1
- package/dist/library.js +25 -25
- package/dist/media.js +12 -0
- package/dist/storybook.js +26929 -11
- package/package.json +1 -1
- package/src/library.ts +0 -1
- package/src/media/functional/functional-basic/api/api.en.mdx +45 -0
- package/src/media/functional/functional-basic/api/api.ru.mdx +45 -0
- package/src/media/functional/functional-basic/api/api.vi.mdx +45 -0
- package/src/media/functional/functional-basic/classes/Api/Api.en.mdx +54 -54
- package/src/media/functional/functional-basic/classes/Api/Api.ru.mdx +54 -54
- package/src/media/functional/functional-basic/classes/Api/Api.vi.mdx +54 -54
- package/src/media/functional/functional-basic/classes/ApiCache/ApiCache.en.mdx +111 -0
- package/src/media/functional/functional-basic/classes/ApiCache/ApiCache.ru.mdx +111 -0
- package/src/media/functional/functional-basic/classes/ApiCache/ApiCache.vi.mdx +111 -0
- package/src/media/functional/functional-basic/classes/ApiDataReturn/ApiDataReturn.en.mdx +32 -0
- package/src/media/functional/functional-basic/classes/ApiDataReturn/ApiDataReturn.ru.mdx +32 -0
- package/src/media/functional/functional-basic/classes/ApiDataReturn/ApiDataReturn.vi.mdx +32 -0
- package/src/media/functional/functional-basic/classes/ApiDefault/ApiDefault.en.mdx +24 -28
- package/src/media/functional/functional-basic/classes/ApiDefault/ApiDefault.ru.mdx +24 -28
- package/src/media/functional/functional-basic/classes/ApiDefault/ApiDefault.vi.mdx +24 -28
- package/src/media/functional/functional-basic/classes/ApiHeaders/ApiHeaders.en.mdx +28 -14
- package/src/media/functional/functional-basic/classes/ApiHeaders/ApiHeaders.ru.mdx +33 -19
- package/src/media/functional/functional-basic/classes/ApiHeaders/ApiHeaders.vi.mdx +33 -19
- package/src/media/functional/functional-basic/classes/ApiHydration/ApiHydration.en.mdx +56 -0
- package/src/media/functional/functional-basic/classes/ApiHydration/ApiHydration.ru.mdx +56 -0
- package/src/media/functional/functional-basic/classes/ApiHydration/ApiHydration.vi.mdx +55 -0
- package/src/media/functional/functional-basic/classes/ApiInstance/ApiInstance.en.mdx +101 -49
- package/src/media/functional/functional-basic/classes/ApiInstance/ApiInstance.ru.mdx +101 -49
- package/src/media/functional/functional-basic/classes/ApiInstance/ApiInstance.vi.mdx +98 -47
- package/src/media/functional/functional-basic/classes/ApiPreparation/ApiPreparation.en.mdx +44 -26
- package/src/media/functional/functional-basic/classes/ApiPreparation/ApiPreparation.ru.mdx +45 -27
- package/src/media/functional/functional-basic/classes/ApiPreparation/ApiPreparation.vi.mdx +44 -26
- package/src/media/functional/functional-basic/classes/ApiResponse/ApiResponse.en.mdx +50 -21
- package/src/media/functional/functional-basic/classes/ApiResponse/ApiResponse.ru.mdx +54 -25
- package/src/media/functional/functional-basic/classes/ApiResponse/ApiResponse.vi.mdx +55 -26
- package/src/media/functional/functional-basic/classes/ApiStatus/ApiStatus.en.mdx +29 -32
- package/src/media/functional/functional-basic/classes/ApiStatus/ApiStatus.ru.mdx +33 -36
- package/src/media/functional/functional-basic/classes/ApiStatus/ApiStatus.vi.mdx +33 -36
- package/src/media/functional/functional-basic/classes/BroadcastMessage/BroadcastMessage.en.mdx +34 -53
- package/src/media/functional/functional-basic/classes/BroadcastMessage/BroadcastMessage.ru.mdx +33 -52
- package/src/media/functional/functional-basic/classes/BroadcastMessage/BroadcastMessage.vi.mdx +39 -58
- package/src/media/functional/functional-basic/classes/Cache/Cache.en.mdx +7 -4
- package/src/media/functional/functional-basic/classes/Cache/Cache.ru.mdx +7 -4
- package/src/media/functional/functional-basic/classes/Cache/Cache.vi.mdx +28 -25
- package/src/media/functional/functional-basic/classes/CacheItem/CacheItem.en.mdx +45 -53
- package/src/media/functional/functional-basic/classes/CacheItem/CacheItem.ru.mdx +46 -54
- package/src/media/functional/functional-basic/classes/CacheItem/CacheItem.vi.mdx +47 -55
- package/src/media/functional/functional-basic/classes/CacheStatic/CacheStatic.en.mdx +13 -1
- package/src/media/functional/functional-basic/classes/CacheStatic/CacheStatic.ru.mdx +13 -1
- package/src/media/functional/functional-basic/classes/CacheStatic/CacheStatic.vi.mdx +13 -0
- package/src/media/functional/functional-basic/classes/Cookie/Cookie.en.mdx +88 -44
- package/src/media/functional/functional-basic/classes/Cookie/Cookie.ru.mdx +88 -44
- package/src/media/functional/functional-basic/classes/Cookie/Cookie.vi.mdx +85 -41
- package/src/media/functional/functional-basic/classes/CookieBlock/CookieBlock.en.mdx +43 -22
- package/src/media/functional/functional-basic/classes/CookieBlock/CookieBlock.ru.mdx +46 -25
- package/src/media/functional/functional-basic/classes/CookieBlock/CookieBlock.vi.mdx +43 -22
- package/src/media/functional/functional-basic/classes/CookieBlockInstance/CookieBlockInstance.en.mdx +84 -0
- package/src/media/functional/functional-basic/classes/CookieBlockInstance/CookieBlockInstance.ru.mdx +84 -0
- package/src/media/functional/functional-basic/classes/CookieBlockInstance/CookieBlockInstance.vi.mdx +100 -0
- package/src/media/functional/functional-basic/classes/CookieStorage/CookieStorage.en.mdx +153 -0
- package/src/media/functional/functional-basic/classes/CookieStorage/CookieStorage.ru.mdx +153 -0
- package/src/media/functional/functional-basic/classes/CookieStorage/CookieStorage.vi.mdx +153 -0
- package/src/media/functional/functional-basic/classes/DataStorage/DataStorage.en.mdx +32 -25
- package/src/media/functional/functional-basic/classes/DataStorage/DataStorage.ru.mdx +32 -25
- package/src/media/functional/functional-basic/classes/DataStorage/DataStorage.vi.mdx +32 -27
- package/src/media/functional/functional-basic/classes/Datetime/Datetime.en.mdx +36 -4
- package/src/media/functional/functional-basic/classes/Datetime/Datetime.ru.mdx +36 -4
- package/src/media/functional/functional-basic/classes/Datetime/Datetime.vi.mdx +36 -4
- package/src/media/functional/functional-basic/classes/ErrorCenter/ErrorCenter.en.mdx +101 -70
- package/src/media/functional/functional-basic/classes/ErrorCenter/ErrorCenter.ru.mdx +100 -69
- package/src/media/functional/functional-basic/classes/ErrorCenter/ErrorCenter.vi.mdx +101 -70
- package/src/media/functional/functional-basic/classes/ErrorCenterHandler/ErrorCenterHandler.en.mdx +46 -42
- package/src/media/functional/functional-basic/classes/ErrorCenterHandler/ErrorCenterHandler.ru.mdx +46 -42
- package/src/media/functional/functional-basic/classes/ErrorCenterHandler/ErrorCenterHandler.vi.mdx +46 -42
- package/src/media/functional/functional-basic/classes/ErrorCenterInstance/ErrorCenterInstance.en.mdx +44 -96
- package/src/media/functional/functional-basic/classes/ErrorCenterInstance/ErrorCenterInstance.ru.mdx +44 -96
- package/src/media/functional/functional-basic/classes/ErrorCenterInstance/ErrorCenterInstance.vi.mdx +44 -96
- package/src/media/functional/functional-basic/classes/EventItem/EventItem.en.mdx +49 -28
- package/src/media/functional/functional-basic/classes/EventItem/EventItem.ru.mdx +21 -0
- package/src/media/functional/functional-basic/classes/EventItem/EventItem.vi.mdx +63 -42
- package/src/media/functional/functional-basic/classes/Formatters/Formatters.en.mdx +97 -109
- package/src/media/functional/functional-basic/classes/Formatters/Formatters.ru.mdx +86 -98
- package/src/media/functional/functional-basic/classes/Formatters/Formatters.vi.mdx +99 -111
- package/src/media/functional/functional-basic/classes/Geo/Geo.en.mdx +3 -3
- package/src/media/functional/functional-basic/classes/Geo/Geo.ru.mdx +5 -5
- package/src/media/functional/functional-basic/classes/Geo/Geo.vi.mdx +5 -5
- package/src/media/functional/functional-basic/classes/GeoFlag/GeoFlag.en.mdx +83 -40
- package/src/media/functional/functional-basic/classes/GeoFlag/GeoFlag.ru.mdx +83 -40
- package/src/media/functional/functional-basic/classes/GeoFlag/GeoFlag.vi.mdx +87 -44
- package/src/media/functional/functional-basic/classes/GeoInstance/GeoInstance.en.mdx +81 -0
- package/src/media/functional/functional-basic/classes/GeoInstance/GeoInstance.ru.mdx +81 -0
- package/src/media/functional/functional-basic/classes/GeoInstance/GeoInstance.vi.mdx +81 -0
- package/src/media/functional/functional-basic/classes/GeoPhone/GeoPhone.en.mdx +56 -105
- package/src/media/functional/functional-basic/classes/GeoPhone/GeoPhone.ru.mdx +53 -102
- package/src/media/functional/functional-basic/classes/GeoPhone/GeoPhone.vi.mdx +55 -105
- package/src/media/functional/functional-basic/classes/Hash/Hash.en.mdx +18 -7
- package/src/media/functional/functional-basic/classes/Hash/Hash.ru.mdx +18 -7
- package/src/media/functional/functional-basic/classes/Hash/Hash.vi.mdx +18 -7
- package/src/media/functional/functional-basic/classes/HashInstance/HashInstance.en.mdx +54 -0
- package/src/media/functional/functional-basic/classes/HashInstance/HashInstance.ru.mdx +54 -0
- package/src/media/functional/functional-basic/classes/HashInstance/HashInstance.vi.mdx +54 -0
- package/src/media/functional/functional-basic/classes/MetaStatic/MetaStatic.en.mdx +78 -0
- package/src/media/functional/functional-basic/classes/MetaStatic/MetaStatic.ru.mdx +78 -0
- package/src/media/functional/functional-basic/classes/MetaStatic/MetaStatic.vi.mdx +78 -0
- package/src/media/functional/functional-basic/classes/ResumableTimer/ResumableTimer.en.mdx +50 -0
- package/src/media/functional/functional-basic/classes/ResumableTimer/ResumableTimer.ru.mdx +50 -0
- package/src/media/functional/functional-basic/classes/ResumableTimer/ResumableTimer.vi.mdx +50 -0
- package/src/media/functional/functional-basic/classes/ServerStorage/ServerStorage.en.mdx +131 -0
- package/src/media/functional/functional-basic/classes/ServerStorage/ServerStorage.ru.mdx +131 -0
- package/src/media/functional/functional-basic/classes/ServerStorage/ServerStorage.vi.mdx +131 -0
- package/src/media/functional/functional-basic/classes/StorageCallback/StorageCallback.en.mdx +97 -0
- package/src/media/functional/functional-basic/classes/StorageCallback/StorageCallback.ru.mdx +97 -0
- package/src/media/functional/functional-basic/classes/StorageCallback/StorageCallback.vi.mdx +97 -0
- package/src/media/functional/functional-basic/functions/addTagHighlightMatch/addTagHighlightMatch.en.mdx +13 -5
- package/src/media/functional/functional-basic/functions/addTagHighlightMatch/addTagHighlightMatch.ru.mdx +13 -5
- package/src/media/functional/functional-basic/functions/addTagHighlightMatch/addTagHighlightMatch.vi.mdx +13 -5
- package/src/media/functional/functional-basic/functions/anyToString/anyToString.en.mdx +37 -19
- package/src/media/functional/functional-basic/functions/anyToString/anyToString.ru.mdx +37 -19
- package/src/media/functional/functional-basic/functions/anyToString/anyToString.vi.mdx +35 -17
- package/src/media/functional/functional-basic/functions/applyTemplate/applyTemplate.en.mdx +31 -19
- package/src/media/functional/functional-basic/functions/applyTemplate/applyTemplate.ru.mdx +31 -19
- package/src/media/functional/functional-basic/functions/applyTemplate/applyTemplate.vi.mdx +32 -20
- package/src/media/functional/functional-basic/functions/blobToBase64/blobToBase64.en.mdx +29 -15
- package/src/media/functional/functional-basic/functions/blobToBase64/blobToBase64.ru.mdx +28 -14
- package/src/media/functional/functional-basic/functions/blobToBase64/blobToBase64.vi.mdx +28 -14
- package/src/media/functional/functional-basic/functions/capitalize/capitalize.en.mdx +7 -3
- package/src/media/functional/functional-basic/functions/capitalize/capitalize.ru.mdx +7 -3
- package/src/media/functional/functional-basic/functions/capitalize/capitalize.vi.mdx +7 -3
- package/src/media/functional/functional-basic/functions/copyObject/copyObject.en.mdx +17 -13
- package/src/media/functional/functional-basic/functions/copyObject/copyObject.ru.mdx +17 -13
- package/src/media/functional/functional-basic/functions/copyObject/copyObject.vi.mdx +17 -13
- package/src/media/functional/functional-basic/functions/createElement/createElement.en.mdx +2 -0
- package/src/media/functional/functional-basic/functions/createElement/createElement.ru.mdx +2 -0
- package/src/media/functional/functional-basic/functions/createElement/createElement.vi.mdx +2 -0
- package/src/media/functional/functional-basic/functions/encodeAttribute/encodeAttribute.en.mdx +1 -3
- package/src/media/functional/functional-basic/functions/encodeAttribute/encodeAttribute.ru.mdx +1 -3
- package/src/media/functional/functional-basic/functions/encodeAttribute/encodeAttribute.vi.mdx +1 -3
- package/src/media/functional/functional-basic/functions/executeFunction/executeFunction.en.mdx +13 -10
- package/src/media/functional/functional-basic/functions/executeFunction/executeFunction.ru.mdx +14 -11
- package/src/media/functional/functional-basic/functions/executeFunction/executeFunction.vi.mdx +12 -9
- package/src/media/functional/functional-basic/functions/executePromise/executePromise.en.mdx +14 -13
- package/src/media/functional/functional-basic/functions/executePromise/executePromise.ru.mdx +15 -14
- package/src/media/functional/functional-basic/functions/executePromise/executePromise.vi.mdx +14 -13
- package/src/media/functional/functional-basic/functions/forEach/forEach.en.mdx +1 -1
- package/src/media/functional/functional-basic/functions/forEach/forEach.ru.mdx +1 -1
- package/src/media/functional/functional-basic/functions/forEach/forEach.vi.mdx +1 -1
- package/src/media/functional/functional-basic/functions/frame/frame.en.mdx +7 -4
- package/src/media/functional/functional-basic/functions/frame/frame.ru.mdx +6 -3
- package/src/media/functional/functional-basic/functions/frame/frame.vi.mdx +7 -4
- package/src/media/functional/functional-basic/functions/getArrayHighlightMatch/getArrayHighlightMatch.en.mdx +34 -0
- package/src/media/functional/functional-basic/functions/getArrayHighlightMatch/getArrayHighlightMatch.ru.mdx +34 -0
- package/src/media/functional/functional-basic/functions/getArrayHighlightMatch/getArrayHighlightMatch.vi.mdx +35 -0
- package/src/media/functional/functional-basic/functions/getCurrentDate/getCurrentDate.en.mdx +2 -0
- package/src/media/functional/functional-basic/functions/getCurrentDate/getCurrentDate.ru.mdx +2 -0
- package/src/media/functional/functional-basic/functions/getCurrentDate/getCurrentDate.vi.mdx +2 -0
- package/src/media/functional/functional-basic/functions/getCurrentTime/getCurrentTime.en.mdx +21 -0
- package/src/media/functional/functional-basic/functions/getCurrentTime/getCurrentTime.ru.mdx +21 -0
- package/src/media/functional/functional-basic/functions/getCurrentTime/getCurrentTime.vi.mdx +21 -0
- package/src/media/functional/functional-basic/functions/getElementId/getElementId.en.mdx +17 -3
- package/src/media/functional/functional-basic/functions/getElementId/getElementId.ru.mdx +17 -3
- package/src/media/functional/functional-basic/functions/getElementId/getElementId.vi.mdx +18 -4
- package/src/media/functional/functional-basic/functions/getElementSafeScript/getElementSafeScript.en.mdx +31 -0
- package/src/media/functional/functional-basic/functions/getElementSafeScript/getElementSafeScript.ru.mdx +31 -0
- package/src/media/functional/functional-basic/functions/getElementSafeScript/getElementSafeScript.vi.mdx +31 -0
- package/src/media/functional/functional-basic/functions/getOnlyText/getOnlyText.en.mdx +25 -0
- package/src/media/functional/functional-basic/functions/getOnlyText/getOnlyText.ru.mdx +25 -0
- package/src/media/functional/functional-basic/functions/getOnlyText/getOnlyText.vi.mdx +25 -0
- package/src/media/functional/functional-basic/functions/getSearchExp/getSearchExp.en.mdx +11 -4
- package/src/media/functional/functional-basic/functions/getSearchExp/getSearchExp.ru.mdx +14 -7
- package/src/media/functional/functional-basic/functions/getSearchExp/getSearchExp.vi.mdx +13 -6
- package/src/media/functional/functional-basic/functions/getSeparatingSearchExp/getSeparatingSearchExp.en.mdx +3 -2
- package/src/media/functional/functional-basic/functions/getSeparatingSearchExp/getSeparatingSearchExp.ru.mdx +3 -2
- package/src/media/functional/functional-basic/functions/getSeparatingSearchExp/getSeparatingSearchExp.vi.mdx +3 -2
- package/src/media/functional/functional-basic/functions/toNumber/toNumber.en.mdx +25 -9
- package/src/media/functional/functional-basic/functions/toNumber/toNumber.ru.mdx +25 -9
- package/src/media/functional/functional-basic/functions/toNumber/toNumber.vi.mdx +25 -9
- package/src/media/functional/functional-basic/functions/toString/toString.en.mdx +28 -0
- package/src/media/functional/functional-basic/functions/toString/toString.ru.mdx +28 -0
- package/src/media/functional/functional-basic/functions/toString/toString.vi.mdx +28 -0
- package/src/media/functional/ui/about/about.en.mdx +45 -0
- package/src/media/functional/ui/about/about.ru.mdx +45 -0
- package/src/media/functional/ui/about/about.vi.mdx +45 -0
- package/src/media/functional/ui/component/component.en.mdx +104 -0
- package/src/media/functional/ui/component/component.ru.mdx +106 -0
- package/src/media/functional/ui/component/component.vi.mdx +104 -0
- package/src/media/functional/ui/setup/setup.en.mdx +72 -0
- package/src/media/functional/ui/setup/setup.ru.mdx +72 -0
- package/src/media/functional/ui/setup/setup.vi.mdx +72 -0
- package/src/media/functional/ui/wiki-data.en.mdx +114 -0
- package/src/media/functional/ui/wiki-data.ru.mdx +114 -0
- package/src/media/functional/ui/wiki-data.vi.mdx +114 -0
- package/dist/WikiStorybookDescriptions-IKMchHA-.js +0 -26959
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import {Meta} from '@storybook/addon-docs/blocks'
|
|
2
|
+
|
|
3
|
+
<Meta title='@dxtmisha/ru/functional-basic/Classes/MetaStatic - Управление мета-тегами (Static)'/>
|
|
4
|
+
|
|
5
|
+
# Класс MetaStatic
|
|
6
|
+
|
|
7
|
+
Класс `MetaStatic` является **статической точкой входа** для управления мета-тегами страницы, данными Open Graph (OG) и Twitter Card. Он представляет собой статическую обертку над глобально управляемым экземпляром `Meta`, предоставляя удобный синглтон-интерфейс для SEO и социальных сетей.
|
|
8
|
+
|
|
9
|
+
## Ключевые особенности
|
|
10
|
+
|
|
11
|
+
- **Статический интерфейс** — управление заголовками, описаниями и другими данными без необходимости ручного создания экземпляров.
|
|
12
|
+
- **Единое управление** — автоматическая синхронизация заголовков и другой информации между стандартными мета-тегами, OG и Twitter.
|
|
13
|
+
- **Изоляция в SSR** — использует `ServerStorage` для обеспечения изоляции данных между запросами во время рендеринга на стороне сервера.
|
|
14
|
+
- **Fluent API** — поддержка цепочки вызовов (method chaining) в методах установки.
|
|
15
|
+
|
|
16
|
+
## Методы
|
|
17
|
+
|
|
18
|
+
### Доступ
|
|
19
|
+
|
|
20
|
+
- `getItem(): Meta` — Возвращает базовый экземпляр класса `Meta`.
|
|
21
|
+
- `getOg(): MetaOg` — Получает экземпляр `MetaOg` для расширенных операций с Open Graph.
|
|
22
|
+
- `getTwitter(): MetaTwitter` — Получает экземпляр `MetaTwitter` для расширенных операций с Twitter Card.
|
|
23
|
+
|
|
24
|
+
### Получение (Getters)
|
|
25
|
+
|
|
26
|
+
- `getTitle(): string` — Возвращает текущий заголовок (без суффикса).
|
|
27
|
+
- `getDescription(): string` — Возвращает содержимое мета-тега description.
|
|
28
|
+
- `getKeywords(): string` — Возвращает список ключевых слов.
|
|
29
|
+
- `getImage(): string` — Возвращает URL изображения (из настроек OG).
|
|
30
|
+
- `getCanonical(): string` — Возвращает канонический URL.
|
|
31
|
+
- `getRobots(): MetaRobots` — Возвращает текущую директиву robots.
|
|
32
|
+
- `getAuthor(): string` — Возвращает имя автора.
|
|
33
|
+
- `getSiteName(): string` — Возвращает название сайта (из настроек OG).
|
|
34
|
+
- `getLocale(): string` — Возвращает локаль (из настроек OG).
|
|
35
|
+
|
|
36
|
+
### Установка (Setters)
|
|
37
|
+
|
|
38
|
+
Все методы установки возвращают `typeof MetaStatic` для поддержки цепочки вызовов.
|
|
39
|
+
|
|
40
|
+
- `setTitle(title: string): typeof MetaStatic` — Устанавливает заголовок страницы и обновляет заголовки OG/Twitter.
|
|
41
|
+
- `setDescription(description: string): typeof MetaStatic` — Устанавливает мета-тег description.
|
|
42
|
+
- `setKeywords(keywords: string | string[]): typeof MetaStatic` — Устанавливает ключевые слова (строка или массив).
|
|
43
|
+
- `setImage(image: string): typeof MetaStatic` — Устанавливает изображение для OG и Twitter.
|
|
44
|
+
- `setCanonical(canonical: string): typeof MetaStatic` — Устанавливает канонический URL и обновляет URL для OG/Twitter.
|
|
45
|
+
- `setRobots(robots: MetaRobots): typeof MetaStatic` — Устанавливает директиву robots.
|
|
46
|
+
- `setAuthor(author: string): typeof MetaStatic` — Устанавливает мета-тег author.
|
|
47
|
+
- `setSiteName(siteName: string): typeof MetaStatic` — Устанавливает название сайта для OG и Twitter.
|
|
48
|
+
- `setLocale(locale: string): typeof MetaStatic` — Устанавливает локаль для Open Graph.
|
|
49
|
+
- `setSuffix(suffix?: string): typeof MetaStatic` — Устанавливает суффикс (например, " | Мой Сайт"), добавляемый к заголовкам.
|
|
50
|
+
|
|
51
|
+
### Вывод
|
|
52
|
+
|
|
53
|
+
- `html(): string` — Генерирует полную строку HTML-тегов для всех управляемых свойств.
|
|
54
|
+
|
|
55
|
+
## Архитектура
|
|
56
|
+
|
|
57
|
+
`MetaStatic` работает как **статический прокси**. Все вызовы методов перенаправляются на внутренний экземпляр `Meta`, который управляется через `ServerStorage`.
|
|
58
|
+
|
|
59
|
+
### Изоляция запросов (SSR)
|
|
60
|
+
|
|
61
|
+
Благодаря использованию `ServerStorage`, `MetaStatic` гарантирует, что при рендеринге на стороне сервера (SSR) информация одного запроса не попадет в другой. Каждый запрос получает свой изолированный контекст.
|
|
62
|
+
|
|
63
|
+
### Примеры
|
|
64
|
+
|
|
65
|
+
```typescript
|
|
66
|
+
import { MetaStatic } from '@dxtmisha/functional-basic';
|
|
67
|
+
|
|
68
|
+
MetaStatic
|
|
69
|
+
.setSuffix('Мой Интернет Магазин')
|
|
70
|
+
.setTitle('Летняя коллекция')
|
|
71
|
+
.setDescription('Ознакомьтесь с нашими новинками.')
|
|
72
|
+
.setImage('https://example.com/cover.jpg')
|
|
73
|
+
.setLocale('ru_RU');
|
|
74
|
+
|
|
75
|
+
console.log(MetaStatic.getTitle()); // "Летняя коллекция"
|
|
76
|
+
document.title; // "Летняя коллекция - Мой Интернет Магазин"
|
|
77
|
+
```
|
|
78
|
+
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import {Meta} from '@storybook/addon-docs/blocks'
|
|
2
|
+
|
|
3
|
+
<Meta title='@dxtmisha/vi/functional-basic/Classes/MetaStatic - Quản lý Meta Tags (Static)'/>
|
|
4
|
+
|
|
5
|
+
# Class MetaStatic
|
|
6
|
+
|
|
7
|
+
Lớp `MetaStatic` là **điểm truy cập tĩnh** để quản lý các thẻ meta của trang, dữ liệu Open Graph (OG) và Twitter Card. Nó hoạt động như một lớp vỏ bọc tĩnh (static wrapper) xung quanh một thực thể `Meta` được quản lý toàn cục, cung cấp một giao diện singleton sạch sẽ để quản lý SEO và chia sẻ mạng xã hội.
|
|
8
|
+
|
|
9
|
+
## Các tính năng chính
|
|
10
|
+
|
|
11
|
+
- **Giao diện tĩnh** — Quản lý tiêu đề trang, mô tả và nhiều thứ khác mà không cần khởi tạo thủ công.
|
|
12
|
+
- **Quản lý thống nhất** — Tự động đồng bộ hóa tiêu đề và các thông tin khác trên các thẻ meta tiêu chuẩn, OG và Twitter.
|
|
13
|
+
- **Cách ly trong SSR** — Sử dụng `ServerStorage` để xử lý cách ly thực thể trong quá trình render phía máy chủ (server-side rendering).
|
|
14
|
+
- **Fluent API** — Hỗ trợ kỹ thuật method chaining cho các phương thức thiết lập (setter).
|
|
15
|
+
|
|
16
|
+
## Các phương thức
|
|
17
|
+
|
|
18
|
+
### Truy cập
|
|
19
|
+
|
|
20
|
+
- `getItem(): Meta` — Trả về thực thể `Meta` cơ sở.
|
|
21
|
+
- `getOg(): MetaOg` — Lấy thực thể `MetaOg` cho các thao tác Open Graph nâng cao.
|
|
22
|
+
- `getTwitter(): MetaTwitter` — Lấy thực thể `MetaTwitter` cho các thao tác Twitter Card nâng cao.
|
|
23
|
+
|
|
24
|
+
### Lấy dữ liệu (Getters)
|
|
25
|
+
|
|
26
|
+
- `getTitle(): string` — Lấy tiêu đề trang hiện tại (không bao gồm hậu tố).
|
|
27
|
+
- `getDescription(): string` — Lấy nội dung thẻ meta description.
|
|
28
|
+
- `getKeywords(): string` — Lấy các từ khóa hiện tại.
|
|
29
|
+
- `getImage(): string` — Lấy URL hình ảnh (từ cài đặt OG).
|
|
30
|
+
- `getCanonical(): string` — Lấy URL chuẩn (canonical).
|
|
31
|
+
- `getRobots(): MetaRobots` — Lấy chỉ thị robots hiện tại.
|
|
32
|
+
- `getAuthor(): string` — Lấy tên tác giả.
|
|
33
|
+
- `getSiteName(): string` — Lấy tên trang web (từ cài đặt OG).
|
|
34
|
+
- `getLocale(): string` — Lấy mã ngôn ngữ/khu vực (từ cài đặt OG).
|
|
35
|
+
|
|
36
|
+
### Thiết lập (Setters)
|
|
37
|
+
|
|
38
|
+
Tất cả các phương thức thiết lập đều trả về `typeof MetaStatic` để hỗ trợ method chaining.
|
|
39
|
+
|
|
40
|
+
- `setTitle(title: string): typeof MetaStatic` — Thiết lập tiêu đề trang và cập nhật tiêu đề OG/Twitter.
|
|
41
|
+
- `setDescription(description: string): typeof MetaStatic` — Thiết lập thẻ meta description.
|
|
42
|
+
- `setKeywords(keywords: string | string[]): typeof MetaStatic` — Thiết lập từ khóa (chuỗi hoặc mảng).
|
|
43
|
+
- `setImage(image: string): typeof MetaStatic` — Thiết lập hình ảnh cho OG và Twitter.
|
|
44
|
+
- `setCanonical(canonical: string): typeof MetaStatic` — Thiết lập URL chuẩn và cập nhật URL cho OG/Twitter.
|
|
45
|
+
- `setRobots(robots: MetaRobots): typeof MetaStatic` — Thiết lập chỉ thị robots.
|
|
46
|
+
- `setAuthor(author: string): typeof MetaStatic` — Thiết lập thẻ meta author.
|
|
47
|
+
- `setSiteName(siteName: string): typeof MetaStatic` — Thiết lập tên trang web cho OG và Twitter.
|
|
48
|
+
- `setLocale(locale: string): typeof MetaStatic` — Thiết lập mã ngôn ngữ cho Open Graph.
|
|
49
|
+
- `setSuffix(suffix?: string): typeof MetaStatic` — Thiết lập hậu tố (ví dụ: " | My Site") được thêm vào cuối tiêu đề.
|
|
50
|
+
|
|
51
|
+
### Đầu ra
|
|
52
|
+
|
|
53
|
+
- `html(): string` — Tạo ra một chuỗi đầy đủ các thẻ HTML meta cho tất cả các thuộc tính được quản lý.
|
|
54
|
+
|
|
55
|
+
## Kiến trúc
|
|
56
|
+
|
|
57
|
+
`MetaStatic` hoạt động như một **proxy tĩnh**. Tất cả các cuộc gọi phương thức được chuyển tiếp đến một thực thể `Meta` nội bộ được quản lý thông qua `ServerStorage`.
|
|
58
|
+
|
|
59
|
+
### Cách ly yêu cầu (SSR)
|
|
60
|
+
|
|
61
|
+
Bằng cách sử dụng `ServerStorage`, `MetaStatic` đảm bảo rằng trong quá trình Render phía máy chủ (SSR), thông tin meta của một yêu cầu không bị rò rỉ sang yêu cầu khác. Mỗi yêu cầu có một bối cảnh cách ly riêng.
|
|
62
|
+
|
|
63
|
+
### Ví dụ
|
|
64
|
+
|
|
65
|
+
```typescript
|
|
66
|
+
import { MetaStatic } from '@dxtmisha/functional-basic';
|
|
67
|
+
|
|
68
|
+
MetaStatic
|
|
69
|
+
.setSuffix('Cửa hàng trực tuyến của tôi')
|
|
70
|
+
.setTitle('Bộ sưu tập mùa hè')
|
|
71
|
+
.setDescription('Khám phá các sản phẩm mới nhất của chúng tôi.')
|
|
72
|
+
.setImage('https://example.com/cover.jpg')
|
|
73
|
+
.setLocale('vi_VN');
|
|
74
|
+
|
|
75
|
+
console.log(MetaStatic.getTitle()); // "Bộ sưu tập mùa hè"
|
|
76
|
+
document.title; // "Bộ sưu tập mùa hè - Cửa hàng trực tuyến của tôi"
|
|
77
|
+
```
|
|
78
|
+
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import {Meta} from '@storybook/addon-docs/blocks'
|
|
2
|
+
|
|
3
|
+
<Meta title='@dxtmisha/en/functional-basic/Classes/ResumableTimer - Pausable Timer'/>
|
|
4
|
+
|
|
5
|
+
# ResumableTimer Class
|
|
6
|
+
|
|
7
|
+
A class for creating a timer that can be paused, resumed, reset, and cleared. It is useful for UI elements that need to track elapsed time even when interrupted, such as progress bars, auto-closing notifications, or slides.
|
|
8
|
+
|
|
9
|
+
## Key Features
|
|
10
|
+
|
|
11
|
+
- **Pause & Resume** — stop the countdown and continue later from the exact millisecond where it left off.
|
|
12
|
+
- **Completion Tracking** — explicitly tracks if the timer has finished its execution.
|
|
13
|
+
- **Robust Logic** — handles edge cases like resuming when time has already elapsed.
|
|
14
|
+
- **Fluent Interface** — methods return `this`, allowing for method chaining.
|
|
15
|
+
|
|
16
|
+
## Initialization
|
|
17
|
+
|
|
18
|
+
To initialize the object, call the constructor `ResumableTimer(callback, delay, blockStart)`.
|
|
19
|
+
|
|
20
|
+
**Parameters:**
|
|
21
|
+
- `callback: FunctionVoid` — the function to be called after the delay.
|
|
22
|
+
- `delay: number = 320` — delay in milliseconds.
|
|
23
|
+
- `blockStart: boolean = false` — if true, the timer will not start immediately.
|
|
24
|
+
|
|
25
|
+
```typescript
|
|
26
|
+
import { ResumableTimer } from '@dxtmisha/functional-basic'
|
|
27
|
+
|
|
28
|
+
// 1. Basic initialization (starts immediately)
|
|
29
|
+
const timer = new ResumableTimer(() => {
|
|
30
|
+
console.log('Timer finished!')
|
|
31
|
+
}, 5000)
|
|
32
|
+
|
|
33
|
+
// 2. Initialization without starting
|
|
34
|
+
const delayedTimer = new ResumableTimer(
|
|
35
|
+
() => console.log('Task started!'),
|
|
36
|
+
3000,
|
|
37
|
+
true
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
delayedTimer.resume() // Start it manually
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Methods
|
|
44
|
+
|
|
45
|
+
### Management
|
|
46
|
+
|
|
47
|
+
- `resume(): this` — Starts or resumes the timer.
|
|
48
|
+
- `pause(): this` — Pauses the timer and calculates the remaining time.
|
|
49
|
+
- `reset(): this` — Completely clears the current state and restarts the timer with the original delay.
|
|
50
|
+
- `clear(): this` — Completely stops the timer and resets all internal states.
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import {Meta} from '@storybook/addon-docs/blocks'
|
|
2
|
+
|
|
3
|
+
<Meta title='@dxtmisha/ru/functional-basic/Classes/ResumableTimer - Таймер с паузой'/>
|
|
4
|
+
|
|
5
|
+
# Класс ResumableTimer
|
|
6
|
+
|
|
7
|
+
Класс для создания таймера, который можно приостанавливать, возобновлять, сбрасывать и очищать. Он полезен для элементов интерфейса, которым необходимо отслеживать прошедшее время даже при прерывании, таких как прогресс-бары, автоматически закрывающиеся уведомления или слайды.
|
|
8
|
+
|
|
9
|
+
## Ключевые особенности
|
|
10
|
+
|
|
11
|
+
- **Пауза и возобновление** — останавливает обратный отсчет и продолжает его позже с точностью до миллисекунды.
|
|
12
|
+
- **Отслеживание завершения** — явно отслеживает, закончил ли таймер свое выполнение.
|
|
13
|
+
- **Надежная логика** — обрабатывает крайние случаи, такие как возобновление, когда время уже истекло.
|
|
14
|
+
- **Fluent Interface** — методы возвращают `this`, что позволяет использовать цепочки вызовов.
|
|
15
|
+
|
|
16
|
+
## Инициализация
|
|
17
|
+
|
|
18
|
+
Для инициализации объекта вызовите конструктор `ResumableTimer(callback, delay, blockStart)`.
|
|
19
|
+
|
|
20
|
+
**Параметры:**
|
|
21
|
+
- `callback: FunctionVoid` — функция, которая будет вызвана после задержки.
|
|
22
|
+
- `delay: number = 320` — задержка в миллисекундах.
|
|
23
|
+
- `blockStart: boolean = false` — если true, таймер не запустится сразу.
|
|
24
|
+
|
|
25
|
+
```typescript
|
|
26
|
+
import { ResumableTimer } from '@dxtmisha/functional-basic'
|
|
27
|
+
|
|
28
|
+
// 1. Базовая инициализация (запускается сразу)
|
|
29
|
+
const timer = new ResumableTimer(() => {
|
|
30
|
+
console.log('Таймер завершен!')
|
|
31
|
+
}, 5000)
|
|
32
|
+
|
|
33
|
+
// 2. Инициализация без немедленного запуска
|
|
34
|
+
const delayedTimer = new ResumableTimer(
|
|
35
|
+
() => console.log('Задача запущена!'),
|
|
36
|
+
3000,
|
|
37
|
+
true
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
delayedTimer.resume() // Запуск вручную
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Методы
|
|
44
|
+
|
|
45
|
+
### Управление
|
|
46
|
+
|
|
47
|
+
- `resume(): this` — Запускает или возобновляет таймер.
|
|
48
|
+
- `pause(): this` — Приостанавливает таймер и вычисляет оставшееся время.
|
|
49
|
+
- `reset(): this` — Полностью сбрасывает текущее состояние и перезапускает таймер с исходной задержкой.
|
|
50
|
+
- `clear(): this` — Полностью останавливает таймер и сбрасывает все внутренние состояния.
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import {Meta} from '@storybook/addon-docs/blocks'
|
|
2
|
+
|
|
3
|
+
<Meta title='@dxtmisha/vi/functional-basic/Classes/ResumableTimer - Bộ hẹn giờ có thể tạm dừng'/>
|
|
4
|
+
|
|
5
|
+
# Lớp ResumableTimer
|
|
6
|
+
|
|
7
|
+
Lớp chuyên dùng để tạo bộ hẹn giờ có thể tạm dừng, tiếp tục, thiết lập lại và xóa bỏ. Nó hữu ích cho các thành phần giao diện người dùng cần theo dõi thời gian đã trôi qua ngay cả khi bị gián đoạn, chẳng hạn như thanh tiến trình, thông báo tự động đóng hoặc các slide.
|
|
8
|
+
|
|
9
|
+
## Các tính năng chính
|
|
10
|
+
|
|
11
|
+
- **Tạm dừng & Tiếp tục** — dừng đếm ngược và tiếp tục sau đó từ chính xác mili giây đã dừng lại.
|
|
12
|
+
- **Theo dõi hoàn thành** — theo dõi rõ ràng xem bộ hẹn giờ đã kết thúc thực thi hay chưa.
|
|
13
|
+
- **Logic mạnh mẽ** — xử lý các trường hợp biên như tiếp tục khi thời gian đã trôi qua hết.
|
|
14
|
+
- **Giao diện mượt mà (Fluent Interface)** — các phương thức trả về `this`, cho phép gọi chuỗi phương thức.
|
|
15
|
+
|
|
16
|
+
## Khởi tạo
|
|
17
|
+
|
|
18
|
+
Để khởi tạo đối tượng, hãy gọi hàm khởi tạo `ResumableTimer(callback, delay, blockStart)`.
|
|
19
|
+
|
|
20
|
+
**Tham số:**
|
|
21
|
+
- `callback: FunctionVoid` — hàm sẽ được gọi sau khoảng thời gian trễ.
|
|
22
|
+
- `delay: number = 320` — thời gian trễ tính bằng mili giây.
|
|
23
|
+
- `blockStart: boolean = false` — nếu là true, bộ hẹn giờ sẽ không bắt đầu ngay lập tức.
|
|
24
|
+
|
|
25
|
+
```typescript
|
|
26
|
+
import { ResumableTimer } from '@dxtmisha/functional-basic'
|
|
27
|
+
|
|
28
|
+
// 1. Khởi tạo cơ bản (bắt đầu ngay lập tức)
|
|
29
|
+
const timer = new ResumableTimer(() => {
|
|
30
|
+
console.log('Hết giờ!')
|
|
31
|
+
}, 5000)
|
|
32
|
+
|
|
33
|
+
// 2. Khởi tạo không bắt đầu ngay
|
|
34
|
+
const delayedTimer = new ResumableTimer(
|
|
35
|
+
() => console.log('Nhiệm vụ bắt đầu!'),
|
|
36
|
+
3000,
|
|
37
|
+
true
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
delayedTimer.resume() // Bắt đầu thủ công
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Các phương thức
|
|
44
|
+
|
|
45
|
+
### Quản lý
|
|
46
|
+
|
|
47
|
+
- `resume(): this` — Bắt đầu hoặc tiếp tục bộ hẹn giờ.
|
|
48
|
+
- `pause(): this` — Tạm dừng bộ hẹn giờ và tính toán thời gian còn lại.
|
|
49
|
+
- `reset(): this` — Xóa hoàn toàn trạng thái hiện tại và khởi động lại với độ trễ ban đầu.
|
|
50
|
+
- `clear(): this` — Dừng hoàn toàn bộ hẹn giờ và thiết lập lại tất cả các trạng thái nội bộ.
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import {Meta} from '@storybook/addon-docs/blocks'
|
|
2
|
+
|
|
3
|
+
<Meta title='@dxtmisha/en/functional-basic/Classes/ServerStorage - Data Isolation in SSR'/>
|
|
4
|
+
|
|
5
|
+
# ServerStorage Class
|
|
6
|
+
|
|
7
|
+
`ServerStorage` is a mechanism for managing **isolated global state** in applications with SSR (Server-Side Rendering) support.
|
|
8
|
+
|
|
9
|
+
The class allows you to work with data as easily as with static variables, but ensures that user data on the server does not intermingle between parallel requests.
|
|
10
|
+
|
|
11
|
+
## Key Features
|
|
12
|
+
|
|
13
|
+
- **Request Isolation** — data on the server is bound to the context of the current human or machine request.
|
|
14
|
+
- **Hydration** — ability to automatically transfer state from the server to the client via JSON.
|
|
15
|
+
- **Security** — automatic XSS escaping during data transfer.
|
|
16
|
+
|
|
17
|
+
```typescript
|
|
18
|
+
import { ServerStorage } from '@dxtmisha/functional-basic'
|
|
19
|
+
|
|
20
|
+
// Save data with a hydration flag (will be available on the client)
|
|
21
|
+
ServerStorage.set('theme', () => 'dark', true)
|
|
22
|
+
|
|
23
|
+
// Retrieve data
|
|
24
|
+
const theme = ServerStorage.get('theme') // 'dark'
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Data Access Methods
|
|
28
|
+
|
|
29
|
+
### `get`
|
|
30
|
+
|
|
31
|
+
Retrieves a value by key. If it doesn't exist, creates it using the default value factory.
|
|
32
|
+
|
|
33
|
+
**Parameters:**
|
|
34
|
+
- `key: string` — unique storage key.
|
|
35
|
+
- `defaultValue?: () => T` — function that returns the default value if not found.
|
|
36
|
+
- `hydration: boolean` — if `true`, the value will be included in the JSON for the client (default: `false`).
|
|
37
|
+
|
|
38
|
+
**Returns:** `T`
|
|
39
|
+
|
|
40
|
+
### `set`
|
|
41
|
+
|
|
42
|
+
Saves a value to the storage.
|
|
43
|
+
|
|
44
|
+
**Parameters:**
|
|
45
|
+
- `key: string` — unique storage key.
|
|
46
|
+
- `value: () => T` — function that returns the value to save.
|
|
47
|
+
- `hydration: boolean` — if `true`, the value will be included in the JSON for the client (default: `false`).
|
|
48
|
+
|
|
49
|
+
**Returns:** `T`
|
|
50
|
+
|
|
51
|
+
## Utility & Lifecycle Methods
|
|
52
|
+
|
|
53
|
+
- `init(listener: () => Record<string, any>): typeof ServerStorage` — Initializes the storage with a context listener. On the server, this listener should return an object unique to each request.
|
|
54
|
+
- `has(key: string): boolean` — Checks for the existence of a key in the current context.
|
|
55
|
+
- `reset(): void` — Resets the storage, clearing all stored data and the listener. Useful for performing cleanup.
|
|
56
|
+
- `toString(): string` — Generates an HTML `<script type="application/json">` tag containing all data marked for hydration.
|
|
57
|
+
|
|
58
|
+
## Isolation in SSR
|
|
59
|
+
|
|
60
|
+
In standard client-side applications, global state belongs to a single user. However, in an SSR environment, one Node.js process handles many concurrent requests simultaneously. To prevent user data from "leaking" between these requests (State Pollution), `ServerStorage` must be correctly isolated.
|
|
61
|
+
|
|
62
|
+
To achieve this, you must initialize `ServerStorage` with the `init` method. This method accepts a listener function that returns a data object unique to the current request context.
|
|
63
|
+
|
|
64
|
+
> Important: Correct isolation is critical for security. If not configured, data from one user could be served to another.
|
|
65
|
+
|
|
66
|
+
### Node.js (AsyncLocalStorage)
|
|
67
|
+
|
|
68
|
+
The recommended way for Node.js is to use `AsyncLocalStorage` to store context throughout an asynchronous request.
|
|
69
|
+
|
|
70
|
+
```typescript
|
|
71
|
+
import { AsyncLocalStorage } from 'node:async_hooks'
|
|
72
|
+
import { ServerStorage } from '@dxtmisha/functional-basic'
|
|
73
|
+
|
|
74
|
+
const als = new AsyncLocalStorage<Record<string, any>>()
|
|
75
|
+
|
|
76
|
+
// Initialization
|
|
77
|
+
ServerStorage.init(() => als.getStore() || {})
|
|
78
|
+
|
|
79
|
+
// Usage in server
|
|
80
|
+
http.createServer((req, res) => {
|
|
81
|
+
als.run({}, () => {
|
|
82
|
+
// All calls to ServerStorage inside this block will be isolated
|
|
83
|
+
ServerStorage.set('requestId', () => req.id)
|
|
84
|
+
})
|
|
85
|
+
})
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### Nuxt / Nitro
|
|
89
|
+
|
|
90
|
+
In Nuxt/Nitro, isolation is managed via the `h3` event context using `useEvent()` within a server plugin.
|
|
91
|
+
|
|
92
|
+
```typescript
|
|
93
|
+
// server/plugins/server-storage.ts
|
|
94
|
+
import { ServerStorage } from '@dxtmisha/functional-basic'
|
|
95
|
+
|
|
96
|
+
export default defineNitroPlugin(() => {
|
|
97
|
+
ServerStorage.init(() => {
|
|
98
|
+
try {
|
|
99
|
+
return useEvent().context
|
|
100
|
+
} catch {
|
|
101
|
+
return {}
|
|
102
|
+
}
|
|
103
|
+
})
|
|
104
|
+
})
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
## Hydration (Transferring Data to Client)
|
|
108
|
+
|
|
109
|
+
Hydration is the process of transferring the application state set on the server to the client. This allows the browser to pick up where the server left off, ensuring consistency and preventing redundant data fetching or "flickering" during page load.
|
|
110
|
+
|
|
111
|
+
### 1. Identify Data for Hydration
|
|
112
|
+
|
|
113
|
+
When using `set()` or `get()`, pass `true` as the third parameter (`hydration`). Only values marked this way will be transferred to the client.
|
|
114
|
+
|
|
115
|
+
```typescript
|
|
116
|
+
// Set on server
|
|
117
|
+
ServerStorage.set('userSettings', () => ({ fontSize: 16 }), true)
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
### 2. Injecting State into HTML
|
|
121
|
+
|
|
122
|
+
On the server, you must call `ServerStorage.toString()` and insert its result into your page template (usually at the very end of the `<body>` tag, before your application scripts).
|
|
123
|
+
|
|
124
|
+
This method generates a special script tag:
|
|
125
|
+
```html
|
|
126
|
+
<script id="__ui:server:storage:id__" type="application/json">
|
|
127
|
+
{"userSettings":{"fontSize":16}}
|
|
128
|
+
</script>
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import {Meta} from '@storybook/addon-docs/blocks'
|
|
2
|
+
|
|
3
|
+
<Meta title='@dxtmisha/ru/functional-basic/Classes/ServerStorage - Изоляция данных в SSR'/>
|
|
4
|
+
|
|
5
|
+
# Класс ServerStorage
|
|
6
|
+
|
|
7
|
+
`ServerStorage` — это механизм для управления **изолированным глобальным состоянием** в приложениях с поддержкой SSR (Server-Side Rendering).
|
|
8
|
+
|
|
9
|
+
Класс позволяет работать с данными так же просто, как со статическими переменными, но гарантирует, что на сервере данные разных пользователей не будут смешиваться.
|
|
10
|
+
|
|
11
|
+
## Основные возможности
|
|
12
|
+
|
|
13
|
+
- **Изоляция запросов** — на сервере данные привязываются к контексту текущего HTTP-запроса.
|
|
14
|
+
- **Гидратация** — возможность автоматически передавать состояние с сервера на клиент через JSON.
|
|
15
|
+
- **Безопасность** — автоматическое экранирование XSS при передаче данных.
|
|
16
|
+
|
|
17
|
+
```typescript
|
|
18
|
+
import { ServerStorage } from '@dxtmisha/functional-basic'
|
|
19
|
+
|
|
20
|
+
// Сохранение данных с флагом гидратации (будут доступны на клиенте)
|
|
21
|
+
ServerStorage.set('theme', () => 'dark', true)
|
|
22
|
+
|
|
23
|
+
// Получение данных
|
|
24
|
+
const theme = ServerStorage.get('theme') // 'dark'
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Методы доступа к данным
|
|
28
|
+
|
|
29
|
+
### `get`
|
|
30
|
+
|
|
31
|
+
Извлекает значение по ключу. Если оно не существует, создает его с помощью фабрики значений по умолчанию.
|
|
32
|
+
|
|
33
|
+
**Параметры:**
|
|
34
|
+
- `key: string` — уникальный ключ хранилища.
|
|
35
|
+
- `defaultValue?: () => T` — функция, возвращающая значение по умолчанию, если оно не найдено.
|
|
36
|
+
- `hydration: boolean` — если `true`, значение будет включено в JSON для передачи на клиент (по умолчанию: `false`).
|
|
37
|
+
|
|
38
|
+
**Возвращает:** `T`
|
|
39
|
+
|
|
40
|
+
### `set`
|
|
41
|
+
|
|
42
|
+
Записывает значение в хранилище.
|
|
43
|
+
|
|
44
|
+
**Параметры:**
|
|
45
|
+
- `key: string` — уникальный ключ хранилища.
|
|
46
|
+
- `value: () => T` — функция, возвращающая значение для сохранения.
|
|
47
|
+
- `hydration: boolean` — если `true`, значение будет включено в JSON для передачи на клиент (по умолчанию: `false`).
|
|
48
|
+
|
|
49
|
+
**Возвращает:** `T`
|
|
50
|
+
|
|
51
|
+
## Вспомогательные методы и жизненный цикл
|
|
52
|
+
|
|
53
|
+
- `init(listener: () => Record<string, any>): typeof ServerStorage` — Инициализирует хранилище слушателем контекста. На сервере этот слушатель должен возвращать объект, уникальный для каждого запроса.
|
|
54
|
+
- `has(key: string): boolean` — Проверяет наличие ключа в текущем контексте.
|
|
55
|
+
- `reset(): void` — Сбрасывает хранилище, очищая все сохраненные данные и слушателя. Полезно для выполнения очистки.
|
|
56
|
+
- `toString(): string` — Генерирует HTML-тег `<script type="application/json">` со всеми данными, помеченными для гидратации.
|
|
57
|
+
|
|
58
|
+
## Изоляция в SSR
|
|
59
|
+
|
|
60
|
+
В обычных клиентских приложениях глобальное состояние принадлежит одному пользователю. Однако в среде SSR один процесс Node.js обрабатывает множество одновременных запросов. Чтобы данные пользователей не смешивались между собой (Загрязнение состояния), `ServerStorage` должен быть правильно изолирован.
|
|
61
|
+
|
|
62
|
+
Для этого необходимо инициализировать `ServerStorage` с помощью метода `init`. Он принимает функцию-слушатель, которая возвращает объект данных, уникальный для контекста текущего запроса.
|
|
63
|
+
|
|
64
|
+
> Важно: Правильная изоляция критична для безопасности. Без нее данные одного пользователя могут быть по ошибке переданы другому.
|
|
65
|
+
|
|
66
|
+
### Node.js (AsyncLocalStorage)
|
|
67
|
+
|
|
68
|
+
Рекомендуемый способ для Node.js — использование `AsyncLocalStorage` для сохранения контекста на протяжении асинхронного запроса.
|
|
69
|
+
|
|
70
|
+
```typescript
|
|
71
|
+
import { AsyncLocalStorage } from 'node:async_hooks'
|
|
72
|
+
import { ServerStorage } from '@dxtmisha/functional-basic'
|
|
73
|
+
|
|
74
|
+
const als = new AsyncLocalStorage<Record<string, any>>()
|
|
75
|
+
|
|
76
|
+
// Инициализация
|
|
77
|
+
ServerStorage.init(() => als.getStore() || {})
|
|
78
|
+
|
|
79
|
+
// Использование на сервере
|
|
80
|
+
http.createServer((req, res) => {
|
|
81
|
+
als.run({}, () => {
|
|
82
|
+
// Внутри этого блока все вызовы ServerStorage будут изолированы
|
|
83
|
+
ServerStorage.set('requestId', () => req.id)
|
|
84
|
+
})
|
|
85
|
+
})
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### Nuxt / Nitro
|
|
89
|
+
|
|
90
|
+
В Nuxt/Nitro изоляция управляется через контекст события `h3` с помощью `useEvent()` внутри серверного плагина.
|
|
91
|
+
|
|
92
|
+
```typescript
|
|
93
|
+
// server/plugins/server-storage.ts
|
|
94
|
+
import { ServerStorage } from '@dxtmisha/functional-basic'
|
|
95
|
+
|
|
96
|
+
export default defineNitroPlugin(() => {
|
|
97
|
+
ServerStorage.init(() => {
|
|
98
|
+
try {
|
|
99
|
+
return useEvent().context
|
|
100
|
+
} catch {
|
|
101
|
+
return {}
|
|
102
|
+
}
|
|
103
|
+
})
|
|
104
|
+
})
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
## Гидратация (Передача данных клиенту)
|
|
108
|
+
|
|
109
|
+
Гидратация — это процесс передачи состояния приложения, установленного на сервере, клиенту. Это позволяет браузеру «подхватить» данные там, где закончил сервер, обеспечивая согласованность и предотвращая повторные запросы данных или «мерцание» страницы при загрузке.
|
|
110
|
+
|
|
111
|
+
### 1. Пометка данных для гидратации
|
|
112
|
+
|
|
113
|
+
При использовании `set()` или `get()` передайте `true` третьим параметром (`hydration`). Только значения, помеченные таким образом, будут переданы на клиент.
|
|
114
|
+
|
|
115
|
+
```typescript
|
|
116
|
+
// Установка на сервере
|
|
117
|
+
ServerStorage.set('userSettings', () => ({ fontSize: 16 }), true)
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
### 2. Вставка состояния в HTML
|
|
121
|
+
|
|
122
|
+
На сервере необходимо вызвать `ServerStorage.toString()` и вставить результат в шаблон страницы (обычно в самый конец тега `<body>`, перед скриптами приложения).
|
|
123
|
+
|
|
124
|
+
Этот метод генерирует специальный тег script:
|
|
125
|
+
```html
|
|
126
|
+
<script id="__ui:server:storage:id__" type="application/json">
|
|
127
|
+
{"userSettings":{"fontSize":16}}
|
|
128
|
+
</script>
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
|