@codingfactory/socialkit-vue 0.1.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. package/dist/index.d.ts +9 -1
  2. package/dist/index.d.ts.map +1 -1
  3. package/dist/index.js +3 -0
  4. package/dist/index.js.map +1 -1
  5. package/dist/services/circles.d.ts +470 -0
  6. package/dist/services/circles.d.ts.map +1 -0
  7. package/dist/services/circles.js +1924 -0
  8. package/dist/services/circles.js.map +1 -0
  9. package/dist/services/identity.d.ts +29 -0
  10. package/dist/services/identity.d.ts.map +1 -0
  11. package/dist/services/identity.js +150 -0
  12. package/dist/services/identity.js.map +1 -0
  13. package/dist/stores/auth.d.ts +3 -0
  14. package/dist/stores/auth.d.ts.map +1 -1
  15. package/dist/stores/circles.d.ts +4283 -0
  16. package/dist/stores/circles.d.ts.map +1 -0
  17. package/dist/stores/circles.js +1670 -0
  18. package/dist/stores/circles.js.map +1 -0
  19. package/dist/types/api.d.ts +19 -0
  20. package/dist/types/api.d.ts.map +1 -1
  21. package/dist/types/auth.d.ts +34 -0
  22. package/dist/types/auth.d.ts.map +1 -0
  23. package/dist/types/auth.js +8 -0
  24. package/dist/types/auth.js.map +1 -0
  25. package/dist/types/identity.d.ts +34 -0
  26. package/dist/types/identity.d.ts.map +1 -0
  27. package/dist/types/identity.js +5 -0
  28. package/dist/types/identity.js.map +1 -0
  29. package/dist/types/user.d.ts +1 -0
  30. package/dist/types/user.d.ts.map +1 -1
  31. package/dist/types/user.js.map +1 -1
  32. package/package.json +1 -1
  33. package/src/index.ts +105 -0
  34. package/src/services/circles.ts +2767 -0
  35. package/src/services/identity.ts +281 -0
  36. package/src/stores/circles.ts +2114 -0
  37. package/src/types/api.ts +20 -0
  38. package/src/types/auth.ts +39 -0
  39. package/src/types/identity.ts +41 -0
  40. package/src/types/user.ts +1 -0
