@thetechfossil/auth2 1.2.6 → 1.2.8

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 CHANGED
@@ -1,5 +1,6 @@
1
- "use client";
2
1
  import axios from 'axios';
2
+ import { UpfilesClient, ImageManager } from '@thetechfossil/upfiles';
3
+ export { ConnectProjectDialog, ImageManager, ProjectFilesWidget, UpfilesClient, Uploader } from '@thetechfossil/upfiles';
3
4
  import React3, { createContext, forwardRef, useContext, useState, useCallback, useEffect, useRef, useMemo } from 'react';
4
5
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
5
6
  import PhoneInputWithCountry from 'react-phone-number-input';
@@ -116,11 +117,10 @@ var HttpClient = class {
116
117
  }
117
118
  }
118
119
  };
119
-
120
- // src/core/auth-service.ts
121
120
  var AuthService = class {
122
121
  constructor(config) {
123
122
  this.token = null;
123
+ this.upfilesClient = null;
124
124
  this.config = {
125
125
  localStorageKey: "auth_token",
126
126
  csrfEnabled: true,
@@ -128,6 +128,15 @@ var AuthService = class {
128
128
  };
129
129
  this.httpClient = new HttpClient(this.config.baseUrl);
130
130
  this.loadTokenFromStorage();
131
+ if (this.config.upfilesConfig) {
132
+ this.upfilesClient = new UpfilesClient({
133
+ baseUrl: this.config.upfilesConfig.baseUrl,
134
+ apiKey: this.config.upfilesConfig.apiKey,
135
+ apiKeyHeader: this.config.upfilesConfig.apiKeyHeader,
136
+ presignUrl: this.config.upfilesConfig.presignUrl,
137
+ presignPath: this.config.upfilesConfig.presignPath
138
+ });
139
+ }
131
140
  if (typeof window !== "undefined") {
132
141
  const frontendBaseUrl = process.env.NEXT_PUBLIC_FRONTEND_BASE_URL || process.env.REACT_APP_FRONTEND_BASE_URL || process.env.NEXT_PUBLIC_APP_URL || window.location.origin;
133
142
  if (frontendBaseUrl) {
@@ -355,6 +364,28 @@ var AuthService = class {
355
364
  }
356
365
  return response;
357
366
  }
367
+ async uploadAndUpdateAvatar(file) {
368
+ if (!this.token) {
369
+ throw new Error("Not authenticated");
370
+ }
371
+ if (!this.upfilesClient) {
372
+ throw new Error("Upfiles configuration is required. Please provide upfilesConfig in AuthConfig.");
373
+ }
374
+ try {
375
+ const folderPath = this.config.upfilesConfig?.folderPath || "avatars/";
376
+ const uploadResult = await this.upfilesClient.upload(file, {
377
+ folderPath,
378
+ fetchThumbnails: true
379
+ });
380
+ const response = await this.updateAvatar(uploadResult.publicUrl);
381
+ return response;
382
+ } catch (error) {
383
+ throw new Error(`Failed to upload avatar: ${error.message || "Unknown error"}`);
384
+ }
385
+ }
386
+ getUpfilesClient() {
387
+ return this.upfilesClient;
388
+ }
358
389
  async requestEmailChange(newEmail) {
359
390
  if (!this.token) {
360
391
  throw new Error("Not authenticated");
@@ -526,7 +557,8 @@ var AuthProvider = ({ children, config }) => {
526
557
  const authConfig = {
527
558
  baseUrl: config?.baseUrl || (typeof window !== "undefined" ? process.env.NEXT_PUBLIC_AUTH_API_URL || process.env.REACT_APP_AUTH_API_URL || "http://localhost:7000" : "http://localhost:7000"),
528
559
  localStorageKey: config?.localStorageKey || "auth_token",
529
- csrfEnabled: config?.csrfEnabled !== void 0 ? config.csrfEnabled : true
560
+ csrfEnabled: config?.csrfEnabled !== void 0 ? config.csrfEnabled : true,
561
+ upfilesConfig: config?.upfilesConfig
530
562
  };
531
563
  const [authService] = useState(() => new AuthService(authConfig));
532
564
  const [user, setUser] = useState(null);
@@ -676,6 +708,18 @@ var AuthProvider = ({ children, config }) => {
676
708
  setLoading(false);
677
709
  }
678
710
  }, [authService]);
711
+ const uploadAndUpdateAvatar = useCallback(async (file) => {
712
+ setLoading(true);
713
+ try {
714
+ const response = await authService.uploadAndUpdateAvatar(file);
715
+ if (response.success && response.user) {
716
+ setUser(response.user);
717
+ }
718
+ return response;
719
+ } finally {
720
+ setLoading(false);
721
+ }
722
+ }, [authService]);
679
723
  const requestEmailChange = useCallback(async (newEmail) => {
680
724
  setLoading(true);
681
725
  try {
@@ -773,6 +817,7 @@ var AuthProvider = ({ children, config }) => {
773
817
  resetPassword,
774
818
  changePassword,
775
819
  updateAvatar,
820
+ uploadAndUpdateAvatar,
776
821
  requestEmailChange,
777
822
  verifyEmailChange,
778
823
  generate2FA,
@@ -908,6 +953,18 @@ var useAuth2 = (config) => {
908
953
  setLoading(false);
909
954
  }
910
955
  }, [authService]);
956
+ const uploadAndUpdateAvatar = useCallback(async (file) => {
957
+ setLoading(true);
958
+ try {
959
+ const response = await authService.uploadAndUpdateAvatar(file);
960
+ if (response.success && response.user) {
961
+ setUser(response.user);
962
+ }
963
+ return response;
964
+ } finally {
965
+ setLoading(false);
966
+ }
967
+ }, [authService]);
911
968
  return {
912
969
  user,
913
970
  isAuthenticated,
@@ -920,7 +977,8 @@ var useAuth2 = (config) => {
920
977
  updateProfile,
921
978
  getProfile,
922
979
  getAllUsers,
923
- getUserById
980
+ getUserById,
981
+ uploadAndUpdateAvatar
924
982
  };
925
983
  };
926
984
 
@@ -4375,15 +4433,85 @@ var ChangePassword = ({ onSuccess, appearance }) => {
4375
4433
  )
4376
4434
  ] }) });
4377
4435
  };
4436
+ var AvatarUploader = ({
4437
+ onUploadComplete,
4438
+ onError,
4439
+ className,
4440
+ buttonClassName,
4441
+ maxFileSize = 5 * 1024 * 1024,
4442
+ // 5MB default
4443
+ upfilesConfig,
4444
+ buttonText = "Upload Avatar"
4445
+ }) => {
4446
+ const { uploadAndUpdateAvatar } = useAuth();
4447
+ const [open, setOpen] = useState(false);
4448
+ const [uploading, setUploading] = useState(false);
4449
+ const handleSelect = async (image) => {
4450
+ setUploading(true);
4451
+ try {
4452
+ const response = await fetch(image.url);
4453
+ const blob = await response.blob();
4454
+ const file = new File([blob], image.originalName, { type: image.contentType });
4455
+ const result = await uploadAndUpdateAvatar(file);
4456
+ if (result.success && result.user?.avatar) {
4457
+ onUploadComplete?.(result.user.avatar);
4458
+ setOpen(false);
4459
+ } else {
4460
+ throw new Error(result.message || "Failed to update avatar");
4461
+ }
4462
+ } catch (error) {
4463
+ const err = error instanceof Error ? error : new Error("Upload failed");
4464
+ onError?.(err);
4465
+ } finally {
4466
+ setUploading(false);
4467
+ }
4468
+ };
4469
+ return /* @__PURE__ */ jsxs("div", { className, children: [
4470
+ /* @__PURE__ */ jsx(
4471
+ "button",
4472
+ {
4473
+ type: "button",
4474
+ onClick: () => setOpen(true),
4475
+ disabled: uploading,
4476
+ className: buttonClassName || "px-4 py-2 text-sm rounded border bg-blue-600 text-white hover:bg-blue-700 disabled:opacity-50",
4477
+ children: uploading ? "Uploading..." : buttonText
4478
+ }
4479
+ ),
4480
+ /* @__PURE__ */ jsx(
4481
+ ImageManager,
4482
+ {
4483
+ open,
4484
+ onOpenChange: setOpen,
4485
+ clientOptions: {
4486
+ baseUrl: upfilesConfig.baseUrl,
4487
+ apiKey: upfilesConfig.apiKey,
4488
+ apiKeyHeader: upfilesConfig.apiKeyHeader || "authorization",
4489
+ presignUrl: upfilesConfig.presignUrl,
4490
+ presignPath: upfilesConfig.presignPath
4491
+ },
4492
+ projectId: upfilesConfig.projectId,
4493
+ folderPath: upfilesConfig.folderPath || "avatars/",
4494
+ title: "Select Avatar",
4495
+ description: "Upload a new avatar or select from existing images.",
4496
+ mode: "full",
4497
+ maxFileSize,
4498
+ maxFiles: 1,
4499
+ autoRecordToDb: true,
4500
+ fetchThumbnails: true,
4501
+ onSelect: handleSelect
4502
+ }
4503
+ )
4504
+ ] });
4505
+ };
4378
4506
  var UserProfile = ({
4379
4507
  showAvatar = true,
4380
4508
  showEmailChange = true,
4381
- showPasswordChange = true
4509
+ showPasswordChange = true,
4510
+ upfilesConfig
4382
4511
  }) => {
4383
4512
  const { user, updateProfile, requestEmailChange } = useAuth();
4384
4513
  const colors = useThemeColors();
4385
4514
  const [name, setName] = useState(user?.name || "");
4386
- const [avatar, setAvatar] = useState(user?.avatar || "");
4387
4515
  const [phoneNumber, setPhoneNumber] = useState(user?.phoneNumber || "");
4388
4516
  const [newEmail, setNewEmail] = useState("");
4389
4517
  const [isLoading, setIsLoading] = useState(false);
@@ -4399,9 +4527,6 @@ var UserProfile = ({
4399
4527
  if (name !== user?.name) {
4400
4528
  updates.name = name;
4401
4529
  }
4402
- if (showAvatar && avatar !== user?.avatar) {
4403
- updates.avatar = avatar;
4404
- }
4405
4530
  if (phoneNumber !== user?.phoneNumber) {
4406
4531
  updates.phoneNumber = phoneNumber;
4407
4532
  }
@@ -4422,6 +4547,12 @@ var UserProfile = ({
4422
4547
  setIsLoading(false);
4423
4548
  }
4424
4549
  };
4550
+ const handleAvatarUploadComplete = (avatarUrl) => {
4551
+ setSuccess("Avatar updated successfully!");
4552
+ };
4553
+ const handleAvatarUploadError = (error2) => {
4554
+ setError(error2.message || "Failed to upload avatar");
4555
+ };
4425
4556
  const handleRequestEmailChange = async (e) => {
4426
4557
  e.preventDefault();
4427
4558
  setIsLoading(true);
@@ -4524,34 +4655,36 @@ var UserProfile = ({
4524
4655
  }
4525
4656
  )
4526
4657
  ] }),
4527
- showAvatar && /* @__PURE__ */ jsxs("div", { style: { marginBottom: "20px" }, children: [
4528
- /* @__PURE__ */ jsx("label", { htmlFor: "avatar", style: {
4658
+ showAvatar && upfilesConfig && /* @__PURE__ */ jsxs("div", { style: { marginBottom: "20px" }, children: [
4659
+ /* @__PURE__ */ jsx("label", { style: {
4529
4660
  display: "block",
4530
4661
  marginBottom: "8px",
4531
4662
  fontWeight: 500,
4532
4663
  color: colors.textSecondary,
4533
4664
  fontSize: "14px"
4534
- }, children: "Avatar URL" }),
4535
- /* @__PURE__ */ jsx(
4536
- "input",
4665
+ }, children: "Avatar" }),
4666
+ user?.avatar && /* @__PURE__ */ jsx("div", { style: { marginBottom: "12px" }, children: /* @__PURE__ */ jsx(
4667
+ "img",
4537
4668
  {
4538
- id: "avatar",
4539
- type: "url",
4540
- value: avatar,
4541
- onChange: (e) => setAvatar(e.target.value),
4542
- disabled: isLoading,
4669
+ src: user.avatar,
4670
+ alt: "Current avatar",
4543
4671
  style: {
4544
- width: "100%",
4545
- padding: "12px 16px",
4546
- border: `1px solid ${colors.borderSecondary}`,
4547
- borderRadius: "8px",
4548
- fontSize: "16px",
4549
- boxSizing: "border-box",
4550
- backgroundColor: colors.bgSecondary,
4551
- color: colors.textPrimary,
4552
- transition: "all 0.2s ease"
4553
- },
4554
- placeholder: "https://example.com/avatar.jpg"
4672
+ width: "80px",
4673
+ height: "80px",
4674
+ borderRadius: "50%",
4675
+ objectFit: "cover",
4676
+ border: `2px solid ${colors.borderSecondary}`
4677
+ }
4678
+ }
4679
+ ) }),
4680
+ /* @__PURE__ */ jsx(
4681
+ AvatarUploader,
4682
+ {
4683
+ upfilesConfig,
4684
+ onUploadComplete: handleAvatarUploadComplete,
4685
+ onError: handleAvatarUploadError,
4686
+ maxFileSize: 5 * 1024 * 1024,
4687
+ accept: ["image/*"]
4555
4688
  }
4556
4689
  )
4557
4690
  ] }),
@@ -4663,6 +4796,65 @@ var UserProfile = ({
4663
4796
  ] })
4664
4797
  ] });
4665
4798
  };
