@svadmin/core 0.50.0 → 0.52.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.
Files changed (97) hide show
  1. package/package.json +21 -4
  2. package/src/access-control-contract.ts +250 -0
  3. package/src/adapters/casbin.ts +20 -14
  4. package/src/adapters/casl.ts +22 -19
  5. package/src/admin-tool.ts +7 -7
  6. package/src/audit-contract.ts +105 -0
  7. package/src/audit.ts +88 -128
  8. package/src/auth-hooks.svelte.ts +593 -261
  9. package/src/auth-mutation-contract.ts +143 -0
  10. package/src/auth-query-contract.ts +97 -0
  11. package/src/captured-mutation.svelte.ts +45 -0
  12. package/src/chatProvider.svelte.ts +1 -1
  13. package/src/command-contract.ts +195 -0
  14. package/src/context.svelte.ts +217 -205
  15. package/src/contract-context.svelte.ts +37 -0
  16. package/src/contract-form.svelte.ts +566 -0
  17. package/src/create-contract.ts +56 -0
  18. package/src/create-hooks.svelte.ts +347 -0
  19. package/src/create-many-contract.ts +90 -0
  20. package/src/create-many-hooks.svelte.ts +396 -0
  21. package/src/data-transfer.svelte.ts +1 -215
  22. package/src/defined-options.ts +50 -0
  23. package/src/delete-contract.ts +50 -0
  24. package/src/delete-hooks.svelte.ts +403 -0
  25. package/src/delete-many-contract.ts +60 -0
  26. package/src/delete-many-hooks.svelte.ts +402 -0
  27. package/src/enterprise.ts +4 -4
  28. package/src/export-format.ts +16 -14
  29. package/src/export-hooks.svelte.ts +191 -0
  30. package/src/feature-gate-contract.ts +53 -0
  31. package/src/hook-utils.svelte.ts +53 -105
  32. package/src/hooks.svelte.ts +19 -776
  33. package/src/http.ts +88 -87
  34. package/src/i18n.svelte.ts +56 -2
  35. package/src/import-contract.ts +106 -0
  36. package/src/import-hooks.svelte.ts +310 -0
  37. package/src/index.ts +77 -30
  38. package/src/inferencer-graphql.ts +7 -6
  39. package/src/infinite-query.svelte.ts +228 -0
  40. package/src/invalidation-contract.ts +26 -0
  41. package/src/live-sse.ts +91 -127
  42. package/src/live-subscription.svelte.ts +130 -0
  43. package/src/live-transport.ts +127 -0
  44. package/src/live-websocket.ts +85 -118
  45. package/src/live.svelte.ts +66 -68
  46. package/src/notification.svelte.ts +17 -15
  47. package/src/permission-catalog.ts +121 -0
  48. package/src/permission-hints-contract.ts +48 -0
  49. package/src/permissions.svelte.ts +112 -59
  50. package/src/plain-data.ts +61 -0
  51. package/src/provider-bundle.ts +85 -79
  52. package/src/provider-response.ts +35 -0
  53. package/src/query-hooks.svelte.ts +241 -288
  54. package/src/query-invalidation.ts +172 -0
  55. package/src/query-keys.ts +221 -110
  56. package/src/query-session.svelte.ts +216 -0
  57. package/src/query-snapshot.ts +144 -0
  58. package/src/reactive-projection.ts +53 -0
  59. package/src/record-decoder.ts +63 -0
  60. package/src/resource-binding.svelte.ts +19 -0
  61. package/src/resource-contract.ts +595 -0
  62. package/src/resource-mutation-types.ts +30 -0
  63. package/src/resource-schemas.ts +371 -0
  64. package/src/resource-transport-config.ts +156 -0
  65. package/src/route-parsing.ts +11 -11
  66. package/src/router-provider.ts +64 -59
  67. package/src/router.ts +8 -3
  68. package/src/routing-hooks.svelte.ts +90 -62
  69. package/src/schema-validation.ts +92 -0
  70. package/src/schema.ts +13 -0
  71. package/src/select-options.ts +95 -0
  72. package/src/select-query.svelte.ts +191 -0
  73. package/src/session-query.svelte.ts +88 -0
  74. package/src/strict-command-hooks.svelte.ts +333 -0
  75. package/src/strict-hooks.svelte.ts +198 -0
  76. package/src/table-hooks.svelte.ts +180 -174
  77. package/src/table-state.svelte.ts +117 -117
  78. package/src/task-contract.ts +87 -0
  79. package/src/task-hooks.svelte.ts +193 -149
  80. package/src/task-provider.ts +115 -0
  81. package/src/task-subscription.ts +132 -0
  82. package/src/theme.svelte.ts +155 -154
  83. package/src/toast.svelte.ts +38 -37
  84. package/src/types.ts +55 -108
  85. package/src/unsafe.ts +7 -0
  86. package/src/update-contract.ts +65 -0
  87. package/src/update-hooks.svelte.ts +347 -0
  88. package/src/update-many-contract.ts +79 -0
  89. package/src/update-many-hooks.svelte.ts +373 -0
  90. package/src/url-sync.ts +11 -10
  91. package/src/useCan.ts +96 -31
  92. package/src/useParsed.svelte.ts +18 -14
  93. package/src/useStepsForm.svelte.ts +123 -63
  94. package/src/utility-hooks.svelte.ts +101 -158
  95. package/src/form-hooks.svelte.ts +0 -889
  96. package/src/mutation-hooks.svelte.ts +0 -561
  97. package/src/schema-form.ts +0 -31
