@taruvi/sdk 1.0.2 → 1.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,30 +1,266 @@
1
1
  import { getRuntimeEnvironment } from "../../utils/utils.js"
2
2
 
3
+ /**
4
+ * Token management interface for Web UI Flow authentication
5
+ */
6
+ export interface AuthTokens {
7
+ sessionToken?: string | undefined;
8
+ accessToken: string;
9
+ refreshToken: string;
10
+ expiresIn?: number | undefined;
11
+ expiresAt?: number | undefined;
12
+ tokenType?: string | undefined;
13
+ }
14
+
15
+ /**
16
+ * TokenClient - Manages authentication tokens for both browser and server environments
17
+ * Implements Web UI Flow token handling as described in Taruvi documentation
18
+ */
3
19
  export class TokenClient {
4
- // private tenantAdminToken: string | null = null
20
+ private static readonly ACCESS_TOKEN_KEY = 'jwt';
21
+ private static readonly REFRESH_TOKEN_KEY = 'refresh_token';
22
+ private static readonly SESSION_TOKEN_KEY = 'session_token';
23
+ private static readonly EXPIRES_AT_KEY = 'token_expires_at';
24
+ private static readonly TOKEN_TYPE_KEY = 'token_type';
25
+
5
26
  private runTimeEnvironment: string
6
27
  private browserRunTime: boolean
7
- // private adminSessionToken: string | null
28
+ private serverToken: string | null = null
8
29
 
9
30
  constructor(token?: string) {
10
31
  this.runTimeEnvironment = getRuntimeEnvironment()
11
32
  this.browserRunTime = this.runTimeEnvironment == "Browser"
12
- // this.adminSessionToken = this.getToken()
33
+
34
+ // For server-side usage, store the token
35
+ if (!this.browserRunTime && token) {
36
+ this.serverToken = token
37
+ }
13
38
  }
14
39
 
40
+ /**
41
+ * Get access token (supports both browser and server)
42
+ */
15
43
  getToken(): string | null {
16
44
  if (this.browserRunTime) {
17
- // return localStorage.getItem("")
18
- return localStorage.getItem("jwt")
45
+ if (typeof window === 'undefined' || typeof localStorage === 'undefined') {
46
+ return null
47
+ }
48
+ return localStorage.getItem(TokenClient.ACCESS_TOKEN_KEY)
49
+ }
50
+ return this.serverToken
51
+ }
52
+
53
+ /**
54
+ * Set all authentication tokens from Web UI Flow callback
55
+ */
56
+ setTokens(tokens: AuthTokens): void {
57
+ if (!this.browserRunTime) {
58
+ console.warn('Token storage is only available in browser environment')
59
+ return
60
+ }
61
+
62
+ if (typeof window === 'undefined' || typeof localStorage === 'undefined') {
63
+ return
64
+ }
65
+
66
+ try {
67
+ // Store access token
68
+ localStorage.setItem(TokenClient.ACCESS_TOKEN_KEY, tokens.accessToken)
69
+
70
+ // Store refresh token
71
+ localStorage.setItem(TokenClient.REFRESH_TOKEN_KEY, tokens.refreshToken)
72
+
73
+ // Store session token if provided
74
+ if (tokens.sessionToken) {
75
+ localStorage.setItem(TokenClient.SESSION_TOKEN_KEY, tokens.sessionToken)
76
+ }
77
+
78
+ // Calculate and store expiration time
79
+ if (tokens.expiresIn) {
80
+ const expiresAt = Date.now() + (tokens.expiresIn * 1000)
81
+ localStorage.setItem(TokenClient.EXPIRES_AT_KEY, expiresAt.toString())
82
+ } else if (tokens.expiresAt) {
83
+ localStorage.setItem(TokenClient.EXPIRES_AT_KEY, tokens.expiresAt.toString())
84
+ }
85
+
86
+ // Store token type
87
+ if (tokens.tokenType) {
88
+ localStorage.setItem(TokenClient.TOKEN_TYPE_KEY, tokens.tokenType)
89
+ }
90
+ } catch (err) {
91
+ console.error('Failed to store authentication tokens:', err)
92
+ }
93
+ }
94
+
95
+ /**
96
+ * Get all stored tokens
97
+ */
98
+ getTokens(): AuthTokens | null {
99
+ if (!this.browserRunTime) {
100
+ return null
101
+ }
102
+
103
+ if (typeof window === 'undefined' || typeof localStorage === 'undefined') {
104
+ return null
105
+ }
106
+
107
+ try {
108
+ const accessToken = localStorage.getItem(TokenClient.ACCESS_TOKEN_KEY)
109
+ const refreshToken = localStorage.getItem(TokenClient.REFRESH_TOKEN_KEY)
110
+ const sessionToken = localStorage.getItem(TokenClient.SESSION_TOKEN_KEY)
111
+ const expiresAt = localStorage.getItem(TokenClient.EXPIRES_AT_KEY)
112
+ const tokenType = localStorage.getItem(TokenClient.TOKEN_TYPE_KEY)
113
+
114
+ if (!accessToken || !refreshToken) {
115
+ return null
116
+ }
117
+
118
+ const tokens: any = {
119
+ accessToken,
120
+ refreshToken,
121
+ tokenType: tokenType || 'Bearer',
122
+ }
123
+
124
+ if (sessionToken) {
125
+ tokens.sessionToken = sessionToken
126
+ }
127
+
128
+ if (expiresAt) {
129
+ tokens.expiresIn = Math.floor((parseInt(expiresAt) - Date.now()) / 1000)
130
+ tokens.expiresAt = parseInt(expiresAt)
131
+ }
132
+
133
+ return tokens
134
+ } catch (err) {
135
+ console.error('Failed to retrieve authentication tokens:', err)
136
+ return null
137
+ }
138
+ }
139
+
140
+ /**
141
+ * Get refresh token
142
+ */
143
+ getRefreshToken(): string | null {
144
+ if (!this.browserRunTime) {
145
+ return null
146
+ }
147
+
148
+ if (typeof window === 'undefined' || typeof localStorage === 'undefined') {
149
+ return null
150
+ }
151
+
152
+ return localStorage.getItem(TokenClient.REFRESH_TOKEN_KEY)
153
+ }
154
+
155
+ /**
156
+ * Get session token
157
+ */
158
+ getSessionToken(): string | null {
159
+ if (!this.browserRunTime) {
160
+ return null
161
+ }
162
+
163
+ if (typeof window === 'undefined' || typeof localStorage === 'undefined') {
164
+ return null
165
+ }
166
+
167
+ return localStorage.getItem(TokenClient.SESSION_TOKEN_KEY)
168
+ }
169
+
170
+ /**
171
+ * Check if user is authenticated (has valid access token)
172
+ */
173
+ isAuthenticated(): boolean {
174
+ return !!this.getToken()
175
+ }
176
+
177
+ /**
178
+ * Check if access token is expired
179
+ */
180
+ isTokenExpired(): boolean {
181
+ if (!this.browserRunTime) {
182
+ return true
183
+ }
184
+
185
+ if (typeof window === 'undefined' || typeof localStorage === 'undefined') {
186
+ return true
187
+ }
188
+
189
+ const expiresAt = localStorage.getItem(TokenClient.EXPIRES_AT_KEY)
190
+ if (!expiresAt) {
191
+ return true
19
192
  }
20
- return null
21
- // return this.tenantAdminToken
193
+
194
+ return parseInt(expiresAt) < Date.now()
22
195
  }
23
196
 
24
- // TODO: Implement token management
25
- // - setToken
26
- // - getToken
27
- // - refreshToken
28
- // - clearToken
29
- // - isTokenExpired
197
+ /**
198
+ * Update access token after refresh
199
+ * ⚠️ IMPORTANT: Taruvi uses refresh token rotation
200
+ * When you refresh, you get BOTH a new access token AND a new refresh token
201
+ */
202
+ updateAccessToken(accessToken: string, expiresIn: number): void {
203
+ if (!this.browserRunTime) {
204
+ console.warn('Token update is only available in browser environment')
205
+ return
206
+ }
207
+
208
+ if (typeof window === 'undefined' || typeof localStorage === 'undefined') {
209
+ return
210
+ }
211
+
212
+ try {
213
+ localStorage.setItem(TokenClient.ACCESS_TOKEN_KEY, accessToken)
214
+ const expiresAt = Date.now() + (expiresIn * 1000)
215
+ localStorage.setItem(TokenClient.EXPIRES_AT_KEY, expiresAt.toString())
216
+ } catch (err) {
217
+ console.error('Failed to update access token:', err)
218
+ }
219
+ }
220
+
221
+ /**
222
+ * Update refresh token after rotation
223
+ * ⚠️ IMPORTANT: Taruvi rotates refresh tokens
224
+ * Always update the refresh token when you receive a new one
225
+ */
226
+ updateRefreshToken(refreshToken: string): void {
227
+ if (!this.browserRunTime) {
228
+ console.warn('Token update is only available in browser environment')
229
+ return
230
+ }
231
+
232
+ if (typeof window === 'undefined' || typeof localStorage === 'undefined') {
233
+ return
234
+ }
235
+
236
+ try {
237
+ localStorage.setItem(TokenClient.REFRESH_TOKEN_KEY, refreshToken)
238
+ } catch (err) {
239
+ console.error('Failed to update refresh token:', err)
240
+ }
241
+ }
242
+
243
+ /**
244
+ * Clear all tokens (logout)
245
+ */
246
+ clearTokens(): void {
247
+ if (!this.browserRunTime) {
248
+ this.serverToken = null
249
+ return
250
+ }
251
+
252
+ if (typeof window === 'undefined' || typeof localStorage === 'undefined') {
253
+ return
254
+ }
255
+
256
+ try {
257
+ localStorage.removeItem(TokenClient.ACCESS_TOKEN_KEY)
258
+ localStorage.removeItem(TokenClient.REFRESH_TOKEN_KEY)
259
+ localStorage.removeItem(TokenClient.SESSION_TOKEN_KEY)
260
+ localStorage.removeItem(TokenClient.EXPIRES_AT_KEY)
261
+ localStorage.removeItem(TokenClient.TOKEN_TYPE_KEY)
262
+ } catch (err) {
263
+ console.error('Failed to clear tokens:', err)
264
+ }
265
+ }
30
266
  }
File without changes