@up-im/medotvet_sdk 0.0.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.
Files changed (250) hide show
  1. package/.cursor/rules/apcheki_sdk.mdc +90 -0
  2. package/README.md +136 -0
  3. package/dist/api/abstract.d.ts +21 -0
  4. package/dist/api/abstract.js +125 -0
  5. package/dist/api/bookmarks.d.ts +28 -0
  6. package/dist/api/bookmarks.js +121 -0
  7. package/dist/api/chat.d.ts +30 -0
  8. package/dist/api/chat.js +118 -0
  9. package/dist/api/content.d.ts +154 -0
  10. package/dist/api/content.js +237 -0
  11. package/dist/api/geoIp.d.ts +8 -0
  12. package/dist/api/geoIp.js +14 -0
  13. package/dist/api/index.d.ts +27 -0
  14. package/dist/api/index.js +31 -0
  15. package/dist/api/payment.d.ts +54 -0
  16. package/dist/api/payment.js +90 -0
  17. package/dist/api/promocode.d.ts +9 -0
  18. package/dist/api/promocode.js +22 -0
  19. package/dist/api/push.d.ts +54 -0
  20. package/dist/api/push.js +99 -0
  21. package/dist/api/receipt.d.ts +34 -0
  22. package/dist/api/receipt.js +60 -0
  23. package/dist/api/stat.d.ts +21 -0
  24. package/dist/api/stat.js +75 -0
  25. package/dist/api/survey.d.ts +82 -0
  26. package/dist/api/survey.js +122 -0
  27. package/dist/api/user.d.ts +80 -0
  28. package/dist/api/user.js +167 -0
  29. package/dist/eventBus/abstract.d.ts +4 -0
  30. package/dist/eventBus/abstract.js +29 -0
  31. package/dist/eventBus/userLogin.d.ts +5 -0
  32. package/dist/eventBus/userLogin.js +11 -0
  33. package/dist/eventBus/userLogout.d.ts +4 -0
  34. package/dist/eventBus/userLogout.js +11 -0
  35. package/dist/http/apiError.d.ts +4 -0
  36. package/dist/http/apiError.js +10 -0
  37. package/dist/http/apiRoute.d.ts +98 -0
  38. package/dist/http/apiRoute.js +197 -0
  39. package/dist/index.d.ts +2 -0
  40. package/dist/index.js +7 -0
  41. package/dist/interfaces/BannerType.d.ts +5 -0
  42. package/dist/interfaces/BannerType.js +7 -0
  43. package/dist/interfaces/apiStatEvents.d.ts +1 -0
  44. package/dist/interfaces/apiStatEvents.js +18 -0
  45. package/dist/interfaces/diplomaStatus.d.ts +8 -0
  46. package/dist/interfaces/diplomaStatus.js +9 -0
  47. package/dist/interfaces/iAppStore.d.ts +1 -0
  48. package/dist/interfaces/iAppStore.js +2 -0
  49. package/dist/interfaces/iAppVersionCheck.d.ts +5 -0
  50. package/dist/interfaces/iAppVersionCheck.js +2 -0
  51. package/dist/interfaces/iArticle.d.ts +15 -0
  52. package/dist/interfaces/iArticle.js +2 -0
  53. package/dist/interfaces/iBalance.d.ts +6 -0
  54. package/dist/interfaces/iBalance.js +2 -0
  55. package/dist/interfaces/iBank.d.ts +4 -0
  56. package/dist/interfaces/iBank.js +2 -0
  57. package/dist/interfaces/iBanner.d.ts +6 -0
  58. package/dist/interfaces/iBanner.js +2 -0
  59. package/dist/interfaces/iBookmark.d.ts +3 -0
  60. package/dist/interfaces/iBookmark.js +2 -0
  61. package/dist/interfaces/iBrand.d.ts +6 -0
  62. package/dist/interfaces/iBrand.js +2 -0
  63. package/dist/interfaces/iCatalog.d.ts +50 -0
  64. package/dist/interfaces/iCatalog.js +2 -0
  65. package/dist/interfaces/iCatalogNode.d.ts +3 -0
  66. package/dist/interfaces/iCatalogNode.js +2 -0
  67. package/dist/interfaces/iCatalogPreview.d.ts +17 -0
  68. package/dist/interfaces/iCatalogPreview.js +2 -0
  69. package/dist/interfaces/iCity.d.ts +4 -0
  70. package/dist/interfaces/iCity.js +2 -0
  71. package/dist/interfaces/iContentItem.d.ts +7 -0
  72. package/dist/interfaces/iContentItem.js +2 -0
  73. package/dist/interfaces/iEnv.d.ts +6 -0
  74. package/dist/interfaces/iEnv.js +2 -0
  75. package/dist/interfaces/iFilter.d.ts +11 -0
  76. package/dist/interfaces/iFilter.js +2 -0
  77. package/dist/interfaces/iGetNodeListProps.d.ts +8 -0
  78. package/dist/interfaces/iGetNodeListProps.js +2 -0
  79. package/dist/interfaces/iInstruction.d.ts +6 -0
  80. package/dist/interfaces/iInstruction.js +2 -0
  81. package/dist/interfaces/iIntro.d.ts +6 -0
  82. package/dist/interfaces/iIntro.js +2 -0
  83. package/dist/interfaces/iMessage.d.ts +25 -0
  84. package/dist/interfaces/iMessage.js +2 -0
  85. package/dist/interfaces/iNode.d.ts +26 -0
  86. package/dist/interfaces/iNode.js +2 -0
  87. package/dist/interfaces/iNodeTree.d.ts +14 -0
  88. package/dist/interfaces/iNodeTree.js +2 -0
  89. package/dist/interfaces/iPagingItems.d.ts +9 -0
  90. package/dist/interfaces/iPagingItems.js +2 -0
  91. package/dist/interfaces/iPayment.d.ts +20 -0
  92. package/dist/interfaces/iPayment.js +2 -0
  93. package/dist/interfaces/iPush.d.ts +14 -0
  94. package/dist/interfaces/iPush.js +2 -0
  95. package/dist/interfaces/iQuestion.d.ts +7 -0
  96. package/dist/interfaces/iQuestion.js +2 -0
  97. package/dist/interfaces/iReceipt.d.ts +20 -0
  98. package/dist/interfaces/iReceipt.js +2 -0
  99. package/dist/interfaces/iReceiptAddProps.d.ts +8 -0
  100. package/dist/interfaces/iReceiptAddProps.js +2 -0
  101. package/dist/interfaces/iReceiptProduct.d.ts +7 -0
  102. package/dist/interfaces/iReceiptProduct.js +2 -0
  103. package/dist/interfaces/iSearchParams.d.ts +11 -0
  104. package/dist/interfaces/iSearchParams.js +2 -0
  105. package/dist/interfaces/iShop.d.ts +6 -0
  106. package/dist/interfaces/iShop.js +2 -0
  107. package/dist/interfaces/iShopAddress.d.ts +5 -0
  108. package/dist/interfaces/iShopAddress.js +2 -0
  109. package/dist/interfaces/iSorter.d.ts +7 -0
  110. package/dist/interfaces/iSorter.js +2 -0
  111. package/dist/interfaces/iSpecialization.d.ts +4 -0
  112. package/dist/interfaces/iSpecialization.js +2 -0
  113. package/dist/interfaces/iStatView.d.ts +4 -0
  114. package/dist/interfaces/iStatView.js +2 -0
  115. package/dist/interfaces/iStorage.d.ts +5 -0
  116. package/dist/interfaces/iStorage.js +2 -0
  117. package/dist/interfaces/iStories.d.ts +13 -0
  118. package/dist/interfaces/iStories.js +2 -0
  119. package/dist/interfaces/iSubstance.d.ts +4 -0
  120. package/dist/interfaces/iSubstance.js +2 -0
  121. package/dist/interfaces/iSurvey.d.ts +36 -0
  122. package/dist/interfaces/iSurvey.js +2 -0
  123. package/dist/interfaces/iSurveyQuestion.d.ts +11 -0
  124. package/dist/interfaces/iSurveyQuestion.js +2 -0
  125. package/dist/interfaces/iSymptoms.d.ts +4 -0
  126. package/dist/interfaces/iSymptoms.js +2 -0
  127. package/dist/interfaces/iTestQuestion.d.ts +20 -0
  128. package/dist/interfaces/iTestQuestion.js +2 -0
  129. package/dist/interfaces/iTestResult.d.ts +17 -0
  130. package/dist/interfaces/iTestResult.js +2 -0
  131. package/dist/interfaces/iText.d.ts +3 -0
  132. package/dist/interfaces/iText.js +2 -0
  133. package/dist/interfaces/iUser.d.ts +35 -0
  134. package/dist/interfaces/iUser.js +2 -0
  135. package/dist/interfaces/iUserData.d.ts +10 -0
  136. package/dist/interfaces/iUserData.js +2 -0
  137. package/dist/interfaces/iUserEditProps.d.ts +20 -0
  138. package/dist/interfaces/iUserEditProps.js +2 -0
  139. package/dist/interfaces/iUserStat.d.ts +7 -0
  140. package/dist/interfaces/iUserStat.js +2 -0
  141. package/dist/interfaces/iUserSurvey.d.ts +21 -0
  142. package/dist/interfaces/iUserSurvey.js +11 -0
  143. package/dist/interfaces/iUserTokens.d.ts +4 -0
  144. package/dist/interfaces/iUserTokens.js +2 -0
  145. package/dist/interfaces/intRange.d.ts +3 -0
  146. package/dist/interfaces/intRange.js +2 -0
  147. package/dist/interfaces/itemType.d.ts +9 -0
  148. package/dist/interfaces/itemType.js +11 -0
  149. package/dist/interfaces/paymentStatus.d.ts +7 -0
  150. package/dist/interfaces/paymentStatus.js +9 -0
  151. package/dist/interfaces/paymentType.d.ts +5 -0
  152. package/dist/interfaces/paymentType.js +7 -0
  153. package/dist/interfaces/payoutType.d.ts +5 -0
  154. package/dist/interfaces/payoutType.js +7 -0
  155. package/dist/interfaces/pushStatus.d.ts +6 -0
  156. package/dist/interfaces/pushStatus.js +8 -0
  157. package/dist/interfaces/receiptStatus.d.ts +7 -0
  158. package/dist/interfaces/receiptStatus.js +9 -0
  159. package/dist/interfaces/testStatus.d.ts +6 -0
  160. package/dist/interfaces/testStatus.js +7 -0
  161. package/dist/interfaces/userRole.d.ts +6 -0
  162. package/dist/interfaces/userRole.js +14 -0
  163. package/dist/interfaces/userStatEvent.d.ts +5 -0
  164. package/dist/interfaces/userStatEvent.js +7 -0
  165. package/dist/interfaces/viewEventType.d.ts +13 -0
  166. package/dist/interfaces/viewEventType.js +19 -0
  167. package/dist/service/webSocketClient.d.ts +21 -0
  168. package/dist/service/webSocketClient.js +87 -0
  169. package/dist/storage/default.d.ts +2 -0
  170. package/dist/storage/default.js +8 -0
  171. package/dist/storage/user.d.ts +21 -0
  172. package/dist/storage/user.js +107 -0
  173. package/dist/utils/queryString.d.ts +3 -0
  174. package/dist/utils/queryString.js +21 -0
  175. package/package.json +31 -0
  176. package/src/api/abstract.ts +136 -0
  177. package/src/api/bookmarks.ts +109 -0
  178. package/src/api/chat.ts +127 -0
  179. package/src/api/content.ts +258 -0
  180. package/src/api/geoIp.ts +12 -0
  181. package/src/api/index.ts +38 -0
  182. package/src/api/payment.ts +105 -0
  183. package/src/api/promocode.ts +18 -0
  184. package/src/api/push.ts +102 -0
  185. package/src/api/stat.ts +74 -0
  186. package/src/api/survey.ts +164 -0
  187. package/src/api/user.ts +176 -0
  188. package/src/eventBus/abstract.ts +33 -0
  189. package/src/eventBus/userLogin.ts +13 -0
  190. package/src/eventBus/userLogout.ts +12 -0
  191. package/src/http/apiError.ts +9 -0
  192. package/src/http/apiRoute.ts +234 -0
  193. package/src/index.ts +2 -0
  194. package/src/interfaces/BannerType.ts +6 -0
  195. package/src/interfaces/apiStatEvents.ts +18 -0
  196. package/src/interfaces/diplomaStatus.ts +10 -0
  197. package/src/interfaces/iAppStore.ts +1 -0
  198. package/src/interfaces/iArticle.ts +12 -0
  199. package/src/interfaces/iBalance.ts +6 -0
  200. package/src/interfaces/iBank.ts +4 -0
  201. package/src/interfaces/iBanner.ts +6 -0
  202. package/src/interfaces/iBookmark.ts +3 -0
  203. package/src/interfaces/iCity.ts +4 -0
  204. package/src/interfaces/iContentItem.ts +6 -0
  205. package/src/interfaces/iEnv.ts +6 -0
  206. package/src/interfaces/iFilter.ts +16 -0
  207. package/src/interfaces/iGetNodeListProps.ts +9 -0
  208. package/src/interfaces/iInstruction.ts +6 -0
  209. package/src/interfaces/iIntro.ts +6 -0
  210. package/src/interfaces/iMessage.ts +25 -0
  211. package/src/interfaces/iNode.ts +24 -0
  212. package/src/interfaces/iNodeTree.ts +14 -0
  213. package/src/interfaces/iPagingItems.ts +8 -0
  214. package/src/interfaces/iPayment.ts +28 -0
  215. package/src/interfaces/iPush.ts +15 -0
  216. package/src/interfaces/iQuestion.ts +4 -0
  217. package/src/interfaces/iSearchParams.ts +12 -0
  218. package/src/interfaces/iSorter.ts +10 -0
  219. package/src/interfaces/iSpecialization.ts +4 -0
  220. package/src/interfaces/iStatView.ts +4 -0
  221. package/src/interfaces/iStorage.ts +5 -0
  222. package/src/interfaces/iStories.ts +10 -0
  223. package/src/interfaces/iSubstance.ts +4 -0
  224. package/src/interfaces/iSurvey.ts +38 -0
  225. package/src/interfaces/iSurveyQuestion.ts +15 -0
  226. package/src/interfaces/iSymptoms.ts +4 -0
  227. package/src/interfaces/iTestQuestion.ts +21 -0
  228. package/src/interfaces/iTestResult.ts +20 -0
  229. package/src/interfaces/iText.ts +3 -0
  230. package/src/interfaces/iUser.ts +37 -0
  231. package/src/interfaces/iUserData.ts +10 -0
  232. package/src/interfaces/iUserEditProps.ts +16 -0
  233. package/src/interfaces/iUserStat.ts +8 -0
  234. package/src/interfaces/iUserSurvey.ts +23 -0
  235. package/src/interfaces/iUserTokens.ts +4 -0
  236. package/src/interfaces/intRange.ts +5 -0
  237. package/src/interfaces/itemType.ts +10 -0
  238. package/src/interfaces/paymentStatus.ts +8 -0
  239. package/src/interfaces/paymentType.ts +6 -0
  240. package/src/interfaces/payoutType.ts +6 -0
  241. package/src/interfaces/pushStatus.ts +7 -0
  242. package/src/interfaces/testStatus.ts +8 -0
  243. package/src/interfaces/userRole.ts +13 -0
  244. package/src/interfaces/userStatEvent.ts +6 -0
  245. package/src/interfaces/viewEventType.ts +17 -0
  246. package/src/service/webSocketClient.ts +94 -0
  247. package/src/storage/default.ts +7 -0
  248. package/src/storage/user.ts +109 -0
  249. package/src/utils/queryString.ts +22 -0
  250. package/tsconfig.json +27 -0
