@anythink-cloud/sdk 0.1.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.
package/dist/index.mjs ADDED
@@ -0,0 +1,472 @@
1
+ import axios, { AxiosError } from 'axios';
2
+ import { create } from 'zustand';
3
+ import { persist, createJSONStorage } from 'zustand/middleware';
4
+
5
+ // src/auth/client.ts
6
+ var createAuthStore = (storageKey = "anythink_auth_session") => {
7
+ return create()(
8
+ persist(
9
+ (set) => ({
10
+ session: null,
11
+ isLoading: false,
12
+ error: null,
13
+ setSession: (session) => {
14
+ set({ session, error: null });
15
+ },
16
+ signOut: () => {
17
+ set({ session: null, error: null });
18
+ },
19
+ clearError: () => {
20
+ set({ error: null });
21
+ },
22
+ setLoading: (isLoading) => {
23
+ set({ isLoading });
24
+ },
25
+ setError: (error) => {
26
+ set({ error });
27
+ }
28
+ }),
29
+ {
30
+ name: storageKey,
31
+ storage: createJSONStorage(() => {
32
+ if (typeof globalThis !== "undefined" && "localStorage" in globalThis) {
33
+ return globalThis.localStorage;
34
+ }
35
+ return {
36
+ getItem: () => null,
37
+ setItem: () => {
38
+ },
39
+ removeItem: () => {
40
+ }
41
+ };
42
+ }),
43
+ // Only persist the session, not loading/error states
44
+ partialize: (state) => ({ session: state.session })
45
+ }
46
+ )
47
+ );
48
+ };
49
+
50
+ // src/auth/client.ts
51
+ var AuthClient = class {
52
+ constructor(config) {
53
+ this.config = {
54
+ tokenEndpoint: "/auth/v1/token",
55
+ refreshEndpoint: "/auth/v1/refresh",
56
+ changePasswordEndpoint: "/users/me/password",
57
+ storageKey: "anythink_auth_session",
58
+ onSignOut: () => {
59
+ return;
60
+ },
61
+ ...config
62
+ };
63
+ this.store = createAuthStore(this.config.storageKey);
64
+ this.axiosClient = axios.create({
65
+ baseURL: this.config.instanceUrl,
66
+ headers: {
67
+ "Content-Type": "application/json"
68
+ }
69
+ });
70
+ if (typeof config.onSessionChanged === "function") {
71
+ this.onSessionChanged = config.onSessionChanged;
72
+ }
73
+ }
74
+ /**
75
+ * Set the onSessionChanged handler.
76
+ * @param handler Callback fired whenever the session changes
77
+ */
78
+ setOnSessionChanged(handler) {
79
+ this.onSessionChanged = handler;
80
+ }
81
+ /**
82
+ * Internal helper to call the session-changed handler, if present.
83
+ */
84
+ _callSessionChanged(session) {
85
+ if (typeof this.onSessionChanged === "function") {
86
+ try {
87
+ this.onSessionChanged(session);
88
+ } catch (e) {
89
+ console.warn("onSessionChanged threw:", e);
90
+ }
91
+ }
92
+ }
93
+ /**
94
+ * Sign in with email and password
95
+ * @param email User email
96
+ * @param password User password
97
+ * @param orgId Optional organization ID
98
+ * @returns Session object with tokens
99
+ */
100
+ async signIn(email, password, orgId) {
101
+ try {
102
+ this.store.getState().setLoading(true);
103
+ this.store.getState().clearError();
104
+ const params = orgId ? { org_id: orgId.toString() } : void 0;
105
+ const response = await this.axiosClient.post(
106
+ this.config.tokenEndpoint,
107
+ { email, password },
108
+ { params }
109
+ );
110
+ const tokenPair = response.data;
111
+ const session = {
112
+ access_token: tokenPair.access_token,
113
+ refresh_token: tokenPair.refresh_token,
114
+ expires_in: tokenPair.expires_in,
115
+ expires_at: Math.floor(Date.now() / 1e3) + tokenPair.expires_in
116
+ };
117
+ this.store.getState().setSession(session);
118
+ this._callSessionChanged(session);
119
+ this.store.getState().setLoading(false);
120
+ return { data: { session }, error: null };
121
+ } catch (error) {
122
+ let authError;
123
+ if (error instanceof AxiosError) {
124
+ const errorMessage = typeof error.response?.data === "string" ? error.response.data : error.response?.data?.message || error.message || "Invalid email or password";
125
+ authError = new Error(errorMessage);
126
+ } else {
127
+ authError = error instanceof Error ? error : new Error("Sign in failed");
128
+ }
129
+ this.store.getState().setError(authError);
130
+ this.store.getState().setLoading(false);
131
+ this.store.getState().setSession(null);
132
+ this._callSessionChanged(null);
133
+ return {
134
+ data: { session: null },
135
+ error: authError
136
+ };
137
+ }
138
+ }
139
+ /**
140
+ * Register a new user
141
+ * @param firstName User's first name
142
+ * @param lastName User's last name
143
+ * @param email User's email
144
+ * @param password User's password
145
+ * @returns Error object or null if successful
146
+ */
147
+ async register(firstName, lastName, email, password) {
148
+ try {
149
+ await this.axiosClient.post("/auth/v1/register", {
150
+ first_name: firstName,
151
+ last_name: lastName,
152
+ email,
153
+ password,
154
+ org_id: this.config.orgId
155
+ });
156
+ return { error: null };
157
+ } catch (error) {
158
+ let authError;
159
+ if (error instanceof AxiosError) {
160
+ const errorMessage = typeof error.response?.data === "string" ? error.response.data : error.response?.data?.message || error.message || "Failed to register";
161
+ authError = new Error(errorMessage);
162
+ } else {
163
+ authError = error instanceof Error ? error : new Error("Failed to register");
164
+ }
165
+ return {
166
+ error: authError
167
+ };
168
+ }
169
+ }
170
+ /**
171
+ * Refresh the access token using the refresh token
172
+ * @returns Session object with new tokens
173
+ */
174
+ async refreshSession() {
175
+ const { session } = this.store.getState();
176
+ if (!session?.refresh_token) {
177
+ const error = new Error("No refresh token found");
178
+ this.store.getState().setError(error);
179
+ return {
180
+ data: { session: null },
181
+ error
182
+ };
183
+ }
184
+ try {
185
+ this.store.getState().setLoading(true);
186
+ this.store.getState().clearError();
187
+ const response = await this.axiosClient.post(
188
+ this.config.refreshEndpoint,
189
+ { token: session.refresh_token }
190
+ );
191
+ const tokenPair = response.data;
192
+ const newSession = {
193
+ access_token: tokenPair.access_token,
194
+ refresh_token: tokenPair.refresh_token,
195
+ expires_in: tokenPair.expires_in,
196
+ expires_at: Math.floor(Date.now() / 1e3) + tokenPair.expires_in
197
+ };
198
+ this.store.getState().setSession(newSession);
199
+ this._callSessionChanged(newSession);
200
+ this.store.getState().setLoading(false);
201
+ return { data: { session: newSession }, error: null };
202
+ } catch (error) {
203
+ this.store.getState().setSession(null);
204
+ this._callSessionChanged(null);
205
+ this.store.getState().setLoading(false);
206
+ let authError;
207
+ if (error instanceof AxiosError) {
208
+ const errorMessage = typeof error.response?.data === "string" ? error.response.data : error.response?.data?.message || error.message || "Invalid refresh token";
209
+ authError = new Error(errorMessage);
210
+ } else {
211
+ authError = error instanceof Error ? error : new Error("Token refresh failed");
212
+ }
213
+ this.store.getState().setError(authError);
214
+ return {
215
+ data: { session: null },
216
+ error: authError
217
+ };
218
+ }
219
+ }
220
+ /**
221
+ * Get the current session
222
+ * @returns Session object or null if not authenticated
223
+ */
224
+ getSession() {
225
+ const session = this.store.getState().session;
226
+ if (session && session.expires_at && Date.now() >= session.expires_at * 1e3) {
227
+ return { data: { session: null } };
228
+ }
229
+ return { data: { session } };
230
+ }
231
+ /**
232
+ * Set session from tokens (useful for OAuth flows or token exchange)
233
+ * @param accessToken Access token
234
+ * @param refreshToken Refresh token
235
+ * @param expiresIn Expiration time in seconds
236
+ */
237
+ async setSession({
238
+ access_token,
239
+ refresh_token,
240
+ expires_in
241
+ }) {
242
+ try {
243
+ const session = {
244
+ access_token,
245
+ refresh_token,
246
+ expires_in,
247
+ expires_at: Math.floor(Date.now() / 1e3) + expires_in
248
+ };
249
+ this.store.getState().setSession(session);
250
+ this._callSessionChanged(session);
251
+ return { error: null };
252
+ } catch (error) {
253
+ this._callSessionChanged(null);
254
+ return {
255
+ error: error instanceof Error ? error : new Error("Failed to set session")
256
+ };
257
+ }
258
+ }
259
+ /**
260
+ * Change the current user's password
261
+ * @param currentPassword Current password
262
+ * @param newPassword New password
263
+ * @returns Error object or null if successful
264
+ */
265
+ async changePassword(currentPassword, newPassword) {
266
+ try {
267
+ const token = this.getAccessToken();
268
+ if (!token) {
269
+ throw new Error("No access token found");
270
+ }
271
+ await this.axiosClient.post(
272
+ this.config.changePasswordEndpoint,
273
+ {
274
+ current_password: currentPassword,
275
+ new_password: newPassword
276
+ },
277
+ {
278
+ headers: {
279
+ Authorization: `Bearer ${token}`
280
+ }
281
+ }
282
+ );
283
+ return { error: null };
284
+ } catch (error) {
285
+ let authError;
286
+ if (error instanceof AxiosError) {
287
+ const errorMessage = typeof error.response?.data === "string" ? error.response.data : error.response?.data?.message || error.message || "Failed to change password";
288
+ authError = new Error(errorMessage);
289
+ } else {
290
+ authError = error instanceof Error ? error : new Error("Failed to change password");
291
+ }
292
+ return {
293
+ error: authError
294
+ };
295
+ }
296
+ }
297
+ /**
298
+ * Sign out and clear session
299
+ */
300
+ async signOut() {
301
+ this.store.getState().signOut();
302
+ this._callSessionChanged(null);
303
+ if (this.config.onSignOut) {
304
+ this.config.onSignOut();
305
+ }
306
+ return { error: null };
307
+ }
308
+ /**
309
+ * Get the current access token
310
+ */
311
+ getAccessToken() {
312
+ const session = this.store.getState().session;
313
+ if (!session) return null;
314
+ if (session.expires_at && Date.now() >= session.expires_at * 1e3) {
315
+ return null;
316
+ }
317
+ return session.access_token;
318
+ }
319
+ /**
320
+ * Get the current refresh token
321
+ */
322
+ getRefreshToken() {
323
+ return this.store.getState().session?.refresh_token || null;
324
+ }
325
+ /**
326
+ * Check if user is authenticated
327
+ */
328
+ isAuthenticated() {
329
+ const session = this.store.getState().session;
330
+ if (!session) return false;
331
+ if (session.expires_at && Date.now() >= session.expires_at * 1e3) {
332
+ return false;
333
+ }
334
+ return true;
335
+ }
336
+ /**
337
+ * Get the Zustand store (for React hooks)
338
+ */
339
+ getStore() {
340
+ return this.store;
341
+ }
342
+ };
343
+ var AuthenticatedBaseService = class {
344
+ constructor(authClient, instanceUrl) {
345
+ this.authClient = authClient;
346
+ this.instanceUrl = instanceUrl;
347
+ this.client = axios.create({
348
+ baseURL: this.instanceUrl
349
+ });
350
+ this.setupInterceptors();
351
+ }
352
+ /**
353
+ * Setup request and response interceptors
354
+ */
355
+ setupInterceptors() {
356
+ this.client.interceptors.request.use(
357
+ (config) => {
358
+ const token = this.authClient.getAccessToken();
359
+ if (token) {
360
+ config.headers.Authorization = `Bearer ${token}`;
361
+ }
362
+ return config;
363
+ },
364
+ (error) => {
365
+ return Promise.reject(error);
366
+ }
367
+ );
368
+ this.client.interceptors.response.use(
369
+ (response) => response,
370
+ async (error) => {
371
+ const originalRequest = error.config;
372
+ if (error.response?.status === 401 && originalRequest && !originalRequest._retry) {
373
+ originalRequest._retry = true;
374
+ try {
375
+ const { data, error: refreshError } = await this.authClient.refreshSession();
376
+ if (data.session && !refreshError) {
377
+ const token = this.authClient.getAccessToken();
378
+ if (token) {
379
+ if (!originalRequest.headers) {
380
+ originalRequest.headers = {};
381
+ }
382
+ originalRequest.headers.Authorization = `Bearer ${token}`;
383
+ }
384
+ return this.client(originalRequest);
385
+ } else {
386
+ await this.authClient.signOut();
387
+ }
388
+ } catch (refreshError) {
389
+ await this.authClient.signOut();
390
+ return Promise.reject(refreshError);
391
+ }
392
+ }
393
+ return Promise.reject(error);
394
+ }
395
+ );
396
+ }
397
+ /**
398
+ * GET request
399
+ */
400
+ async get(url, config) {
401
+ const response = await this.client.get(url, config);
402
+ return response.data;
403
+ }
404
+ /**
405
+ * POST request
406
+ */
407
+ async post(url, data, config) {
408
+ const response = await this.client.post(
409
+ url,
410
+ data,
411
+ config
412
+ );
413
+ return response.data;
414
+ }
415
+ /**
416
+ * POST request with form data
417
+ */
418
+ async postFormData(url, data) {
419
+ const response = await this.client.post(
420
+ url,
421
+ data,
422
+ {
423
+ headers: {
424
+ "Content-Type": "multipart/form-data"
425
+ }
426
+ }
427
+ );
428
+ return response.data;
429
+ }
430
+ /**
431
+ * PUT request
432
+ */
433
+ async put(url, data, config) {
434
+ const response = await this.client.put(
435
+ url,
436
+ data,
437
+ config
438
+ );
439
+ return response.data;
440
+ }
441
+ /**
442
+ * PATCH request
443
+ */
444
+ async patch(url, data, config) {
445
+ const response = await this.client.patch(
446
+ url,
447
+ data,
448
+ config
449
+ );
450
+ return response.data;
451
+ }
452
+ /**
453
+ * DELETE request
454
+ */
455
+ async delete(url, config) {
456
+ const response = await this.client.delete(url, config);
457
+ return response.data;
458
+ }
459
+ /**
460
+ * Get the underlying Axios instance (for advanced usage)
461
+ */
462
+ getClient() {
463
+ return this.client;
464
+ }
465
+ };
466
+
467
+ // src/index.ts
468
+ var version = "0.1.0";
469
+
470
+ export { AuthClient, AuthenticatedBaseService, createAuthStore, version };
471
+ //# sourceMappingURL=index.mjs.map
472
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/auth/store.ts","../src/auth/client.ts","../src/services/AuthenticatedBaseService.ts","../src/index.ts"],"names":["axios"],"mappings":"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","file":"index.mjs","sourcesContent":["import { create } from \"zustand\";\nimport { persist, createJSONStorage } from \"zustand/middleware\";\nimport type { Session } from \"@/types/auth\";\n\ninterface AuthState {\n session: Session | null;\n isLoading: boolean;\n error: Error | null;\n\n // Actions\n setSession: (session: Session | null) => void;\n signOut: () => void;\n clearError: () => void;\n setLoading: (isLoading: boolean) => void;\n setError: (error: Error | null) => void;\n}\n\n/**\n * Creates the auth store with persistence\n * @param storageKey - Key for localStorage persistence\n */\nexport const createAuthStore = (\n storageKey: string = \"anythink_auth_session\"\n) => {\n return create<AuthState>()(\n persist(\n (set) => ({\n session: null,\n isLoading: false,\n error: null,\n\n setSession: (session: Session | null) => {\n set({ session, error: null });\n },\n\n signOut: () => {\n set({ session: null, error: null });\n },\n\n clearError: () => {\n set({ error: null });\n },\n\n setLoading: (isLoading: boolean) => {\n set({ isLoading });\n },\n\n setError: (error: Error | null) => {\n set({ error });\n },\n }),\n {\n name: storageKey,\n storage: createJSONStorage(() => {\n // Use localStorage for persistence\n if (\n typeof globalThis !== \"undefined\" &&\n \"localStorage\" in globalThis\n ) {\n return (globalThis as any).localStorage;\n }\n // Fallback for SSR\n return {\n getItem: () => null,\n setItem: () => {},\n removeItem: () => {},\n };\n }),\n // Only persist the session, not loading/error states\n partialize: (state: AuthState) => ({ session: state.session }),\n }\n )\n );\n};\n","import axios, { AxiosError, AxiosInstance } from \"axios\";\nimport type {\n AuthConfig,\n Session,\n SignInResponse,\n RefreshResponse,\n TokenPair,\n} from \"@/types/auth\";\nimport { createAuthStore } from \"@/auth/store\";\n\n/**\n * Auth client for handling authentication with the Anythink API\n */\nexport class AuthClient {\n private store: ReturnType<typeof createAuthStore>;\n private config: Required<AuthConfig>;\n private onSessionChanged?: (session: Session | null) => void;\n private axiosClient: AxiosInstance;\n\n constructor(\n config: AuthConfig & {\n onSessionChanged?: (session: Session | null) => void;\n }\n ) {\n this.config = {\n tokenEndpoint: \"/auth/v1/token\",\n refreshEndpoint: \"/auth/v1/refresh\",\n changePasswordEndpoint: \"/users/me/password\",\n storageKey: \"anythink_auth_session\",\n onSignOut: () => {\n return;\n },\n ...config,\n };\n\n this.store = createAuthStore(this.config.storageKey);\n\n // Create axios instance with base URL\n this.axiosClient = axios.create({\n baseURL: this.config.instanceUrl,\n headers: {\n \"Content-Type\": \"application/json\",\n },\n });\n\n if (typeof config.onSessionChanged === \"function\") {\n this.onSessionChanged = config.onSessionChanged;\n }\n }\n\n /**\n * Set the onSessionChanged handler.\n * @param handler Callback fired whenever the session changes\n */\n setOnSessionChanged(\n handler: ((session: Session | null) => void) | undefined\n ) {\n this.onSessionChanged = handler;\n }\n\n /**\n * Internal helper to call the session-changed handler, if present.\n */\n private _callSessionChanged(session: Session | null) {\n if (typeof this.onSessionChanged === \"function\") {\n try {\n this.onSessionChanged(session);\n } catch (e) {\n // Avoid throwing in userland\n console.warn(\"onSessionChanged threw:\", e);\n }\n }\n }\n\n /**\n * Sign in with email and password\n * @param email User email\n * @param password User password\n * @param orgId Optional organization ID\n * @returns Session object with tokens\n */\n async signIn(\n email: string,\n password: string,\n orgId?: number\n ): Promise<SignInResponse> {\n try {\n this.store.getState().setLoading(true);\n this.store.getState().clearError();\n\n const params = orgId ? { org_id: orgId.toString() } : undefined;\n\n // Always expect snake_case fields from the API\n const response = await this.axiosClient.post<TokenPair>(\n this.config.tokenEndpoint,\n { email, password },\n { params }\n );\n\n const tokenPair = response.data;\n\n const session: Session = {\n access_token: tokenPair.access_token,\n refresh_token: tokenPair.refresh_token,\n expires_in: tokenPair.expires_in,\n expires_at: Math.floor(Date.now() / 1000) + tokenPair.expires_in,\n };\n\n this.store.getState().setSession(session);\n this._callSessionChanged(session); // Call hook here\n this.store.getState().setLoading(false);\n\n return { data: { session }, error: null };\n } catch (error) {\n let authError: Error;\n if (error instanceof AxiosError) {\n const errorMessage =\n typeof error.response?.data === \"string\"\n ? error.response.data\n : error.response?.data?.message ||\n error.message ||\n \"Invalid email or password\";\n authError = new Error(errorMessage);\n } else {\n authError =\n error instanceof Error ? error : new Error(\"Sign in failed\");\n }\n this.store.getState().setError(authError);\n this.store.getState().setLoading(false);\n this.store.getState().setSession(null);\n this._callSessionChanged(null); // Call hook for failed sign in\n\n return {\n data: { session: null },\n error: authError,\n };\n }\n }\n\n /**\n * Register a new user\n * @param firstName User's first name\n * @param lastName User's last name\n * @param email User's email\n * @param password User's password\n * @returns Error object or null if successful\n */\n async register(\n firstName: string,\n lastName: string,\n email: string,\n password: string\n ): Promise<{ error: Error | null }> {\n try {\n await this.axiosClient.post(\"/auth/v1/register\", {\n first_name: firstName,\n last_name: lastName,\n email,\n password,\n org_id: this.config.orgId,\n });\n return { error: null };\n } catch (error) {\n let authError: Error;\n if (error instanceof AxiosError) {\n const errorMessage =\n typeof error.response?.data === \"string\"\n ? error.response.data\n : error.response?.data?.message ||\n error.message ||\n \"Failed to register\";\n authError = new Error(errorMessage);\n } else {\n authError =\n error instanceof Error ? error : new Error(\"Failed to register\");\n }\n return {\n error: authError,\n };\n }\n }\n\n /**\n * Refresh the access token using the refresh token\n * @returns Session object with new tokens\n */\n async refreshSession(): Promise<RefreshResponse> {\n const { session } = this.store.getState();\n if (!session?.refresh_token) {\n const error = new Error(\"No refresh token found\");\n this.store.getState().setError(error);\n return {\n data: { session: null },\n error,\n };\n }\n\n try {\n this.store.getState().setLoading(true);\n this.store.getState().clearError();\n\n const response = await this.axiosClient.post<TokenPair>(\n this.config.refreshEndpoint,\n { token: session.refresh_token }\n );\n\n const tokenPair = response.data;\n\n const newSession: Session = {\n access_token: tokenPair.access_token,\n refresh_token: tokenPair.refresh_token,\n expires_in: tokenPair.expires_in,\n expires_at: Math.floor(Date.now() / 1000) + tokenPair.expires_in,\n };\n\n this.store.getState().setSession(newSession);\n this._callSessionChanged(newSession); // Call here\n this.store.getState().setLoading(false);\n\n return { data: { session: newSession }, error: null };\n } catch (error) {\n // Clear invalid tokens\n this.store.getState().setSession(null);\n this._callSessionChanged(null); // Call hook here on null-out\n this.store.getState().setLoading(false);\n\n let authError: Error;\n if (error instanceof AxiosError) {\n const errorMessage =\n typeof error.response?.data === \"string\"\n ? error.response.data\n : error.response?.data?.message ||\n error.message ||\n \"Invalid refresh token\";\n authError = new Error(errorMessage);\n } else {\n authError =\n error instanceof Error ? error : new Error(\"Token refresh failed\");\n }\n this.store.getState().setError(authError);\n\n return {\n data: { session: null },\n error: authError,\n };\n }\n }\n\n /**\n * Get the current session\n * @returns Session object or null if not authenticated\n */\n getSession(): { data: { session: Session | null } } {\n const session = this.store.getState().session;\n\n // Check if session is expired\n // expires_at is in seconds (Unix timestamp), Date.now() is in milliseconds\n if (\n session &&\n session.expires_at &&\n Date.now() >= session.expires_at * 1000\n ) {\n // Session expired, return null\n // The caller should handle refresh if needed\n return { data: { session: null } };\n }\n\n return { data: { session } };\n }\n\n /**\n * Set session from tokens (useful for OAuth flows or token exchange)\n * @param accessToken Access token\n * @param refreshToken Refresh token\n * @param expiresIn Expiration time in seconds\n */\n async setSession({\n access_token,\n refresh_token,\n expires_in,\n }: {\n access_token: string;\n refresh_token: string;\n expires_in: number;\n }): Promise<{ error: Error | null }> {\n try {\n const session: Session = {\n access_token,\n refresh_token,\n expires_in,\n expires_at: Math.floor(Date.now() / 1000) + expires_in,\n };\n this.store.getState().setSession(session);\n this._callSessionChanged(session); // Call here\n return { error: null };\n } catch (error) {\n this._callSessionChanged(null); // Defensive, though only on explicit error\n return {\n error:\n error instanceof Error ? error : new Error(\"Failed to set session\"),\n };\n }\n }\n\n /**\n * Change the current user's password\n * @param currentPassword Current password\n * @param newPassword New password\n * @returns Error object or null if successful\n */\n async changePassword(\n currentPassword: string,\n newPassword: string\n ): Promise<{ error: Error | null }> {\n try {\n const token = this.getAccessToken();\n if (!token) {\n throw new Error(\"No access token found\");\n }\n await this.axiosClient.post(\n this.config.changePasswordEndpoint,\n {\n current_password: currentPassword,\n new_password: newPassword,\n },\n {\n headers: {\n Authorization: `Bearer ${token}`,\n },\n }\n );\n return { error: null };\n } catch (error) {\n let authError: Error;\n if (error instanceof AxiosError) {\n const errorMessage =\n typeof error.response?.data === \"string\"\n ? error.response.data\n : error.response?.data?.message ||\n error.message ||\n \"Failed to change password\";\n authError = new Error(errorMessage);\n } else {\n authError =\n error instanceof Error\n ? error\n : new Error(\"Failed to change password\");\n }\n return {\n error: authError,\n };\n }\n }\n\n /**\n * Sign out and clear session\n */\n async signOut(): Promise<{ error: null }> {\n this.store.getState().signOut();\n this._callSessionChanged(null); // Call on sign out\n if (this.config.onSignOut) {\n this.config.onSignOut();\n }\n return { error: null };\n }\n\n /**\n * Get the current access token\n */\n getAccessToken(): string | null {\n const session = this.store.getState().session;\n if (!session) return null;\n\n // Check if expired\n // expires_at is in seconds (Unix timestamp), Date.now() is in milliseconds\n if (session.expires_at && Date.now() >= session.expires_at * 1000) {\n return null;\n }\n\n return session.access_token;\n }\n\n /**\n * Get the current refresh token\n */\n getRefreshToken(): string | null {\n return this.store.getState().session?.refresh_token || null;\n }\n\n /**\n * Check if user is authenticated\n */\n isAuthenticated(): boolean {\n const session = this.store.getState().session;\n if (!session) return false;\n\n // Check if expired\n // expires_at is in seconds (Unix timestamp), Date.now() is in milliseconds\n if (session.expires_at && Date.now() >= session.expires_at * 1000) {\n return false;\n }\n\n return true;\n }\n\n /**\n * Get the Zustand store (for React hooks)\n */\n getStore(): ReturnType<typeof createAuthStore> {\n return this.store;\n }\n}\n","import axios, {\n AxiosError,\n AxiosInstance,\n AxiosRequestConfig,\n AxiosResponse,\n} from \"axios\";\nimport { AuthClient } from \"@/auth/client\";\n\n/**\n * Base service class with automatic token injection and refresh handling\n */\nexport class AuthenticatedBaseService {\n public client: AxiosInstance;\n private authClient: AuthClient;\n private instanceUrl: string;\n\n constructor(authClient: AuthClient, instanceUrl: string) {\n this.authClient = authClient;\n this.instanceUrl = instanceUrl;\n\n this.client = axios.create({\n baseURL: this.instanceUrl,\n });\n\n this.setupInterceptors();\n }\n\n /**\n * Setup request and response interceptors\n */\n private setupInterceptors(): void {\n // Request interceptor: Inject access token\n this.client.interceptors.request.use(\n (config) => {\n const token = this.authClient.getAccessToken();\n if (token) {\n config.headers.Authorization = `Bearer ${token}`;\n }\n return config;\n },\n (error) => {\n return Promise.reject(error);\n }\n );\n\n // Response interceptor: Handle token refresh on 401\n this.client.interceptors.response.use(\n (response) => response,\n async (error: AxiosError) => {\n const originalRequest = error.config as AxiosRequestConfig & {\n _retry?: boolean;\n };\n\n // If the error is 401 (Unauthorized) and we haven't already tried to refresh\n if (\n error.response?.status === 401 &&\n originalRequest &&\n !originalRequest._retry\n ) {\n originalRequest._retry = true;\n\n try {\n // Try to refresh the token\n const { data, error: refreshError } =\n await this.authClient.refreshSession();\n\n if (data.session && !refreshError) {\n // Retry the original request with the new token\n const token = this.authClient.getAccessToken();\n if (token) {\n if (!originalRequest.headers) {\n originalRequest.headers = {};\n }\n originalRequest.headers.Authorization = `Bearer ${token}`;\n }\n return this.client(originalRequest);\n } else {\n // Refresh failed, sign out\n await this.authClient.signOut();\n }\n } catch (refreshError) {\n // Refresh failed, sign out\n await this.authClient.signOut();\n return Promise.reject(refreshError);\n }\n }\n\n return Promise.reject(error);\n }\n );\n }\n\n /**\n * GET request\n */\n protected async get<T>(url: string, config?: AxiosRequestConfig): Promise<T> {\n const response: AxiosResponse<T> = await this.client.get(url, config);\n return response.data;\n }\n\n /**\n * POST request\n */\n protected async post<TRequest, TResponse>(\n url: string,\n data?: TRequest,\n config?: AxiosRequestConfig\n ): Promise<TResponse> {\n const response: AxiosResponse<TResponse> = await this.client.post(\n url,\n data,\n config\n );\n return response.data;\n }\n\n /**\n * POST request with form data\n */\n protected async postFormData<FormData, TResponse>(\n url: string,\n data: FormData\n ): Promise<TResponse> {\n const response: AxiosResponse<TResponse> = await this.client.post(\n url,\n data,\n {\n headers: {\n \"Content-Type\": \"multipart/form-data\",\n },\n }\n );\n return response.data;\n }\n\n /**\n * PUT request\n */\n protected async put<TRequest, TResponse>(\n url: string,\n data?: TRequest,\n config?: AxiosRequestConfig\n ): Promise<TResponse> {\n const response: AxiosResponse<TResponse> = await this.client.put(\n url,\n data,\n config\n );\n return response.data;\n }\n\n /**\n * PATCH request\n */\n protected async patch<TRequest, TResponse>(\n url: string,\n data?: TRequest,\n config?: AxiosRequestConfig\n ): Promise<TResponse> {\n const response: AxiosResponse<TResponse> = await this.client.patch(\n url,\n data,\n config\n );\n return response.data;\n }\n\n /**\n * DELETE request\n */\n protected async delete<T = void>(\n url: string,\n config?: AxiosRequestConfig\n ): Promise<T> {\n const response: AxiosResponse<T> = await this.client.delete(url, config);\n return response.data;\n }\n\n /**\n * Get the underlying Axios instance (for advanced usage)\n */\n getClient(): AxiosInstance {\n return this.client;\n }\n}\n","/**\n * Anythink SDK\n *\n * A reusable Typescript SDK for the Anythink platform.\n */\n\n// Version\nexport const version = \"0.1.0\";\n\n// Auth exports\nexport { AuthClient } from \"@/auth/client\";\nexport { createAuthStore } from \"@/auth/store\";\n\n// Service exports\nexport { AuthenticatedBaseService } from \"@/services/AuthenticatedBaseService\";\n\n// Type exports\nexport type {\n AuthConfig,\n Session,\n SignInResponse,\n RefreshResponse,\n TokenPair,\n} from \"@/types/auth\";\n"]}
package/package.json ADDED
@@ -0,0 +1,55 @@
1
+ {
2
+ "name": "@anythink-cloud/sdk",
3
+ "version": "0.1.0",
4
+ "description": "Reusable Typescript SDK for Anythink platform",
5
+ "homepage": "https://anythink.cloud",
6
+ "bugs": "https://github.com/Anythink-Ltd/anythink-sdk/issues",
7
+ "main": "./dist/index.js",
8
+ "module": "./dist/index.mjs",
9
+ "types": "./dist/index.d.ts",
10
+ "exports": {
11
+ ".": {
12
+ "import": "./dist/index.mjs",
13
+ "require": "./dist/index.js",
14
+ "types": "./dist/index.d.ts"
15
+ }
16
+ },
17
+ "files": [
18
+ "dist",
19
+ "README.md",
20
+ "LICENSE"
21
+ ],
22
+ "scripts": {
23
+ "build": "tsup",
24
+ "dev": "tsup --watch",
25
+ "lint": "eslint src --ext .ts,.tsx",
26
+ "typecheck": "tsc --noEmit",
27
+ "prepublishOnly": "npm run build"
28
+ },
29
+ "keywords": [
30
+ "anythink",
31
+ "sdk"
32
+ ],
33
+ "author": "Anythink",
34
+ "license": "MIT",
35
+ "repository": {
36
+ "type": "git",
37
+ "url": "git+https://github.com/Anythink-Ltd/anythink-sdk.git"
38
+ },
39
+ "publishConfig": {
40
+ "access": "public"
41
+ },
42
+ "devDependencies": {
43
+ "@types/node": "^20.0.0",
44
+ "@typescript-eslint/eslint-plugin": "^7.0.0",
45
+ "@typescript-eslint/parser": "^7.0.0",
46
+ "eslint": "^9.0.0",
47
+ "tsup": "^8.0.0",
48
+ "typescript": "^5.0.0"
49
+ },
50
+ "peerDependencies": {},
51
+ "dependencies": {
52
+ "axios": "^1.13.2",
53
+ "zustand": "^5.0.8"
54
+ }
55
+ }