@contentgrowth/content-auth 0.5.0 → 0.5.2

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.
@@ -20,11 +20,16 @@ var AuthForm = ({
20
20
  defaultEmail = "",
21
21
  lockEmail = false,
22
22
  forgotPasswordUrl,
23
- turnstileSiteKey
23
+ turnstileSiteKey,
24
+ redirectUrl,
25
+ showName = true,
26
+ signinUrl,
27
+ signupUrl
24
28
  }) => {
25
29
  const [isLogin, setIsLogin] = useState(view !== "signup");
26
30
  const [email, setEmail] = useState(defaultEmail);
27
31
  const [password, setPassword] = useState("");
32
+ const [confirmPassword, setConfirmPassword] = useState("");
28
33
  const [name, setName] = useState("");
29
34
  const [loading, setLoading] = useState(false);
30
35
  const [error, setError] = useState(null);
@@ -55,6 +60,10 @@ var AuthForm = ({
55
60
  };
56
61
  const handleSubmit = async (e) => {
57
62
  e.preventDefault();
63
+ if (!isLogin && password !== confirmPassword) {
64
+ setError("Passwords do not match");
65
+ return;
66
+ }
58
67
  if (turnstileRequired && !turnstileToken) {
59
68
  setError("Please complete the security challenge");
60
69
  return;
@@ -72,9 +81,11 @@ var AuthForm = ({
72
81
  } else {
73
82
  const signupData = {
74
83
  email,
75
- password,
76
- name
84
+ password
77
85
  };
86
+ if (showName) {
87
+ signupData.name = name;
88
+ }
78
89
  if (turnstileToken) {
79
90
  signupData.turnstileToken = turnstileToken;
80
91
  }
@@ -82,6 +93,9 @@ var AuthForm = ({
82
93
  if (response.error) throw response.error;
83
94
  }
84
95
  onSuccess?.(response.data);
96
+ if (redirectUrl) {
97
+ window.location.href = redirectUrl;
98
+ }
85
99
  } catch (err) {
86
100
  const errorMessage = err.message || "";
87
101
  const errorCode = err.code || "";
@@ -117,7 +131,7 @@ var AuthForm = ({
117
131
  try {
118
132
  await client.signIn.social({
119
133
  provider,
120
- callbackURL: window.location.href
134
+ callbackURL: redirectUrl || window.location.href
121
135
  });
122
136
  } catch (err) {
123
137
  setError(err.message || `Failed to sign in with ${provider}`);
@@ -181,7 +195,7 @@ var AuthForm = ({
181
195
  ] }) });
182
196
  }
183
197
  return /* @__PURE__ */ jsxs("form", { onSubmit: handleSubmit, className: "ca-form", children: [
184
- !isLogin && /* @__PURE__ */ jsxs("div", { className: "ca-input-group", children: [
198
+ !isLogin && showName && /* @__PURE__ */ jsxs("div", { className: "ca-input-group", children: [
185
199
  /* @__PURE__ */ jsx("label", { className: "ca-label", htmlFor: "name", children: "Name" }),
186
200
  /* @__PURE__ */ jsx(
187
201
  "input",
@@ -227,6 +241,20 @@ var AuthForm = ({
227
241
  }
228
242
  )
229
243
  ] }),
244
+ !isLogin && /* @__PURE__ */ jsxs("div", { className: "ca-input-group", children: [
245
+ /* @__PURE__ */ jsx("label", { className: "ca-label", htmlFor: "confirm-password", children: "Confirm Password" }),
246
+ /* @__PURE__ */ jsx(
247
+ "input",
248
+ {
249
+ id: "confirm-password",
250
+ type: "password",
251
+ className: "ca-input",
252
+ value: confirmPassword,
253
+ onChange: (e) => setConfirmPassword(e.target.value),
254
+ required: true
255
+ }
256
+ )
257
+ ] }),
230
258
  renderTurnstile(),
231
259
  error && /* @__PURE__ */ jsx("div", { className: "ca-error", children: error }),
232
260
  /* @__PURE__ */ jsx(
@@ -247,11 +275,20 @@ var AuthForm = ({
247
275
  {
248
276
  className: "ca-link",
249
277
  onClick: () => {
278
+ if (isLogin && signupUrl) {
279
+ window.location.href = signupUrl;
280
+ return;
281
+ }
282
+ if (!isLogin && signinUrl) {
283
+ window.location.href = signinUrl;
284
+ return;
285
+ }
250
286
  if (onSwitchMode) {
251
287
  onSwitchMode();
252
288
  } else {
253
289
  setIsLogin(!isLogin);
254
290
  }
291
+ setConfirmPassword("");
255
292
  if (turnstileRef.current) {
256
293
  turnstileRef.current.reset();
257
294
  setTurnstileToken(null);
@@ -262,7 +299,7 @@ var AuthForm = ({
262
299
  }
263
300
  )
264
301
  ] });
265
- const titleContent = title ? typeof title === "string" ? /* @__PURE__ */ jsx("h2", { className: "ca-title", children: title }) : title : /* @__PURE__ */ jsx("h2", { className: "ca-title", children: isLogin ? "Welcome Back" : "Create Account" });
302
+ const titleContent = title ? typeof title === "string" ? /* @__PURE__ */ jsx("h2", { className: "ca-title", children: title }) : title : null;
266
303
  if (layout === "split") {
267
304
  return /* @__PURE__ */ jsxs("div", { className: containerClass, children: [
268
305
  titleContent,
@@ -271,7 +308,7 @@ var AuthForm = ({
271
308
  renderForm(),
272
309
  renderFooter()
273
310
  ] }),
274
- socialProviders.length > 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
311
+ !lockEmail && socialProviders.length > 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
275
312
  /* @__PURE__ */ jsx("div", { className: "ca-split-divider", children: /* @__PURE__ */ jsx("span", { className: "ca-split-divider-text", children: "Or" }) }),
276
313
  /* @__PURE__ */ jsxs("div", { className: "ca-split-social", children: [
277
314
  /* @__PURE__ */ jsx("h3", { className: "ca-social-header", children: isLogin ? "Sign In With" : "Sign Up With" }),
@@ -14,6 +14,9 @@ export interface Props {
14
14
  forgotPasswordUrl?: string;
15
15
  turnstileSiteKey?: string;
16
16
  redirectUrl?: string;
17
+ showName?: boolean;
18
+ signinUrl?: string;
19
+ signupUrl?: string;
17
20
  }
18
21
 
19
22
  const {
@@ -29,7 +32,10 @@ const {
29
32
  lockEmail = false,
30
33
  forgotPasswordUrl,
31
34
  turnstileSiteKey,
32
- redirectUrl
35
+ redirectUrl,
36
+ showName = true,
37
+ signinUrl,
38
+ signupUrl
33
39
  } = Astro.props;
34
40
 
35
41
  const isLogin = view !== 'signup';
@@ -42,14 +48,14 @@ const googleSvg = `<svg class="ca-icon" viewBox="0 0 24 24" width="20" height="2
42
48
  const githubSvg = `<svg class="ca-icon" viewBox="0 0 24 24" width="20" height="20" xmlns="http://www.w3.org/2000/svg"><path d="M12 2C6.477 2 2 6.477 2 12c0 4.42 2.865 8.17 6.839 9.49.5.092.682-.217.682-.482 0-.237-.008-.866-.013-1.7-2.782.604-3.369-1.34-3.369-1.34-.454-1.156-1.11-1.464-1.11-1.464-.908-.62.069-.608.069-.608 1.003.07 1.531 1.03 1.531 1.03.892 1.529 2.341 1.087 2.91.832.092-.647.35-1.088.636-1.338-2.22-.253-4.555-1.11-4.555-4.943 0-1.091.39-1.984 1.029-2.683-.103-.253-.446-1.27.098-2.647 0 0 .84-.269 2.75 1.026A9.564 9.564 0 0 1 12 6.844c.85.004 1.705.115 2.504.337 1.909-1.296 2.747-1.027 2.747-1.027.546 1.379.202 2.398.1 2.651.64.699 1.028 1.592 1.028 2.683 0 3.842-2.339 4.687-4.566 4.935.359.309.678.92.678 1.855 0 1.338-.012 2.419-.012 2.747 0 .268.18.58.688.482A10.019 10.019 0 0 0 22 12c0-5.523-4.477-10-10-10z" fill="currentColor" /></svg>`;
43
49
  ---
44
50
 
45
- <div class={containerClass} data-auth-form data-base-url={baseUrl} data-view={view} data-redirect-url={redirectUrl} data-lock-email={lockEmail} data-turnstile-site-key={turnstileSiteKey}>
46
- <h2 class="ca-title" data-title>{title || defaultTitle}</h2>
51
+ <div class={containerClass} data-auth-form data-base-url={baseUrl} data-view={view} data-redirect-url={redirectUrl} data-lock-email={lockEmail} data-turnstile-site-key={turnstileSiteKey} data-show-name={showName} data-signin-url={signinUrl} data-signup-url={signupUrl}>
52
+ {title && <h2 class="ca-title" data-title>{title}</h2>}
47
53
 
48
54
  {layout === 'split' ? (
49
55
  <div class="ca-split-body">
50
56
  <div class="ca-split-main">
51
57
  <form class="ca-form" data-auth-form-element>
52
- {!isLogin && (
58
+ {!isLogin && showName && (
53
59
  <div class="ca-input-group" data-name-group>
54
60
  <label class="ca-label" for="name">Name</label>
55
61
  <input id="name" type="text" class="ca-input" name="name" required />
@@ -79,6 +85,13 @@ const githubSvg = `<svg class="ca-icon" viewBox="0 0 24 24" width="20" height="2
79
85
  <input id="password" type="password" class="ca-input" name="password" required />
80
86
  </div>
81
87
 
88
+ {!isLogin && (
89
+ <div class="ca-input-group" data-confirm-password-group>
90
+ <label class="ca-label" for="confirm-password">Confirm Password</label>
91
+ <input id="confirm-password" type="password" class="ca-input" name="confirm-password" required />
92
+ </div>
93
+ )}
94
+
82
95
  {turnstileSiteKey && !isLogin && (
83
96
  <div class="ca-turnstile" data-turnstile-container>
84
97
  <p class="ca-turnstile-hint">Please complete the security check above</p>
@@ -147,7 +160,7 @@ const githubSvg = `<svg class="ca-icon" viewBox="0 0 24 24" width="20" height="2
147
160
  )}
148
161
 
149
162
  <form class="ca-form" data-auth-form-element>
150
- {!isLogin && (
163
+ {!isLogin && showName && (
151
164
  <div class="ca-input-group" data-name-group>
152
165
  <label class="ca-label" for="name">Name</label>
153
166
  <input id="name" type="text" class="ca-input" name="name" required />
@@ -177,6 +190,13 @@ const githubSvg = `<svg class="ca-icon" viewBox="0 0 24 24" width="20" height="2
177
190
  <input id="password" type="password" class="ca-input" name="password" required />
178
191
  </div>
179
192
 
193
+ {!isLogin && (
194
+ <div class="ca-input-group" data-confirm-password-group>
195
+ <label class="ca-label" for="confirm-password">Confirm Password</label>
196
+ <input id="confirm-password" type="password" class="ca-input" name="confirm-password" required />
197
+ </div>
198
+ )}
199
+
180
200
  {turnstileSiteKey && !isLogin && (
181
201
  <div class="ca-turnstile" data-turnstile-container>
182
202
  <p class="ca-turnstile-hint">Please complete the security check above</p>
@@ -230,6 +250,9 @@ document.querySelectorAll('[data-auth-form]').forEach((container) => {
230
250
  const redirectUrl = container.getAttribute('data-redirect-url');
231
251
  const lockEmail = container.getAttribute('data-lock-email') === 'true';
232
252
  const turnstileSiteKey = container.getAttribute('data-turnstile-site-key');
253
+ const showName = container.getAttribute('data-show-name') !== 'false';
254
+ const signinUrl = container.getAttribute('data-signin-url');
255
+ const signupUrl = container.getAttribute('data-signup-url');
233
256
 
234
257
  const form = container.querySelector('[data-auth-form-element]') as HTMLFormElement;
235
258
  const submitBtn = container.querySelector('[data-submit-button]') as HTMLButtonElement;
@@ -238,6 +261,7 @@ document.querySelectorAll('[data-auth-form]').forEach((container) => {
238
261
  const modeText = container.querySelector('[data-mode-text]') as HTMLSpanElement;
239
262
  const titleEl = container.querySelector('[data-title]') as HTMLHeadingElement;
240
263
  const nameGroup = container.querySelector('[data-name-group]') as HTMLDivElement | null;
264
+ const confirmPasswordGroup = container.querySelector('[data-confirm-password-group]') as HTMLDivElement | null;
241
265
  const socialHeader = container.querySelector('[data-social-header]') as HTMLHeadingElement | null;
242
266
  const socialButtons = container.querySelectorAll('[data-social-provider]');
243
267
  const turnstileContainer = container.querySelector('[data-turnstile-container]') as HTMLDivElement | null;
@@ -287,7 +311,8 @@ document.querySelectorAll('[data-auth-form]').forEach((container) => {
287
311
  if (modeText) modeText.textContent = isLogin ? "Don't have an account? " : "Already have an account? ";
288
312
  if (switchBtn) switchBtn.textContent = isLogin ? 'Sign up' : 'Sign in';
289
313
  if (submitBtn) submitBtn.textContent = isLogin ? 'Sign In' : 'Sign Up';
290
- if (nameGroup) nameGroup.style.display = isLogin ? 'none' : 'flex';
314
+ if (nameGroup) nameGroup.style.display = (isLogin || !showName) ? 'none' : 'flex';
315
+ if (confirmPasswordGroup) confirmPasswordGroup.style.display = isLogin ? 'none' : 'flex';
291
316
  if (socialHeader) socialHeader.textContent = isLogin ? 'Sign In With' : 'Sign Up With';
292
317
  if (turnstileContainer) {
293
318
  turnstileContainer.style.display = isLogin ? 'none' : 'flex';
@@ -300,6 +325,15 @@ document.querySelectorAll('[data-auth-form]').forEach((container) => {
300
325
 
301
326
  // Handle mode switch
302
327
  switchBtn?.addEventListener('click', () => {
328
+ if (isLogin && signupUrl) {
329
+ window.location.href = signupUrl;
330
+ return;
331
+ }
332
+ if (!isLogin && signinUrl) {
333
+ window.location.href = signinUrl;
334
+ return;
335
+ }
336
+
303
337
  isLogin = !isLogin;
304
338
  updateMode();
305
339
  hideError();
@@ -332,8 +366,16 @@ document.querySelectorAll('[data-auth-form]').forEach((container) => {
332
366
  const formData = new FormData(form);
333
367
  const email = formData.get('email') as string;
334
368
  const password = formData.get('password') as string;
369
+ const confirmPassword = formData.get('confirm-password') as string;
335
370
  const name = formData.get('name') as string;
336
371
 
372
+ if (!isLogin) {
373
+ if (password !== confirmPassword) {
374
+ showError('Passwords do not match');
375
+ return;
376
+ }
377
+ }
378
+
337
379
  if (!isLogin && turnstileSiteKey && !turnstileToken) {
338
380
  showError('Please complete the security challenge');
339
381
  return;
@@ -347,7 +389,8 @@ document.querySelectorAll('[data-auth-form]').forEach((container) => {
347
389
  response = await client.signIn.email({ email, password });
348
390
  if (response.error) throw response.error;
349
391
  } else {
350
- const signupData: any = { email, password, name };
392
+ const signupData: any = { email, password };
393
+ if (showName) signupData.name = name;
351
394
  if (turnstileToken) signupData.turnstileToken = turnstileToken;
352
395
  response = await client.signUp.email(signupData);
353
396
  if (response.error) throw response.error;
@@ -16,6 +16,9 @@ interface Props {
16
16
  forgotPasswordUrl?: string;
17
17
  turnstileSiteKey?: string;
18
18
  redirectUrl?: string;
19
+ showName?: boolean;
20
+ signinUrl?: string;
21
+ signupUrl?: string;
19
22
  }
20
23
 
21
24
  const props = withDefaults(defineProps<Props>(), {
@@ -27,6 +30,7 @@ const props = withDefaults(defineProps<Props>(), {
27
30
  socialPosition: 'top',
28
31
  defaultEmail: '',
29
32
  lockEmail: false,
33
+ showName: true,
30
34
  });
31
35
 
32
36
  const emit = defineEmits<{
@@ -40,6 +44,7 @@ const client = computed(() => createClient(props.baseUrl));
40
44
  const isLogin = ref(props.view !== 'signup');
41
45
  const email = ref(props.defaultEmail);
42
46
  const password = ref('');
47
+ const confirmPassword = ref('');
43
48
  const name = ref('');
44
49
  const loading = ref(false);
45
50
  const error = ref<string | null>(null);
@@ -61,7 +66,7 @@ const socialClass = computed(() =>
61
66
  );
62
67
 
63
68
  const displayTitle = computed(() =>
64
- props.title || (isLogin.value ? 'Welcome Back' : 'Create Account')
69
+ props.title
65
70
  );
66
71
 
67
72
  const turnstileEnabled = computed(() => !!props.turnstileSiteKey);
@@ -77,6 +82,11 @@ onMounted(() => {
77
82
  });
78
83
 
79
84
  const handleSubmit = async () => {
85
+ if (!isLogin.value && password.value !== confirmPassword.value) {
86
+ error.value = 'Passwords do not match';
87
+ return;
88
+ }
89
+
80
90
  if (turnstileRequired.value && !turnstileToken.value) {
81
91
  error.value = 'Please complete the security challenge';
82
92
  return;
@@ -97,8 +107,10 @@ const handleSubmit = async () => {
97
107
  const signupData: any = {
98
108
  email: email.value,
99
109
  password: password.value,
100
- name: name.value,
101
110
  };
111
+ if (props.showName) {
112
+ signupData.name = name.value;
113
+ }
102
114
  if (turnstileToken.value) {
103
115
  signupData.turnstileToken = turnstileToken.value;
104
116
  }
@@ -154,8 +166,19 @@ const handleSocialLogin = async (provider: string) => {
154
166
  };
155
167
 
156
168
  const switchMode = () => {
169
+ // Navigate to separate auth pages if URLs provided
170
+ if (isLogin.value && props.signupUrl) {
171
+ window.location.href = props.signupUrl;
172
+ return;
173
+ }
174
+ if (!isLogin.value && props.signinUrl) {
175
+ window.location.href = props.signinUrl;
176
+ return;
177
+ }
178
+
157
179
  isLogin.value = !isLogin.value;
158
180
  error.value = null;
181
+ confirmPassword.value = '';
159
182
  turnstileToken.value = null;
160
183
  emit('switchMode');
161
184
  };
@@ -172,7 +195,7 @@ const handleTurnstileError = () => {
172
195
 
173
196
  <template>
174
197
  <div :class="containerClass">
175
- <h2 class="ca-title">{{ displayTitle }}</h2>
198
+ <h2 v-if="displayTitle" class="ca-title">{{ displayTitle }}</h2>
176
199
 
177
200
  <!-- Default Layout -->
178
201
  <template v-if="layout !== 'split'">
@@ -199,7 +222,7 @@ const handleTurnstileError = () => {
199
222
 
200
223
  <!-- Form -->
201
224
  <form class="ca-form" @submit.prevent="handleSubmit">
202
- <div v-if="!isLogin" class="ca-input-group">
225
+ <div v-if="!isLogin && showName" class="ca-input-group">
203
226
  <label class="ca-label" for="name">Name</label>
204
227
  <input
205
228
  id="name"
@@ -238,6 +261,17 @@ const handleTurnstileError = () => {
238
261
  />
239
262
  </div>
240
263
 
264
+ <div v-if="!isLogin" class="ca-input-group">
265
+ <label class="ca-label" for="confirm-password">Confirm Password</label>
266
+ <input
267
+ id="confirm-password"
268
+ v-model="confirmPassword"
269
+ type="password"
270
+ class="ca-input"
271
+ required
272
+ />
273
+ </div>
274
+
241
275
  <!-- Turnstile placeholder - implement with vue-turnstile if needed -->
242
276
  <div v-if="turnstileSiteKey && !isLogin" class="ca-turnstile">
243
277
  <p class="ca-turnstile-hint">Please complete the security check above</p>
@@ -289,7 +323,7 @@ const handleTurnstileError = () => {
289
323
  <div class="ca-split-body">
290
324
  <div class="ca-split-main">
291
325
  <form class="ca-form" @submit.prevent="handleSubmit">
292
- <div v-if="!isLogin" class="ca-input-group">
326
+ <div v-if="!isLogin && showName" class="ca-input-group">
293
327
  <label class="ca-label" for="name">Name</label>
294
328
  <input id="name" v-model="name" type="text" class="ca-input" required />
295
329
  </div>
@@ -304,6 +338,13 @@ const handleTurnstileError = () => {
304
338
  </div>
305
339
  <input id="password" v-model="password" type="password" class="ca-input" required />
306
340
  </div>
341
+ <div v-if="!isLogin" class="ca-input-group">
342
+ <label class="ca-label" for="confirm-password">Confirm Password</label>
343
+ <input id="confirm-password" v-model="confirmPassword" type="password" class="ca-input" required />
344
+ </div>
345
+ <div v-if="turnstileSiteKey && !isLogin" class="ca-turnstile">
346
+ <p class="ca-turnstile-hint">Please complete the security check above</p>
347
+ </div>
307
348
  <div v-if="error" class="ca-error">{{ error }}</div>
308
349
  <button type="submit" class="ca-button" :disabled="loading || !canSubmit">
309
350
  {{ loading ? 'Loading...' : (isLogin ? 'Sign In' : 'Sign Up') }}
@@ -26,6 +26,14 @@ interface AuthFormProps {
26
26
  forgotPasswordUrl?: string;
27
27
  /** Cloudflare Turnstile site key. When set, shows Turnstile widget on signup. */
28
28
  turnstileSiteKey?: string;
29
+ /** URL to redirect to after successful authentication */
30
+ redirectUrl?: string;
31
+ /** Whether to show the name field on signup (default: true) */
32
+ showName?: boolean;
33
+ /** URL to navigate to for signin (if set, navigates instead of switching mode inline) */
34
+ signinUrl?: string;
35
+ /** URL to navigate to for signup (if set, navigates instead of switching mode inline) */
36
+ signupUrl?: string;
29
37
  }
30
38
  declare const AuthForm: React.FC<AuthFormProps>;
31
39
 
@@ -7,7 +7,7 @@ import {
7
7
  PasswordChanger,
8
8
  ProfileEditor,
9
9
  ResetPasswordForm
10
- } from "../chunk-3HNFZJ7S.js";
10
+ } from "../chunk-7QOUBGQS.js";
11
11
  import {
12
12
  authClient,
13
13
  createClient
package/dist/index.js CHANGED
@@ -19,7 +19,7 @@ import {
19
19
  PasswordChanger,
20
20
  ProfileEditor,
21
21
  ResetPasswordForm
22
- } from "./chunk-3HNFZJ7S.js";
22
+ } from "./chunk-7QOUBGQS.js";
23
23
  import {
24
24
  authClient,
25
25
  createClient
package/dist/styles.css CHANGED
@@ -348,6 +348,10 @@ button[type="submit"]:disabled {
348
348
  }
349
349
  }
350
350
 
351
+ .ca-social-grid:has(> :only-child) {
352
+ grid-template-columns: 1fr;
353
+ }
354
+
351
355
  /* Turnstile Widget */
352
356
  .ca-turnstile {
353
357
  display: flex;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@contentgrowth/content-auth",
3
- "version": "0.5.0",
3
+ "version": "0.5.2",
4
4
  "description": "Better Auth wrapper with UI components for Cloudflare Workers & Pages. Includes custom schema mapping, Turnstile bot protection, and email normalization.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -53,7 +53,7 @@
53
53
  "LICENSE"
54
54
  ],
55
55
  "scripts": {
56
- "build": "tsup && cp src/styles.css dist/styles.css && mkdir -p dist/frontend/components && cp -r src/frontend/components/vue dist/frontend/components/vue && cp -r src/frontend/components/astro dist/frontend/components/astro",
56
+ "build": "tsup && cp src/styles.css dist/styles.css && mkdir -p dist/frontend/components && cp -r src/frontend/components/vue dist/frontend/components/ && cp -r src/frontend/components/astro dist/frontend/components/",
57
57
  "dev": "tsup --watch",
58
58
  "prepublishOnly": "npm run build"
59
59
  },
@@ -108,4 +108,4 @@
108
108
  "typescript": "^5.9.3",
109
109
  "vue": "^3.5.27"
110
110
  }
111
- }
111
+ }