@svadmin/core 0.31.0 → 0.32.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.31.0",
3
+ "version": "0.32.0",
4
4
  "author": "zuohuadong",
5
5
  "repository": {
6
6
  "type": "git",
@@ -10,9 +10,9 @@
10
10
  "main": "src/index.ts",
11
11
  "devDependencies": {
12
12
  "@happy-dom/global-registrator": "^20.10.0",
13
- "@sveltejs/vite-plugin-svelte": "^7.1.2",
13
+ "@sveltejs/vite-plugin-svelte": "^7.2.0",
14
14
  "@testing-library/dom": "^10.4.1",
15
- "@testing-library/svelte": "^5.3.1",
15
+ "@testing-library/svelte": "^5.4.2",
16
16
  "@testing-library/user-event": "^14.6.1",
17
17
  "@types/bun": "^1.3.14",
18
18
  "@types/jsdom": "^28.0.3",
@@ -2,10 +2,10 @@
2
2
  // Each hook encapsulates the auth call + loading state + error handling + redirect
3
3
  // Uses module-level $state — no component init-time constraints.
4
4
 
5
- import { getAuthProvider } from './context.svelte';
6
- import { navigate } from './router';
5
+ import { captureAdminContext } from './context.svelte';
6
+ import type { AdminContextAccessor } from './context.svelte';
7
7
  import { notify } from './notification.svelte';
8
- import { t } from './i18n.svelte';
8
+ import { t, useTranslation } from './i18n.svelte';
9
9
  import type { AuthActionResult, CheckResult, Identity, AuthProvider } from './types';
10
10
  import { useQueryClient } from '@tanstack/svelte-query';
11
11
 
@@ -19,14 +19,16 @@ interface CreateAuthMutationOptions {
19
19
  method: keyof AuthProvider;
20
20
  successMessage?: string | null;
21
21
  errorMessage?: string | false;
22
- onSuccess?: (result: AuthActionResult) => void;
22
+ onSuccess?: (result: AuthActionResult, adminContext: AdminContextAccessor) => void | Promise<void>;
23
23
  }
24
24
 
25
25
  function createAuthMutation(options: CreateAuthMutationOptions) {
26
- const provider = getAuthProvider();
26
+ const adminContext = captureAdminContext();
27
+ const i18n = useTranslation();
27
28
  let isLoading = $state(false);
28
29
 
29
30
  async function mutate(params?: Record<string, unknown>): Promise<AuthActionResult> {
31
+ const provider = adminContext.authProvider;
30
32
  if (!provider) throw new Error('AuthProvider not configured');
31
33
  const fn = provider[options.method] as ((params?: Record<string, unknown>) => Promise<AuthActionResult>) | undefined;
32
34
  if (!fn) throw new Error(`AuthProvider.${options.method} not implemented`);
@@ -36,14 +38,14 @@ function createAuthMutation(options: CreateAuthMutationOptions) {
36
38
  const result = await fn.call(provider, params);
37
39
  if (result.success) {
38
40
  if (options.successMessage) notify({ type: 'success', message: options.successMessage });
39
- if (options.onSuccess) options.onSuccess(result);
41
+ if (options.onSuccess) await options.onSuccess(result, adminContext);
40
42
  } else {
41
- const msg = result.error?.message ?? (typeof options.errorMessage === 'string' ? options.errorMessage : t('common.operationFailed'));
43
+ const msg = result.error?.message ?? (typeof options.errorMessage === 'string' ? options.errorMessage : i18n.t('common.operationFailed'));
42
44
  if (options.errorMessage !== false) notify({ type: 'error', message: msg });
43
45
  }
44
46
  return result;
45
47
  } catch (err) {
46
- const msg = err instanceof Error ? err.message : (typeof options.errorMessage === 'string' ? options.errorMessage : t('common.operationFailed'));
48
+ const msg = err instanceof Error ? err.message : (typeof options.errorMessage === 'string' ? options.errorMessage : i18n.t('common.operationFailed'));
47
49
  if (options.errorMessage !== false) notify({ type: 'error', message: msg });
48
50
  return { success: false, error: { message: msg } };
49
51
  } finally {
@@ -64,23 +66,26 @@ export function useLogin(opts?: { errorMessage?: string | false }) {
64
66
  method: 'login',
65
67
  successMessage: t('common.operationSuccess'),
66
68
  errorMessage: opts?.errorMessage ?? t('common.loginFailed'),
67
- onSuccess: (result) => { navigate(result.redirectTo ?? '/'); }
69
+ onSuccess: async (result, adminContext) => { await adminContext.navigate(result.redirectTo ?? '/'); }
68
70
  });
69
71
  }
70
72
 
71
73
  // ─── useLogout ────────────────────────────────────────────────
72
74
 
73
75
  export function useLogout() {
76
+ let queryClient: ReturnType<typeof useQueryClient> | undefined;
77
+ try {
78
+ queryClient = useQueryClient();
79
+ } catch {
80
+ // Auth hooks remain usable without TanStack Query; cache clearing is best-effort.
81
+ }
74
82
  return createAuthMutation({
75
83
  method: 'logout',
76
84
  successMessage: null,
77
- onSuccess: (result) => {
85
+ onSuccess: async (result, adminContext) => {
78
86
  _logoutVersion++;
79
- try {
80
- const queryClient = useQueryClient();
81
- queryClient.clear();
82
- } catch { /* intentional */}
83
- navigate(result.redirectTo ?? '/login');
87
+ queryClient?.clear();
88
+ await adminContext.navigate(result.redirectTo ?? '/login');
84
89
  }
85
90
  });
86
91
  }
@@ -91,7 +96,9 @@ export function useRegister() {
91
96
  return createAuthMutation({
92
97
  method: 'register',
93
98
  successMessage: t('auth.registerSuccess'),
94
- onSuccess: (result) => { if (result.redirectTo) navigate(result.redirectTo); }
99
+ onSuccess: async (result, adminContext) => {
100
+ if (result.redirectTo) await adminContext.navigate(result.redirectTo);
101
+ }
95
102
  });
96
103
  }
97
104
 
@@ -110,7 +117,9 @@ export function useUpdatePassword() {
110
117
  return createAuthMutation({
111
118
  method: 'updatePassword',
112
119
  successMessage: t('common.operationSuccess'),
113
- onSuccess: (result) => { if (result.redirectTo) navigate(result.redirectTo); }
120
+ onSuccess: async (result, adminContext) => {
121
+ if (result.redirectTo) await adminContext.navigate(result.redirectTo);
122
+ }
114
123
  });
115
124
  }
116
125
 
@@ -120,7 +129,9 @@ export function useUpdateIdentity() {
120
129
  return createAuthMutation({
121
130
  method: 'updateIdentity',
122
131
  successMessage: t('common.operationSuccess'),
123
- onSuccess: (result) => { if (result.redirectTo) navigate(result.redirectTo); }
132
+ onSuccess: async (result, adminContext) => {
133
+ if (result.redirectTo) await adminContext.navigate(result.redirectTo);
134
+ }
124
135
  });
125
136
  }
126
137
 
@@ -128,19 +139,22 @@ export function useUpdateProfile() {
128
139
  return createAuthMutation({
129
140
  method: 'updateProfile',
130
141
  successMessage: t('common.operationSuccess'),
131
- onSuccess: (result) => { if (result.redirectTo) navigate(result.redirectTo); }
142
+ onSuccess: async (result, adminContext) => {
143
+ if (result.redirectTo) await adminContext.navigate(result.redirectTo);
144
+ }
132
145
  });
133
146
  }
134
147
 
135
148
  // ─── useGetIdentity ──────────────────────────────────────────
136
149
 
137
150
  export function useGetIdentity() {
138
- const provider = getAuthProvider({ optional: true });
151
+ const adminContext = captureAdminContext();
139
152
  let data = $state<Identity | null>(null);
140
153
  let isLoading = $state(true);
141
154
  let error = $state<Error | null>(null);
142
155
 
143
156
  function fetch() {
157
+ const provider = adminContext.authProvider;
144
158
  if (!provider) { isLoading = false; return; }
145
159
  isLoading = true;
146
160
  provider.getIdentity().then(identity => {
@@ -172,12 +186,13 @@ export function useGetIdentity() {
172
186
  // ─── useIsAuthenticated ──────────────────────────────────────
173
187
 
174
188
  export function useIsAuthenticated() {
175
- const provider = getAuthProvider({ optional: true });
189
+ const adminContext = captureAdminContext();
176
190
  let isAuthenticated = $state(false);
177
191
  let isLoading = $state(true);
178
192
  let checkResult = $state<CheckResult | null>(null);
179
193
 
180
194
  function check() {
195
+ const provider = adminContext.authProvider;
181
196
  if (!provider) {
182
197
  isAuthenticated = true;
183
198
  isLoading = false;
@@ -227,9 +242,10 @@ export function useIsAuthenticated() {
227
242
  * If it returns { redirectTo }, navigates there.
228
243
  */
229
244
  export function useOnError() {
230
- const provider = getAuthProvider({ optional: true });
245
+ const adminContext = captureAdminContext();
231
246
 
232
247
  async function mutate(error: unknown) {
248
+ const provider = adminContext.authProvider;
233
249
  if (!provider?.onError) {
234
250
  console.warn('[svadmin] useOnError: authProvider.onError not implemented');
235
251
  return;
@@ -238,9 +254,9 @@ export function useOnError() {
238
254
  const result = await provider.onError(error);
239
255
  if (result.logout) {
240
256
  await provider.logout?.();
241
- navigate(result.redirectTo ?? '/login');
257
+ await adminContext.navigate(result.redirectTo ?? '/login');
242
258
  } else if (result.redirectTo) {
243
- navigate(result.redirectTo);
259
+ await adminContext.navigate(result.redirectTo);
244
260
  }
245
261
  } catch (err) {
246
262
  console.warn('[svadmin] useOnError failed:', err);
@@ -268,13 +284,14 @@ export function useOnError() {
268
284
  * ```
269
285
  */
270
286
  export function usePermissions<T = unknown>() {
271
- const provider = getAuthProvider();
287
+ const adminContext = captureAdminContext();
272
288
  let permissions = $state<T | null>(null);
273
289
  let isLoading = $state(true);
274
290
  let error = $state<Error | null>(null);
275
291
  let version = $state(0);
276
292
 
277
293
  function fetch() {
294
+ const provider = adminContext.authProvider;
278
295
  if (!provider?.getPermissions) { isLoading = false; return; }
279
296
  isLoading = true;
280
297
  error = null;
@@ -1,8 +1,10 @@
1
- // Svelte 5 Context — module-level $state singletons (no setContext/getContext required)
2
- // This removes the constraint that hooks must be called at component init time.
1
+ // Svelte 5 Context — application trees use scoped context while the module-level
2
+ // setters remain as a compatibility facade for non-component consumers.
3
3
 
4
+ import { createContext } from 'svelte';
4
5
  import type { DataProvider, AuthProvider, ResourceDefinition, TaskProvider } from './types';
5
6
  import type { RouterProvider } from './router-provider';
7
+ import type { LiveProvider } from './live.svelte';
6
8
  import { resetNotificationProvider } from './notification.svelte';
7
9
  import { resetAuditLogProvider } from './audit';
8
10
  import { resetAccessControlProvider } from './permissions.svelte';
@@ -11,7 +13,15 @@ import { resetI18n } from './i18n.svelte';
11
13
  import { resetChatProvider } from './chatProvider.svelte';
12
14
  import { resetToast } from './toast.svelte';
13
15
  import { resetTheme } from './theme.svelte';
14
- import { resetRouter } from './router';
16
+ import {
17
+ currentPath as currentLegacyPath,
18
+ currentPathWithProvider,
19
+ formatLink as formatLegacyLink,
20
+ formatLinkWithProvider,
21
+ navigate as navigateLegacy,
22
+ navigateWithProvider,
23
+ resetRouter,
24
+ } from './router';
15
25
  import { resetUnsavedChanges } from './unsaved-changes.svelte';
16
26
  import { resetGlobalPath } from './useParsed.svelte';
17
27
  import { resetLogoutVersion } from './auth-hooks.svelte';
@@ -26,46 +36,176 @@ import { resetSidebarCollapsed } from './hooks.svelte';
26
36
  */
27
37
  export type DataProviderInput = DataProvider | Record<string, DataProvider>;
28
38
 
39
+ export interface AdminContextSource {
40
+ readonly dataProvider: DataProviderInput;
41
+ readonly authProvider?: AuthProvider | null;
42
+ readonly resources: ResourceDefinition[];
43
+ readonly routerProvider?: RouterProvider;
44
+ readonly liveProvider?: LiveProvider;
45
+ readonly taskProvider?: TaskProvider;
46
+ }
47
+
48
+ export interface AdminContextValue {
49
+ readonly providers: Record<string, DataProvider>;
50
+ readonly authProvider: AuthProvider | null;
51
+ readonly resources: ResourceDefinition[];
52
+ readonly routerProvider: RouterProvider | undefined;
53
+ readonly liveProvider: LiveProvider | undefined;
54
+ readonly taskProvider: TaskProvider | undefined;
55
+ }
56
+
57
+ /**
58
+ * Initialization-time snapshot of the owning AdminContext tree.
59
+ *
60
+ * The accessor keeps the scoped context object (whose fields are reactive
61
+ * getters) instead of calling Svelte's getContext from later DOM/query
62
+ * callbacks. When no scoped context exists, getters intentionally continue to
63
+ * read the module-level compatibility setters dynamically.
64
+ */
65
+ export interface AdminContextAccessor {
66
+ readonly providers: Record<string, DataProvider> | null;
67
+ readonly authProvider: AuthProvider | null;
68
+ readonly resources: ResourceDefinition[];
69
+ readonly routerProvider: RouterProvider | undefined;
70
+ readonly liveProvider: LiveProvider | undefined;
71
+ readonly taskProvider: TaskProvider | undefined;
72
+ getDataProvider(name?: string): DataProvider;
73
+ getDataProviderNames(): string[];
74
+ getDataProviderForResource(resourceName: string, overrideName?: string): DataProvider;
75
+ getResource(nameOrIdentifier: string): ResourceDefinition;
76
+ currentPath(): string;
77
+ formatLink(path: string): string;
78
+ navigate(path: string, options?: { replaceState?: boolean }): Promise<void>;
79
+ back(): void;
80
+ }
81
+
82
+ const [getRequiredAdminContext, setAdminContext] = createContext<AdminContextValue>();
83
+
84
+ function normalizeDataProviders(provider: DataProviderInput): Record<string, DataProvider> {
85
+ return isDataProvider(provider)
86
+ ? { default: provider }
87
+ : provider;
88
+ }
89
+
90
+ export function createAdminContext(source: AdminContextSource): AdminContextValue {
91
+ return {
92
+ get providers() { return normalizeDataProviders(source.dataProvider); },
93
+ get authProvider() { return source.authProvider ?? null; },
94
+ get resources() { return source.resources; },
95
+ get routerProvider() { return source.routerProvider; },
96
+ get liveProvider() { return source.liveProvider; },
97
+ get taskProvider() { return source.taskProvider; },
98
+ };
99
+ }
100
+
101
+ /** Provide request/tree-scoped admin state to all descendants. */
102
+ export function provideAdminContext(source: AdminContextSource): AdminContextValue {
103
+ const context = createAdminContext(source);
104
+ setAdminContext(context);
105
+ return context;
106
+ }
107
+
108
+ /** Return the current tree context when called during component initialization/render. */
109
+ export function getAdminContext(): AdminContextValue | undefined {
110
+ try {
111
+ return getRequiredAdminContext();
112
+ } catch {
113
+ return undefined;
114
+ }
115
+ }
116
+
29
117
  let providers = $state<Record<string, DataProvider> | null>(null);
30
118
 
119
+ /** Capture the current tree once so delayed callbacks never re-enter getContext. */
120
+ export function captureAdminContext(): AdminContextAccessor {
121
+ const scopedContext = getAdminContext();
122
+
123
+ const accessor: AdminContextAccessor = {
124
+ get providers() { return scopedContext ? scopedContext.providers : providers; },
125
+ get authProvider() { return scopedContext ? scopedContext.authProvider : authProvider; },
126
+ get resources() { return scopedContext ? scopedContext.resources : resources ?? []; },
127
+ get routerProvider() { return scopedContext ? scopedContext.routerProvider : routerProvider; },
128
+ get liveProvider() { return scopedContext ? scopedContext.liveProvider : liveProviderState; },
129
+ get taskProvider() { return scopedContext ? scopedContext.taskProvider : taskProviderState; },
130
+ getDataProvider(name) {
131
+ const activeProviders = accessor.providers;
132
+ if (!activeProviders) throw new Error('DataProvider not found. Did you call setDataProvider in App.svelte?');
133
+ const key = name ?? 'default';
134
+ const provider = activeProviders[key];
135
+ if (!provider) {
136
+ throw new Error(`DataProvider "${key}" not found. Available: ${Object.keys(activeProviders).join(', ')}`);
137
+ }
138
+ return provider;
139
+ },
140
+ getDataProviderNames() {
141
+ return accessor.providers ? Object.keys(accessor.providers) : [];
142
+ },
143
+ getDataProviderForResource(resourceName, overrideName) {
144
+ if (overrideName) {
145
+ try {
146
+ return accessor.getDataProvider(overrideName);
147
+ } catch {
148
+ // Preserve the historical fallback to the resource/default provider.
149
+ }
150
+ }
151
+ try {
152
+ const resource = accessor.getResource(resourceName);
153
+ const dataProviderName = resource.meta?.dataProviderName as string | undefined;
154
+ if (dataProviderName) return accessor.getDataProvider(dataProviderName);
155
+ } catch {
156
+ // Preserve the historical fallback when a resource is not registered.
157
+ }
158
+ return accessor.getDataProvider();
159
+ },
160
+ getResource(nameOrIdentifier) {
161
+ const resource = accessor.resources.find(
162
+ (candidate) => candidate.identifier === nameOrIdentifier || candidate.name === nameOrIdentifier,
163
+ );
164
+ if (!resource) throw new Error(`Resource "${nameOrIdentifier}" not found in resource definitions.`);
165
+ return resource;
166
+ },
167
+ currentPath() {
168
+ if (scopedContext) return currentPathWithProvider(scopedContext.routerProvider);
169
+ return currentLegacyPath();
170
+ },
171
+ formatLink(path) {
172
+ if (scopedContext) return formatLinkWithProvider(scopedContext.routerProvider, path);
173
+ return formatLegacyLink(path);
174
+ },
175
+ async navigate(path, options) {
176
+ if (scopedContext) {
177
+ await navigateWithProvider(scopedContext.routerProvider, path, options);
178
+ return;
179
+ }
180
+ await navigateLegacy(path, options);
181
+ },
182
+ back() {
183
+ const activeRouter = accessor.routerProvider;
184
+ if (activeRouter?.back) {
185
+ activeRouter.back();
186
+ } else if (typeof window !== 'undefined') {
187
+ window.history.back();
188
+ }
189
+ },
190
+ };
191
+
192
+ return accessor;
193
+ }
194
+
31
195
  export function setDataProvider(provider: DataProviderInput): void {
32
- if (isDataProvider(provider)) {
33
- providers = { default: provider } as Record<string, DataProvider>;
34
- } else {
35
- providers = provider as Record<string, DataProvider>;
36
- }
196
+ providers = normalizeDataProviders(provider);
37
197
  }
38
198
 
39
199
  export function getDataProvider(name?: string): DataProvider {
40
- if (!providers) throw new Error('DataProvider not found. Did you call setDataProvider in App.svelte?');
41
- const key = name ?? 'default';
42
- const provider = providers[key];
43
- if (!provider) {
44
- throw new Error(`DataProvider "${key}" not found. Available: ${Object.keys(providers).join(', ')}`);
45
- }
46
- return provider;
200
+ return captureAdminContext().getDataProvider(name);
47
201
  }
48
202
 
49
203
  export function getDataProviderNames(): string[] {
50
- return providers ? Object.keys(providers) : [];
204
+ return captureAdminContext().getDataProviderNames();
51
205
  }
52
206
 
53
207
  export function getDataProviderForResource(resourceName: string, overrideName?: string): DataProvider {
54
- if (overrideName) {
55
- try {
56
- return getDataProvider(overrideName);
57
- } catch {
58
- // ignore
59
- }
60
- }
61
- try {
62
- const resource = getResource(resourceName);
63
- const dpName = resource.meta?.dataProviderName as string | undefined;
64
- if (dpName) return getDataProvider(dpName);
65
- } catch {
66
- // ignore
67
- }
68
- return getDataProvider();
208
+ return captureAdminContext().getDataProviderForResource(resourceName, overrideName);
69
209
  }
70
210
 
71
211
  function isDataProvider(value: unknown): value is DataProvider {
@@ -88,8 +228,9 @@ export function setAuthProvider(provider: AuthProvider | null | undefined): void
88
228
  export function getAuthProvider(): AuthProvider;
89
229
  export function getAuthProvider(options: { optional: true }): AuthProvider | null;
90
230
  export function getAuthProvider(options?: { optional?: boolean }): AuthProvider | null {
91
- if (!authProvider && !options?.optional) throw new Error('AuthProvider not found. Did you call setAuthProvider in App.svelte?');
92
- return authProvider;
231
+ const activeAuthProvider = captureAdminContext().authProvider;
232
+ if (!activeAuthProvider && !options?.optional) throw new Error('AuthProvider not found. Did you call setAuthProvider in App.svelte?');
233
+ return activeAuthProvider;
93
234
  }
94
235
 
95
236
  // ─── Resources ──────────────────────────────────────────────────
@@ -101,39 +242,36 @@ export function setResources(newResources: ResourceDefinition[]): void {
101
242
  }
102
243
 
103
244
  export function getResources(): ResourceDefinition[] {
104
- return resources ?? [];
245
+ return captureAdminContext().resources;
105
246
  }
106
247
 
107
248
  export function getResource(nameOrIdentifier: string): ResourceDefinition {
108
- const rList = getResources();
109
- const resource = rList.find(r => r.identifier === nameOrIdentifier || r.name === nameOrIdentifier);
110
- if (!resource) throw new Error(`Resource "${nameOrIdentifier}" not found in resource definitions.`);
111
- return resource;
249
+ return captureAdminContext().getResource(nameOrIdentifier);
112
250
  }
113
251
 
114
252
  // ─── Router Provider ────────────────────────────────────────────
115
253
 
116
254
  let routerProvider = $state<RouterProvider | undefined>(undefined);
117
255
 
118
- export function setRouterProvider(provider: RouterProvider): void {
256
+ export function setRouterProvider(provider: RouterProvider | undefined): void {
119
257
  routerProvider = provider;
120
258
  }
121
259
 
122
260
  export function getRouterProvider(): RouterProvider | undefined {
123
- return routerProvider;
261
+ return captureAdminContext().routerProvider;
124
262
  }
125
263
 
126
264
 
127
265
  // ─── Live Provider ──────────────────────────────────────────────
128
266
 
129
- let liveProviderState = $state<import('./live.svelte').LiveProvider | undefined>(undefined);
267
+ let liveProviderState = $state<LiveProvider | undefined>(undefined);
130
268
 
131
- export function setLiveProvider(provider: import('./live.svelte').LiveProvider): void {
269
+ export function setLiveProvider(provider: LiveProvider): void {
132
270
  liveProviderState = provider;
133
271
  }
134
272
 
135
- export function getLiveProvider(): import('./live.svelte').LiveProvider | undefined {
136
- return liveProviderState;
273
+ export function getLiveProvider(): LiveProvider | undefined {
274
+ return captureAdminContext().liveProvider;
137
275
  }
138
276
 
139
277
  // ─── Task Provider ──────────────────────────────────────────────
@@ -147,10 +285,11 @@ export function setTaskProvider(provider: TaskProvider | undefined): void {
147
285
  export function getTaskProvider(): TaskProvider;
148
286
  export function getTaskProvider(options: { optional: true }): TaskProvider | undefined;
149
287
  export function getTaskProvider(options?: { optional?: boolean }): TaskProvider | undefined {
150
- if (!taskProviderState && !options?.optional) {
288
+ const activeTaskProvider = captureAdminContext().taskProvider;
289
+ if (!activeTaskProvider && !options?.optional) {
151
290
  throw new Error('TaskProvider not found. Did you call setTaskProvider in App.svelte?');
152
291
  }
153
- return taskProviderState;
292
+ return activeTaskProvider;
154
293
  }
155
294
 
156
295
  // ─── Reset — for testing / HMR ─────────────────────────────────
@@ -1,4 +1,4 @@
1
- import { getDataProviderForResource } from './context.svelte';
1
+ import { captureAdminContext } from './context.svelte';
2
2
  import { useParsed } from './useParsed.svelte';
3
3
  import type { Sort, Filter, BaseRecord } from './types';
4
4
  import { downloadData } from './export-format';
@@ -26,6 +26,7 @@ export interface UseExportOptions<TData extends BaseRecord = BaseRecord> {
26
26
  * Supports mapData, sorters, filters, maxItemCount, pageSize
27
27
  */
28
28
  export function useExport<TData extends BaseRecord = BaseRecord>(options: UseExportOptions<TData> = {}) {
29
+ const adminContext = captureAdminContext();
29
30
  const parsed = useParsed();
30
31
  const resource = $derived(options.resource ?? parsed.resource ?? '');
31
32
  let isLoading = $state(false);
@@ -35,7 +36,7 @@ export function useExport<TData extends BaseRecord = BaseRecord>(options: UseExp
35
36
  isLoading = true;
36
37
 
37
38
  try {
38
- const provider = getDataProviderForResource(exportResource, options.dataProviderName);
39
+ const provider = adminContext.getDataProviderForResource(exportResource, options.dataProviderName);
39
40
  const batchSize = options.pageSize ?? 20;
40
41
  const maxItems = options.maxItemCount ?? Infinity;
41
42
  let allRecords: TData[] = [];
@@ -98,6 +99,7 @@ export interface UseImportOptions<TData = Record<string, unknown>> {
98
99
  * Supports mapData, batchSize, onFinish, onProgress, meta
99
100
  */
100
101
  export function useImport<TData = Record<string, unknown>>(options: UseImportOptions<TData> = {}) {
102
+ const adminContext = captureAdminContext();
101
103
  const parsed = useParsed();
102
104
  const resource = $derived(options.resource ?? parsed.resource ?? '');
103
105
  let isLoading = $state(false);
@@ -110,7 +112,7 @@ export function useImport<TData = Record<string, unknown>>(options: UseImportOpt
110
112
  const errored: { request: unknown; error: unknown }[] = [];
111
113
 
112
114
  try {
113
- const provider = getDataProviderForResource(importResource, options.dataProviderName);
115
+ const provider = adminContext.getDataProviderForResource(importResource, options.dataProviderName);
114
116
  let text = await info.file.text();
115
117
  // Strip BOM
116
118
  if (text.charCodeAt(0) === 0xFEFF) {