@skroz/profile-api 1.0.21 → 1.0.22

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 (2) hide show
  1. package/README.md +197 -0
  2. package/package.json +2 -2
package/README.md ADDED
@@ -0,0 +1,197 @@
1
+ # @skroz/profile-api
2
+
3
+ GraphQL-резолверы и сервисы для аутентификации пользователей. Построена на type-graphql + TypeORM + Redis.
4
+
5
+ ## Архитектура
6
+
7
+ Библиотека предоставляет **фабрики резолверов** — функции, которые принимают зависимости и возвращают класс резолвера для регистрации в GraphQL-схеме. Это позволяет переиспользовать логику в разных приложениях с разными User-сущностями.
8
+
9
+ ## Билд
10
+
11
+ ```bash
12
+ cd libs/utils/packages/profile-api
13
+ yarn build
14
+ ```
15
+
16
+ ## Экспорты
17
+
18
+ ### Типы
19
+
20
+ - **`AuthUser`** — интерфейс пользователя: `id`, `email`, `name`, `avatar`, `password`, `isEmailConfirmed`, `isBanned`, `isTempPassword`, `urlSlug`, `telegramId`, `isEmailNotificationEnabled`, `isTelegramNotificationEnabled`, `lastSeenAt`, `save()`
21
+ - **`ProfileDbAdapter`** — интерфейс БД-адаптера, который нужно реализовать: `findUserByEmail`, `findUserById`, `findUserByTelegramId`, `createUser`, `isEmailTaken`, `findUserByProviderId`, `updateUserProviderId`
22
+ - **`ProfileAuthConfig`** — конфиг токенов/лимитов: `resendEmailLimitSeconds`, `confirmationTokenLifetimeMinutes`, `recoveryTokenLifetimeMinutes`
23
+ - **`EmailConfig`** — extends ProfileAuthConfig + настройки email: `domain`, `websiteUrl`, `primaryBrandColor`, `logoUrl`, `fromEmailUsername`, `templateDir`, `isOnlineSeconds`, `isOnlineRecentlySeconds`
24
+ - **`ProfileEmailTemplate`** — enum шаблонов писем: `CONFIRM_EMAIL`, `FORGOT_PASSWORD`, `TEMP_PASSWORD`, `GENERIC_NOTIFICATION`
25
+ - **`ProfileLocales`** — структура переводов для auth-ошибок и email-шаблонов
26
+ - **`ProfileContext<TUser>`** — GraphQL-контекст: `user?`, `req`, `res`, `t`
27
+
28
+ ### TypeOrmProfileAdapter
29
+
30
+ Готовая реализация `ProfileDbAdapter` поверх TypeORM.
31
+
32
+ ```ts
33
+ import { TypeOrmProfileAdapter } from '@skroz/profile-api';
34
+
35
+ const db = new TypeOrmProfileAdapter(() =>
36
+ getConnection().getRepository(User)
37
+ );
38
+ ```
39
+
40
+ Провайдер-ID ищет по полю `${provider}Id` (т.е. `googleId`, `vkId`, `telegramId` и т.д.) — эти поля должны быть в сущности User.
41
+
42
+ ### TypeOrmBaseUser
43
+
44
+ Базовая TypeORM-сущность со всеми полями `AuthUser`. Можно наследовать:
45
+
46
+ ```ts
47
+ import { TypeOrmBaseUser } from '@skroz/profile-api';
48
+
49
+ @Entity()
50
+ export class User extends TypeOrmBaseUser {
51
+ // дополнительные поля
52
+ }
53
+ ```
54
+
55
+ ### ProfileAuthService
56
+
57
+ Основной сервис. Принимает `(db, email, redis, config)`.
58
+
59
+ ```ts
60
+ import { ProfileAuthService } from '@skroz/profile-api';
61
+
62
+ const authService = new ProfileAuthService(db, emailService, redis, {
63
+ resendEmailLimitSeconds: 60,
64
+ confirmationTokenLifetimeMinutes: 60,
65
+ recoveryTokenLifetimeMinutes: 30,
66
+ });
67
+ ```
68
+
69
+ Публичные поля: `db`, `email`, `redis`, `config`.
70
+ Методы: `hashPassword`, `verifyPassword`, `setTokenToRedis`, `removeTokenFromRedis`, `getUserByToken`, `sendLink`.
71
+
72
+ ### ProfileEmailService
73
+
74
+ Отправка писем (confirm email, forgot password, temp password). Передаётся в `ProfileAuthService`.
75
+
76
+ ---
77
+
78
+ ## Резолверы
79
+
80
+ Все резолверы создаются через фабричные функции. `authService` в deps может быть как экземпляром, так и функцией `(ctx) => ProfileAuthService` (для per-request сервисов).
81
+
82
+ ### createAuthResolver(deps)
83
+
84
+ Auth-мутации: `register`, `login`, `logout`, `confirmEmail`, `sendToken`, `recoverPassword`.
85
+
86
+ ```ts
87
+ import { createAuthResolver } from '@skroz/profile-api';
88
+
89
+ const AuthResolver = createAuthResolver({
90
+ authService, // ProfileAuthService | (ctx) => ProfileAuthService
91
+ userType: User, // GraphQL ObjectType
92
+ onUserCreated: async (user, ctx) => { /* ... */ },
93
+ onLogin: async (user, ctx) => { /* ... */ },
94
+ onLogout: async (user, ctx) => { /* ... */ },
95
+ onEmailConfirmed: async (user, ctx) => { /* ... */ },
96
+ onPasswordRecovered: async (user, ctx) => { /* ... */ },
97
+ logTelegramBot: { sendError: async (msg) => { /* ... */ } },
98
+ });
99
+ ```
100
+
101
+ ### createProfileResolver(deps)
102
+
103
+ Мутации профиля (только для авторизованных): `updateEmail`, `updatePassword`, `updateProfile`, `toggleEmailNotification`.
104
+
105
+ ```ts
106
+ import { createProfileResolver } from '@skroz/profile-api';
107
+
108
+ const ProfileResolver = createProfileResolver({ authService, userType: User });
109
+ ```
110
+
111
+ ### createOauthResolver(deps)
112
+
113
+ OAuth-авторизация и вход через Telegram-бот.
114
+
115
+ Мутации:
116
+ - `oauthLogin(input: OauthLoginInput)` — вход через Google/VK/Яндекс/Mail/Apple/Telegram-виджет
117
+ - `generateTelegramAuthToken` → `{ token, url }` — генерирует токен и deep link для бота
118
+ - `confirmTelegramAuthToken(token)` → `{ confirmed, expired }` — polling со стороны фронта
119
+
120
+ ```ts
121
+ import { createOauthResolver, GoogleOauth, VKOauth } from '@skroz/profile-api';
122
+
123
+ const OauthResolver = createOauthResolver({
124
+ authService,
125
+ userType: User,
126
+ providers: {
127
+ google: new GoogleOauth(clientId, clientSecret, redirectUri),
128
+ vk: new VKOauth(clientId, clientSecret, redirectUri),
129
+ // ya, mail, apple — аналогично
130
+ },
131
+ telegramBotToken: process.env.TELEGRAM_BOT_TOKEN, // для Telegram Login Widget
132
+ telegramBotName: 'MyBot', // имя бота без @, для deep link авторизации
133
+ redis: getRedis(), // клиент с методами get/setex/del
134
+ onUserCreated: async (user, ctx) => { /* ... */ },
135
+ onLogin: async (user, ctx) => { /* ... */ },
136
+ });
137
+ ```
138
+
139
+ ---
140
+
141
+ ## confirmTelegramBotAuth
142
+
143
+ Вспомогательная функция для **Telegram-бота** (не для GraphQL-резолвера).
144
+
145
+ Когда пользователь переходит по deep link `/start tgauth_<token>`, бот вызывает эту функцию — она записывает `telegramUserId` в Redis, и фронт получает `confirmed: true` при следующем polling.
146
+
147
+ ```ts
148
+ import { confirmTelegramBotAuth } from '@skroz/profile-api';
149
+
150
+ // В обработчике команды /start в Telegram-боте:
151
+ if (text.startsWith('/start tgauth_')) {
152
+ const token = text.replace('/start tgauth_', '');
153
+ const confirmed = await confirmTelegramBotAuth(redis, token, user.id);
154
+ if (confirmed) {
155
+ // отправить пользователю сообщение об успешной авторизации
156
+ }
157
+ }
158
+ ```
159
+
160
+ Возвращает `true` если токен найден и подтверждён, `false` если истёк или не существует.
161
+ Использует тот же Redis-префикс (`skroz:profile:tgbotauth`) и TTL (300 сек), что и `generateTelegramAuthToken`.
162
+
163
+ ---
164
+
165
+ ## OAuth-провайдеры
166
+
167
+ ```ts
168
+ import { GoogleOauth, VKOauth, YandexOauth, MailOauth, AppleOauth } from '@skroz/profile-api';
169
+ ```
170
+
171
+ Каждый провайдер реализует интерфейс `OAuthProvider`:
172
+
173
+ ```ts
174
+ interface OAuthProvider {
175
+ exchangeCode(code: string): Promise<OAuthProfile>;
176
+ readonly trustedEmail: boolean; // true = email верифицирован провайдером
177
+ }
178
+
179
+ interface OAuthProfile {
180
+ providerId: string;
181
+ email?: string | null;
182
+ name?: string | null;
183
+ avatarUrl?: string | null;
184
+ }
185
+ ```
186
+
187
+ `trustedEmail: true` у Google, VK, Яндекс, Mail, Apple — при входе через них `isEmailConfirmed` и `isEmailNotificationEnabled` автоматически выставляются в `true`.
188
+
189
+ ---
190
+
191
+ ## DTO
192
+
193
+ GraphQL input/output классы для использования в схеме:
194
+
195
+ `AuthInput`, `UpdateEmailInput`, `UpdatePasswordInput`, `UpdateProfileInput`,
196
+ `ConfirmEmailInput`, `RecoverPasswordInput`, `SendTokenInput`, `SendTokenPayload`,
197
+ `OauthLoginInput`, `TelegramAuthData`
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@skroz/profile-api",
3
- "version": "1.0.21",
3
+ "version": "1.0.22",
4
4
  "license": "MIT",
5
5
  "repository": "git@gitlab.com:skroz/libs/utils.git",
6
6
  "main": "dist/index.js",
@@ -44,5 +44,5 @@
44
44
  "type-graphql": "^1.1.1",
45
45
  "typeorm": "^0.2.45"
46
46
  },
47
- "gitHead": "4d48bd69998725da84ce966a6ab383fb5eb208cc"
47
+ "gitHead": "b76953b60d5790c28dd02476788130a62c255a94"
48
48
  }