@svadmin/core 0.37.0 → 0.38.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@svadmin/core",
3
- "version": "0.37.0",
3
+ "version": "0.38.0",
4
4
  "author": "zuohuadong",
5
5
  "repository": {
6
6
  "type": "git",
@@ -14,7 +14,7 @@
14
14
  "@testing-library/dom": "^10.4.1",
15
15
  "@testing-library/svelte": "^5.4.2",
16
16
  "@testing-library/user-event": "^14.6.4",
17
- "@types/bun": "^1.3.14",
17
+ "@types/bun": "^1.4.0",
18
18
  "@types/jsdom": "^30.0.0",
19
19
  "happy-dom": "^20.11.2",
20
20
  "jsdom": "^30.0.1",
@@ -10,6 +10,7 @@ import type { AuthActionResult, CheckResult, Identity, AuthProvider } from './ty
10
10
  import { useQueryClient } from '@tanstack/svelte-query';
11
11
 
12
12
  let _logoutVersion = $state(0);
13
+ let nextAuthMutationInstanceId = 0;
13
14
  export function getLogoutVersion() { return _logoutVersion; }
14
15
  export function resetLogoutVersion() { _logoutVersion = 0; }
15
16
 
@@ -22,7 +23,21 @@ interface CreateAuthMutationOptions {
22
23
  onSuccess?: (result: AuthActionResult, adminContext: AdminContextAccessor) => void | Promise<void>;
23
24
  }
24
25
 
26
+ export interface AuthNotificationOptions {
27
+ /** Set to false when the page owns the success state. */
28
+ successNotification?: string | false;
29
+ errorNotification?: string | false;
30
+ }
31
+
32
+ function resolveSuccessMessage(
33
+ configured: string | false | undefined,
34
+ defaultMessage: string,
35
+ ): string | null {
36
+ return configured === false ? null : configured ?? defaultMessage;
37
+ }
38
+
25
39
  function createAuthMutation(options: CreateAuthMutationOptions) {
40
+ const mutationInstanceId = nextAuthMutationInstanceId++;
26
41
  const adminContext = captureAdminContext();
27
42
  const i18n = useTranslation();
28
43
  let isLoading = $state(false);
@@ -57,18 +72,31 @@ function createAuthMutation(options: CreateAuthMutationOptions) {
57
72
  try {
58
73
  const result = await fn.call(provider, params);
59
74
  if (!isActiveMutation(epoch, provider, tenantIdentity)) return result;
75
+ const eventKey = `auth:${mutationInstanceId}:${String(options.method)}:${epoch}`;
60
76
  if (result.success) {
61
- if (options.successMessage) sendNotification({ type: 'success', message: options.successMessage });
77
+ if (options.successMessage) {
78
+ sendNotification({
79
+ type: 'success',
80
+ message: options.successMessage,
81
+ key: `${eventKey}:success`,
82
+ });
83
+ }
62
84
  if (options.onSuccess) await options.onSuccess(result, adminContext);
63
85
  } else {
64
86
  const msg = result.error?.message ?? (typeof options.errorMessage === 'string' ? options.errorMessage : i18n.t('common.operationFailed'));
65
- if (options.errorMessage !== false) sendNotification({ type: 'error', message: msg });
87
+ if (options.errorMessage !== false) {
88
+ sendNotification({ type: 'error', message: msg, key: `${eventKey}:error` });
89
+ }
66
90
  }
67
91
  return result;
68
92
  } catch (err) {
69
93
  const msg = err instanceof Error ? err.message : (typeof options.errorMessage === 'string' ? options.errorMessage : i18n.t('common.operationFailed'));
70
94
  if (isActiveMutation(epoch, provider, tenantIdentity) && options.errorMessage !== false) {
71
- sendNotification({ type: 'error', message: msg });
95
+ sendNotification({
96
+ type: 'error',
97
+ message: msg,
98
+ key: `auth:${mutationInstanceId}:${String(options.method)}:${epoch}:error`,
99
+ });
72
100
  }
73
101
  return { success: false, error: { message: msg } };
74
102
  } finally {
@@ -100,11 +128,11 @@ function createAuthMutation(options: CreateAuthMutationOptions) {
100
128
 
101
129
  // ─── useLogin ─────────────────────────────────────────────────
102
130
 
103
- export function useLogin(opts?: { errorMessage?: string | false }) {
131
+ export function useLogin(opts?: AuthNotificationOptions & { errorMessage?: string | false }) {
104
132
  return createAuthMutation({
105
133
  method: 'login',
106
- successMessage: t('common.operationSuccess'),
107
- errorMessage: opts?.errorMessage ?? t('common.loginFailed'),
134
+ successMessage: resolveSuccessMessage(opts?.successNotification, t('common.operationSuccess')),
135
+ errorMessage: opts?.errorNotification ?? opts?.errorMessage ?? t('common.loginFailed'),
108
136
  onSuccess: async (result, adminContext) => { await adminContext.navigate(result.redirectTo ?? '/'); }
109
137
  });
110
138
  }
@@ -131,10 +159,11 @@ export function useLogout() {
131
159
 
132
160
  // ─── useRegister ──────────────────────────────────────────────
133
161
 
134
- export function useRegister() {
162
+ export function useRegister(opts?: AuthNotificationOptions) {
135
163
  return createAuthMutation({
136
164
  method: 'register',
137
- successMessage: t('auth.registerSuccess'),
165
+ successMessage: resolveSuccessMessage(opts?.successNotification, t('auth.registerSuccess')),
166
+ errorMessage: opts?.errorNotification,
138
167
  onSuccess: async (result, adminContext) => {
139
168
  if (result.redirectTo) await adminContext.navigate(result.redirectTo);
140
169
  }
@@ -143,19 +172,21 @@ export function useRegister() {
143
172
 
144
173
  // ─── useForgotPassword ───────────────────────────────────────
145
174
 
146
- export function useForgotPassword() {
175
+ export function useForgotPassword(opts?: AuthNotificationOptions) {
147
176
  return createAuthMutation({
148
177
  method: 'forgotPassword',
149
- successMessage: t('auth.resetLinkSent')
178
+ successMessage: resolveSuccessMessage(opts?.successNotification, t('auth.resetLinkSent')),
179
+ errorMessage: opts?.errorNotification,
150
180
  });
151
181
  }
152
182
 
153
183
  // ─── useUpdatePassword ───────────────────────────────────────
154
184
 
155
- export function useUpdatePassword() {
185
+ export function useUpdatePassword(opts?: AuthNotificationOptions) {
156
186
  return createAuthMutation({
157
187
  method: 'updatePassword',
158
- successMessage: t('common.operationSuccess'),
188
+ successMessage: resolveSuccessMessage(opts?.successNotification, t('common.operationSuccess')),
189
+ errorMessage: opts?.errorNotification,
159
190
  onSuccess: async (result, adminContext) => {
160
191
  if (result.redirectTo) await adminContext.navigate(result.redirectTo);
161
192
  }
@@ -164,20 +195,22 @@ export function useUpdatePassword() {
164
195
 
165
196
  // ─── useUpdateIdentity / useUpdateProfile ────────────────────
166
197
 
167
- export function useUpdateIdentity() {
198
+ export function useUpdateIdentity(opts?: AuthNotificationOptions) {
168
199
  return createAuthMutation({
169
200
  method: 'updateIdentity',
170
- successMessage: t('common.operationSuccess'),
201
+ successMessage: resolveSuccessMessage(opts?.successNotification, t('common.operationSuccess')),
202
+ errorMessage: opts?.errorNotification,
171
203
  onSuccess: async (result, adminContext) => {
172
204
  if (result.redirectTo) await adminContext.navigate(result.redirectTo);
173
205
  }
174
206
  });
175
207
  }
176
208
 
177
- export function useUpdateProfile() {
209
+ export function useUpdateProfile(opts?: AuthNotificationOptions) {
178
210
  return createAuthMutation({
179
211
  method: 'updateProfile',
180
- successMessage: t('common.operationSuccess'),
212
+ successMessage: resolveSuccessMessage(opts?.successNotification, t('common.operationSuccess')),
213
+ errorMessage: opts?.errorNotification,
181
214
  onSuccess: async (result, adminContext) => {
182
215
  if (result.redirectTo) await adminContext.navigate(result.redirectTo);
183
216
  }
@@ -128,7 +128,12 @@ export function createLiveSubscription(paramsFn: () => LiveSubscriptionParams):
128
128
  export type NotificationConfig =
129
129
  | string
130
130
  | false
131
- | ((data?: unknown, values?: unknown, resource?: string) => { message: string; description?: string; type?: 'success' | 'error' })
131
+ | ((data?: unknown, values?: unknown, resource?: string) => {
132
+ message: string;
133
+ description?: string;
134
+ type?: 'success' | 'error';
135
+ key?: string;
136
+ })
132
137
  | undefined;
133
138
 
134
139
  export interface SuccessNotificationRequest {
@@ -154,7 +159,12 @@ export function fireSuccessNotification(request: SuccessNotificationRequest): vo
154
159
  if (!config && !defaultMessage) return;
155
160
  if (typeof config === 'function') {
156
161
  const result = config(data, values, resource);
157
- notifyWithProvider({ type: 'success', message: result.message, description: result.description }, provider);
162
+ notifyWithProvider({
163
+ type: 'success',
164
+ message: result.message,
165
+ description: result.description,
166
+ key: result.key,
167
+ }, provider);
158
168
  return;
159
169
  }
160
170
  notifyWithProvider({ type: 'success', message: config || defaultMessage }, provider);
@@ -166,7 +176,12 @@ export function fireErrorNotification(request: ErrorNotificationRequest): void {
166
176
  if (!config && !defaultMessage) return;
167
177
  if (typeof config === 'function') {
168
178
  const result = config(error, undefined, resource);
169
- notifyWithProvider({ type: 'error', message: result.message, description: result.description }, provider);
179
+ notifyWithProvider({
180
+ type: 'error',
181
+ message: result.message,
182
+ description: result.description,
183
+ key: result.key,
184
+ }, provider);
170
185
  return;
171
186
  }
172
187
  const errMsg = error instanceof Error ? error.message : String(error ?? '');
@@ -125,6 +125,8 @@ const baseLocales: Record<string, Record<string, string>> = {
125
125
  'auth.forgotPasswordDescription': '输入您的邮箱地址,我们将发送重置密码的链接。',
126
126
  'auth.resetPasswordDescription': '设置一个新的登录密码。',
127
127
  'auth.resetLinkSent': '重置链接已发送,请查看您的邮箱。',
128
+ 'auth.resetLinkSentTitle': '重置链接已发送',
129
+ 'auth.resetLinkSentDescription': '如果该账号存在,请按照邮件中的步骤重置密码。',
128
130
  'auth.passwordMismatch': '两次输入的密码不一致',
129
131
  'auth.emailRequired': '请输入邮箱',
130
132
  'auth.passwordRequired': '请输入密码',
@@ -754,6 +756,8 @@ const baseLocales: Record<string, Record<string, string>> = {
754
756
  'auth.forgotPasswordDescription': 'Enter your email address and we will send you a reset link.',
755
757
  'auth.resetPasswordDescription': 'Set a new sign-in password.',
756
758
  'auth.resetLinkSent': 'Reset link sent! Check your email.',
759
+ 'auth.resetLinkSentTitle': 'Reset link sent',
760
+ 'auth.resetLinkSentDescription': 'If the account exists, follow the instructions in the email to reset the password.',
757
761
  'auth.passwordMismatch': 'Passwords do not match',
758
762
  'auth.emailRequired': 'Email is required',
759
763
  'auth.passwordRequired': 'Password is required',
package/src/index.ts CHANGED
@@ -136,6 +136,7 @@ export {
136
136
  useOnError, usePermissions,
137
137
  getLogoutVersion, resetLogoutVersion,
138
138
  } from './auth-hooks.svelte';
139
+ export type { AuthNotificationOptions } from './auth-hooks.svelte';
139
140
  export {
140
141
  useSubmitTask,
141
142
  useTask,