@@ -0,0 +1,191 @@
1
+ import { captureAdminContext } from './context.svelte';
2
+ import { definedOptions } from './defined-options';
3
+ import { HttpError } from './types';
4
+ import { contractKey, parseContractRecord, type ResourceContract, type ContractSchemas, type ContractRecord } from './resource-contract';
5
+ import type { ContractFilter, ContractSort } from './strict-hooks.svelte';
6
+ import { captureQueryProvider, snapshotListParams } from './query-snapshot';
7
+ import { decodeBaseRecord, decodeListResult } from './record-decoder';
8
+ import { snapshotPlainData } from './plain-data';
9
+ import { downloadData, type ExportFormat } from './export-format';
10
+
11
+ export interface UseExportOptions<S extends ContractSchemas> {
12
+ resource: ResourceContract<S>;
13
+ mapData?: (item: NoInfer<ContractRecord<S>>) => Record<string, unknown>;
14
+ sorters?: ContractSort<NoInfer<ContractRecord<S>>>[];
15
+ filters?: ContractFilter<NoInfer<ContractRecord<S>>>[];
16
+ maxItemCount?: number;
17
+ pageSize?: number;
18
+ download?: boolean;
19
+ format?: ExportFormat;
20
+ meta?: Record<string, unknown>;
21
+ dataProviderName?: string;
22
+ onError?: (error: HttpError) => void | Promise<void>;
23
+ }
24
+
25
+ function cancelled(): HttpError {
26
+ return new HttpError('Export scope changed', 409, undefined, { code: 'EXPORT_CANCELLED' });
27
+ }
28
+
29
+ function invalidInput(): never {
30
+ throw new HttpError('Invalid export input', 422, undefined, { code: 'INVALID_RESOURCE_INPUT' });
31
+ }
32
+
33
+ function exportFailure(cause: unknown): HttpError {
34
+ let code: unknown;
35
+ try {
36
+ if (typeof cause === 'object' && cause !== null) code = Object.getOwnPropertyDescriptor(cause, 'code')?.value;
37
+ } catch {
38
+ // Revoked proxies and accessor-backed errors are not trusted diagnostic sources.
39
+ }
40
+ if (code === 'INVALID_RESOURCE_INPUT') {
41
+ return new HttpError('Invalid export input', 422, undefined, { code: 'INVALID_RESOURCE_INPUT' });
42
+ }
43
+ if (code === 'INVALID_PROVIDER_RESPONSE') {
44
+ return new HttpError('Invalid provider response', 502, undefined, { code: 'INVALID_PROVIDER_RESPONSE' });
45
+ }
46
+ return new HttpError('Export failed', 500, undefined, { code: 'EXPORT_FAILED' });
47
+ }
48
+
49
+ /** Export only records proven by the bound business schema, within one captured scope. */
50
+ export function useExport<S extends ContractSchemas>(options: UseExportOptions<S>) {
51
+ const context = captureAdminContext();
52
+ contractKey(options.resource);
53
+ let isLoading = $state(false);
54
+ let error = $state<HttpError | null>(null);
55
+ let mounted = true;
56
+
57
+ function captureScope() {
58
+ const contract = options.resource;
59
+ const key = contractKey(contract);
60
+ const captured = captureQueryProvider(context, {
61
+ resource: contract.name, contract,
62
+ ...definedOptions({ dataProviderName: options.dataProviderName, meta: options.meta }),
63
+ });
64
+ return {
65
+ contract, ...captured,
66
+ key: JSON.stringify([key, captured.source, context.tenantCacheKey?.__svadminTenant, captured.meta]),
67
+ };
68
+ }
69
+ type Scope = ReturnType<typeof captureScope>;
70
+ let current: { token: object; scope: Scope; promise: Promise<ContractRecord<S>[]> } | undefined;
71
+
72
+ function isActive(token: object, scope: Scope): boolean {
73
+ if (!mounted || current?.token !== token) return false;
74
+ try { return captureScope().key === scope.key; }
75
+ catch { return false; }
76
+ }
77
+
78
+ let initialized = false;
79
+ let previousScope: string | undefined;
80
+ $effect(() => {
81
+ let nextScope: string | undefined;
82
+ try { nextScope = captureScope().key; }
83
+ catch { nextScope = undefined; }
84
+ if (initialized && previousScope !== nextScope) {
85
+ current = undefined;
86
+ isLoading = false;
87
+ error = null;
88
+ }
89
+ previousScope = nextScope;
90
+ initialized = true;
91
+ });
92
+ $effect(() => () => {
93
+ mounted = false;
94
+ current = undefined;
95
+ });
96
+
97
+ function report(failure: HttpError, handler: UseExportOptions<S>['onError']): void {
98
+ error = failure;
99
+ try {
100
+ void Promise.resolve(handler?.(failure)).catch(() => {
101
+ // Async notification failures must not become unhandled rejections.
102
+ });
103
+ }
104
+ catch {
105
+ // Consumer callback failures must not replace the sanitized export failure.
106
+ }
107
+ }
108
+
109
+ function triggerExport(): Promise<ContractRecord<S>[]> {
110
+ if (!mounted) return Promise.reject(cancelled());
111
+ let onError: UseExportOptions<S>['onError'];
112
+ try {
113
+ const scope = captureScope();
114
+ if (current?.scope.key === scope.key) return current.promise;
115
+ previousScope = scope.key;
116
+ initialized = true;
117
+ const batchSize = options.pageSize ?? 20;
118
+ const maxItems = options.maxItemCount ?? Infinity;
119
+ const format = options.format ?? 'csv';
120
+ const download = options.download ?? true;
121
+ const mapData = options.mapData;
122
+ onError = options.onError;
123
+ if (!Number.isSafeInteger(batchSize) || batchSize <= 0 ||
124
+ (maxItems !== Infinity && (!Number.isSafeInteger(maxItems) || maxItems < 0)) ||
125
+ !['csv', 'json', 'xlsx'].includes(format) || typeof download !== 'boolean' ||
126
+ (mapData !== undefined && typeof mapData !== 'function') ||
127
+ (onError !== undefined && typeof onError !== 'function')) invalidInput();
128
+ const handler = onError;
129
+ const params = snapshotListParams({
130
+ resource: scope.contract.name,
131
+ ...definedOptions({
132
+ pagination: { current: 1, pageSize: batchSize },
133
+ filters: options.filters, sorters: options.sorters, meta: scope.meta,
134
+ }),
135
+ });
136
+ const token = {};
137
+ const ensureActive = () => { if (!isActive(token, scope)) throw cancelled(); };
138
+ isLoading = true;
139
+ error = null;
140
+ // Install the invocation before transport code or user callbacks can re-enter it.
141
+ const promise = Promise.resolve().then(async () => {
142
+ try {
143
+ ensureActive();
144
+ const records: ContractRecord<S>[] = [];
145
+ let page = 1;
146
+ while (records.length < maxItems) {
147
+ const response = await scope.provider.getList(snapshotListParams({
148
+ ...params, pagination: { current: page, pageSize: batchSize },
149
+ }));
150
+ ensureActive();
151
+ const result = decodeListResult(response, value => parseContractRecord(scope.contract, value));
152
+ records.push(...result.data.slice(0, maxItems - records.length));
153
+ if (result.data.length < batchSize || records.length >= result.total) break;
154
+ page++;
155
+ }
156
+ ensureActive();
157
+ const mapped = mapData ? records.map(record => {
158
+ ensureActive();
159
+ // Mapping receives its own checked copy, never the records returned to the caller.
160
+ return decodeBaseRecord(snapshotPlainData(mapData(parseContractRecord(scope.contract, record))));
161
+ }) : records;
162
+ ensureActive();
163
+ if (download && mapped.length > 0) downloadData(mapped, scope.contract.name, format);
164
+ return records;
165
+ } catch (cause) {
166
+ if (!isActive(token, scope)) throw cancelled();
167
+ const failure = exportFailure(cause);
168
+ current = undefined;
169
+ isLoading = false;
170
+ report(failure, handler);
171
+ throw failure;
172
+ } finally {
173
+ if (current?.token === token) {
174
+ current = undefined;
175
+ isLoading = false;
176
+ }
177
+ }
178
+ });
179
+ current = { token, scope, promise };
180
+ return promise;
181
+ } catch (cause) {
182
+ current = undefined;
183
+ isLoading = false;
184
+ const failure = exportFailure(cause);
185
+ report(failure, typeof onError === 'function' ? onError : undefined);
186
+ return Promise.reject(failure);
187
+ }
188
+ }
189
+
190
+ return { triggerExport, get isLoading() { return isLoading; }, get error() { return error; } };
191
+ }
@@ -0,0 +1,53 @@
1
+ import { Type } from '@sinclair/typebox';
2
+ import { checkExact } from './schema-validation';
3
+ import { snapshotPlainData } from './plain-data';
4
+ import { HttpError } from './types';
5
+ import type { FeatureGateConfig, FeatureGateUser } from './permissions.svelte';
6
+
7
+ const name = Type.String({ minLength: 1, pattern: '\\S' });
8
+ const constraints = {
9
+ roles: Type.Optional(Type.Array(name)),
10
+ permissions: Type.Optional(Type.Array(name)),
11
+ };
12
+ const configuration = Type.Union([
13
+ Type.Object(constraints, { additionalProperties: false }),
14
+ Type.Object({
15
+ ...constraints,
16
+ minRole: name,
17
+ roleHierarchy: Type.Array(name, { minItems: 1, uniqueItems: true }),
18
+ }, { additionalProperties: false }),
19
+ ]);
20
+ const user = Type.Object({
21
+ role: name,
22
+ permissions: Type.Array(name),
23
+ }, { additionalProperties: false });
24
+
25
+ export function snapshotFeatureGateConfig(value: unknown): FeatureGateConfig {
26
+ try {
27
+ const candidate = snapshotPlainData(value);
28
+ if (checkExact(configuration, candidate) &&
29
+ (!('minRole' in candidate) || candidate.roleHierarchy.includes(candidate.minRole))) {
30
+ if (candidate.roles) Object.freeze(candidate.roles);
31
+ if (candidate.permissions) Object.freeze(candidate.permissions);
32
+ if ('roleHierarchy' in candidate) Object.freeze(candidate.roleHierarchy);
33
+ return Object.freeze(candidate);
34
+ }
35
+ } catch {
36
+ // Configuration errors never retain caller data or reflection diagnostics.
37
+ }
38
+ throw new HttpError('Invalid feature gate configuration', 422, undefined, { code: 'INVALID_FEATURE_GATE_CONFIG' });
39
+ }
40
+
41
+ /** Invalid presentation hints deny visibility instead of throwing during rendering. */
42
+ export function parseFeatureGateUser(value: unknown): FeatureGateUser | undefined {
43
+ try {
44
+ const candidate = snapshotPlainData(value);
45
+ if (checkExact(user, candidate)) {
46
+ Object.freeze(candidate.permissions);
47
+ return Object.freeze(candidate);
48
+ }
49
+ } catch {
50
+ // Never invoke user getters or custom permission-collection methods.
51
+ }
52
+ return undefined;
53
+ }
@@ -1,41 +1,25 @@
1
+ import { definedOptions } from './defined-options';
1
2
  // Hook Utilities — shared reactive helpers for all hooks
