@mercurjs/dashboard-sdk 2.3.6-canary.1 → 2.3.6-canary.10
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/dist/index.cjs +24 -17
- package/dist/index.d.cts +5 -58
- package/dist/index.d.ts +5 -58
- package/dist/index.js +21 -15
- package/dist/types-BTgTMD_t.d.cts +282 -0
- package/dist/types-BTgTMD_t.d.ts +282 -0
- package/dist/vite.cjs +22 -4
- package/dist/vite.d.cts +1 -1
- package/dist/vite.d.ts +1 -1
- package/dist/vite.js +22 -4
- package/package.json +4 -3
- package/dist/types-CTuDKgPc.d.cts +0 -142
- package/dist/types-CTuDKgPc.d.ts +0 -142
package/dist/index.cjs
CHANGED
|
@@ -20,12 +20,13 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
20
20
|
// src/index.ts
|
|
21
21
|
var index_exports = {};
|
|
22
22
|
__export(index_exports, {
|
|
23
|
-
|
|
23
|
+
PERMISSION_RIGHT_RANK: () => PERMISSION_RIGHT_RANK,
|
|
24
24
|
buildPermission: () => buildPermission,
|
|
25
25
|
defineCustomFieldsConfig: () => defineCustomFieldsConfig,
|
|
26
26
|
defineNavigationConfig: () => defineNavigationConfig,
|
|
27
27
|
defineWidgetConfig: () => defineWidgetConfig,
|
|
28
|
-
parsePermission: () => parsePermission
|
|
28
|
+
parsePermission: () => parsePermission,
|
|
29
|
+
satisfiesPermission: () => satisfiesPermission
|
|
29
30
|
});
|
|
30
31
|
module.exports = __toCommonJS(index_exports);
|
|
31
32
|
|
|
@@ -47,33 +48,39 @@ function defineCustomFieldsConfig(config) {
|
|
|
47
48
|
}
|
|
48
49
|
|
|
49
50
|
// src/permissions.ts
|
|
50
|
-
var
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
delete: ["delete"],
|
|
55
|
-
"*": ["read", "create", "update", "delete", "*"]
|
|
51
|
+
var PERMISSION_RIGHT_RANK = {
|
|
52
|
+
view: 1,
|
|
53
|
+
edit: 2,
|
|
54
|
+
manage: 3
|
|
56
55
|
};
|
|
57
56
|
function parsePermission(permission) {
|
|
58
|
-
const
|
|
59
|
-
if (
|
|
57
|
+
const index = permission.lastIndexOf(":");
|
|
58
|
+
if (index <= 0) {
|
|
59
|
+
return null;
|
|
60
|
+
}
|
|
61
|
+
const right = permission.slice(index + 1);
|
|
62
|
+
if (!(right in PERMISSION_RIGHT_RANK)) {
|
|
60
63
|
return null;
|
|
61
64
|
}
|
|
62
|
-
const [resource, operation] = parts;
|
|
63
65
|
return {
|
|
64
|
-
|
|
65
|
-
|
|
66
|
+
key: permission.slice(0, index),
|
|
67
|
+
right
|
|
66
68
|
};
|
|
67
69
|
}
|
|
68
|
-
function buildPermission(
|
|
69
|
-
return `${
|
|
70
|
+
function buildPermission(key, right) {
|
|
71
|
+
return `${key}:${right}`;
|
|
72
|
+
}
|
|
73
|
+
function satisfiesPermission(permissions, key, right) {
|
|
74
|
+
const granted = permissions[key];
|
|
75
|
+
return !!granted && PERMISSION_RIGHT_RANK[granted] >= PERMISSION_RIGHT_RANK[right];
|
|
70
76
|
}
|
|
71
77
|
// Annotate the CommonJS export names for ESM import in node:
|
|
72
78
|
0 && (module.exports = {
|
|
73
|
-
|
|
79
|
+
PERMISSION_RIGHT_RANK,
|
|
74
80
|
buildPermission,
|
|
75
81
|
defineCustomFieldsConfig,
|
|
76
82
|
defineNavigationConfig,
|
|
77
83
|
defineWidgetConfig,
|
|
78
|
-
parsePermission
|
|
84
|
+
parsePermission,
|
|
85
|
+
satisfiesPermission
|
|
79
86
|
});
|
package/dist/index.d.cts
CHANGED
|
@@ -1,59 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Open registry interfaces. Each panel package ships a generated
|
|
6
|
-
* `extension-targets.d.ts` that seeds the built-in ids into these interfaces
|
|
7
|
-
* (declaration merging), and a developer augments them by hand to register a
|
|
8
|
-
* zone their own page renders. The helper unions read off the interface keys.
|
|
9
|
-
*
|
|
10
|
-
* @example
|
|
11
|
-
* declare module "@mercurjs/dashboard-sdk" {
|
|
12
|
-
* interface WidgetZoneRegistry {
|
|
13
|
-
* "erp.dashboard.before": true
|
|
14
|
-
* }
|
|
15
|
-
* }
|
|
16
|
-
*/
|
|
17
|
-
interface WidgetZoneRegistry {
|
|
18
|
-
}
|
|
19
|
-
interface NavItemRegistry {
|
|
20
|
-
}
|
|
21
|
-
interface NavParentRegistry {
|
|
22
|
-
}
|
|
23
|
-
type WidgetZoneId = keyof WidgetZoneRegistry extends never ? string : keyof WidgetZoneRegistry;
|
|
24
|
-
type NavItemId = keyof NavItemRegistry extends never ? string : keyof NavItemRegistry;
|
|
25
|
-
type NavParentId = keyof NavParentRegistry extends never ? string : keyof NavParentRegistry;
|
|
26
|
-
/**
|
|
27
|
-
* A widget is a React component attached to a named zone on a page. The
|
|
28
|
-
* placement (`before | after`) is encoded as the zone-id suffix, so there is no
|
|
29
|
-
* separate rank field — multiple `before`/`after` widgets stack in registration
|
|
30
|
-
* order.
|
|
31
|
-
*/
|
|
32
|
-
interface WidgetConfig {
|
|
33
|
-
zone: WidgetZoneId | WidgetZoneId[];
|
|
34
|
-
/** Stable id; derived from the file path at build time when omitted. */
|
|
35
|
-
id?: string;
|
|
36
|
-
}
|
|
37
|
-
/** Override for a single built-in navigation item. */
|
|
38
|
-
interface NavItemOverride {
|
|
39
|
-
id: NavItemId;
|
|
40
|
-
/** Order within the item's parent (or among top-level items). */
|
|
41
|
-
rank?: number;
|
|
42
|
-
/** Remove from the sidebar (route may still be reachable directly). */
|
|
43
|
-
hidden?: boolean;
|
|
44
|
-
/** i18n key or literal replacing the item's label. */
|
|
45
|
-
label?: string;
|
|
46
|
-
/** Icon component replacing the item's icon. */
|
|
47
|
-
icon?: ComponentType;
|
|
48
|
-
/**
|
|
49
|
-
* Re-parent the item: a built-in parent id moves it under that parent's
|
|
50
|
-
* children; `null` promotes a nested item to the top level.
|
|
51
|
-
*/
|
|
52
|
-
nested?: NavParentId | null;
|
|
53
|
-
}
|
|
54
|
-
interface NavigationConfig {
|
|
55
|
-
items: NavItemOverride[];
|
|
56
|
-
}
|
|
1
|
+
import { h as NavigationConfig, W as WidgetConfig } from './types-BTgTMD_t.cjs';
|
|
2
|
+
export { B as BuiltMercurConfig, M as MercurConfig, N as NavGroupConfig, a as NavGroupId, b as NavGroupRegistry, c as NavItemId, d as NavItemOverride, e as NavItemRegistry, f as NavParentId, g as NavParentRegistry, P as PERMISSION_RIGHT_RANK, i as Permission, j as PermissionKey, k as PermissionKeys, l as PermissionMap, m as PermissionRight, n as PermissionsContextValue, R as RouteConfig, o as RouteHandle, p as WidgetZoneId, q as WidgetZoneRegistry, r as buildPermission, s as parsePermission, t as satisfiesPermission } from './types-BTgTMD_t.cjs';
|
|
3
|
+
import { ReactNode, ComponentType } from 'react';
|
|
57
4
|
|
|
58
5
|
/**
|
|
59
6
|
* Minimal structural stand-in for a Zod schema, so the SDK stays free of a zod
|
|
@@ -189,7 +136,7 @@ interface CustomFieldsConfig<TModel extends CustomFieldModel = CustomFieldModel>
|
|
|
189
136
|
}
|
|
190
137
|
|
|
191
138
|
declare function defineWidgetConfig(config: WidgetConfig): WidgetConfig;
|
|
192
|
-
declare function defineNavigationConfig(config: NavigationConfig): NavigationConfig
|
|
139
|
+
declare function defineNavigationConfig<TGroup extends string = never>(config: NavigationConfig<TGroup>): NavigationConfig<TGroup>;
|
|
193
140
|
declare function defineCustomFieldsConfig<TModel extends CustomFieldModel>(config: CustomFieldsConfig<TModel>): CustomFieldsConfig<TModel>;
|
|
194
141
|
|
|
195
|
-
export { type ActivityEntry, type CustomColumn, type CustomDisplayEntry, type CustomDisplayField, type CustomFieldAction, type CustomFieldActionRegistry, type CustomFieldModel, type CustomFieldsConfig, type CustomFieldsRegistry, type CustomFormEntry, type CustomFormField, type CustomFormTab, type CustomFormZone, type CustomListExtension, type FieldValidation,
|
|
142
|
+
export { type ActivityEntry, type CustomColumn, type CustomDisplayEntry, type CustomDisplayField, type CustomFieldAction, type CustomFieldActionRegistry, type CustomFieldModel, type CustomFieldsConfig, type CustomFieldsRegistry, type CustomFormEntry, type CustomFormField, type CustomFormTab, type CustomFormZone, type CustomListExtension, type FieldValidation, NavigationConfig, type SectionAction, WidgetConfig, defineCustomFieldsConfig, defineNavigationConfig, defineWidgetConfig };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,59 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Open registry interfaces. Each panel package ships a generated
|
|
6
|
-
* `extension-targets.d.ts` that seeds the built-in ids into these interfaces
|
|
7
|
-
* (declaration merging), and a developer augments them by hand to register a
|
|
8
|
-
* zone their own page renders. The helper unions read off the interface keys.
|
|
9
|
-
*
|
|
10
|
-
* @example
|
|
11
|
-
* declare module "@mercurjs/dashboard-sdk" {
|
|
12
|
-
* interface WidgetZoneRegistry {
|
|
13
|
-
* "erp.dashboard.before": true
|
|
14
|
-
* }
|
|
15
|
-
* }
|
|
16
|
-
*/
|
|
17
|
-
interface WidgetZoneRegistry {
|
|
18
|
-
}
|
|
19
|
-
interface NavItemRegistry {
|
|
20
|
-
}
|
|
21
|
-
interface NavParentRegistry {
|
|
22
|
-
}
|
|
23
|
-
type WidgetZoneId = keyof WidgetZoneRegistry extends never ? string : keyof WidgetZoneRegistry;
|
|
24
|
-
type NavItemId = keyof NavItemRegistry extends never ? string : keyof NavItemRegistry;
|
|
25
|
-
type NavParentId = keyof NavParentRegistry extends never ? string : keyof NavParentRegistry;
|
|
26
|
-
/**
|
|
27
|
-
* A widget is a React component attached to a named zone on a page. The
|
|
28
|
-
* placement (`before | after`) is encoded as the zone-id suffix, so there is no
|
|
29
|
-
* separate rank field — multiple `before`/`after` widgets stack in registration
|
|
30
|
-
* order.
|
|
31
|
-
*/
|
|
32
|
-
interface WidgetConfig {
|
|
33
|
-
zone: WidgetZoneId | WidgetZoneId[];
|
|
34
|
-
/** Stable id; derived from the file path at build time when omitted. */
|
|
35
|
-
id?: string;
|
|
36
|
-
}
|
|
37
|
-
/** Override for a single built-in navigation item. */
|
|
38
|
-
interface NavItemOverride {
|
|
39
|
-
id: NavItemId;
|
|
40
|
-
/** Order within the item's parent (or among top-level items). */
|
|
41
|
-
rank?: number;
|
|
42
|
-
/** Remove from the sidebar (route may still be reachable directly). */
|
|
43
|
-
hidden?: boolean;
|
|
44
|
-
/** i18n key or literal replacing the item's label. */
|
|
45
|
-
label?: string;
|
|
46
|
-
/** Icon component replacing the item's icon. */
|
|
47
|
-
icon?: ComponentType;
|
|
48
|
-
/**
|
|
49
|
-
* Re-parent the item: a built-in parent id moves it under that parent's
|
|
50
|
-
* children; `null` promotes a nested item to the top level.
|
|
51
|
-
*/
|
|
52
|
-
nested?: NavParentId | null;
|
|
53
|
-
}
|
|
54
|
-
interface NavigationConfig {
|
|
55
|
-
items: NavItemOverride[];
|
|
56
|
-
}
|
|
1
|
+
import { h as NavigationConfig, W as WidgetConfig } from './types-BTgTMD_t.js';
|
|
2
|
+
export { B as BuiltMercurConfig, M as MercurConfig, N as NavGroupConfig, a as NavGroupId, b as NavGroupRegistry, c as NavItemId, d as NavItemOverride, e as NavItemRegistry, f as NavParentId, g as NavParentRegistry, P as PERMISSION_RIGHT_RANK, i as Permission, j as PermissionKey, k as PermissionKeys, l as PermissionMap, m as PermissionRight, n as PermissionsContextValue, R as RouteConfig, o as RouteHandle, p as WidgetZoneId, q as WidgetZoneRegistry, r as buildPermission, s as parsePermission, t as satisfiesPermission } from './types-BTgTMD_t.js';
|
|
3
|
+
import { ReactNode, ComponentType } from 'react';
|
|
57
4
|
|
|
58
5
|
/**
|
|
59
6
|
* Minimal structural stand-in for a Zod schema, so the SDK stays free of a zod
|
|
@@ -189,7 +136,7 @@ interface CustomFieldsConfig<TModel extends CustomFieldModel = CustomFieldModel>
|
|
|
189
136
|
}
|
|
190
137
|
|
|
191
138
|
declare function defineWidgetConfig(config: WidgetConfig): WidgetConfig;
|
|
192
|
-
declare function defineNavigationConfig(config: NavigationConfig): NavigationConfig
|
|
139
|
+
declare function defineNavigationConfig<TGroup extends string = never>(config: NavigationConfig<TGroup>): NavigationConfig<TGroup>;
|
|
193
140
|
declare function defineCustomFieldsConfig<TModel extends CustomFieldModel>(config: CustomFieldsConfig<TModel>): CustomFieldsConfig<TModel>;
|
|
194
141
|
|
|
195
|
-
export { type ActivityEntry, type CustomColumn, type CustomDisplayEntry, type CustomDisplayField, type CustomFieldAction, type CustomFieldActionRegistry, type CustomFieldModel, type CustomFieldsConfig, type CustomFieldsRegistry, type CustomFormEntry, type CustomFormField, type CustomFormTab, type CustomFormZone, type CustomListExtension, type FieldValidation,
|
|
142
|
+
export { type ActivityEntry, type CustomColumn, type CustomDisplayEntry, type CustomDisplayField, type CustomFieldAction, type CustomFieldActionRegistry, type CustomFieldModel, type CustomFieldsConfig, type CustomFieldsRegistry, type CustomFormEntry, type CustomFormField, type CustomFormTab, type CustomFormZone, type CustomListExtension, type FieldValidation, NavigationConfig, type SectionAction, WidgetConfig, defineCustomFieldsConfig, defineNavigationConfig, defineWidgetConfig };
|
package/dist/index.js
CHANGED
|
@@ -18,32 +18,38 @@ function defineCustomFieldsConfig(config) {
|
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
// src/permissions.ts
|
|
21
|
-
var
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
delete: ["delete"],
|
|
26
|
-
"*": ["read", "create", "update", "delete", "*"]
|
|
21
|
+
var PERMISSION_RIGHT_RANK = {
|
|
22
|
+
view: 1,
|
|
23
|
+
edit: 2,
|
|
24
|
+
manage: 3
|
|
27
25
|
};
|
|
28
26
|
function parsePermission(permission) {
|
|
29
|
-
const
|
|
30
|
-
if (
|
|
27
|
+
const index = permission.lastIndexOf(":");
|
|
28
|
+
if (index <= 0) {
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
const right = permission.slice(index + 1);
|
|
32
|
+
if (!(right in PERMISSION_RIGHT_RANK)) {
|
|
31
33
|
return null;
|
|
32
34
|
}
|
|
33
|
-
const [resource, operation] = parts;
|
|
34
35
|
return {
|
|
35
|
-
|
|
36
|
-
|
|
36
|
+
key: permission.slice(0, index),
|
|
37
|
+
right
|
|
37
38
|
};
|
|
38
39
|
}
|
|
39
|
-
function buildPermission(
|
|
40
|
-
return `${
|
|
40
|
+
function buildPermission(key, right) {
|
|
41
|
+
return `${key}:${right}`;
|
|
42
|
+
}
|
|
43
|
+
function satisfiesPermission(permissions, key, right) {
|
|
44
|
+
const granted = permissions[key];
|
|
45
|
+
return !!granted && PERMISSION_RIGHT_RANK[granted] >= PERMISSION_RIGHT_RANK[right];
|
|
41
46
|
}
|
|
42
47
|
export {
|
|
43
|
-
|
|
48
|
+
PERMISSION_RIGHT_RANK,
|
|
44
49
|
buildPermission,
|
|
45
50
|
defineCustomFieldsConfig,
|
|
46
51
|
defineNavigationConfig,
|
|
47
52
|
defineWidgetConfig,
|
|
48
|
-
parsePermission
|
|
53
|
+
parsePermission,
|
|
54
|
+
satisfiesPermission
|
|
49
55
|
};
|
|
@@ -0,0 +1,282 @@
|
|
|
1
|
+
import { ComponentType, ReactNode } from 'react';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Permission strings follow `{key}:{right}`, e.g. `orders:view`,
|
|
5
|
+
* `products:edit`, `sellers.approval:edit`.
|
|
6
|
+
*
|
|
7
|
+
* Keys mirror the catalog declared server-side with `defineMercurPermissions`
|
|
8
|
+
* (`packages/core/src/permissions/definitions`). Rights nest:
|
|
9
|
+
* `manage` implies `edit`, `edit` implies `view`.
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* Registry of permission keys. Plugins add their own keys through declaration
|
|
13
|
+
* merging:
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* declare module "@mercurjs/dashboard-sdk" {
|
|
17
|
+
* interface PermissionKeys {
|
|
18
|
+
* messaging: true
|
|
19
|
+
* }
|
|
20
|
+
* }
|
|
21
|
+
*/
|
|
22
|
+
interface PermissionKeys {
|
|
23
|
+
"sellers": true;
|
|
24
|
+
"sellers.approval": true;
|
|
25
|
+
"sellers.premium": true;
|
|
26
|
+
"members": true;
|
|
27
|
+
"members.invites": true;
|
|
28
|
+
"roles": true;
|
|
29
|
+
"roles.owner": true;
|
|
30
|
+
"orders": true;
|
|
31
|
+
"orders.refunds": true;
|
|
32
|
+
"orders.returns": true;
|
|
33
|
+
"orders.edits": true;
|
|
34
|
+
"order_groups": true;
|
|
35
|
+
"payments": true;
|
|
36
|
+
"customers": true;
|
|
37
|
+
"customer_groups": true;
|
|
38
|
+
"products": true;
|
|
39
|
+
"products.review": true;
|
|
40
|
+
"product_changes": true;
|
|
41
|
+
"product_categories": true;
|
|
42
|
+
"product_collections": true;
|
|
43
|
+
"product_types": true;
|
|
44
|
+
"product_tags": true;
|
|
45
|
+
"product_attributes": true;
|
|
46
|
+
"offers": true;
|
|
47
|
+
"inventory_items": true;
|
|
48
|
+
"reservations": true;
|
|
49
|
+
"stock_locations": true;
|
|
50
|
+
"price_lists": true;
|
|
51
|
+
"price_preferences": true;
|
|
52
|
+
"promotions": true;
|
|
53
|
+
"campaigns": true;
|
|
54
|
+
"commission_rates": true;
|
|
55
|
+
"commission_lines": true;
|
|
56
|
+
"payouts": true;
|
|
57
|
+
"payout_accounts": true;
|
|
58
|
+
"shipping_profiles": true;
|
|
59
|
+
"shipping_options": true;
|
|
60
|
+
"fulfillment_sets": true;
|
|
61
|
+
"regions": true;
|
|
62
|
+
"tax_regions": true;
|
|
63
|
+
"store": true;
|
|
64
|
+
"sales_channels": true;
|
|
65
|
+
"return_reasons": true;
|
|
66
|
+
"refund_reasons": true;
|
|
67
|
+
"users": true;
|
|
68
|
+
"api_keys": true;
|
|
69
|
+
"translations": true;
|
|
70
|
+
"notifications": true;
|
|
71
|
+
"workflow_executions": true;
|
|
72
|
+
"reviews": true;
|
|
73
|
+
}
|
|
74
|
+
type PermissionKey = Extract<keyof PermissionKeys, string>;
|
|
75
|
+
type PermissionRight = "view" | "edit" | "manage";
|
|
76
|
+
type Permission = `${PermissionKey}:${PermissionRight}`;
|
|
77
|
+
/** Effective rights of the acting user, as returned by `fields=+permissions`. */
|
|
78
|
+
type PermissionMap = Partial<Record<string, PermissionRight>>;
|
|
79
|
+
declare const PERMISSION_RIGHT_RANK: Record<PermissionRight, number>;
|
|
80
|
+
interface PermissionsContextValue {
|
|
81
|
+
/** `null` while no access-control module is enforcing permissions. */
|
|
82
|
+
permissions: PermissionMap | null;
|
|
83
|
+
isLoading: boolean;
|
|
84
|
+
/** When `false`, every check resolves to `true`. */
|
|
85
|
+
isEnforced: boolean;
|
|
86
|
+
hasPermission: (permission: Permission) => boolean;
|
|
87
|
+
hasAnyPermission: (permissions: Permission[]) => boolean;
|
|
88
|
+
hasAllPermissions: (permissions: Permission[]) => boolean;
|
|
89
|
+
can: (key: PermissionKey, right?: PermissionRight) => boolean;
|
|
90
|
+
}
|
|
91
|
+
declare function parsePermission(permission: string): {
|
|
92
|
+
key: PermissionKey;
|
|
93
|
+
right: PermissionRight;
|
|
94
|
+
} | null;
|
|
95
|
+
declare function buildPermission(key: PermissionKey, right: PermissionRight): Permission;
|
|
96
|
+
declare function satisfiesPermission(permissions: PermissionMap, key: string, right: PermissionRight): boolean;
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Open registry interfaces. Each panel package ships a generated
|
|
100
|
+
* `extension-targets.d.ts` that seeds the built-in ids into these interfaces
|
|
101
|
+
* (declaration merging), and a developer augments them by hand to register a
|
|
102
|
+
* zone their own page renders. The helper unions read off the interface keys.
|
|
103
|
+
*
|
|
104
|
+
* @example
|
|
105
|
+
* declare module "@mercurjs/dashboard-sdk" {
|
|
106
|
+
* interface WidgetZoneRegistry {
|
|
107
|
+
* "erp.dashboard.before": true
|
|
108
|
+
* }
|
|
109
|
+
* }
|
|
110
|
+
*/
|
|
111
|
+
interface WidgetZoneRegistry {
|
|
112
|
+
}
|
|
113
|
+
interface NavItemRegistry {
|
|
114
|
+
}
|
|
115
|
+
interface NavParentRegistry {
|
|
116
|
+
}
|
|
117
|
+
interface NavGroupRegistry {
|
|
118
|
+
}
|
|
119
|
+
type WidgetZoneId = keyof WidgetZoneRegistry extends never ? string : keyof WidgetZoneRegistry;
|
|
120
|
+
type NavItemId = keyof NavItemRegistry extends never ? string : keyof NavItemRegistry;
|
|
121
|
+
type NavParentId = keyof NavParentRegistry extends never ? string : keyof NavParentRegistry;
|
|
122
|
+
type NavGroupId = keyof NavGroupRegistry extends never ? string : keyof NavGroupRegistry;
|
|
123
|
+
/**
|
|
124
|
+
* A widget is a React component attached to a named zone on a page. The
|
|
125
|
+
* placement (`before | after`) is encoded as the zone-id suffix, so there is no
|
|
126
|
+
* separate rank field — multiple `before`/`after` widgets stack in registration
|
|
127
|
+
* order.
|
|
128
|
+
*/
|
|
129
|
+
interface WidgetConfig {
|
|
130
|
+
zone: WidgetZoneId | WidgetZoneId[];
|
|
131
|
+
/** Stable id; derived from the file path at build time when omitted. */
|
|
132
|
+
id?: string;
|
|
133
|
+
/**
|
|
134
|
+
* Permission(s) the actor needs for the widget to render. With several, any
|
|
135
|
+
* one is enough.
|
|
136
|
+
*/
|
|
137
|
+
permission?: Permission | Permission[];
|
|
138
|
+
/**
|
|
139
|
+
* i18n key or literal naming the tab. Required for a `*.tabs.*` zone, where
|
|
140
|
+
* the widget renders as a tab's panel; ignored elsewhere.
|
|
141
|
+
*/
|
|
142
|
+
label?: string;
|
|
143
|
+
}
|
|
144
|
+
/** Override for a single built-in navigation item. */
|
|
145
|
+
interface NavItemOverride<TGroup extends string = never> {
|
|
146
|
+
id: NavItemId;
|
|
147
|
+
/** Order within the item's parent (or among top-level items). */
|
|
148
|
+
rank?: number;
|
|
149
|
+
/** Remove from the sidebar (route may still be reachable directly). */
|
|
150
|
+
hidden?: boolean;
|
|
151
|
+
/** i18n key or literal replacing the item's label. */
|
|
152
|
+
label?: string;
|
|
153
|
+
/** Icon component replacing the item's icon. */
|
|
154
|
+
icon?: ComponentType;
|
|
155
|
+
/**
|
|
156
|
+
* Re-parent the item: a built-in parent id moves it under that parent's
|
|
157
|
+
* children; `null` promotes a nested item to the top level.
|
|
158
|
+
*/
|
|
159
|
+
nested?: NavParentId | null;
|
|
160
|
+
/**
|
|
161
|
+
* List the item under a group heading: a built-in settings group id or one
|
|
162
|
+
* declared in `groups`. Main sidebar items only join declared groups.
|
|
163
|
+
*/
|
|
164
|
+
group?: NavGroupId | TGroup;
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Declares a sidebar group, or overrides a built-in settings group by id. A
|
|
168
|
+
* group renders in whichever sidebar its items live in.
|
|
169
|
+
*/
|
|
170
|
+
interface NavGroupConfig<TId extends string = string> {
|
|
171
|
+
id: NavGroupId | TId;
|
|
172
|
+
/** i18n key (with `translationNs`) or literal. Falls back to the id. */
|
|
173
|
+
label?: string;
|
|
174
|
+
translationNs?: string;
|
|
175
|
+
/** Order among groups, lower first. Built-in settings groups rank 0, 1, 2… */
|
|
176
|
+
rank?: number;
|
|
177
|
+
/** Remove the group and its items from the sidebar. */
|
|
178
|
+
hidden?: boolean;
|
|
179
|
+
}
|
|
180
|
+
interface NavigationConfig<TGroup extends string = never> {
|
|
181
|
+
groups?: NavGroupConfig<TGroup>[];
|
|
182
|
+
items?: NavItemOverride<NoInfer<TGroup>>[];
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Configuration for the Mercur dashboard plugin.
|
|
187
|
+
*
|
|
188
|
+
* Passed to `mercurDashboardPlugin()` in `vite.config.ts` to configure
|
|
189
|
+
* the vendor or admin dashboard at build time.
|
|
190
|
+
*
|
|
191
|
+
* @example
|
|
192
|
+
* ```ts
|
|
193
|
+
* mercurDashboardPlugin({
|
|
194
|
+
* medusaConfigPath: '../../packages/api/medusa-config.ts',
|
|
195
|
+
* enableSellerRegistration: true,
|
|
196
|
+
* })
|
|
197
|
+
* ```
|
|
198
|
+
*/
|
|
199
|
+
interface MercurConfig {
|
|
200
|
+
/** Path to the MedusaJS config file, resolved relative to the project root. */
|
|
201
|
+
medusaConfigPath: string;
|
|
202
|
+
/**
|
|
203
|
+
* Backend URL for API requests.
|
|
204
|
+
* @default "http://localhost:9000"
|
|
205
|
+
*/
|
|
206
|
+
backendUrl?: string;
|
|
207
|
+
/**
|
|
208
|
+
* Absolute base URL for the vendor dashboard, including any path prefix
|
|
209
|
+
* (for example `https://vendors.example.com/seller`).
|
|
210
|
+
*
|
|
211
|
+
* The plugin does not read `.env` files on its own. Load env in your
|
|
212
|
+
* app's `vite.config.ts` and pass the value here when you need
|
|
213
|
+
* cross-origin links such as seller invite URLs.
|
|
214
|
+
*
|
|
215
|
+
* If omitted, the plugin falls back to vendor module dev server
|
|
216
|
+
* detection in development and to the configured vendor path in
|
|
217
|
+
* production.
|
|
218
|
+
*/
|
|
219
|
+
vendorUrl?: string;
|
|
220
|
+
/** Dashboard display name. */
|
|
221
|
+
name?: string;
|
|
222
|
+
/** Path to a logo asset for the dashboard. */
|
|
223
|
+
logo?: string;
|
|
224
|
+
/** Internationalization settings. */
|
|
225
|
+
i18n?: {
|
|
226
|
+
/** The default language code (e.g. `"en"`). */
|
|
227
|
+
defaultLanguage: string;
|
|
228
|
+
};
|
|
229
|
+
/** Whether to allow new sellers to register from the login screen. */
|
|
230
|
+
enableSellerRegistration?: boolean;
|
|
231
|
+
/**
|
|
232
|
+
* Maximum allowed size for image uploads, in bytes.
|
|
233
|
+
* Used by dashboard upload components to reject oversized files
|
|
234
|
+
* before they are sent to the backend.
|
|
235
|
+
* @default 2_097_152 // 2 MB
|
|
236
|
+
*/
|
|
237
|
+
imageLimit?: number;
|
|
238
|
+
}
|
|
239
|
+
interface BuiltMercurConfig extends MercurConfig {
|
|
240
|
+
backendUrl: string;
|
|
241
|
+
base?: string;
|
|
242
|
+
root: string;
|
|
243
|
+
srcDir: string;
|
|
244
|
+
pluginExtensions: string[];
|
|
245
|
+
imageLimit: number;
|
|
246
|
+
}
|
|
247
|
+
type RouteConfig = {
|
|
248
|
+
label: string;
|
|
249
|
+
icon?: ComponentType;
|
|
250
|
+
rank?: number;
|
|
251
|
+
nested?: string;
|
|
252
|
+
/**
|
|
253
|
+
* Sidebar group to list the route under: one declared in `_navigation.ts`
|
|
254
|
+
* or, for a `/settings/*` route, a built-in settings group. Must be a
|
|
255
|
+
* string literal.
|
|
256
|
+
*/
|
|
257
|
+
group?: NavGroupId | (string & {});
|
|
258
|
+
translationNs?: string;
|
|
259
|
+
public?: boolean;
|
|
260
|
+
/**
|
|
261
|
+
* Permissions the actor must hold for this route's sidebar entry to be
|
|
262
|
+
* shown. Enforcement of the route itself comes from `handle.permissions`
|
|
263
|
+
* — this only controls navigation visibility.
|
|
264
|
+
*/
|
|
265
|
+
permissions?: Permission[];
|
|
266
|
+
/** If true, ALL `permissions` are required. Defaults to ANY. */
|
|
267
|
+
requireAll?: boolean;
|
|
268
|
+
};
|
|
269
|
+
/**
|
|
270
|
+
* The value of a route module's `export const handle`. Read by react-router's
|
|
271
|
+
* `useMatches()`; `permissions` is enforced by `RoutePermissionGuard`.
|
|
272
|
+
*/
|
|
273
|
+
type RouteHandle = {
|
|
274
|
+
permissions?: Permission | Permission[];
|
|
275
|
+
/** If true (default at the route level), ALL permissions are required. */
|
|
276
|
+
requireAll?: boolean;
|
|
277
|
+
/** Where to send the actor on denial. Renders Access Denied when unset. */
|
|
278
|
+
redirectTo?: string;
|
|
279
|
+
breadcrumb?: (match: never) => ReactNode;
|
|
280
|
+
};
|
|
281
|
+
|
|
282
|
+
export { type BuiltMercurConfig as B, type MercurConfig as M, type NavGroupConfig as N, PERMISSION_RIGHT_RANK as P, type RouteConfig as R, type WidgetConfig as W, type NavGroupId as a, type NavGroupRegistry as b, type NavItemId as c, type NavItemOverride as d, type NavItemRegistry as e, type NavParentId as f, type NavParentRegistry as g, type NavigationConfig as h, type Permission as i, type PermissionKey as j, type PermissionKeys as k, type PermissionMap as l, type PermissionRight as m, type PermissionsContextValue as n, type RouteHandle as o, type WidgetZoneId as p, type WidgetZoneRegistry as q, buildPermission as r, parsePermission as s, satisfiesPermission as t };
|
|
@@ -0,0 +1,282 @@
|
|
|
1
|
+
import { ComponentType, ReactNode } from 'react';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Permission strings follow `{key}:{right}`, e.g. `orders:view`,
|
|
5
|
+
* `products:edit`, `sellers.approval:edit`.
|
|
6
|
+
*
|
|
7
|
+
* Keys mirror the catalog declared server-side with `defineMercurPermissions`
|
|
8
|
+
* (`packages/core/src/permissions/definitions`). Rights nest:
|
|
9
|
+
* `manage` implies `edit`, `edit` implies `view`.
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* Registry of permission keys. Plugins add their own keys through declaration
|
|
13
|
+
* merging:
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* declare module "@mercurjs/dashboard-sdk" {
|
|
17
|
+
* interface PermissionKeys {
|
|
18
|
+
* messaging: true
|
|
19
|
+
* }
|
|
20
|
+
* }
|
|
21
|
+
*/
|
|
22
|
+
interface PermissionKeys {
|
|
23
|
+
"sellers": true;
|
|
24
|
+
"sellers.approval": true;
|
|
25
|
+
"sellers.premium": true;
|
|
26
|
+
"members": true;
|
|
27
|
+
"members.invites": true;
|
|
28
|
+
"roles": true;
|
|
29
|
+
"roles.owner": true;
|
|
30
|
+
"orders": true;
|
|
31
|
+
"orders.refunds": true;
|
|
32
|
+
"orders.returns": true;
|
|
33
|
+
"orders.edits": true;
|
|
34
|
+
"order_groups": true;
|
|
35
|
+
"payments": true;
|
|
36
|
+
"customers": true;
|
|
37
|
+
"customer_groups": true;
|
|
38
|
+
"products": true;
|
|
39
|
+
"products.review": true;
|
|
40
|
+
"product_changes": true;
|
|
41
|
+
"product_categories": true;
|
|
42
|
+
"product_collections": true;
|
|
43
|
+
"product_types": true;
|
|
44
|
+
"product_tags": true;
|
|
45
|
+
"product_attributes": true;
|
|
46
|
+
"offers": true;
|
|
47
|
+
"inventory_items": true;
|
|
48
|
+
"reservations": true;
|
|
49
|
+
"stock_locations": true;
|
|
50
|
+
"price_lists": true;
|
|
51
|
+
"price_preferences": true;
|
|
52
|
+
"promotions": true;
|
|
53
|
+
"campaigns": true;
|
|
54
|
+
"commission_rates": true;
|
|
55
|
+
"commission_lines": true;
|
|
56
|
+
"payouts": true;
|
|
57
|
+
"payout_accounts": true;
|
|
58
|
+
"shipping_profiles": true;
|
|
59
|
+
"shipping_options": true;
|
|
60
|
+
"fulfillment_sets": true;
|
|
61
|
+
"regions": true;
|
|
62
|
+
"tax_regions": true;
|
|
63
|
+
"store": true;
|
|
64
|
+
"sales_channels": true;
|
|
65
|
+
"return_reasons": true;
|
|
66
|
+
"refund_reasons": true;
|
|
67
|
+
"users": true;
|
|
68
|
+
"api_keys": true;
|
|
69
|
+
"translations": true;
|
|
70
|
+
"notifications": true;
|
|
71
|
+
"workflow_executions": true;
|
|
72
|
+
"reviews": true;
|
|
73
|
+
}
|
|
74
|
+
type PermissionKey = Extract<keyof PermissionKeys, string>;
|
|
75
|
+
type PermissionRight = "view" | "edit" | "manage";
|
|
76
|
+
type Permission = `${PermissionKey}:${PermissionRight}`;
|
|
77
|
+
/** Effective rights of the acting user, as returned by `fields=+permissions`. */
|
|
78
|
+
type PermissionMap = Partial<Record<string, PermissionRight>>;
|
|
79
|
+
declare const PERMISSION_RIGHT_RANK: Record<PermissionRight, number>;
|
|
80
|
+
interface PermissionsContextValue {
|
|
81
|
+
/** `null` while no access-control module is enforcing permissions. */
|
|
82
|
+
permissions: PermissionMap | null;
|
|
83
|
+
isLoading: boolean;
|
|
84
|
+
/** When `false`, every check resolves to `true`. */
|
|
85
|
+
isEnforced: boolean;
|
|
86
|
+
hasPermission: (permission: Permission) => boolean;
|
|
87
|
+
hasAnyPermission: (permissions: Permission[]) => boolean;
|
|
88
|
+
hasAllPermissions: (permissions: Permission[]) => boolean;
|
|
89
|
+
can: (key: PermissionKey, right?: PermissionRight) => boolean;
|
|
90
|
+
}
|
|
91
|
+
declare function parsePermission(permission: string): {
|
|
92
|
+
key: PermissionKey;
|
|
93
|
+
right: PermissionRight;
|
|
94
|
+
} | null;
|
|
95
|
+
declare function buildPermission(key: PermissionKey, right: PermissionRight): Permission;
|
|
96
|
+
declare function satisfiesPermission(permissions: PermissionMap, key: string, right: PermissionRight): boolean;
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Open registry interfaces. Each panel package ships a generated
|
|
100
|
+
* `extension-targets.d.ts` that seeds the built-in ids into these interfaces
|
|
101
|
+
* (declaration merging), and a developer augments them by hand to register a
|
|
102
|
+
* zone their own page renders. The helper unions read off the interface keys.
|
|
103
|
+
*
|
|
104
|
+
* @example
|
|
105
|
+
* declare module "@mercurjs/dashboard-sdk" {
|
|
106
|
+
* interface WidgetZoneRegistry {
|
|
107
|
+
* "erp.dashboard.before": true
|
|
108
|
+
* }
|
|
109
|
+
* }
|
|
110
|
+
*/
|
|
111
|
+
interface WidgetZoneRegistry {
|
|
112
|
+
}
|
|
113
|
+
interface NavItemRegistry {
|
|
114
|
+
}
|
|
115
|
+
interface NavParentRegistry {
|
|
116
|
+
}
|
|
117
|
+
interface NavGroupRegistry {
|
|
118
|
+
}
|
|
119
|
+
type WidgetZoneId = keyof WidgetZoneRegistry extends never ? string : keyof WidgetZoneRegistry;
|
|
120
|
+
type NavItemId = keyof NavItemRegistry extends never ? string : keyof NavItemRegistry;
|
|
121
|
+
type NavParentId = keyof NavParentRegistry extends never ? string : keyof NavParentRegistry;
|
|
122
|
+
type NavGroupId = keyof NavGroupRegistry extends never ? string : keyof NavGroupRegistry;
|
|
123
|
+
/**
|
|
124
|
+
* A widget is a React component attached to a named zone on a page. The
|
|
125
|
+
* placement (`before | after`) is encoded as the zone-id suffix, so there is no
|
|
126
|
+
* separate rank field — multiple `before`/`after` widgets stack in registration
|
|
127
|
+
* order.
|
|
128
|
+
*/
|
|
129
|
+
interface WidgetConfig {
|
|
130
|
+
zone: WidgetZoneId | WidgetZoneId[];
|
|
131
|
+
/** Stable id; derived from the file path at build time when omitted. */
|
|
132
|
+
id?: string;
|
|
133
|
+
/**
|
|
134
|
+
* Permission(s) the actor needs for the widget to render. With several, any
|
|
135
|
+
* one is enough.
|
|
136
|
+
*/
|
|
137
|
+
permission?: Permission | Permission[];
|
|
138
|
+
/**
|
|
139
|
+
* i18n key or literal naming the tab. Required for a `*.tabs.*` zone, where
|
|
140
|
+
* the widget renders as a tab's panel; ignored elsewhere.
|
|
141
|
+
*/
|
|
142
|
+
label?: string;
|
|
143
|
+
}
|
|
144
|
+
/** Override for a single built-in navigation item. */
|
|
145
|
+
interface NavItemOverride<TGroup extends string = never> {
|
|
146
|
+
id: NavItemId;
|
|
147
|
+
/** Order within the item's parent (or among top-level items). */
|
|
148
|
+
rank?: number;
|
|
149
|
+
/** Remove from the sidebar (route may still be reachable directly). */
|
|
150
|
+
hidden?: boolean;
|
|
151
|
+
/** i18n key or literal replacing the item's label. */
|
|
152
|
+
label?: string;
|
|
153
|
+
/** Icon component replacing the item's icon. */
|
|
154
|
+
icon?: ComponentType;
|
|
155
|
+
/**
|
|
156
|
+
* Re-parent the item: a built-in parent id moves it under that parent's
|
|
157
|
+
* children; `null` promotes a nested item to the top level.
|
|
158
|
+
*/
|
|
159
|
+
nested?: NavParentId | null;
|
|
160
|
+
/**
|
|
161
|
+
* List the item under a group heading: a built-in settings group id or one
|
|
162
|
+
* declared in `groups`. Main sidebar items only join declared groups.
|
|
163
|
+
*/
|
|
164
|
+
group?: NavGroupId | TGroup;
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Declares a sidebar group, or overrides a built-in settings group by id. A
|
|
168
|
+
* group renders in whichever sidebar its items live in.
|
|
169
|
+
*/
|
|
170
|
+
interface NavGroupConfig<TId extends string = string> {
|
|
171
|
+
id: NavGroupId | TId;
|
|
172
|
+
/** i18n key (with `translationNs`) or literal. Falls back to the id. */
|
|
173
|
+
label?: string;
|
|
174
|
+
translationNs?: string;
|
|
175
|
+
/** Order among groups, lower first. Built-in settings groups rank 0, 1, 2… */
|
|
176
|
+
rank?: number;
|
|
177
|
+
/** Remove the group and its items from the sidebar. */
|
|
178
|
+
hidden?: boolean;
|
|
179
|
+
}
|
|
180
|
+
interface NavigationConfig<TGroup extends string = never> {
|
|
181
|
+
groups?: NavGroupConfig<TGroup>[];
|
|
182
|
+
items?: NavItemOverride<NoInfer<TGroup>>[];
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Configuration for the Mercur dashboard plugin.
|
|
187
|
+
*
|
|
188
|
+
* Passed to `mercurDashboardPlugin()` in `vite.config.ts` to configure
|
|
189
|
+
* the vendor or admin dashboard at build time.
|
|
190
|
+
*
|
|
191
|
+
* @example
|
|
192
|
+
* ```ts
|
|
193
|
+
* mercurDashboardPlugin({
|
|
194
|
+
* medusaConfigPath: '../../packages/api/medusa-config.ts',
|
|
195
|
+
* enableSellerRegistration: true,
|
|
196
|
+
* })
|
|
197
|
+
* ```
|
|
198
|
+
*/
|
|
199
|
+
interface MercurConfig {
|
|
200
|
+
/** Path to the MedusaJS config file, resolved relative to the project root. */
|
|
201
|
+
medusaConfigPath: string;
|
|
202
|
+
/**
|
|
203
|
+
* Backend URL for API requests.
|
|
204
|
+
* @default "http://localhost:9000"
|
|
205
|
+
*/
|
|
206
|
+
backendUrl?: string;
|
|
207
|
+
/**
|
|
208
|
+
* Absolute base URL for the vendor dashboard, including any path prefix
|
|
209
|
+
* (for example `https://vendors.example.com/seller`).
|
|
210
|
+
*
|
|
211
|
+
* The plugin does not read `.env` files on its own. Load env in your
|
|
212
|
+
* app's `vite.config.ts` and pass the value here when you need
|
|
213
|
+
* cross-origin links such as seller invite URLs.
|
|
214
|
+
*
|
|
215
|
+
* If omitted, the plugin falls back to vendor module dev server
|
|
216
|
+
* detection in development and to the configured vendor path in
|
|
217
|
+
* production.
|
|
218
|
+
*/
|
|
219
|
+
vendorUrl?: string;
|
|
220
|
+
/** Dashboard display name. */
|
|
221
|
+
name?: string;
|
|
222
|
+
/** Path to a logo asset for the dashboard. */
|
|
223
|
+
logo?: string;
|
|
224
|
+
/** Internationalization settings. */
|
|
225
|
+
i18n?: {
|
|
226
|
+
/** The default language code (e.g. `"en"`). */
|
|
227
|
+
defaultLanguage: string;
|
|
228
|
+
};
|
|
229
|
+
/** Whether to allow new sellers to register from the login screen. */
|
|
230
|
+
enableSellerRegistration?: boolean;
|
|
231
|
+
/**
|
|
232
|
+
* Maximum allowed size for image uploads, in bytes.
|
|
233
|
+
* Used by dashboard upload components to reject oversized files
|
|
234
|
+
* before they are sent to the backend.
|
|
235
|
+
* @default 2_097_152 // 2 MB
|
|
236
|
+
*/
|
|
237
|
+
imageLimit?: number;
|
|
238
|
+
}
|
|
239
|
+
interface BuiltMercurConfig extends MercurConfig {
|
|
240
|
+
backendUrl: string;
|
|
241
|
+
base?: string;
|
|
242
|
+
root: string;
|
|
243
|
+
srcDir: string;
|
|
244
|
+
pluginExtensions: string[];
|
|
245
|
+
imageLimit: number;
|
|
246
|
+
}
|
|
247
|
+
type RouteConfig = {
|
|
248
|
+
label: string;
|
|
249
|
+
icon?: ComponentType;
|
|
250
|
+
rank?: number;
|
|
251
|
+
nested?: string;
|
|
252
|
+
/**
|
|
253
|
+
* Sidebar group to list the route under: one declared in `_navigation.ts`
|
|
254
|
+
* or, for a `/settings/*` route, a built-in settings group. Must be a
|
|
255
|
+
* string literal.
|
|
256
|
+
*/
|
|
257
|
+
group?: NavGroupId | (string & {});
|
|
258
|
+
translationNs?: string;
|
|
259
|
+
public?: boolean;
|
|
260
|
+
/**
|
|
261
|
+
* Permissions the actor must hold for this route's sidebar entry to be
|
|
262
|
+
* shown. Enforcement of the route itself comes from `handle.permissions`
|
|
263
|
+
* — this only controls navigation visibility.
|
|
264
|
+
*/
|
|
265
|
+
permissions?: Permission[];
|
|
266
|
+
/** If true, ALL `permissions` are required. Defaults to ANY. */
|
|
267
|
+
requireAll?: boolean;
|
|
268
|
+
};
|
|
269
|
+
/**
|
|
270
|
+
* The value of a route module's `export const handle`. Read by react-router's
|
|
271
|
+
* `useMatches()`; `permissions` is enforced by `RoutePermissionGuard`.
|
|
272
|
+
*/
|
|
273
|
+
type RouteHandle = {
|
|
274
|
+
permissions?: Permission | Permission[];
|
|
275
|
+
/** If true (default at the route level), ALL permissions are required. */
|
|
276
|
+
requireAll?: boolean;
|
|
277
|
+
/** Where to send the actor on denial. Renders Access Denied when unset. */
|
|
278
|
+
redirectTo?: string;
|
|
279
|
+
breadcrumb?: (match: never) => ReactNode;
|
|
280
|
+
};
|
|
281
|
+
|
|
282
|
+
export { type BuiltMercurConfig as B, type MercurConfig as M, type NavGroupConfig as N, PERMISSION_RIGHT_RANK as P, type RouteConfig as R, type WidgetConfig as W, type NavGroupId as a, type NavGroupRegistry as b, type NavItemId as c, type NavItemOverride as d, type NavItemRegistry as e, type NavParentId as f, type NavParentRegistry as g, type NavigationConfig as h, type Permission as i, type PermissionKey as j, type PermissionKeys as k, type PermissionMap as l, type PermissionRight as m, type PermissionsContextValue as n, type RouteHandle as o, type WidgetZoneId as p, type WidgetZoneRegistry as q, buildPermission as r, parsePermission as s, satisfiesPermission as t };
|
package/dist/vite.cjs
CHANGED
|
@@ -464,6 +464,13 @@ function processConfigProperties(properties) {
|
|
|
464
464
|
if (nested && (0, import_types.isObjectProperty)(nested) && (0, import_types.isStringLiteral)(nested.value)) {
|
|
465
465
|
nestedValue = nested.value.value;
|
|
466
466
|
}
|
|
467
|
+
const group = properties.find(
|
|
468
|
+
(prop) => (0, import_types.isObjectProperty)(prop) && (0, import_types.isIdentifier)(prop.key, { name: "group" })
|
|
469
|
+
);
|
|
470
|
+
let groupValue;
|
|
471
|
+
if (group && (0, import_types.isObjectProperty)(group) && (0, import_types.isStringLiteral)(group.value)) {
|
|
472
|
+
groupValue = group.value.value;
|
|
473
|
+
}
|
|
467
474
|
const translationNs = properties.find(
|
|
468
475
|
(prop) => (0, import_types.isObjectProperty)(prop) && (0, import_types.isIdentifier)(prop.key, { name: "translationNs" })
|
|
469
476
|
);
|
|
@@ -490,6 +497,7 @@ function processConfigProperties(properties) {
|
|
|
490
497
|
icon: hasIcon,
|
|
491
498
|
rank: rankValue,
|
|
492
499
|
nested: nestedValue,
|
|
500
|
+
group: groupValue,
|
|
493
501
|
translationNs: translationNsValue,
|
|
494
502
|
// Referenced by identifier at runtime rather than extracted here, so
|
|
495
503
|
// the array may be computed instead of a string-literal list.
|
|
@@ -539,6 +547,7 @@ function generateMenuItem(config, file, routesDir, index) {
|
|
|
539
547
|
path: getRoute2(file, routesDir),
|
|
540
548
|
rank: config.rank,
|
|
541
549
|
nested: config.nested,
|
|
550
|
+
group: config.group,
|
|
542
551
|
translationNs: config.translationNs ? `${configName}.translationNs` : void 0,
|
|
543
552
|
permissions: config.permissions ? `${configName}.permissions` : void 0,
|
|
544
553
|
requireAll: config.requireAll
|
|
@@ -551,6 +560,7 @@ function formatMenuItem(menuItem) {
|
|
|
551
560
|
` path: "${menuItem.path}"`,
|
|
552
561
|
` rank: ${menuItem.rank !== void 0 ? menuItem.rank : "undefined"}`,
|
|
553
562
|
` nested: ${menuItem.nested ? `"${menuItem.nested}"` : "undefined"}`,
|
|
563
|
+
` group: ${menuItem.group ? JSON.stringify(menuItem.group) : "undefined"}`,
|
|
554
564
|
` translationNs: ${menuItem.translationNs || "undefined"}`,
|
|
555
565
|
` permissions: ${menuItem.permissions || "undefined"}`,
|
|
556
566
|
` requireAll: ${menuItem.requireAll !== void 0 ? menuItem.requireAll : "undefined"}`
|
|
@@ -665,7 +675,7 @@ export default [${sources.join(", ")}].reduce(mergeResources, {})
|
|
|
665
675
|
// src/widgets.ts
|
|
666
676
|
var import_fs5 = __toESM(require("fs"), 1);
|
|
667
677
|
var import_path5 = __toESM(require("path"), 1);
|
|
668
|
-
function
|
|
678
|
+
function extractStrings(value, zones) {
|
|
669
679
|
if ((0, import_types.isStringLiteral)(value)) {
|
|
670
680
|
zones.push(value.value);
|
|
671
681
|
} else if ((0, import_types.isArrayExpression)(value)) {
|
|
@@ -676,18 +686,26 @@ function extractZones(value, zones) {
|
|
|
676
686
|
}
|
|
677
687
|
function readWidgetConfig(properties) {
|
|
678
688
|
const zones = [];
|
|
689
|
+
const permissions = [];
|
|
679
690
|
let id;
|
|
691
|
+
let label;
|
|
680
692
|
for (const prop of properties) {
|
|
681
693
|
if (!(0, import_types.isObjectProperty)(prop)) continue;
|
|
682
694
|
if ((0, import_types.isIdentifier)(prop.key, { name: "zone" })) {
|
|
683
|
-
|
|
695
|
+
extractStrings(prop.value, zones);
|
|
696
|
+
}
|
|
697
|
+
if ((0, import_types.isIdentifier)(prop.key, { name: "permission" })) {
|
|
698
|
+
extractStrings(prop.value, permissions);
|
|
684
699
|
}
|
|
685
700
|
if ((0, import_types.isIdentifier)(prop.key, { name: "id" }) && (0, import_types.isStringLiteral)(prop.value)) {
|
|
686
701
|
id = prop.value.value;
|
|
687
702
|
}
|
|
703
|
+
if ((0, import_types.isIdentifier)(prop.key, { name: "label" }) && (0, import_types.isStringLiteral)(prop.value)) {
|
|
704
|
+
label = prop.value.value;
|
|
705
|
+
}
|
|
688
706
|
}
|
|
689
707
|
if (zones.length === 0) return null;
|
|
690
|
-
return { zones, id };
|
|
708
|
+
return { zones, id, label, permissions };
|
|
691
709
|
}
|
|
692
710
|
function getConfigProperties(node) {
|
|
693
711
|
if ((0, import_types.isCallExpression)(node) && node.arguments.length > 0 && (0, import_types.isObjectExpression)(node.arguments[0])) {
|
|
@@ -751,7 +769,7 @@ function parseWidgetFile(file, widgetsDir, index) {
|
|
|
751
769
|
import: `import ${name} from "${importPath}"`,
|
|
752
770
|
entry: ` { Component: ${name}, zone: ${zonesLiteral}, widgetId: ${JSON.stringify(
|
|
753
771
|
id
|
|
754
|
-
)} }`
|
|
772
|
+
)}${info.label ? `, label: ${JSON.stringify(info.label)}` : ""}${info.permissions.length ? `, permission: ${JSON.stringify(info.permissions)}` : ""} }`
|
|
755
773
|
};
|
|
756
774
|
}
|
|
757
775
|
function collectWidgets(srcDir, startIndex = 0) {
|
package/dist/vite.d.cts
CHANGED
package/dist/vite.d.ts
CHANGED
package/dist/vite.js
CHANGED
|
@@ -444,6 +444,13 @@ function processConfigProperties(properties) {
|
|
|
444
444
|
if (nested && isObjectProperty(nested) && isStringLiteral(nested.value)) {
|
|
445
445
|
nestedValue = nested.value.value;
|
|
446
446
|
}
|
|
447
|
+
const group = properties.find(
|
|
448
|
+
(prop) => isObjectProperty(prop) && isIdentifier(prop.key, { name: "group" })
|
|
449
|
+
);
|
|
450
|
+
let groupValue;
|
|
451
|
+
if (group && isObjectProperty(group) && isStringLiteral(group.value)) {
|
|
452
|
+
groupValue = group.value.value;
|
|
453
|
+
}
|
|
447
454
|
const translationNs = properties.find(
|
|
448
455
|
(prop) => isObjectProperty(prop) && isIdentifier(prop.key, { name: "translationNs" })
|
|
449
456
|
);
|
|
@@ -470,6 +477,7 @@ function processConfigProperties(properties) {
|
|
|
470
477
|
icon: hasIcon,
|
|
471
478
|
rank: rankValue,
|
|
472
479
|
nested: nestedValue,
|
|
480
|
+
group: groupValue,
|
|
473
481
|
translationNs: translationNsValue,
|
|
474
482
|
// Referenced by identifier at runtime rather than extracted here, so
|
|
475
483
|
// the array may be computed instead of a string-literal list.
|
|
@@ -519,6 +527,7 @@ function generateMenuItem(config, file, routesDir, index) {
|
|
|
519
527
|
path: getRoute2(file, routesDir),
|
|
520
528
|
rank: config.rank,
|
|
521
529
|
nested: config.nested,
|
|
530
|
+
group: config.group,
|
|
522
531
|
translationNs: config.translationNs ? `${configName}.translationNs` : void 0,
|
|
523
532
|
permissions: config.permissions ? `${configName}.permissions` : void 0,
|
|
524
533
|
requireAll: config.requireAll
|
|
@@ -531,6 +540,7 @@ function formatMenuItem(menuItem) {
|
|
|
531
540
|
` path: "${menuItem.path}"`,
|
|
532
541
|
` rank: ${menuItem.rank !== void 0 ? menuItem.rank : "undefined"}`,
|
|
533
542
|
` nested: ${menuItem.nested ? `"${menuItem.nested}"` : "undefined"}`,
|
|
543
|
+
` group: ${menuItem.group ? JSON.stringify(menuItem.group) : "undefined"}`,
|
|
534
544
|
` translationNs: ${menuItem.translationNs || "undefined"}`,
|
|
535
545
|
` permissions: ${menuItem.permissions || "undefined"}`,
|
|
536
546
|
` requireAll: ${menuItem.requireAll !== void 0 ? menuItem.requireAll : "undefined"}`
|
|
@@ -645,7 +655,7 @@ export default [${sources.join(", ")}].reduce(mergeResources, {})
|
|
|
645
655
|
// src/widgets.ts
|
|
646
656
|
import fs5 from "fs";
|
|
647
657
|
import path5 from "path";
|
|
648
|
-
function
|
|
658
|
+
function extractStrings(value, zones) {
|
|
649
659
|
if (isStringLiteral(value)) {
|
|
650
660
|
zones.push(value.value);
|
|
651
661
|
} else if (isArrayExpression(value)) {
|
|
@@ -656,18 +666,26 @@ function extractZones(value, zones) {
|
|
|
656
666
|
}
|
|
657
667
|
function readWidgetConfig(properties) {
|
|
658
668
|
const zones = [];
|
|
669
|
+
const permissions = [];
|
|
659
670
|
let id;
|
|
671
|
+
let label;
|
|
660
672
|
for (const prop of properties) {
|
|
661
673
|
if (!isObjectProperty(prop)) continue;
|
|
662
674
|
if (isIdentifier(prop.key, { name: "zone" })) {
|
|
663
|
-
|
|
675
|
+
extractStrings(prop.value, zones);
|
|
676
|
+
}
|
|
677
|
+
if (isIdentifier(prop.key, { name: "permission" })) {
|
|
678
|
+
extractStrings(prop.value, permissions);
|
|
664
679
|
}
|
|
665
680
|
if (isIdentifier(prop.key, { name: "id" }) && isStringLiteral(prop.value)) {
|
|
666
681
|
id = prop.value.value;
|
|
667
682
|
}
|
|
683
|
+
if (isIdentifier(prop.key, { name: "label" }) && isStringLiteral(prop.value)) {
|
|
684
|
+
label = prop.value.value;
|
|
685
|
+
}
|
|
668
686
|
}
|
|
669
687
|
if (zones.length === 0) return null;
|
|
670
|
-
return { zones, id };
|
|
688
|
+
return { zones, id, label, permissions };
|
|
671
689
|
}
|
|
672
690
|
function getConfigProperties(node) {
|
|
673
691
|
if (isCallExpression(node) && node.arguments.length > 0 && isObjectExpression(node.arguments[0])) {
|
|
@@ -731,7 +749,7 @@ function parseWidgetFile(file, widgetsDir, index) {
|
|
|
731
749
|
import: `import ${name} from "${importPath}"`,
|
|
732
750
|
entry: ` { Component: ${name}, zone: ${zonesLiteral}, widgetId: ${JSON.stringify(
|
|
733
751
|
id
|
|
734
|
-
)} }`
|
|
752
|
+
)}${info.label ? `, label: ${JSON.stringify(info.label)}` : ""}${info.permissions.length ? `, permission: ${JSON.stringify(info.permissions)}` : ""} }`
|
|
735
753
|
};
|
|
736
754
|
}
|
|
737
755
|
function collectWidgets(srcDir, startIndex = 0) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mercurjs/dashboard-sdk",
|
|
3
|
-
"version": "2.3.6-canary.
|
|
3
|
+
"version": "2.3.6-canary.10",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "https://github.com/mercurjs/mercur",
|
|
@@ -31,12 +31,13 @@
|
|
|
31
31
|
"scripts": {
|
|
32
32
|
"dev": "tsup --watch",
|
|
33
33
|
"build": "tsup",
|
|
34
|
+
"test:types": "tsc -p src/__tests__/types",
|
|
34
35
|
"lint": "oxlint --max-warnings 0"
|
|
35
36
|
},
|
|
36
37
|
"dependencies": {
|
|
37
38
|
"@babel/parser": "8.0.5",
|
|
38
|
-
"@babel/traverse": "
|
|
39
|
-
"@babel/types": "8.0.
|
|
39
|
+
"@babel/traverse": "8.0.6",
|
|
40
|
+
"@babel/types": "8.0.6",
|
|
40
41
|
"esbuild-register": "^3.6.0"
|
|
41
42
|
},
|
|
42
43
|
"devDependencies": {
|
|
@@ -1,142 +0,0 @@
|
|
|
1
|
-
import { ComponentType, ReactNode } from 'react';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Permission strings follow the pattern `{resource}:{operation}`, e.g.
|
|
5
|
-
* `customer:read`, `product:create`, `order:*`.
|
|
6
|
-
*
|
|
7
|
-
* The resource list mirrors the policies registered server-side — Medusa's own
|
|
8
|
-
* catalog plus Mercur's (`packages/core/src/policies`). A name that is not
|
|
9
|
-
* registered there is not a type error, it simply never matches a granted
|
|
10
|
-
* policy, so the two are kept in sync by a test in `packages/admin`.
|
|
11
|
-
*/
|
|
12
|
-
type PermissionResource = "api_key" | "campaign" | "commission_line" | "commission_rate" | "commission_rule" | "currency" | "customer" | "customer_address" | "customer_group" | "file" | "fulfillment" | "fulfillment_provider" | "fulfillment_set" | "inventory_item" | "inventory_level" | "invite" | "member_invite" | "notification" | "offer" | "order" | "order_change" | "order_claim" | "order_claim_item" | "order_exchange" | "order_group" | "order_item" | "payment" | "payment_collection" | "payment_method" | "payment_session" | "payout" | "payout_account" | "price" | "price_list" | "price_preference" | "product" | "product_attribute" | "product_attribute_value" | "product_category" | "product_change" | "product_collection" | "product_option" | "product_option_value" | "product_tag" | "product_type" | "product_variant" | "promotion" | "rbac_policy" | "rbac_role" | "refund_reason" | "region" | "reservation_item" | "return" | "return_reason" | "review" | "sales_channel" | "seller" | "seller_member" | "service_zone" | "shipping_option" | "shipping_option_type" | "shipping_profile" | "stock_location" | "store" | "store_locale" | "tax_provider" | "tax_rate" | "tax_region" | "translation" | "translation_setting" | "user" | "workflow_execution";
|
|
13
|
-
type PermissionOperation = "read" | "create" | "update" | "delete" | "*";
|
|
14
|
-
type Permission = `${PermissionResource}:${PermissionOperation}`;
|
|
15
|
-
interface UserPolicy {
|
|
16
|
-
permissions: Permission[];
|
|
17
|
-
}
|
|
18
|
-
interface PermissionRequirement {
|
|
19
|
-
permissions: Permission[];
|
|
20
|
-
/** If true, ALL permissions are required. Defaults to ANY. */
|
|
21
|
-
requireAll?: boolean;
|
|
22
|
-
/** Optional label describing where the requirement came from. */
|
|
23
|
-
source?: string;
|
|
24
|
-
}
|
|
25
|
-
interface PermissionsContextValue {
|
|
26
|
-
policy: UserPolicy | null;
|
|
27
|
-
isLoading: boolean;
|
|
28
|
-
/** Whether RBAC is active. When `false`, every check resolves to `true`. */
|
|
29
|
-
isRbacEnabled: boolean;
|
|
30
|
-
hasPermission: (permission: Permission) => boolean;
|
|
31
|
-
hasAnyPermission: (permissions: Permission[]) => boolean;
|
|
32
|
-
hasAllPermissions: (permissions: Permission[]) => boolean;
|
|
33
|
-
can: (resource: PermissionResource, operation: PermissionOperation) => boolean;
|
|
34
|
-
}
|
|
35
|
-
interface PermissionsRequirementsContextValue {
|
|
36
|
-
requiredPermissions: PermissionRequirement[];
|
|
37
|
-
registerRequiredPermissions: (id: string, requirement: PermissionRequirement) => void;
|
|
38
|
-
unregisterRequiredPermissions: (id: string) => void;
|
|
39
|
-
}
|
|
40
|
-
/**
|
|
41
|
-
* Operations implied by a granted operation. Only the wildcard fans out.
|
|
42
|
-
* Note that `update` does not imply `read` — grants must be explicit.
|
|
43
|
-
*/
|
|
44
|
-
declare const OPERATION_IMPLICATIONS: Record<PermissionOperation, PermissionOperation[]>;
|
|
45
|
-
declare function parsePermission(permission: string): {
|
|
46
|
-
resource: PermissionResource;
|
|
47
|
-
operation: PermissionOperation;
|
|
48
|
-
} | null;
|
|
49
|
-
declare function buildPermission(resource: PermissionResource, operation: PermissionOperation): Permission;
|
|
50
|
-
|
|
51
|
-
/**
|
|
52
|
-
* Configuration for the Mercur dashboard plugin.
|
|
53
|
-
*
|
|
54
|
-
* Passed to `mercurDashboardPlugin()` in `vite.config.ts` to configure
|
|
55
|
-
* the vendor or admin dashboard at build time.
|
|
56
|
-
*
|
|
57
|
-
* @example
|
|
58
|
-
* ```ts
|
|
59
|
-
* mercurDashboardPlugin({
|
|
60
|
-
* medusaConfigPath: '../../packages/api/medusa-config.ts',
|
|
61
|
-
* enableSellerRegistration: true,
|
|
62
|
-
* })
|
|
63
|
-
* ```
|
|
64
|
-
*/
|
|
65
|
-
interface MercurConfig {
|
|
66
|
-
/** Path to the MedusaJS config file, resolved relative to the project root. */
|
|
67
|
-
medusaConfigPath: string;
|
|
68
|
-
/**
|
|
69
|
-
* Backend URL for API requests.
|
|
70
|
-
* @default "http://localhost:9000"
|
|
71
|
-
*/
|
|
72
|
-
backendUrl?: string;
|
|
73
|
-
/**
|
|
74
|
-
* Absolute base URL for the vendor dashboard, including any path prefix
|
|
75
|
-
* (for example `https://vendors.example.com/seller`).
|
|
76
|
-
*
|
|
77
|
-
* The plugin does not read `.env` files on its own. Load env in your
|
|
78
|
-
* app's `vite.config.ts` and pass the value here when you need
|
|
79
|
-
* cross-origin links such as seller invite URLs.
|
|
80
|
-
*
|
|
81
|
-
* If omitted, the plugin falls back to vendor module dev server
|
|
82
|
-
* detection in development and to the configured vendor path in
|
|
83
|
-
* production.
|
|
84
|
-
*/
|
|
85
|
-
vendorUrl?: string;
|
|
86
|
-
/** Dashboard display name. */
|
|
87
|
-
name?: string;
|
|
88
|
-
/** Path to a logo asset for the dashboard. */
|
|
89
|
-
logo?: string;
|
|
90
|
-
/** Internationalization settings. */
|
|
91
|
-
i18n?: {
|
|
92
|
-
/** The default language code (e.g. `"en"`). */
|
|
93
|
-
defaultLanguage: string;
|
|
94
|
-
};
|
|
95
|
-
/** Whether to allow new sellers to register from the login screen. */
|
|
96
|
-
enableSellerRegistration?: boolean;
|
|
97
|
-
/**
|
|
98
|
-
* Maximum allowed size for image uploads, in bytes.
|
|
99
|
-
* Used by dashboard upload components to reject oversized files
|
|
100
|
-
* before they are sent to the backend.
|
|
101
|
-
* @default 2_097_152 // 2 MB
|
|
102
|
-
*/
|
|
103
|
-
imageLimit?: number;
|
|
104
|
-
}
|
|
105
|
-
interface BuiltMercurConfig extends MercurConfig {
|
|
106
|
-
backendUrl: string;
|
|
107
|
-
base?: string;
|
|
108
|
-
root: string;
|
|
109
|
-
srcDir: string;
|
|
110
|
-
pluginExtensions: string[];
|
|
111
|
-
imageLimit: number;
|
|
112
|
-
}
|
|
113
|
-
type RouteConfig = {
|
|
114
|
-
label: string;
|
|
115
|
-
icon?: ComponentType;
|
|
116
|
-
rank?: number;
|
|
117
|
-
nested?: string;
|
|
118
|
-
translationNs?: string;
|
|
119
|
-
public?: boolean;
|
|
120
|
-
/**
|
|
121
|
-
* Permissions the actor must hold for this route's sidebar entry to be
|
|
122
|
-
* shown. Enforcement of the route itself comes from `handle.permissions`
|
|
123
|
-
* — this only controls navigation visibility.
|
|
124
|
-
*/
|
|
125
|
-
permissions?: Permission[];
|
|
126
|
-
/** If true, ALL `permissions` are required. Defaults to ANY. */
|
|
127
|
-
requireAll?: boolean;
|
|
128
|
-
};
|
|
129
|
-
/**
|
|
130
|
-
* The value of a route module's `export const handle`. Read by react-router's
|
|
131
|
-
* `useMatches()`; `permissions` is enforced by `RoutePermissionGuard`.
|
|
132
|
-
*/
|
|
133
|
-
type RouteHandle = {
|
|
134
|
-
permissions?: Permission | Permission[];
|
|
135
|
-
/** If true (default at the route level), ALL permissions are required. */
|
|
136
|
-
requireAll?: boolean;
|
|
137
|
-
/** Where to send the actor on denial. Renders Access Denied when unset. */
|
|
138
|
-
redirectTo?: string;
|
|
139
|
-
breadcrumb?: (match: never) => ReactNode;
|
|
140
|
-
};
|
|
141
|
-
|
|
142
|
-
export { type BuiltMercurConfig as B, type MercurConfig as M, OPERATION_IMPLICATIONS as O, type Permission as P, type RouteConfig as R, type UserPolicy as U, type PermissionOperation as a, type PermissionRequirement as b, type PermissionResource as c, type PermissionsContextValue as d, type PermissionsRequirementsContextValue as e, type RouteHandle as f, buildPermission as g, parsePermission as p };
|
package/dist/types-CTuDKgPc.d.ts
DELETED
|
@@ -1,142 +0,0 @@
|
|
|
1
|
-
import { ComponentType, ReactNode } from 'react';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Permission strings follow the pattern `{resource}:{operation}`, e.g.
|
|
5
|
-
* `customer:read`, `product:create`, `order:*`.
|
|
6
|
-
*
|
|
7
|
-
* The resource list mirrors the policies registered server-side — Medusa's own
|
|
8
|
-
* catalog plus Mercur's (`packages/core/src/policies`). A name that is not
|
|
9
|
-
* registered there is not a type error, it simply never matches a granted
|
|
10
|
-
* policy, so the two are kept in sync by a test in `packages/admin`.
|
|
11
|
-
*/
|
|
12
|
-
type PermissionResource = "api_key" | "campaign" | "commission_line" | "commission_rate" | "commission_rule" | "currency" | "customer" | "customer_address" | "customer_group" | "file" | "fulfillment" | "fulfillment_provider" | "fulfillment_set" | "inventory_item" | "inventory_level" | "invite" | "member_invite" | "notification" | "offer" | "order" | "order_change" | "order_claim" | "order_claim_item" | "order_exchange" | "order_group" | "order_item" | "payment" | "payment_collection" | "payment_method" | "payment_session" | "payout" | "payout_account" | "price" | "price_list" | "price_preference" | "product" | "product_attribute" | "product_attribute_value" | "product_category" | "product_change" | "product_collection" | "product_option" | "product_option_value" | "product_tag" | "product_type" | "product_variant" | "promotion" | "rbac_policy" | "rbac_role" | "refund_reason" | "region" | "reservation_item" | "return" | "return_reason" | "review" | "sales_channel" | "seller" | "seller_member" | "service_zone" | "shipping_option" | "shipping_option_type" | "shipping_profile" | "stock_location" | "store" | "store_locale" | "tax_provider" | "tax_rate" | "tax_region" | "translation" | "translation_setting" | "user" | "workflow_execution";
|
|
13
|
-
type PermissionOperation = "read" | "create" | "update" | "delete" | "*";
|
|
14
|
-
type Permission = `${PermissionResource}:${PermissionOperation}`;
|
|
15
|
-
interface UserPolicy {
|
|
16
|
-
permissions: Permission[];
|
|
17
|
-
}
|
|
18
|
-
interface PermissionRequirement {
|
|
19
|
-
permissions: Permission[];
|
|
20
|
-
/** If true, ALL permissions are required. Defaults to ANY. */
|
|
21
|
-
requireAll?: boolean;
|
|
22
|
-
/** Optional label describing where the requirement came from. */
|
|
23
|
-
source?: string;
|
|
24
|
-
}
|
|
25
|
-
interface PermissionsContextValue {
|
|
26
|
-
policy: UserPolicy | null;
|
|
27
|
-
isLoading: boolean;
|
|
28
|
-
/** Whether RBAC is active. When `false`, every check resolves to `true`. */
|
|
29
|
-
isRbacEnabled: boolean;
|
|
30
|
-
hasPermission: (permission: Permission) => boolean;
|
|
31
|
-
hasAnyPermission: (permissions: Permission[]) => boolean;
|
|
32
|
-
hasAllPermissions: (permissions: Permission[]) => boolean;
|
|
33
|
-
can: (resource: PermissionResource, operation: PermissionOperation) => boolean;
|
|
34
|
-
}
|
|
35
|
-
interface PermissionsRequirementsContextValue {
|
|
36
|
-
requiredPermissions: PermissionRequirement[];
|
|
37
|
-
registerRequiredPermissions: (id: string, requirement: PermissionRequirement) => void;
|
|
38
|
-
unregisterRequiredPermissions: (id: string) => void;
|
|
39
|
-
}
|
|
40
|
-
/**
|
|
41
|
-
* Operations implied by a granted operation. Only the wildcard fans out.
|
|
42
|
-
* Note that `update` does not imply `read` — grants must be explicit.
|
|
43
|
-
*/
|
|
44
|
-
declare const OPERATION_IMPLICATIONS: Record<PermissionOperation, PermissionOperation[]>;
|
|
45
|
-
declare function parsePermission(permission: string): {
|
|
46
|
-
resource: PermissionResource;
|
|
47
|
-
operation: PermissionOperation;
|
|
48
|
-
} | null;
|
|
49
|
-
declare function buildPermission(resource: PermissionResource, operation: PermissionOperation): Permission;
|
|
50
|
-
|
|
51
|
-
/**
|
|
52
|
-
* Configuration for the Mercur dashboard plugin.
|
|
53
|
-
*
|
|
54
|
-
* Passed to `mercurDashboardPlugin()` in `vite.config.ts` to configure
|
|
55
|
-
* the vendor or admin dashboard at build time.
|
|
56
|
-
*
|
|
57
|
-
* @example
|
|
58
|
-
* ```ts
|
|
59
|
-
* mercurDashboardPlugin({
|
|
60
|
-
* medusaConfigPath: '../../packages/api/medusa-config.ts',
|
|
61
|
-
* enableSellerRegistration: true,
|
|
62
|
-
* })
|
|
63
|
-
* ```
|
|
64
|
-
*/
|
|
65
|
-
interface MercurConfig {
|
|
66
|
-
/** Path to the MedusaJS config file, resolved relative to the project root. */
|
|
67
|
-
medusaConfigPath: string;
|
|
68
|
-
/**
|
|
69
|
-
* Backend URL for API requests.
|
|
70
|
-
* @default "http://localhost:9000"
|
|
71
|
-
*/
|
|
72
|
-
backendUrl?: string;
|
|
73
|
-
/**
|
|
74
|
-
* Absolute base URL for the vendor dashboard, including any path prefix
|
|
75
|
-
* (for example `https://vendors.example.com/seller`).
|
|
76
|
-
*
|
|
77
|
-
* The plugin does not read `.env` files on its own. Load env in your
|
|
78
|
-
* app's `vite.config.ts` and pass the value here when you need
|
|
79
|
-
* cross-origin links such as seller invite URLs.
|
|
80
|
-
*
|
|
81
|
-
* If omitted, the plugin falls back to vendor module dev server
|
|
82
|
-
* detection in development and to the configured vendor path in
|
|
83
|
-
* production.
|
|
84
|
-
*/
|
|
85
|
-
vendorUrl?: string;
|
|
86
|
-
/** Dashboard display name. */
|
|
87
|
-
name?: string;
|
|
88
|
-
/** Path to a logo asset for the dashboard. */
|
|
89
|
-
logo?: string;
|
|
90
|
-
/** Internationalization settings. */
|
|
91
|
-
i18n?: {
|
|
92
|
-
/** The default language code (e.g. `"en"`). */
|
|
93
|
-
defaultLanguage: string;
|
|
94
|
-
};
|
|
95
|
-
/** Whether to allow new sellers to register from the login screen. */
|
|
96
|
-
enableSellerRegistration?: boolean;
|
|
97
|
-
/**
|
|
98
|
-
* Maximum allowed size for image uploads, in bytes.
|
|
99
|
-
* Used by dashboard upload components to reject oversized files
|
|
100
|
-
* before they are sent to the backend.
|
|
101
|
-
* @default 2_097_152 // 2 MB
|
|
102
|
-
*/
|
|
103
|
-
imageLimit?: number;
|
|
104
|
-
}
|
|
105
|
-
interface BuiltMercurConfig extends MercurConfig {
|
|
106
|
-
backendUrl: string;
|
|
107
|
-
base?: string;
|
|
108
|
-
root: string;
|
|
109
|
-
srcDir: string;
|
|
110
|
-
pluginExtensions: string[];
|
|
111
|
-
imageLimit: number;
|
|
112
|
-
}
|
|
113
|
-
type RouteConfig = {
|
|
114
|
-
label: string;
|
|
115
|
-
icon?: ComponentType;
|
|
116
|
-
rank?: number;
|
|
117
|
-
nested?: string;
|
|
118
|
-
translationNs?: string;
|
|
119
|
-
public?: boolean;
|
|
120
|
-
/**
|
|
121
|
-
* Permissions the actor must hold for this route's sidebar entry to be
|
|
122
|
-
* shown. Enforcement of the route itself comes from `handle.permissions`
|
|
123
|
-
* — this only controls navigation visibility.
|
|
124
|
-
*/
|
|
125
|
-
permissions?: Permission[];
|
|
126
|
-
/** If true, ALL `permissions` are required. Defaults to ANY. */
|
|
127
|
-
requireAll?: boolean;
|
|
128
|
-
};
|
|
129
|
-
/**
|
|
130
|
-
* The value of a route module's `export const handle`. Read by react-router's
|
|
131
|
-
* `useMatches()`; `permissions` is enforced by `RoutePermissionGuard`.
|
|
132
|
-
*/
|
|
133
|
-
type RouteHandle = {
|
|
134
|
-
permissions?: Permission | Permission[];
|
|
135
|
-
/** If true (default at the route level), ALL permissions are required. */
|
|
136
|
-
requireAll?: boolean;
|
|
137
|
-
/** Where to send the actor on denial. Renders Access Denied when unset. */
|
|
138
|
-
redirectTo?: string;
|
|
139
|
-
breadcrumb?: (match: never) => ReactNode;
|
|
140
|
-
};
|
|
141
|
-
|
|
142
|
-
export { type BuiltMercurConfig as B, type MercurConfig as M, OPERATION_IMPLICATIONS as O, type Permission as P, type RouteConfig as R, type UserPolicy as U, type PermissionOperation as a, type PermissionRequirement as b, type PermissionResource as c, type PermissionsContextValue as d, type PermissionsRequirementsContextValue as e, type RouteHandle as f, buildPermission as g, parsePermission as p };
|