@@ -0,0 +1,281 @@
1
+ /**
2
+ * Configurable identity service for SocialKit-powered frontends.
3
+ */
4
+
5
+ import type { AxiosInstance } from 'axios'
6
+ import type { TokenStorage } from '../utils/tokenStorage.js'
7
+ import { extractTokenFromResponse } from '../utils/tokenStorage.js'
8
+ import type {
9
+ AccountDeletionConfirmationResult,
10
+ AccountDeletionRequestResult,
11
+ ChangePasswordPayload,
12
+ ChangePasswordResult,
13
+ TwoFactorDisablePayload,
14
+ TwoFactorEnableResult,
15
+ TwoFactorEnrollment,
16
+ TwoFactorStatus
17
+ } from '../types/identity.js'
18
+ import type { IdentityUser } from '../types/user.js'
19
+
20
+ interface IdentityUserResponse {
21
+ id: string
22
+ handle?: string
23
+ name: string
24
+ avatar?: string | { url: string; thumb_url?: string } | null
25
+ avatar_url?: string | null
26
+ cover_photo?: string | null
27
+ bio?: string | null
28
+ email?: string
29
+ created_at?: string
30
+ updated_at?: string
31
+ }
32
+
33
+ interface DataEnvelope<T> {
34
+ data?: T
35
+ message?: string
36
+ }
37
+
38
+ interface TwoFactorStatusPayload {
39
+ enabled?: unknown
40
+ }
41
+
42
+ interface TwoFactorEnrollmentPayload {
43
+ qr_code_url?: unknown
44
+ secret_base32?: unknown
45
+ }
46
+
47
+ interface RecoveryCodesPayload {
48
+ recovery_codes?: unknown
49
+ }
50
+
51
+ interface AccountDeletionRequestPayload {
52
+ id?: unknown
53
+ status?: unknown
54
+ confirmation_token?: unknown
55
+ dev_token?: unknown
56
+ }
57
+
58
+ interface AccountDeletionConfirmationPayload {
59
+ status?: unknown
60
+ }
61
+
62
+ export interface IdentityServiceConfig {
63
+ client: AxiosInstance
64
+ tokenStorage: TokenStorage
65
+ }
66
+
67
+ export interface IdentityServiceInstance {
68
+ getCurrentUser(): Promise<IdentityUser>
69
+ getUser(userId: string): Promise<IdentityUser>
70
+ updateUser(userId: string, payload: Partial<IdentityUser>): Promise<IdentityUser>
71
+ uploadAvatar(file: File): Promise<{ url: string }>
72
+ changePassword(payload: ChangePasswordPayload): Promise<ChangePasswordResult>
73
+ getTwoFactorStatus(): Promise<TwoFactorStatus>
74
+ startTwoFactorEnrollment(currentPassword: string): Promise<TwoFactorEnrollment>
75
+ enableTwoFactor(code: string): Promise<TwoFactorEnableResult>
76
+ regenerateTwoFactorRecoveryCodes(code: string): Promise<TwoFactorEnableResult>
77
+ disableTwoFactor(payload: TwoFactorDisablePayload): Promise<void>
78
+ requestAccountDeletion(): Promise<AccountDeletionRequestResult>
79
+ confirmAccountDeletion(
80
+ requestId: string,
81
+ confirmationToken: string
82
+ ): Promise<AccountDeletionConfirmationResult>
83
+ }
84
+
85
+ class IdentityService implements IdentityServiceInstance {
86
+ public constructor(
87
+ private readonly client: AxiosInstance,
88
+ private readonly tokenStorage: TokenStorage
89
+ ) {}
90
+
91
+ public async getCurrentUser(): Promise<IdentityUser> {
92
+ const response = await this.client.get<DataEnvelope<unknown>>('/v1/me')
93
+ return this.normalizeUser(response.data.data)
94
+ }
95
+
96
+ public async getUser(userId: string): Promise<IdentityUser> {
97
+ const response = await this.client.get<DataEnvelope<unknown>>('/v1/identity/users/by-ids', {
98
+ params: {
99
+ ids: userId
100
+ }
101
+ })
102
+
103
+ const users = Array.isArray(response.data?.data) ? response.data.data : []
104
+ const user = users.find((candidate: unknown) => {
105
+ if (!candidate || typeof candidate !== 'object') {
106
+ return false
107
+ }
108
+
109
+ const candidateWithId = candidate as { id?: unknown }
110
+
111
+ return candidateWithId.id === userId
112
+ })
113
+
114
+ if (!user) {
115
+ throw new Error('User not found')
116
+ }
117
+
118
+ return this.normalizeUser(user)
119
+ }
120
+
121
+ public async updateUser(
122
+ _userId: string,
123
+ payload: Partial<IdentityUser>
124
+ ): Promise<IdentityUser> {
125
+ const response = await this.client.patch<DataEnvelope<unknown>>('/v1/me', payload)
126
+ return this.normalizeUser(response.data.data)
127
+ }
128
+
129
+ public async uploadAvatar(file: File): Promise<{ url: string }> {
130
+ const formData = new FormData()
131
+ formData.append('file', file)
132
+
133
+ const response = await this.client.post<{ url: string }>('/v1/media/upload', formData)
134
+ return response.data
135
+ }
136
+
137
+ public async changePassword(payload: ChangePasswordPayload): Promise<ChangePasswordResult> {
138
+ const response = await this.client.patch<DataEnvelope<unknown>>('/v1/me/password', {
139
+ current_password: payload.currentPassword,
140
+ password: payload.newPassword,
141
+ password_confirmation: payload.confirmPassword
142
+ })
143
+
144
+ const rotatedToken = extractTokenFromResponse(response.data)
145
+ if (rotatedToken) {
146
+ this.tokenStorage.setToken(rotatedToken)
147
+ }
148
+
149
+ const message = typeof response.data?.message === 'string' && response.data.message.trim() !== ''
150
+ ? response.data.message
151
+ : 'Password updated successfully'
152
+
153
+ return { message }
154
+ }
155
+
156
+ public async getTwoFactorStatus(): Promise<TwoFactorStatus> {
157
+ const response = await this.client.get<DataEnvelope<TwoFactorStatusPayload>>('/v1/security/2fa/status')
158
+
159
+ return {
160
+ enabled: response.data?.data?.enabled === true
161
+ }
162
+ }
163
+
164
+ public async startTwoFactorEnrollment(currentPassword: string): Promise<TwoFactorEnrollment> {
165
+ const response = await this.client.post<DataEnvelope<TwoFactorEnrollmentPayload>>(
166
+ '/v1/security/2fa/start',
167
+ {
168
+ current_password: currentPassword
169
+ }
170
+ )
171
+
172
+ const qrCodeUrl = response.data?.data?.qr_code_url
173
+ const secretBase32 = response.data?.data?.secret_base32
174
+
175
+ if (typeof qrCodeUrl !== 'string' || typeof secretBase32 !== 'string') {
176
+ throw new Error('Invalid two-factor enrollment response payload')
177
+ }
178
+
179
+ return {
180
+ qrCodeUrl,
181
+ secretBase32
182
+ }
183
+ }
184
+
185
+ public async enableTwoFactor(code: string): Promise<TwoFactorEnableResult> {
186
+ const response = await this.client.post<DataEnvelope<RecoveryCodesPayload>>(
187
+ '/v1/security/2fa/enable',
188
+ { code }
189
+ )
190
+
191
+ return {
192
+ recoveryCodes: this.normalizeRecoveryCodes(response.data?.data?.recovery_codes)
193
+ }
194
+ }
195
+
196
+ public async regenerateTwoFactorRecoveryCodes(code: string): Promise<TwoFactorEnableResult> {
197
+ const response = await this.client.post<DataEnvelope<RecoveryCodesPayload>>(
198
+ '/v1/security/2fa/recovery-codes/regenerate',
199
+ { code }
200
+ )
201
+
202
+ return {
203
+ recoveryCodes: this.normalizeRecoveryCodes(response.data?.data?.recovery_codes)
204
+ }
205
+ }
206
+
207
+ public async disableTwoFactor(payload: TwoFactorDisablePayload): Promise<void> {
208
+ await this.client.post('/v1/security/2fa/disable', {
209
+ password: payload.password,
210
+ code: payload.code
211
+ })
212
+ }
213
+
214
+ public async requestAccountDeletion(): Promise<AccountDeletionRequestResult> {
215
+ const response = await this.client.post<DataEnvelope<AccountDeletionRequestPayload>>('/v1/compliance/dsar/erase')
216
+ const id = response.data?.data?.id
217
+ const status = response.data?.data?.status
218
+ const confirmationToken = response.data?.data?.confirmation_token
219
+ const devToken = response.data?.data?.dev_token
220
+
221
+ if (typeof id !== 'string' || typeof status !== 'string') {
222
+ throw new Error('Invalid account deletion request payload')
223
+ }
224
+
225
+ return {
226
+ requestId: id,
227
+ status,
228
+ confirmationToken: typeof confirmationToken === 'string'
229
+ ? confirmationToken
230
+ : typeof devToken === 'string'
231
+ ? devToken
232
+ : null
233
+ }
234
+ }
235
+
236
+ public async confirmAccountDeletion(
237
+ requestId: string,
238
+ confirmationToken: string
239
+ ): Promise<AccountDeletionConfirmationResult> {
240
+ const response = await this.client.post<DataEnvelope<AccountDeletionConfirmationPayload>>(
241
+ `/v1/compliance/dsar/${encodeURIComponent(requestId)}/confirm`,
242
+ {
243
+ token: confirmationToken
244
+ }
245
+ )
246
+ const status = response.data?.data?.status
247
+
248
+ if (typeof status !== 'string') {
249
+ throw new Error('Invalid account deletion confirmation payload')
250
+ }
251
+
252
+ return { status }
253
+ }
254
+
255
+ private normalizeUser(user: unknown): IdentityUser {
256
+ if (!user || typeof user !== 'object') {
257
+ throw new Error('Invalid user data')
258
+ }
259
+
260
+ const userData = user as IdentityUserResponse
261
+ const avatarUrl = typeof userData.avatar === 'string'
262
+ ? userData.avatar
263
+ : userData.avatar?.url ?? userData.avatar_url ?? null
264
+
265
+ return {
266
+ ...userData,
267
+ avatar: avatarUrl,
268
+ ...(avatarUrl ? { avatar_url: avatarUrl } : {})
269
+ }
270
+ }
271
+
272
+ private normalizeRecoveryCodes(recoveryCodesRaw: unknown): string[] {
273
+ return Array.isArray(recoveryCodesRaw)
274
+ ? recoveryCodesRaw.filter((value: unknown): value is string => typeof value === 'string')
275
+ : []
276
+ }
277
+ }
278
+
279
+ export function createIdentityService(config: IdentityServiceConfig): IdentityServiceInstance {
280
+ return new IdentityService(config.client, config.tokenStorage)
281
+ }