4799
+ var AvatarManager = ({
4800
+ open,
4801
+ onOpenChange,
4802
+ onAvatarUpdated,
4803
+ onError,
4804
+ title = "Select Avatar",
4805
+ description = "Choose an existing image or upload a new one",
4806
+ className,
4807
+ gridClassName,
4808
+ maxFileSize = 5 * 1024 * 1024,
4809
+ // 5MB default
4810
+ mode = "full",
4811
+ showDelete = false,
4812
+ upfilesConfig
4813
+ }) => {
4814
+ const { updateProfile } = useAuth();
4815
+ const [updating, setUpdating] = useState(false);
4816
+ const handleSelect = async (image) => {
4817
+ setUpdating(true);
4818
+ try {
4819
+ const response = await updateProfile({ avatar: image.url });
4820
+ if (response.success && response.user?.avatar) {
4821
+ onAvatarUpdated?.(response.user.avatar);
4822
+ onOpenChange(false);
4823
+ } else {
4824
+ throw new Error(response.message || "Failed to update avatar");
4825
+ }
4826
+ } catch (error) {
4827
+ const err = error instanceof Error ? error : new Error("Failed to update avatar");
4828
+ onError?.(err);
4829
+ } finally {
4830
+ setUpdating(false);
4831
+ }
4832
+ };
4833
+ return /* @__PURE__ */ jsx(
4834
+ ImageManager,
4835
+ {
4836
+ open,
4837
+ onOpenChange,
4838
+ clientOptions: {
4839
+ baseUrl: upfilesConfig.baseUrl,
4840
+ apiKey: upfilesConfig.apiKey,
4841
+ apiKeyHeader: upfilesConfig.apiKeyHeader || "authorization",
4842
+ presignUrl: upfilesConfig.presignUrl,
4843
+ presignPath: upfilesConfig.presignPath
4844
+ },
4845
+ folderPath: upfilesConfig.folderPath || "avatars/",
4846
+ title,
4847
+ description,
4848
+ className,
4849
+ gridClassName,
4850
+ onSelect: handleSelect,
4851
+ maxFileSize,
4852
+ mode,
4853
+ showDelete,
4854
+ fetchThumbnails: true
4855
+ }
4856
+ );
4857
+ };
4666
4858
 