2
3
  // Uses Svelte 5 runes ($state, $effect) for automatic lifecycle management
3
4
 
4
5
  import { useQueryClient } from '@tanstack/svelte-query';
5
- import type { LiveProvider, LiveEvent, LiveMode } from './live.svelte';
6
6
  import { captureAdminContext } from './context.svelte';
7
7
  import type { AdminContextAccessor } from './context.svelte';
8
- import { dataQueryMatches } from './query-keys';
8
+ import { createCheckedLiveSubscription, type LiveSubscriptionParams } from './live-subscription.svelte';
9
+ export type { LiveSubscriptionParams } from './live-subscription.svelte';
9
10
  import { notifyWithProvider } from './notification.svelte';
10
11
  import type { NotificationProvider } from './types';
12
+ import { handleAuthError } from './auth-hooks.svelte';
13
+ import { untrack } from 'svelte';
11
14
 
12
15
  // ─── Auth Error Delegate ────────────────────────────────────────
13
16
  // Delegate auth errors to authProvider.onError() — refine pattern
14
17
 
15
18
  export async function checkError(
16
19
  error: unknown,
17
- adminContext: AdminContextAccessor = captureAdminContext(),
20
+ adminContext: AdminContextAccessor=captureAdminContext(),
18
21
  ): Promise<void> {
19
- try {
20
- const authProvider = adminContext.authProvider;
21
- if (authProvider?.onError) {
22
- const result = await authProvider.onError(error);
23
- if (!result) return;
24
- if (result.logout) {
25
- await authProvider.logout?.();
26
- await adminContext.navigate(result.redirectTo ?? '/login');
27
- } else if (result.redirectTo) {
28
- await adminContext.navigate(result.redirectTo);
29
- }
30
- return;
31
- }
32
- if (error && typeof error === 'object' && 'statusCode' in error) {
33
- const status = (error as { statusCode: number }).statusCode;
34
- if (status === 401) {
35
- await adminContext.navigate('/login');
36
- }
37
- }
38
- } catch { /* auth check failed silently */ }
22
+ await untrack(() => handleAuthError(error,adminContext));
39
23
  }
