@svadmin/core 0.10.0 → 0.12.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 +1 -1
- package/src/auth-hooks.svelte.ts +58 -0
- package/src/index.ts +2 -2
- package/src/types.ts +24 -0
package/package.json
CHANGED
package/src/auth-hooks.svelte.ts
CHANGED
|
@@ -290,3 +290,61 @@ export function usePermissions<T = unknown>() {
|
|
|
290
290
|
get error() { return error; },
|
|
291
291
|
};
|
|
292
292
|
}
|
|
293
|
+
|
|
294
|
+
// ─── useHasPermission ────────────────────────────────────────
|
|
295
|
+
|
|
296
|
+
/**
|
|
297
|
+
* Reactive permission checker — returns a closure that re-evaluates
|
|
298
|
+
* when the underlying permissions data changes.
|
|
299
|
+
*
|
|
300
|
+
* Works with Casbin-style permission arrays, Sets, or permission objects.
|
|
301
|
+
* The returned function is safe to use inside `$derived()` for reactive UI updates.
|
|
302
|
+
*
|
|
303
|
+
* @example
|
|
304
|
+
* ```svelte
|
|
305
|
+
* <script>
|
|
306
|
+
* import { useHasPermission } from '@svadmin/core';
|
|
307
|
+
*
|
|
308
|
+
* const hasPermission = useHasPermission();
|
|
309
|
+
* // ✅ Reactive — UI updates when permissions finish loading
|
|
310
|
+
* const canDelete = $derived(hasPermission('admin'));
|
|
311
|
+
* const canExport = $derived(hasPermission('data:export'));
|
|
312
|
+
* </script>
|
|
313
|
+
*
|
|
314
|
+
* {#if canDelete}
|
|
315
|
+
* <Button variant="destructive">Delete</Button>
|
|
316
|
+
* {/if}
|
|
317
|
+
* ```
|
|
318
|
+
*/
|
|
319
|
+
export function useHasPermission() {
|
|
320
|
+
const provider = getAuthProvider();
|
|
321
|
+
let permissions = $state<unknown>(null);
|
|
322
|
+
let loaded = $state(false);
|
|
323
|
+
|
|
324
|
+
if (provider?.getPermissions) {
|
|
325
|
+
provider.getPermissions().then(p => {
|
|
326
|
+
permissions = p;
|
|
327
|
+
loaded = true;
|
|
328
|
+
}).catch(err => {
|
|
329
|
+
console.warn('[svadmin] useHasPermission: getPermissions failed', err);
|
|
330
|
+
loaded = true;
|
|
331
|
+
});
|
|
332
|
+
} else {
|
|
333
|
+
loaded = true;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
/**
|
|
337
|
+
* Check if the current user has a specific permission.
|
|
338
|
+
* Supports: `string[]`, `Set<string>`, `Record<string, boolean>`, or any object with `.includes` / `.has`.
|
|
339
|
+
*/
|
|
340
|
+
function hasPermission(perm: string): boolean {
|
|
341
|
+
if (!loaded || permissions == null) return false;
|
|
342
|
+
if (Array.isArray(permissions)) return permissions.includes(perm);
|
|
343
|
+
if (permissions instanceof Set) return (permissions as Set<string>).has(perm);
|
|
344
|
+
if (typeof permissions === 'object') return !!(permissions as Record<string, boolean>)[perm];
|
|
345
|
+
return false;
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
return hasPermission;
|
|
349
|
+
}
|
|
350
|
+
|
package/src/index.ts
CHANGED
|
@@ -59,7 +59,7 @@ export type {
|
|
|
59
59
|
DeleteParams, DeleteResult,
|
|
60
60
|
DeleteManyParams, DeleteManyResult,
|
|
61
61
|
Pagination, Sort, Filter, Identity,
|
|
62
|
-
ResourceDefinition, FieldDefinition,
|
|
62
|
+
ResourceDefinition, FieldDefinition, MenuItem,
|
|
63
63
|
AuthActionResult, CheckResult,
|
|
64
64
|
ResourceTypeMap, KnownResources, InferData,
|
|
65
65
|
BaseRecord,
|
|
@@ -79,7 +79,7 @@ export {
|
|
|
79
79
|
useLogin, useLogout,
|
|
80
80
|
useRegister, useForgotPassword, useUpdatePassword,
|
|
81
81
|
useGetIdentity, useIsAuthenticated,
|
|
82
|
-
useOnError, usePermissions,
|
|
82
|
+
useOnError, usePermissions, useHasPermission,
|
|
83
83
|
} from './auth-hooks.svelte';
|
|
84
84
|
export { useParsed } from './useParsed.svelte';
|
|
85
85
|
export * from './useStepsForm.svelte';
|
package/src/types.ts
CHANGED
|
@@ -260,6 +260,30 @@ export interface ResourceDefinition {
|
|
|
260
260
|
meta?: Record<string, unknown> & { dataProviderName?: string; parent?: string };
|
|
261
261
|
}
|
|
262
262
|
|
|
263
|
+
// ─── MenuItem (Multi-Level Menu) ──────────────────────────────
|
|
264
|
+
|
|
265
|
+
export interface MenuItem {
|
|
266
|
+
/** Unique identifier, also used as i18n fallback key: t(`menu.${name}`) */
|
|
267
|
+
name: string;
|
|
268
|
+
/** Display label. Falls back to `t('menu.${name}')` if omitted */
|
|
269
|
+
label?: string;
|
|
270
|
+
/** Icon name string (maps to lucide icon set) or Svelte component */
|
|
271
|
+
icon?: string;
|
|
272
|
+
/** Navigation path — omit for parent-only menu nodes */
|
|
273
|
+
href?: string;
|
|
274
|
+
/** Open in new tab (useful for external links) */
|
|
275
|
+
target?: '_blank' | '_self';
|
|
276
|
+
/** Permission check metadata */
|
|
277
|
+
meta?: {
|
|
278
|
+
resource?: string;
|
|
279
|
+
action?: string;
|
|
280
|
+
/** Hide this item from the menu entirely */
|
|
281
|
+
hidden?: boolean;
|
|
282
|
+
};
|
|
283
|
+
/** Sub-menu items — supports infinite nesting */
|
|
284
|
+
children?: MenuItem[];
|
|
285
|
+
}
|
|
286
|
+
|
|
263
287
|
export interface FieldDefinition {
|
|
264
288
|
key: string;
|
|
265
289
|
label: string;
|