@@ -0,0 +1,90 @@
1
+ ---
2
+ description:
3
+ globs:
4
+ alwaysApply: true
5
+ ---
6
+ # apcheki_sdk Package Overview
7
+
8
+ Этот npm пакет "@up-im/apcheki_sdk" установаться на frontend чтобы взаимодействовать с последней версией API backend
9
+
10
+ This rule describes the structure and usage of the `apcheki_sdk` npm package under the `apcheki_sdk` directory.
11
+
12
+ ## Entry Point
13
+
14
+ - [src/api/index.ts](mdc:apcheki_sdk/src/api/index.ts): defines the `createClient` function
15
+ - Accepts configuration `{ host: string, wsHost: string, storage?: iStorage }`
16
+ - Returns API modules: `user`, `content`, `geoIp`, `receipt`, `payment`, `stat`, `chat`, `bookmarks`, `push`, `promocode`
17
+
18
+ ## Storage
19
+
20
+ - Interface: [src/interfaces/iStorage.ts](mdc:apcheki_sdk/src/interfaces/iStorage.ts)
21
+ - Default implementation: [src/storage/default.ts](mdc:apcheki_sdk/src/storage/default.ts)
22
+ - To override storage, pass a custom object implementing `iStorage` to `createClient`
23
+
24
+ ## API Modules
25
+
26
+ Each API class extends [src/api/abstract.ts](mdc:apcheki_sdk/src/api/abstract.ts) and uses `fetcher` for HTTP calls or WebSocket for `chat`.
27
+
28
+ - [src/api/user.ts](mdc:apcheki_sdk/src/api/user.ts): User authentication and profile endpoints
29
+ - [src/api/content.ts](mdc:apcheki_sdk/src/api/content.ts): Content retrieval and management
30
+ - [src/api/geoIp.ts](mdc:apcheki_sdk/src/api/geoIp.ts): Geo-IP lookup
31
+ - [src/api/receipt.ts](mdc:apcheki_sdk/src/api/receipt.ts): Receipt operations
32
+ - [src/api/payment.ts](mdc:apcheki_sdk/src/api/payment.ts): Payment processing
33
+ - [src/api/stat.ts](mdc:apcheki_sdk/src/api/stat.ts): Statistics endpoints
34
+ - [src/api/chat.ts](mdc:apcheki_sdk/src/api/chat.ts): WebSocket-based chat
35
+ - Handles authentication via token and message events
36
+ - [src/api/bookmarks.ts](mdc:apcheki_sdk/src/api/bookmarks.ts): Bookmark management
37
+ - [src/api/push.ts](mdc:apcheki_sdk/src/api/push.ts): Push notification registration
38
+ - [src/api/promocode.ts](mdc:apcheki_sdk/src/api/promocode.ts): Promo code validation and application
39
+
40
+ ## Error Handling
41
+
42
+ - Uses `ApiError` from [src/http/apiError.ts](mdc:apcheki_sdk/src/http/apiError.ts) for consistent error responses
43
+
44
+ ## Usage Example
45
+
46
+ ```ts
47
+ import { createClient } from "apcheki_sdk"
48
+
49
+ const client = createClient({
50
+ host: "https://api.example.com",
51
+ wsHost: "wss://ws.example.com",
52
+ // optional: storage: customStorage
53
+ })
54
+
55
+ // then use: client.user, client.chat, client.payment, etc.
56
+ ```
57
+
58
+ ## Notes
59
+
60
+ - WebSocket client lives in [src/service/webSocketClient.ts](mdc:apcheki_sdk/src/service/webSocketClient.ts)
61
+ - Keep API modules focused and DRY; add new endpoints by extending `ApiAbstract` and following existing patterns
62
+
63
+ ## Package Update Process (команда "Опубликуй sdk")
64
+
65
+ !!! ВАЖНО при публикации новой версии SDK:
66
+ – Выполнять ТОЛЬКО пункты 1–5 этой инструкции, строго в указанном порядке
67
+ – Никаких дополнительных проверок, изменений, оптимизаций или предложений не выполнять
68
+ – Не добавлять, не удалять и не модифицировать шаги
69
+
70
+ 1. Перейти в папку SDK:
71
+ ```bash
72
+ cd /Users/oreen/MAMP/www/apcheki_sdk
73
+ ```
74
+ 2. Чтение и инкремент версии:
75
+ 2.1. Прочитать текущее значение version из package.json → OLD_VERSION (например, 0.2.35)
76
+ 2.2. Увеличить патч-номер: если версия формата X.Y.Z, то NEW_VERSION = X.Y.(Z+1) (например, 0.2.36)
77
+ 2.3. Записать NEW_VERSION в поле version в package.json
78
+ 3. Сборка и публикация:
79
+ ```bash
80
+ npm i && npm run build && npm publish
81
+ git add . && git commit -m "<NEW_VERSION> <Краткое описание>"
82
+ ```
83
+ 4. Подготовка коммита
84
+ 4.1. Собрать список изменённых файлов: git diff --cached --name-only
85
+ 4.2 Проанализировать эти файлы и сформировать короткое однострочное описание важнейших изменений (например, «Добавлена поддержка X», «Исправлен баг Y», «Обновлены типы в Z»).
86
+ 4.3 Сконструировать сообщение в формате: <NEW_VERSION> <Краткое описание>.
87
+ 5. Создание коммита
88
+ ```bash
89
+ git add . && git commit -m "<NEW_VERSION> <Краткое описание>"
90
+ ```
package/README.md ADDED
@@ -0,0 +1,136 @@
1
+ # Medotvet SDK для React
2
+
3
+ Полноценный клиент для работы с backend из React/Next. Ниже перечислены
4
+ все методы из `src/api` и примеры интеграции.
5
+
6
+ ## Установка
7
+
8
+ ```
9
+ npm i @up-im/medotvet_sdk
10
+ ```
11
+
12
+ ## Инициализация клиента
13
+
14
+ ```ts
15
+ import { createClient } from "@up-im/medotvet_sdk"
16
+
17
+ const client = createClient({
18
+ host: "https://api.example.com",
19
+ wsHost: "wss://ws.example.com",
20
+ // storage?: iStorage (опционально, по умолчанию localStorage)
21
+ })
22
+ ```
23
+
24
+ - Все запросы идут на `host/api/*` через `fetch` с `FormData`.
25
+ - Методы с `options.addToken` требуют авторизацию; refresh токен
26
+ обновляется aвтоматически.
27
+ - В ответах ошибки приходят как `ApiError(status, message)`.
28
+
29
+ ## Модули и методы
30
+
31
+ ### user
32
+ - `get()` — вернуть пользователя из localStorage без запроса на сервер.
33
+ - `getFull()` — получить профиль с backend; 401 без авторизации.
34
+ - `loginOrRegisterByPhone({ phone })` — старт регистрации/логина, шлёт SMS.
35
+ - `loginOrRegisterByPhoneConfirm({ phone, code })` — завершить вход,
36
+ сохранить токены, вернуть пользователя.
37
+ - `setRef({ ref })` — ввести реферальный код; требует токен.
38
+ - `editUser(data: iUserEditProps)` — обновить профиль; при смене email
39
+ может вернуть `false`, тогда повторить с `email_code`.
40
+ - `logout()` — локальный выход, чистит токены, шлёт событие logout.
41
+ - `logoutAllDevice()` — удаляет refresh на сервере, чистит локально,
42
+ рассылает logout.
43
+ - `onLogout` — подписка на событие выхода `client.user.onLogout(cb)`.
44
+ - `delete()` — удалить аккаунт и связанные сущности, затем logout.
45
+ - `getMyReferer()` — вернуть мой рефкод.
46
+ - `uploadDiploma(formData)` — отправить файлы `diploma[]`, ответ:
47
+ `{ success, diploma_files, diploma_status }`. Статусы экспортируются
48
+ как `DiplomaStatus` (числовые значения).
49
+ - `getDiplomaStatus()` — статус диплома (`DiplomaStatus`): 1 не
50
+ загружен, 2 проверка, 3 принят, 4 отклонён + `diploma_reject_reason`.
51
+
52
+ ### content
53
+ - `getEnv()` — общие настройки/реферальные вознаграждения.
54
+ - `checkAppVersion({ appStore, appVersion })` — проверка актуальности
55
+ версии в сторе, ответ `{ isActual }`.
56
+ - `getCloudVersion(appStore)` — версия для обновления по воздуху (OTA).
57
+ - `getNodeTree(parent?)` — дерево категорий.
58
+ - `getArticleList({ select, page?, filters?, sorters?, perPage? })` —
59
+ статьи.
60
+ - `getArticleOne({ id })` — статья с полем `item`.
61
+ - `getPolicy()` / `getTerms()` / `getLoyalty()` / `getAgreement()` —
62
+ тексты.
63
+ - `getInstruction()` — шаги "Как получить деньги", до 100 элементов.
64
+ - `getBanks({ page, searchTitle? })` — банки для выплат.
65
+ - `getSpecializationList({ page, searchTitle? })` — справочник специализаций.
66
+ - `getCityList({ page, searchTitle? })` — города с пагинацией.
67
+ - `getCityOne({ id })` — один город.
68
+ - `getBannerRand({ type, signal? })` — баннер по типу (требует токен).
69
+ - `getStoriesList({ select, page?, perPage? })` — сторисы, sku сжаты в
70
+ `{ id, title }`.
71
+ - `getStoriesOne({ id })` — сторис с sku приведённым к `{ id, title }`.
72
+ - `getIntro()` — приветственные слайды с сортировкой.
73
+
74
+ ### survey
75
+ - `getList({ page?, select?, bookmarks? })` — доступные опросы,
76
+ сортировка по приоритету.
77
+ - `getBookmarks({ page?, select? })` — избранные опросы, 401 без
78
+ авторизации.
79
+ - `getOne({ id })` — опрос с вопросами.
80
+ - `start(surveyId, signal?)` — начать прохождение, ответ
81
+ `{ success, userSurvey }`.
82
+ - `saveAnswer({ userSurveyId, questionIndex, answer, signal? })` —
83
+ сохранить ответ, возвращает `{ completed, next_question_index,
84
+ message }`.
85
+ - `cancel(userSurveyId, signal?)` — отменить прохождение.
86
+ - `getHistory({ page? })` — история прохождений.
87
+
88
+ ### payment
89
+ - `addSBP({ sum, bank })` — заявка на выплату через СБП, вернёт
90
+ `iPayment`.
91
+ - `addCard({ sum, card_number })` — заявка на карту, вернёт `iPayment`.
92
+ - `getList({ page?, select })` — список выплат, сортировка `id desc`.
93
+ - `balance()` — баланс и суммы начислений/выплат.
94
+ - `getVerificationUrl()` — ссылка на KYC SolarStaff и признак `verified`.
95
+ - `checkVerificationStatus()` — статус KYC:
96
+ `not_started|pending|active|blocked` + текст.
97
+
98
+ ### stat
99
+ - `add({ itemId, event })` — записать событие просмотра/квиза/
100
+ презентации; для CATALOG_SKU + PRESENTATION_SUCCESS|QUESTIONS_SUCCESS
101
+ пишет и начисления.
102
+ - `getEvent({ sku: number[] })` — получить события пользователя по акциям.
103
+
104
+ ### chat (WebSocket)
105
+ - Подключается к `wsHost`, авторизует token при `onOpen`.
106
+ - `messageSubscribe(cb)` — подписка на входящие сообщения массивами;
107
+ вернёт функцию отписки. История последних 10 пачек приходит сразу.
108
+ - `sendMessage({ text, file? })` — отправка текста/файла (конвертируется
109
+ в base64). Доступно только пользователю с `role === 0`.
110
+ - `sendView({ id })` — отметить сообщение прочитанным.
111
+ - `getUnread()` — количество непрочитанных через HTTP.
112
+ - `getMessages({ page })` — запросить сообщения по страницам через WS.
113
+ - `disconnect()` — закрыть WebSocket вручную.
114
+
115
+ ### bookmarks
116
+ - `inBookmarks({ skuId })` — проверить избранное. Дебаунсит запросы,
117
+ требует токен.
118
+ - `mutate({ skuId, isAdd })` — добавить/убрать из избранного и обновить
119
+ кэш.
120
+ - `getTotal()` — общее число избранных или `null`, использует кеш.
121
+
122
+ ### push
123
+ - `getList({ page?, filters?, select })` — список пушей, сортировка
124
+ `id desc`.
125
+ - `countNew()` — количество непрочитанных.
126
+ - `view({ pushId })` — отметить один пуш прочитанным.
127
+ - `viewAll()` — отметить все пуши прочитанными.
128
+ - `register({ token, appStore })` — зарегистрировать push-токен.
129
+ - `unsubscribe()` — отписаться от пушей.
130
+ - `isSubscribed()` — признак активной подписки.
131
+
132
+ ### promocode
133
+ - `activate(code)` — активировать промокод, ответ `{ sum }`; требует токен.
134
+
135
+ ### geoIp
136
+ - `detect()` — определить город по IP.
@@ -0,0 +1,21 @@
1
+ import { UserStorage } from "../storage/user";
2
+ export declare class ApiAbstract {
3
+ protected host: string;
4
+ protected userStorage: UserStorage;
5
+ private static isTokenUpdating;
6
+ constructor({ host, userStorage }: {
7
+ host: string;
8
+ userStorage: UserStorage;
9
+ });
10
+ protected fetcher<TResponse>({ route, postBody, options }: {
11
+ route: string;
12
+ postBody?: {
13
+ [key: string]: any;
14
+ } | null;
15
+ options?: RequestInit & {
16
+ noConsoleError?: boolean;
17
+ addToken?: boolean;
18
+ };
19
+ }): Promise<TResponse>;
20
+ protected getToken(): Promise<string | null>;
21
+ }
@@ -0,0 +1,125 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ApiAbstract = void 0;
4
+ const userLogout_1 = require("../eventBus/userLogout");
5
+ const apiError_1 = require("../http/apiError");
6
+ const apiRoute_1 = require("../http/apiRoute");
7
+ class ApiAbstract {
8
+ constructor({ host, userStorage }) {
9
+ this.host = host;
10
+ this.userStorage = userStorage;
11
+ }
12
+ async fetcher({ route, postBody = null, options }) {
13
+ const formData = new FormData();
14
+ if (postBody) {
15
+ for (let key in postBody) {
16
+ if (postBody[key] instanceof FileList) {
17
+ for (const value of postBody[key]) {
18
+ formData.append(key + '[]', value);
19
+ }
20
+ }
21
+ else if (Array.isArray(postBody[key])) {
22
+ for (const value of postBody[key]) {
23
+ if (value !== null && typeof value == "object") {
24
+ formData.append(key + '[]', JSON.stringify(value));
25
+ }
26
+ else {
27
+ formData.append(key + '[]', value);
28
+ }
29
+ }
30
+ }
31
+ else if (typeof postBody[key] == "object") {
32
+ formData.append(key, JSON.stringify(postBody[key]));
33
+ }
34
+ else {
35
+ formData.append(key, postBody[key]);
36
+ }
37
+ }
38
+ }
39
+ const headers = {};
40
+ if (options?.addToken) {
41
+ const token = await this.getToken();
42
+ headers["Authorization"] = `Bearer ${token}`;
43
+ }
44
+ else if (route.startsWith('/user') && !!postBody) {
45
+ headers["timestamp"] = Date.now().toString();
46
+ }
47
+ try {
48
+ const res = await fetch(this.host + "/api" + route, {
49
+ headers: headers,
50
+ method: postBody ? "POST" : "GET",
51
+ body: postBody ? formData : null,
52
+ credentials: "include",
53
+ ...options
54
+ });
55
+ if (!res.ok) {
56
+ if (res.status == 413)
57
+ throw new apiError_1.ApiError(res.status, "Слишком большой размер файла");
58
+ if (res.status == 401) {
59
+ await this.userStorage.clearUser();
60
+ await userLogout_1.eventBusUserLogout.broadcast();
61
+ }
62
+ if (res.status == 404 && !postBody) {
63
+ if (!options?.noConsoleError)
64
+ console.warn(`not_found: ${this.host + "/api" + route}`);
65
+ }
66
+ try {
67
+ //пробуем расшифровать json с ошибкой
68
+ const answer = await res.json();
69
+ const error = new apiError_1.ApiError(res.status, answer.message);
70
+ throw error;
71
+ }
72
+ catch (error) {
73
+ //ошибка расшифровки json
74
+ if (!options?.noConsoleError)
75
+ console.warn({ url: this.host + "/api" + route });
76
+ if (!(error instanceof apiError_1.ApiError))
77
+ throw new apiError_1.ApiError(res.status, res.statusText);
78
+ throw error;
79
+ }
80
+ }
81
+ return res.json();
82
+ }
83
+ catch (error) {
84
+ if (error instanceof Error && error.message.toLowerCase().includes("fail"))
85
+ throw new apiError_1.ApiError(0, "Нет соединения с интернетом");
86
+ throw error;
87
+ }
88
+ }
89
+ async getToken() {
90
+ const accessToken = await this.userStorage.getAccessToken();
91
+ if (accessToken)
92
+ return accessToken;
93
+ const refreshToken = await this.userStorage.getRefreshToken();
94
+ if (refreshToken) {
95
+ //перевыпуск пары токенов
96
+ if (ApiAbstract.isTokenUpdating) { //дедубликация запросов на обновление токена
97
+ await new Promise(r => setTimeout(r, 100)); //sleep
98
+ return await this.getToken();
99
+ }
100
+ ApiAbstract.isTokenUpdating = true;
101
+ try {
102
+ const data = await this.fetcher({
103
+ route: apiRoute_1.apiRouteUserRefresh,
104
+ postBody: { refreshToken: refreshToken }
105
+ });
106
+ await this.userStorage.setUser(data.accessToken, data.refreshToken);
107
+ ApiAbstract.isTokenUpdating = false;
108
+ return data.accessToken;
109
+ }
110
+ catch (error) {
111
+ console.error(error);
112
+ if (error instanceof apiError_1.ApiError) {
113
+ if (error.status === 404) { //токен не найден
114
+ await this.userStorage.clearUser();
115
+ await userLogout_1.eventBusUserLogout.broadcast();
116
+ }
117
+ }
118
+ }
119
+ ApiAbstract.isTokenUpdating = false;
120
+ }
121
+ return null;
122
+ }
123
+ }
124
+ exports.ApiAbstract = ApiAbstract;
125
+ ApiAbstract.isTokenUpdating = false;
@@ -0,0 +1,28 @@
1
+ import { ApiAbstract } from "./abstract";
2
+ export declare class ApiBookmarks extends ApiAbstract {
3
+ private cache;
4
+ private timeout;
5
+ private requestKeys;
6
+ private total;
7
+ /**
8
+ * принимает id акции (не товара) который находится в поле id метода возвращаемых товаров getCatalogList. В методе есть дебаунсер, что позволяет его вызвать для каждого товара на странице сделав только 1 запрос на сервер
9
+ * @param {number} props.sku - id акции (не товара)
10
+ */
11
+ inBookmarks({ skuId }: {
12
+ skuId: number;
13
+ }): Promise<boolean>;
14
+ private collectKeys;
15
+ /**
16
+ * добавление \ удаление из избранного
17
+ * @param {number} props.sku - id акции (не товара)
18
+ * @param {UserStatEvent} props.isAdd - признак добавление или удаление
19
+ */
20
+ mutate({ skuId, isAdd }: {
21
+ skuId: number;
22
+ isAdd: boolean;
23
+ }): Promise<void>;
24
+ /**
25
+ * возвращает кол-во товаров в избранном или null в случае ошибки
26
+ */
27
+ getTotal(): Promise<number | null>;
28
+ }
@@ -0,0 +1,121 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ApiBookmarks = void 0;
4
+ const abstract_1 = require("./abstract");
5
+ const apiRoute_1 = require("../http/apiRoute");
6
+ const itemType_1 = require("../interfaces/itemType");
7
+ const apiError_1 = require("../http/apiError");
8
+ class ApiBookmarks extends abstract_1.ApiAbstract {
9
+ constructor() {
10
+ super(...arguments);
11
+ this.cache = new Map(); //false - если данные не получены с сервера по ключу
12
+ this.timeout = undefined;
13
+ this.requestKeys = new Set();
14
+ this.total = null;
15
+ }
16
+ /**
17
+ * принимает id акции (не товара) который находится в поле id метода возвращаемых товаров getCatalogList. В методе есть дебаунсер, что позволяет его вызвать для каждого товара на странице сделав только 1 запрос на сервер
18
+ * @param {number} props.sku - id акции (не товара)
19
+ */
20
+ async inBookmarks({ skuId }) {
21
+ if (!skuId || skuId <= 0)
22
+ return false;
23
+ if (!await this.userStorage.isAuth())
24
+ return false;
25
+ const key = `${itemType_1.ItemType.CATALOG_SKU}-${skuId}`;
26
+ return await this.collectKeys(key);
27
+ }
28
+ async collectKeys(key) {
29
+ //has cache
30
+ if (this.cache.has(key)) {
31
+ const val = this.cache.get(key);
32
+ if (val !== false)
33
+ return true;
34
+ return false;
35
+ }
36
+ //no cache
37
+ //собираем включи для 1 запроса со всех вызовов
38
+ if (!this.requestKeys.has(key)) {
39
+ if (this.timeout)
40
+ clearTimeout(this.timeout);
41
+ this.requestKeys.add(key);
42
+ this.timeout = setTimeout(async () => {
43
+ if (!this.requestKeys.size)
44
+ return;
45
+ //все компоненты отрендерены, ключи все запрошены, можно выполнять запрос
46
+ try {
47
+ const arrFromRequestKeys = Array.from(this.requestKeys);
48
+ const data = await this.fetcher({
49
+ route: apiRoute_1.apiRouteBookmarksGet,
50
+ postBody: { itemKeys: arrFromRequestKeys },
51
+ options: { addToken: true }
52
+ });
53
+ for (const requestKey of arrFromRequestKeys) {
54
+ const find = data.find(it => it.item_key == requestKey);
55
+ this.cache.set(requestKey, find?.item_key || false);
56
+ }
57
+ }
58
+ catch (error) {
59
+ this.cache.set(key, false);
60
+ console.error(error);
61
+ }
62
+ this.requestKeys.clear(); //очистка очереди запросов
63
+ }, 200);
64
+ }
65
+ //ждем последнего запроса
66
+ await new Promise(r => setTimeout(r, 300)); //sleep
67
+ return await this.collectKeys(key); //на следующем крузе вернется результат из кэша
68
+ }
69
+ /**
70
+ * добавление \ удаление из избранного
71
+ * @param {number} props.sku - id акции (не товара)
72
+ * @param {UserStatEvent} props.isAdd - признак добавление или удаление
73
+ */
74
+ async mutate({ skuId, isAdd }) {
75
+ if (!skuId || skuId <= 0)
76
+ return;
77
+ if (!await this.userStorage.isAuth())
78
+ throw new apiError_1.ApiError(401, "Пользователь не авторизован");
79
+ try {
80
+ await this.fetcher({
81
+ route: isAdd
82
+ ? apiRoute_1.apiRouteBookmarksAdd
83
+ : apiRoute_1.apiRouteBookmarksRemove,
84
+ postBody: {
85
+ itemType: itemType_1.ItemType.CATALOG_SKU,
86
+ itemId: skuId
87
+ },
88
+ options: {
89
+ addToken: true
90
+ }
91
+ });
92
+ }
93
+ catch (error) {
94
+ console.error(error);
95
+ }
96
+ const key = `${itemType_1.ItemType.CATALOG_SKU}-${skuId}`;
97
+ this.cache.set(key, isAdd ? key : false);
98
+ this.total = (this.total ?? 0) + (isAdd ? 1 : -1);
99
+ }
100
+ /**
101
+ * возвращает кол-во товаров в избранном или null в случае ошибки
102
+ */
103
+ async getTotal() {
104
+ if (this.total !== null)
105
+ return this.total;
106
+ if (!await this.userStorage.isAuth())
107
+ return null;
108
+ try {
109
+ const total = await this.fetcher({
110
+ route: apiRoute_1.apiRouteBookmarksCount,
111
+ options: { addToken: true }
112
+ });
113
+ this.total = total;
114
+ }
115
+ catch (error) {
116
+ console.error(error);
117
+ }
118
+ return this.total;
119
+ }
120
+ }
121
+ exports.ApiBookmarks = ApiBookmarks;
@@ -0,0 +1,30 @@
1
+ import { iMessage } from "../interfaces/iMessage";
2
+ import { ApiAbstract } from "./abstract";
3
+ import { UserStorage } from "../storage/user";
4
+ export declare class ApiChat extends ApiAbstract {
5
+ private client;
6
+ private messageHistory;
7
+ private messageSubscriptions;
8
+ constructor({ host, wsHost, userStorage }: {
9
+ host: string;
10
+ wsHost: string;
11
+ userStorage: UserStorage;
12
+ });
13
+ private auth;
14
+ messageSubscribe(callback: (messages: iMessage[]) => void): () => void;
15
+ sendMessage({ text, file }: {
16
+ text: string;
17
+ file?: FileList | File | null;
18
+ }): Promise<void>;
19
+ sendView({ id }: {
20
+ id: number;
21
+ }): void;
22
+ /**
23
+ * Получить количество непрочитанных сообщений через обычное API
24
+ */
25
+ getUnread(): Promise<number>;
26
+ getMessages({ page }: {
27
+ page: number;
28
+ }): void;
29
+ disconnect(): void;
30
+ }
@@ -0,0 +1,118 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ApiChat = void 0;
4
+ const abstract_1 = require("./abstract");
5
+ const webSocketClient_1 = require("../service/webSocketClient");
6
+ const apiError_1 = require("../http/apiError");
7
+ const userLogout_1 = require("../eventBus/userLogout");
8
+ const apiRoute_1 = require("../http/apiRoute");
9
+ //import { eventBusUserLogin } from "../eventBus/userLogin"
10
+ class ApiChat extends abstract_1.ApiAbstract {
11
+ constructor({ host, wsHost, userStorage }) {
12
+ super({ host, userStorage });
13
+ this.messageHistory = [];
14
+ this.messageSubscriptions = new Set();
15
+ this.client = new webSocketClient_1.WebSocketClient(wsHost);
16
+ this.client.onOpen(async () => await this.auth());
17
+ this.client.onMessage(message => {
18
+ //prepare
19
+ const data = JSON.parse(message);
20
+ if (!Array.isArray(data)) {
21
+ console.error('Входящее сообщения должны быть массивом', data);
22
+ return;
23
+ }
24
+ for (const item of data) {
25
+ if ("date" in item)
26
+ item.date = new Date(item.date);
27
+ }
28
+ //broadcast
29
+ for (const callback of Array.from(this.messageSubscriptions)) {
30
+ callback(data);
31
+ }
32
+ //Последние 10 групп сообщений с сервера для новых подписчиков
33
+ this.messageHistory.push(data);
34
+ if (this.messageHistory.length > 10) {
35
+ this.messageHistory.splice(0, this.messageHistory.length - 10);
36
+ }
37
+ });
38
+ // eventBusUserLogin.subscribe(async () => this.client.connect())
39
+ // this.userStorage.isAuth().then(isAuth => {
40
+ // if (isAuth) this.client.connect()
41
+ // })
42
+ userLogout_1.eventBusUserLogout.subscribe(async () => this.client.close());
43
+ }
44
+ async auth() {
45
+ const token = await this.getToken();
46
+ if (!token) {
47
+ console.error("User token for WebSocket empty");
48
+ return;
49
+ }
50
+ this.client.send(JSON.stringify({ token }), true);
51
+ }
52
+ messageSubscribe(callback) {
53
+ this.messageSubscriptions.add(callback);
54
+ //Последние 10 групп сообщений с сервера для новых подписчиков
55
+ for (const history of this.messageHistory)
56
+ callback(history);
57
+ return () => { this.messageSubscriptions.delete(callback); };
58
+ }
59
+ async sendMessage({ text, file }) {
60
+ const user = await this.userStorage?.getUser();
61
+ if (!user)
62
+ throw new apiError_1.ApiError(401, "Пользователь не авторизован");
63
+ if (user.role !== 0)
64
+ throw new apiError_1.ApiError(400, "Для тестирования чата авторизуйтесь под обычного пользователя");
65
+ const convertToBase64 = (file) => {
66
+ return new Promise((resolve, reject) => {
67
+ const reader = new FileReader();
68
+ reader.onload = () => resolve(reader.result);
69
+ reader.onerror = reject;
70
+ reader.readAsDataURL(file);
71
+ });
72
+ };
73
+ const firstFile = file instanceof FileList
74
+ ? Array.from(file)?.pop()
75
+ : file;
76
+ const message = {
77
+ route: "/message",
78
+ text,
79
+ file: firstFile ? await convertToBase64(firstFile) : undefined
80
+ };
81
+ this.client.send(JSON.stringify(message));
82
+ }
83
+ sendView({ id }) {
84
+ const message = {
85
+ route: "/view",
86
+ message_id: id
87
+ };
88
+ this.client.send(JSON.stringify(message));
89
+ }
90
+ /**
91
+ * Получить количество непрочитанных сообщений через обычное API
92
+ */
93
+ async getUnread() {
94
+ if (!await this.userStorage.isAuth())
95
+ throw new apiError_1.ApiError(401, "Пользователь не авторизован");
96
+ const data = await this.fetcher({
97
+ route: apiRoute_1.apiRouteChatUnread,
98
+ options: { addToken: true }
99
+ });
100
+ return data.unread;
101
+ }
102
+ // getDialogs({page}:{page: number}) {//оставим для оптимизации если диалогов будет много
103
+ // this.client.send(JSON.stringify({
104
+ // route: "/get/dialogs",
105
+ // page,
106
+ // }))
107
+ // }
108
+ getMessages({ page }) {
109
+ this.client.send(JSON.stringify({
110
+ route: "/get/messages",
111
+ page,
112
+ }));
113
+ }
114
+ disconnect() {
115
+ this.client.close();
116
+ }
117
+ }
118
+ exports.ApiChat = ApiChat;