40
24
 
41
25
  // ─── Overtime Tracker ───────────────────────────────────────────
@@ -52,21 +36,21 @@ export interface OvertimeResult {
52
36
 
53
37
  export function createOvertimeTracker(
54
38
  isLoadingFn: () => boolean,
55
- options: OvertimeOptions = {},
39
+ options: OvertimeOptions={},
56
40
  ): OvertimeResult {
57
- const { interval = 1000, onInterval } = options;
58
- let elapsedTime = $state(0);
41
+ const { interval=1000,onInterval }=options;
42
+ let elapsedTime=$state(0);
59
43
 
60
44
  $effect(() => {
61
- if (isLoadingFn()) {
62
- elapsedTime = 0;
63
- const timer = setInterval(() => {
64
- elapsedTime += interval;
45
+ if(isLoadingFn()) {
46
+ elapsedTime=0;
47
+ const timer=setInterval(() => {
48
+ elapsedTime+=interval;
65
49
  onInterval?.(elapsedTime);
66
- }, interval);
50
+ },interval);
67
51
  return () => clearInterval(timer);
68
52
  } else {
69
- elapsedTime = 0;
53
+ elapsedTime=0;
70
54
  }
71
55
  });
72
56
 
@@ -78,63 +62,23 @@ export function createOvertimeTracker(
78
62
  // ─── Live Subscription ──────────────────────────────────────────
79
63
  // Auto-subscribes to realtime events, invalidates queries on 'auto' mode
80
64
 
81
- export interface LiveSubscriptionParams {
82
- resource: string;
83
- liveProvider?: LiveProvider;
84
- liveMode?: LiveMode;
85
- onLiveEvent?: (event: LiveEvent) => void;
86
- liveParams?: Record<string, unknown>;
87
- enabled?: boolean;
88
- dataProviderName?: string;
89
- }
90
-
91
65
  export function createLiveSubscription(paramsFn: () => LiveSubscriptionParams): void {
92
- const queryClient = useQueryClient();
93
- const adminContext = captureAdminContext();
94
-
95
- $effect(() => {
96
- const params = paramsFn();
97
- const liveProvider = params.liveProvider;
98
- const liveMode = params.liveMode ?? 'off';
99
- const enabled = params.enabled ?? true;
100
-
101
- if (!liveProvider || liveMode === 'off' || !enabled) return;
102
-
103
- let unsubscribe: (() => void) | undefined;
104
- try {
105
- unsubscribe = liveProvider.subscribe({
106
- resource: params.resource,
107
- liveParams: params.liveParams,
108
- callback: (event: LiveEvent) => {
109
- params.onLiveEvent?.(event);
110
- if (liveMode === 'auto') {
111
- const matcher = adminContext.queryKeyMatcher(params.resource, params.dataProviderName);
112
- queryClient.invalidateQueries({
113
- predicate: (q) => dataQueryMatches(q.queryKey, { ...matcher, resource: params.resource }),
114
- });
115
- }
116
- },
117
- });
118
- } catch (e) {
119
- console.warn('[svadmin] LiveProvider.subscribe failed:', e);
120
- return;
121
- }
122
- return unsubscribe;
123
- });
66
+ const queryClient=useQueryClient();
67
+ createCheckedLiveSubscription(paramsFn,queryClient);
124
68
  }
125
69
 
126
70
  // ─── Notification Helpers ───────────────────────────────────────
127
71
 
128
- export type NotificationConfig =
129
- | string
130
- | false
131
- | ((data?: unknown, values?: unknown, resource?: string) => {
132
- message: string;
133
- description?: string;
134
- type?: 'success' | 'error';
135
- key?: string;
136
- })
137
- | undefined;
72
+ export type NotificationConfig=
73
+ |string
74
+ |false
75
+ |((data?: unknown,values?: unknown,resource?: string) => {
76
+ message: string;
77
+ description?: string;
78
+ type?: 'success'|'error';
79
+ key?: string;
80
+ })
81
+ |undefined;
138
82
 
139
83
  export interface SuccessNotificationRequest {
140
84
  config: NotificationConfig;
@@ -142,7 +86,7 @@ export interface SuccessNotificationRequest {
142
86
  data?: unknown;
143
87
  values?: unknown;
144
88
  resource?: string;
145
- provider?: NotificationProvider | null;
89
+ provider?: NotificationProvider|null;
146
90
  }
147
91
 
148
92
  export interface ErrorNotificationRequest {
@@ -150,40 +94,44 @@ export interface ErrorNotificationRequest {
150
94
  defaultMessage: string;
151
95
  error?: unknown;
152
96
  resource?: string;
153
- provider?: NotificationProvider | null;
97
+ provider?: NotificationProvider|null;
154
98
  }
155
99
 
156
100
  export function fireSuccessNotification(request: SuccessNotificationRequest): void {
157
- const { config, defaultMessage, data, values, resource, provider } = request;
158
- if (config === false) return;
159
- if (!config && !defaultMessage) return;
160
- if (typeof config === 'function') {
161
- const result = config(data, values, resource);
101
+ const { config,defaultMessage,data,values,resource,provider }=request;
102
+ if(config===false) return;
103
+ if(!config&&!defaultMessage) return;
104
+ if(typeof config==='function') {
105
+ const result=config(data,values,resource);
162
106
  notifyWithProvider({
163
107
  type: 'success',
164
108
  message: result.message,
165
- description: result.description,
166
- key: result.key,
167
- }, provider);
109
+ ...definedOptions({
110
+ description: result.description,
111
+ key: result.key,
112
+ }),
113
+ },provider);
168
114
  return;
169
115
  }
170
- notifyWithProvider({ type: 'success', message: config || defaultMessage }, provider);
116
+ notifyWithProvider({ type: 'success',message: config||defaultMessage },provider);
171
117
  }
172
118
 
173
119
  export function fireErrorNotification(request: ErrorNotificationRequest): void {
174
- const { config, defaultMessage, error, resource, provider } = request;
175
- if (config === false) return;
176
- if (!config && !defaultMessage) return;
177
- if (typeof config === 'function') {
178
- const result = config(error, undefined, resource);
120
+ const { config,defaultMessage,error,resource,provider }=request;
121
+ if(config===false) return;
122
+ if(!config&&!defaultMessage) return;
123
+ if(typeof config==='function') {
124
+ const result=config(error,undefined,resource);
179
125
  notifyWithProvider({
180
126
  type: 'error',
181
127
  message: result.message,
182
- description: result.description,
183
- key: result.key,
184
- }, provider);
128
+ ...definedOptions({
129
+ description: result.description,
130
+ key: result.key,
131
+ }),
132
+ },provider);
185
133
  return;
186
134
  }
187
- const errMsg = error instanceof Error ? error.message : String(error ?? '');
188
- notifyWithProvider({ type: 'error', message: config || `${defaultMessage}${errMsg ? ': ' + errMsg : ''}` }, provider);
135
+ const errMsg=error instanceof Error? error.message:String(error??'');
136
+ notifyWithProvider({ type: 'error',message: config||`${defaultMessage}${errMsg? ': '+errMsg:''}` },provider);
189
137
  }