4667
4859
  // src/react/index.ts
4668
4860
  var react_exports = {};
@@ -4670,6 +4862,8 @@ __export(react_exports, {
4670
4862
  AuthFlow: () => AuthFlow,
4671
4863
  AuthProvider: () => AuthProvider,
4672
4864
  AuthThemeProvider: () => AuthThemeProvider,
4865
+ AvatarManager: () => AvatarManager,
4866
+ AvatarUploader: () => AvatarUploader,
4673
4867
  ChangePassword: () => ChangePassword,
4674
4868
  EmailVerificationPage: () => EmailVerificationPage,
4675
4869
  ForgotPassword: () => ForgotPassword,
@@ -4775,6 +4969,6 @@ var AuthClient = class extends AuthService {
4775
4969
  }
4776
4970
  };
4777
4971
 
4778
- export { AuthFlow, AuthProvider, AuthService, ChangePassword, EmailVerificationPage, ForgotPassword, HttpClient, LoginForm, OtpForm, ProtectedRoute, PublicRoute, RegisterForm, ResetPassword, SignIn, SignOut, SignUp, UserButton, UserProfile, VerifyEmail, node_exports as node, react_exports as react, useAuth };
4972
+ export { AuthFlow, AuthProvider, AuthService, AvatarManager, AvatarUploader, ChangePassword, EmailVerificationPage, ForgotPassword, HttpClient, LoginForm, OtpForm, ProtectedRoute, PublicRoute, RegisterForm, ResetPassword, SignIn, SignOut, SignUp, UserButton, UserProfile, VerifyEmail, node_exports as node, react_exports as react, useAuth };
4779
4973
  //# sourceMappingURL=out.js.map
4780
4974
  //# sourceMappingURL=index.mjs.map