@hartl-services/medusa-base 2.6.1 → 2.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (151) hide show
  1. package/.medusa/server/src/admin/admin-components/features/plugin-features/components/ImageSettingInput.d.ts +3 -2
  2. package/.medusa/server/src/admin/admin-components/features/plugin-features/components/ImageSettingInput.js +4 -4
  3. package/.medusa/server/src/admin/admin-components/features/plugin-features/components/PluginActionsSection.js +4 -4
  4. package/.medusa/server/src/admin/admin-components/features/plugin-features/components/PluginBreadcrumb.d.ts +16 -0
  5. package/.medusa/server/src/admin/admin-components/features/plugin-features/components/PluginBreadcrumb.js +25 -0
  6. package/.medusa/server/src/admin/admin-components/features/plugin-features/components/PluginDetailPage.js +1 -1
  7. package/.medusa/server/src/admin/admin-components/features/plugin-features/components/PluginFeatureSections.d.ts +5 -4
  8. package/.medusa/server/src/admin/admin-components/features/plugin-features/components/PluginFeatureSections.js +8 -5
  9. package/.medusa/server/src/admin/admin-components/features/plugin-features/components/PluginFeaturesCard.d.ts +4 -4
  10. package/.medusa/server/src/admin/admin-components/features/plugin-features/components/PluginFeaturesCard.js +24 -27
  11. package/.medusa/server/src/admin/admin-components/features/plugin-features/components/PluginFeaturesSettingsPage.d.ts +2 -2
  12. package/.medusa/server/src/admin/admin-components/features/plugin-features/components/PluginFeaturesSettingsPage.js +9 -9
  13. package/.medusa/server/src/admin/admin-components/features/plugin-features/components/PluginHubCard.d.ts +5 -1
  14. package/.medusa/server/src/admin/admin-components/features/plugin-features/components/PluginHubCard.js +11 -15
  15. package/.medusa/server/src/admin/admin-components/features/plugin-features/components/PluginPageShell.d.ts +10 -4
  16. package/.medusa/server/src/admin/admin-components/features/plugin-features/components/PluginPageShell.js +10 -5
  17. package/.medusa/server/src/admin/admin-components/features/plugin-features/components/PluginSettingsForm.d.ts +0 -1
  18. package/.medusa/server/src/admin/admin-components/features/plugin-features/components/PluginSettingsForm.js +77 -26
  19. package/.medusa/server/src/admin/admin-components/features/plugin-features/components/PluginStatusChips.d.ts +5 -1
  20. package/.medusa/server/src/admin/admin-components/features/plugin-features/components/PluginStatusChips.js +8 -6
  21. package/.medusa/server/src/admin/admin-components/features/plugin-features/components/ShopMasterDataBanner.d.ts +11 -0
  22. package/.medusa/server/src/admin/admin-components/features/plugin-features/components/ShopMasterDataBanner.js +15 -0
  23. package/.medusa/server/src/admin/admin-components/features/plugin-features/hooks/usePluginFeatureEnabled.d.ts +40 -5
  24. package/.medusa/server/src/admin/admin-components/features/plugin-features/hooks/usePluginFeatures.d.ts +160 -20
  25. package/.medusa/server/src/admin/admin-components/features/plugin-features/hooks/usePluginSettingsForm.d.ts +40 -5
  26. package/.medusa/server/src/admin/admin-components/features/plugin-features/hooks/usePluginSwitch.d.ts +15 -0
  27. package/.medusa/server/src/admin/admin-components/features/plugin-features/hooks/usePluginSwitch.js +66 -0
  28. package/.medusa/server/src/admin/admin-components/features/plugin-features/lib/plugin-features-admin-client.d.ts +160 -20
  29. package/.medusa/server/src/admin/admin-components/features/plugin-features/lib/plugin-view.d.ts +49 -0
  30. package/.medusa/server/src/admin/admin-components/features/plugin-features/lib/plugin-view.js +72 -0
  31. package/.medusa/server/src/admin/admin-components/features/plugin-features/lib/settings-draft.d.ts +1 -12
  32. package/.medusa/server/src/admin/admin-components/features/plugin-features/lib/settings-draft.js +4 -20
  33. package/.medusa/server/src/admin/admin-components/features/plugin-features/lib/settings-layout.d.ts +47 -0
  34. package/.medusa/server/src/admin/admin-components/features/plugin-features/lib/settings-layout.js +70 -0
  35. package/.medusa/server/src/admin/admin-components/i18n/texts.d.ts +22 -2
  36. package/.medusa/server/src/admin/admin-components/i18n/texts.js +29 -7
  37. package/.medusa/server/src/admin/admin-components/index.d.ts +12 -0
  38. package/.medusa/server/src/admin/admin-components/index.js +11 -0
  39. package/.medusa/server/src/admin/admin-components/shared/ui/AdminPageHeader.d.ts +22 -0
  40. package/.medusa/server/src/admin/admin-components/shared/ui/AdminPageHeader.js +8 -0
  41. package/.medusa/server/src/admin/admin-components/shared/ui/AdminSection.d.ts +26 -0
  42. package/.medusa/server/src/admin/admin-components/shared/ui/AdminSection.js +12 -0
  43. package/.medusa/server/src/admin/admin-components/shared/ui/BreadcrumbTrail.d.ts +23 -0
  44. package/.medusa/server/src/admin/admin-components/shared/ui/BreadcrumbTrail.js +20 -0
  45. package/.medusa/server/src/admin/admin-components/shared/ui/FileDropField.d.ts +21 -0
  46. package/.medusa/server/src/admin/admin-components/shared/ui/FileDropField.js +33 -0
  47. package/.medusa/server/src/admin/admin-components/shared/ui/FocusModalShell.d.ts +27 -0
  48. package/.medusa/server/src/admin/admin-components/shared/ui/FocusModalShell.js +13 -0
  49. package/.medusa/server/src/admin/admin-components/shared/ui/InfoTooltip.d.ts +13 -0
  50. package/.medusa/server/src/admin/admin-components/shared/ui/InfoTooltip.js +8 -0
  51. package/.medusa/server/src/admin/admin-components/shared/ui/MultiSelectDropdown.d.ts +22 -0
  52. package/.medusa/server/src/admin/admin-components/shared/ui/MultiSelectDropdown.js +14 -0
  53. package/.medusa/server/src/admin/admin-components/shared/ui/PluginIcon.d.ts +10 -0
  54. package/.medusa/server/src/admin/admin-components/shared/ui/PluginIcon.js +10 -0
  55. package/.medusa/server/src/admin/admin-components/shared/ui/SwitchRow.d.ts +27 -0
  56. package/.medusa/server/src/admin/admin-components/shared/ui/SwitchRow.js +15 -0
  57. package/.medusa/server/src/admin/admin-components/shared/ui/WidgetHeader.d.ts +15 -0
  58. package/.medusa/server/src/admin/admin-components/shared/ui/WidgetHeader.js +8 -0
  59. package/.medusa/server/src/admin/admin-components/shared/ui/file-drop.d.ts +13 -0
  60. package/.medusa/server/src/admin/admin-components/shared/ui/file-drop.js +16 -0
  61. package/.medusa/server/src/admin/admin-components/shared/ui/multi-select.d.ts +13 -0
  62. package/.medusa/server/src/admin/admin-components/shared/ui/multi-select.js +11 -0
  63. package/.medusa/server/src/admin/admin-components/shared/ui/plugin-icon.d.ts +12 -0
  64. package/.medusa/server/src/admin/admin-components/shared/ui/plugin-icon.js +29 -0
  65. package/.medusa/server/src/admin/index.js +3155 -2039
  66. package/.medusa/server/src/admin/index.mjs +3158 -2042
  67. package/.medusa/server/src/api/admin-first-login-password-policy.js +56 -0
  68. package/.medusa/server/src/api/answer-actor-type-casing-not-found.js +26 -0
  69. package/.medusa/server/src/api/answer-code-provider-route-not-found.js +34 -0
  70. package/.medusa/server/src/api/code-account-password-routes.js +92 -0
  71. package/.medusa/server/src/api/middlewares.js +82 -17
  72. package/.medusa/server/src/api/password-policy.js +55 -10
  73. package/.medusa/server/src/api/require-login-code-customer-email.js +40 -0
  74. package/.medusa/server/src/api/store/customer-auth/login-code/route.js +17 -0
  75. package/.medusa/server/src/api/store/customer-auth/password-policy/route.js +19 -0
  76. package/.medusa/server/src/customer-auth/application/prepare-code-account-password-reset.js +111 -0
  77. package/.medusa/server/src/customer-auth/application/request-login-code.js +145 -0
  78. package/.medusa/server/src/customer-auth/customer-auth-methods-snapshot.js +55 -0
  79. package/.medusa/server/src/customer-auth/customer-password-policy.js +40 -0
  80. package/.medusa/server/src/customer-auth/domain/account-linking.js +53 -0
  81. package/.medusa/server/src/customer-auth/domain/auth-methods.js +32 -0
  82. package/.medusa/server/src/customer-auth/domain/login-code.js +39 -0
  83. package/.medusa/server/src/customer-auth/login-code-accounts.js +146 -0
  84. package/.medusa/server/src/customer-auth/login-code-state.js +139 -0
  85. package/.medusa/server/src/customer-auth/plugin-features.js +80 -0
  86. package/.medusa/server/src/customer-auth/remove-provider-identity.js +18 -0
  87. package/.medusa/server/src/customer-auth/start-customer-auth-methods.js +20 -0
  88. package/.medusa/server/src/documents/plugin-features.js +8 -2
  89. package/.medusa/server/src/email/application/deliver-ephemeral-auth-mail.js +186 -0
  90. package/.medusa/server/src/email/application/deliver-login-code.js +89 -0
  91. package/.medusa/server/src/email/application/handle-customer-verification-event.js +29 -168
  92. package/.medusa/server/src/email/application/handle-password-reset-event.js +27 -166
  93. package/.medusa/server/src/email/customer-verification-snapshot.js +20 -108
  94. package/.medusa/server/src/email/domain/business-keys.js +15 -2
  95. package/.medusa/server/src/email/plugin-features.js +8 -3
  96. package/.medusa/server/src/email/rendering/default-templates.js +2 -1
  97. package/.medusa/server/src/email/templates/blocks/dynamic-blocks.js +19 -1
  98. package/.medusa/server/src/email/templates/defaults/documents.js +7 -1
  99. package/.medusa/server/src/email/templates/defaults/subjects.js +3 -1
  100. package/.medusa/server/src/email/templates/defaults/texts.js +5 -2
  101. package/.medusa/server/src/email/templates/render.js +2 -1
  102. package/.medusa/server/src/email/templates/sample-data.js +2 -1
  103. package/.medusa/server/src/email/templates/validate.js +8 -3
  104. package/.medusa/server/src/email/types/email-kinds.js +4 -2
  105. package/.medusa/server/src/email/types/template-data.js +9 -1
  106. package/.medusa/server/src/modules/customer-auth/index.js +14 -0
  107. package/.medusa/server/src/modules/customer-auth/service.js +35 -0
  108. package/.medusa/server/src/modules/email/migrations/Migration20261010090000.js +20 -0
  109. package/.medusa/server/src/modules/plugin-features/domain/plugin-settings.js +30 -6
  110. package/.medusa/server/src/modules/plugin-features/service.js +29 -3
  111. package/.medusa/server/src/providers/email-otp/index.js +8 -0
  112. package/.medusa/server/src/providers/email-otp/service.js +96 -0
  113. package/.medusa/server/src/public/descriptor.js +138 -5
  114. package/.medusa/server/src/public/effective-features.js +22 -1
  115. package/.medusa/server/src/public/index.js +4 -2
  116. package/.medusa/server/src/public/plugin-icons.js +28 -0
  117. package/.medusa/server/src/public/shop-master-data.js +33 -14
  118. package/.medusa/server/src/shared/lib/dates.js +8 -2
  119. package/.medusa/server/src/shared/lib/index.js +2 -1
  120. package/.medusa/server/src/shared/lib/refreshing-snapshot.js +122 -0
  121. package/.medusa/server/src/shop-config/build-food-shop-config.js +38 -1
  122. package/README.md +436 -87
  123. package/dist/customer-auth/customer-auth-methods-snapshot.d.ts +25 -0
  124. package/dist/customer-auth/customer-auth-methods-snapshot.js +54 -0
  125. package/dist/customer-auth/domain/auth-methods.d.ts +16 -0
  126. package/dist/customer-auth/domain/auth-methods.js +31 -0
  127. package/dist/customer-auth/plugin-features.d.ts +2 -0
  128. package/dist/customer-auth/plugin-features.js +79 -0
  129. package/dist/email/customer-verification-snapshot.d.ts +3 -15
  130. package/dist/email/customer-verification-snapshot.js +19 -107
  131. package/dist/email/types/email-kinds.d.ts +4 -3
  132. package/dist/email/types/email-kinds.js +3 -1
  133. package/dist/email/types/template-data.d.ts +8 -0
  134. package/dist/email/types/template-data.js +8 -0
  135. package/dist/public/descriptor.js +137 -4
  136. package/dist/public/effective-features.d.ts +10 -0
  137. package/dist/public/effective-features.js +21 -0
  138. package/dist/public/index.d.ts +2 -1
  139. package/dist/public/index.js +3 -1
  140. package/dist/public/plugin-icons.d.ts +7 -0
  141. package/dist/public/plugin-icons.js +27 -0
  142. package/dist/public/shop-master-data.js +32 -13
  143. package/dist/public/types.d.ts +74 -2
  144. package/dist/shared/lib/dates.d.ts +2 -0
  145. package/dist/shared/lib/dates.js +7 -1
  146. package/dist/shared/lib/index.d.ts +1 -0
  147. package/dist/shared/lib/index.js +1 -0
  148. package/dist/shared/lib/refreshing-snapshot.d.ts +52 -0
  149. package/dist/shared/lib/refreshing-snapshot.js +121 -0
  150. package/dist/shop-config/build-food-shop-config.js +37 -0
  151. package/package.json +8 -3
@@ -0,0 +1,66 @@
1
+ import { usePrompt } from "@medusajs/ui";
2
+ import { useQueryClient } from "@tanstack/react-query";
3
+ import { texts } from "../../../i18n/texts";
4
+ import { configuredFeatures } from "../lib/plugin-view";
5
+ import { pluginFeatureKeys } from "../queries/pluginFeatureKeys";
6
+ import { useUpdatePluginFeatures } from "./usePluginFeatures";
7
+ /**
8
+ * Plugin switch of the hub card and of the plugin page: switching ON saves at
9
+ * once, switching OFF asks for confirmation first (the descriptor's
10
+ * `disable_confirm`, else a generic text). Saves with the loaded `version`, so
11
+ * a concurrent change answers 409 and reloads. After the confirmation the
12
+ * plugin is read from the query cache again, so a save made while the dialog
13
+ * was open does not send a stale `version`. Feature switches save through
14
+ * `saveFeatures`.
15
+ */
16
+ export function usePluginSwitch(plugin) {
17
+ const mutation = useUpdatePluginFeatures();
18
+ const prompt = usePrompt();
19
+ const queryClient = useQueryClient();
20
+ /** The newest cached entry of this plugin (detail or list), else the one rendered with. */
21
+ const latest = () => {
22
+ const candidates = [
23
+ queryClient.getQueryData(pluginFeatureKeys.detail(plugin.plugin_key))?.plugin,
24
+ queryClient
25
+ .getQueryData(pluginFeatureKeys.list())
26
+ ?.plugins.find((entry) => entry.plugin_key === plugin.plugin_key),
27
+ plugin,
28
+ ].filter((entry) => entry !== undefined);
29
+ return candidates.reduce((newest, entry) => entry.version > newest.version ? entry : newest);
30
+ };
31
+ const save = (current, enabled, features) => {
32
+ mutation.mutate({
33
+ plugin_key: current.plugin_key,
34
+ expected_version: current.version,
35
+ enabled,
36
+ features,
37
+ });
38
+ };
39
+ const setEnabled = async (enabled) => {
40
+ if (!enabled) {
41
+ const confirmed = await prompt({
42
+ title: texts.plugin.disableTitle(plugin.label),
43
+ description: plugin.disable_confirm ?? texts.plugin.disableConfirmDefault,
44
+ confirmText: texts.plugin.disable,
45
+ cancelText: texts.plugin.cancel,
46
+ });
47
+ if (!confirmed) {
48
+ return;
49
+ }
50
+ }
51
+ const current = latest();
52
+ save(current, enabled, configuredFeatures(current));
53
+ };
54
+ const setFeature = (key, enabled) => {
55
+ const current = latest();
56
+ save(current, current.enabled, {
57
+ ...configuredFeatures(current),
58
+ [key]: enabled,
59
+ });
60
+ };
61
+ return {
62
+ pending: mutation.isPending,
63
+ setEnabled: (enabled) => void setEnabled(enabled),
64
+ setFeature,
65
+ };
66
+ }
@@ -25,8 +25,12 @@ export declare const listPluginFeatures: () => Promise<{
25
25
  group: string | null;
26
26
  required: boolean;
27
27
  is_set: boolean;
28
- source: "default" | "stored" | "config" | "none";
28
+ source: "none" | "default" | "stored" | "config";
29
29
  invalidates: string[];
30
+ hint: string | null;
31
+ placeholder: string | null;
32
+ width: "full" | "half";
33
+ section: string | null;
30
34
  } | {
31
35
  type: "select";
32
36
  options: {
@@ -41,12 +45,17 @@ export declare const listPluginFeatures: () => Promise<{
41
45
  group: string | null;
42
46
  required: boolean;
43
47
  is_set: boolean;
44
- source: "default" | "stored" | "config" | "none";
48
+ source: "none" | "default" | "stored" | "config";
45
49
  invalidates: string[];
50
+ hint: string | null;
51
+ placeholder: string | null;
52
+ width: "full" | "half";
53
+ section: string | null;
46
54
  } | {
47
55
  type: "number";
48
56
  min: number | null;
49
57
  max: number | null;
58
+ integer: boolean;
50
59
  default: number | null;
51
60
  value: number | null;
52
61
  key: string;
@@ -55,10 +64,14 @@ export declare const listPluginFeatures: () => Promise<{
55
64
  group: string | null;
56
65
  required: boolean;
57
66
  is_set: boolean;
58
- source: "default" | "stored" | "config" | "none";
67
+ source: "none" | "default" | "stored" | "config";
59
68
  invalidates: string[];
69
+ hint: string | null;
70
+ placeholder: string | null;
71
+ width: "full" | "half";
72
+ section: string | null;
60
73
  } | {
61
- type: "string" | "boolean" | "color" | "url" | "image";
74
+ type: "string" | "boolean" | "color" | "image" | "url" | "date";
62
75
  default: string | number | boolean | null;
63
76
  value: string | number | boolean | null;
64
77
  key: string;
@@ -67,8 +80,12 @@ export declare const listPluginFeatures: () => Promise<{
67
80
  group: string | null;
68
81
  required: boolean;
69
82
  is_set: boolean;
70
- source: "default" | "stored" | "config" | "none";
83
+ source: "none" | "default" | "stored" | "config";
71
84
  invalidates: string[];
85
+ hint: string | null;
86
+ placeholder: string | null;
87
+ width: "full" | "half";
88
+ section: string | null;
72
89
  })[];
73
90
  configured: boolean;
74
91
  missing: string[];
@@ -81,6 +98,24 @@ export declare const listPluginFeatures: () => Promise<{
81
98
  confirm: string | null;
82
99
  }[];
83
100
  admin_page: string | null;
101
+ icon: string | null;
102
+ summary: string | null;
103
+ disable_hint: string | null;
104
+ disable_confirm: string | null;
105
+ features_heading: string | null;
106
+ features_note: string | null;
107
+ all_off_warning: string | null;
108
+ require_enabled_feature: boolean;
109
+ setting_groups: {
110
+ name: string;
111
+ description: string | null;
112
+ note: string | null;
113
+ requires_feature: string | null;
114
+ visible_when: {
115
+ setting: string;
116
+ equals: string | boolean;
117
+ } | null;
118
+ }[];
84
119
  }[];
85
120
  }>;
86
121
  export declare const retrievePluginFeatures: (pluginKey: string) => Promise<{
@@ -109,8 +144,12 @@ export declare const retrievePluginFeatures: (pluginKey: string) => Promise<{
109
144
  group: string | null;
110
145
  required: boolean;
111
146
  is_set: boolean;
112
- source: "default" | "stored" | "config" | "none";
147
+ source: "none" | "default" | "stored" | "config";
113
148
  invalidates: string[];
149
+ hint: string | null;
150
+ placeholder: string | null;
151
+ width: "full" | "half";
152
+ section: string | null;
114
153
  } | {
115
154
  type: "select";
116
155
  options: {
@@ -125,12 +164,17 @@ export declare const retrievePluginFeatures: (pluginKey: string) => Promise<{
125
164
  group: string | null;
126
165
  required: boolean;
127
166
  is_set: boolean;
128
- source: "default" | "stored" | "config" | "none";
167
+ source: "none" | "default" | "stored" | "config";
129
168
  invalidates: string[];
169
+ hint: string | null;
170
+ placeholder: string | null;
171
+ width: "full" | "half";
172
+ section: string | null;
130
173
  } | {
131
174
  type: "number";
132
175
  min: number | null;
133
176
  max: number | null;
177
+ integer: boolean;
134
178
  default: number | null;
135
179
  value: number | null;
136
180
  key: string;
@@ -139,10 +183,14 @@ export declare const retrievePluginFeatures: (pluginKey: string) => Promise<{
139
183
  group: string | null;
140
184
  required: boolean;
141
185
  is_set: boolean;
142
- source: "default" | "stored" | "config" | "none";
186
+ source: "none" | "default" | "stored" | "config";
143
187
  invalidates: string[];
188
+ hint: string | null;
189
+ placeholder: string | null;
190
+ width: "full" | "half";
191
+ section: string | null;
144
192
  } | {
145
- type: "string" | "boolean" | "color" | "url" | "image";
193
+ type: "string" | "boolean" | "color" | "image" | "url" | "date";
146
194
  default: string | number | boolean | null;
147
195
  value: string | number | boolean | null;
148
196
  key: string;
@@ -151,8 +199,12 @@ export declare const retrievePluginFeatures: (pluginKey: string) => Promise<{
151
199
  group: string | null;
152
200
  required: boolean;
153
201
  is_set: boolean;
154
- source: "default" | "stored" | "config" | "none";
202
+ source: "none" | "default" | "stored" | "config";
155
203
  invalidates: string[];
204
+ hint: string | null;
205
+ placeholder: string | null;
206
+ width: "full" | "half";
207
+ section: string | null;
156
208
  })[];
157
209
  configured: boolean;
158
210
  missing: string[];
@@ -165,6 +217,24 @@ export declare const retrievePluginFeatures: (pluginKey: string) => Promise<{
165
217
  confirm: string | null;
166
218
  }[];
167
219
  admin_page: string | null;
220
+ icon: string | null;
221
+ summary: string | null;
222
+ disable_hint: string | null;
223
+ disable_confirm: string | null;
224
+ features_heading: string | null;
225
+ features_note: string | null;
226
+ all_off_warning: string | null;
227
+ require_enabled_feature: boolean;
228
+ setting_groups: {
229
+ name: string;
230
+ description: string | null;
231
+ note: string | null;
232
+ requires_feature: string | null;
233
+ visible_when: {
234
+ setting: string;
235
+ equals: string | boolean;
236
+ } | null;
237
+ }[];
168
238
  };
169
239
  }>;
170
240
  export declare const updatePluginFeatures: (payload: UpdatePluginFeaturesPayload) => Promise<{
@@ -193,8 +263,12 @@ export declare const updatePluginFeatures: (payload: UpdatePluginFeaturesPayload
193
263
  group: string | null;
194
264
  required: boolean;
195
265
  is_set: boolean;
196
- source: "default" | "stored" | "config" | "none";
266
+ source: "none" | "default" | "stored" | "config";
197
267
  invalidates: string[];
268
+ hint: string | null;
269
+ placeholder: string | null;
270
+ width: "full" | "half";
271
+ section: string | null;
198
272
  } | {
199
273
  type: "select";
200
274
  options: {
@@ -209,12 +283,17 @@ export declare const updatePluginFeatures: (payload: UpdatePluginFeaturesPayload
209
283
  group: string | null;
210
284
  required: boolean;
211
285
  is_set: boolean;
212
- source: "default" | "stored" | "config" | "none";
286
+ source: "none" | "default" | "stored" | "config";
213
287
  invalidates: string[];
288
+ hint: string | null;
289
+ placeholder: string | null;
290
+ width: "full" | "half";
291
+ section: string | null;
214
292
  } | {
215
293
  type: "number";
216
294
  min: number | null;
217
295
  max: number | null;
296
+ integer: boolean;
218
297
  default: number | null;
219
298
  value: number | null;
220
299
  key: string;
@@ -223,10 +302,14 @@ export declare const updatePluginFeatures: (payload: UpdatePluginFeaturesPayload
223
302
  group: string | null;
224
303
  required: boolean;
225
304
  is_set: boolean;
226
- source: "default" | "stored" | "config" | "none";
305
+ source: "none" | "default" | "stored" | "config";
227
306
  invalidates: string[];
307
+ hint: string | null;
308
+ placeholder: string | null;
309
+ width: "full" | "half";
310
+ section: string | null;
228
311
  } | {
229
- type: "string" | "boolean" | "color" | "url" | "image";
312
+ type: "string" | "boolean" | "color" | "image" | "url" | "date";
230
313
  default: string | number | boolean | null;
231
314
  value: string | number | boolean | null;
232
315
  key: string;
@@ -235,8 +318,12 @@ export declare const updatePluginFeatures: (payload: UpdatePluginFeaturesPayload
235
318
  group: string | null;
236
319
  required: boolean;
237
320
  is_set: boolean;
238
- source: "default" | "stored" | "config" | "none";
321
+ source: "none" | "default" | "stored" | "config";
239
322
  invalidates: string[];
323
+ hint: string | null;
324
+ placeholder: string | null;
325
+ width: "full" | "half";
326
+ section: string | null;
240
327
  })[];
241
328
  configured: boolean;
242
329
  missing: string[];
@@ -249,6 +336,24 @@ export declare const updatePluginFeatures: (payload: UpdatePluginFeaturesPayload
249
336
  confirm: string | null;
250
337
  }[];
251
338
  admin_page: string | null;
339
+ icon: string | null;
340
+ summary: string | null;
341
+ disable_hint: string | null;
342
+ disable_confirm: string | null;
343
+ features_heading: string | null;
344
+ features_note: string | null;
345
+ all_off_warning: string | null;
346
+ require_enabled_feature: boolean;
347
+ setting_groups: {
348
+ name: string;
349
+ description: string | null;
350
+ note: string | null;
351
+ requires_feature: string | null;
352
+ visible_when: {
353
+ setting: string;
354
+ equals: string | boolean;
355
+ } | null;
356
+ }[];
252
357
  };
253
358
  }>;
254
359
  export declare const updatePluginSettings: (pluginKey: string, payload: UpdatePluginSettingsPayload) => Promise<{
@@ -277,8 +382,12 @@ export declare const updatePluginSettings: (pluginKey: string, payload: UpdatePl
277
382
  group: string | null;
278
383
  required: boolean;
279
384
  is_set: boolean;
280
- source: "default" | "stored" | "config" | "none";
385
+ source: "none" | "default" | "stored" | "config";
281
386
  invalidates: string[];
387
+ hint: string | null;
388
+ placeholder: string | null;
389
+ width: "full" | "half";
390
+ section: string | null;
282
391
  } | {
283
392
  type: "select";
284
393
  options: {
@@ -293,12 +402,17 @@ export declare const updatePluginSettings: (pluginKey: string, payload: UpdatePl
293
402
  group: string | null;
294
403
  required: boolean;
295
404
  is_set: boolean;
296
- source: "default" | "stored" | "config" | "none";
405
+ source: "none" | "default" | "stored" | "config";
297
406
  invalidates: string[];
407
+ hint: string | null;
408
+ placeholder: string | null;
409
+ width: "full" | "half";
410
+ section: string | null;
298
411
  } | {
299
412
  type: "number";
300
413
  min: number | null;
301
414
  max: number | null;
415
+ integer: boolean;
302
416
  default: number | null;
303
417
  value: number | null;
304
418
  key: string;
@@ -307,10 +421,14 @@ export declare const updatePluginSettings: (pluginKey: string, payload: UpdatePl
307
421
  group: string | null;
308
422
  required: boolean;
309
423
  is_set: boolean;
310
- source: "default" | "stored" | "config" | "none";
424
+ source: "none" | "default" | "stored" | "config";
311
425
  invalidates: string[];
426
+ hint: string | null;
427
+ placeholder: string | null;
428
+ width: "full" | "half";
429
+ section: string | null;
312
430
  } | {
313
- type: "string" | "boolean" | "color" | "url" | "image";
431
+ type: "string" | "boolean" | "color" | "image" | "url" | "date";
314
432
  default: string | number | boolean | null;
315
433
  value: string | number | boolean | null;
316
434
  key: string;
@@ -319,8 +437,12 @@ export declare const updatePluginSettings: (pluginKey: string, payload: UpdatePl
319
437
  group: string | null;
320
438
  required: boolean;
321
439
  is_set: boolean;
322
- source: "default" | "stored" | "config" | "none";
440
+ source: "none" | "default" | "stored" | "config";
323
441
  invalidates: string[];
442
+ hint: string | null;
443
+ placeholder: string | null;
444
+ width: "full" | "half";
445
+ section: string | null;
324
446
  })[];
325
447
  configured: boolean;
326
448
  missing: string[];
@@ -333,6 +455,24 @@ export declare const updatePluginSettings: (pluginKey: string, payload: UpdatePl
333
455
  confirm: string | null;
334
456
  }[];
335
457
  admin_page: string | null;
458
+ icon: string | null;
459
+ summary: string | null;
460
+ disable_hint: string | null;
461
+ disable_confirm: string | null;
462
+ features_heading: string | null;
463
+ features_note: string | null;
464
+ all_off_warning: string | null;
465
+ require_enabled_feature: boolean;
466
+ setting_groups: {
467
+ name: string;
468
+ description: string | null;
469
+ note: string | null;
470
+ requires_feature: string | null;
471
+ visible_when: {
472
+ setting: string;
473
+ equals: string | boolean;
474
+ } | null;
475
+ }[];
336
476
  };
337
477
  }>;
338
478
  export declare const runPluginAction: (pluginKey: string, actionKey: string) => Promise<{
@@ -0,0 +1,49 @@
1
+ import type { AdminPluginFeature, AdminPluginFeatures, AdminPluginSetting, PluginSettingSource } from "@hartl-services/medusa-food-supplements-contracts/types/plugin-features-admin";
2
+ /** Configured feature values (what the base stores), keyed by feature key. */
3
+ export declare const configuredFeatures: (plugin: Pick<AdminPluginFeatures, "features">) => Record<string, boolean>;
4
+ /** Labels of the required settings that have no value, "A, B". */
5
+ export declare const missingLabels: (plugin: Pick<AdminPluginFeatures, "missing" | "settings">) => string;
6
+ /** The plugin has settings that must be filled for it to count as configured. */
7
+ export declare const hasRequiredSettings: (plugin: Pick<AdminPluginFeatures, "settings">) => boolean;
8
+ /** The plugin is not configured: something required is missing. */
9
+ export declare const isUnconfigured: (plugin: Pick<AdminPluginFeatures, "settings" | "configured">) => boolean;
10
+ /**
11
+ * Every top-level feature is switched off (as configured, regardless of the
12
+ * plugin switch). `false` for a plugin without features.
13
+ */
14
+ export declare const allTopLevelFeaturesOff: (plugin: Pick<AdminPluginFeatures, "features">) => boolean;
15
+ /**
16
+ * The feature is the only enabled top-level feature of a plugin that requires
17
+ * one (`require_enabled_feature`): switching it off would be rejected by the
18
+ * server, so the Admin locks it.
19
+ */
20
+ export declare const isLastRequiredFeature: (plugin: Pick<AdminPluginFeatures, "features" | "require_enabled_feature">, feature: Pick<AdminPluginFeature, "key" | "parent_key" | "enabled">) => boolean;
21
+ /** The feature's parent when that parent is off, else `undefined`. */
22
+ export declare const disabledParent: (features: readonly AdminPluginFeature[], feature: AdminPluginFeature) => AdminPluginFeature | undefined;
23
+ /**
24
+ * Labels of the settings whose change deletes the given secret (reverse of
25
+ * `invalidates`), in the order the settings are declared.
26
+ */
27
+ export declare const invalidatedByLabels: (settings: readonly AdminPluginSetting[], secretKey: string) => string[];
28
+ /** Whether a settings group is dimmed: its required feature exists and is not effective. */
29
+ export declare const isGroupDimmed: (features: readonly AdminPluginFeature[], requiresFeature: string | null) => boolean;
30
+ /**
31
+ * Labels of the secrets that a change of `setting` deletes (forward
32
+ * `invalidates`), in the setting's order; unknown keys fall back to the key.
33
+ */
34
+ export declare const invalidatesLabels: (settings: readonly AdminPluginSetting[], setting: Pick<AdminPluginSetting, "invalidates">) => string[];
35
+ /**
36
+ * The description a setting shows in its info tooltip: only when a `hint`
37
+ * takes the place under the field and the description says something else.
38
+ */
39
+ export declare const settingInfoText: (setting: Pick<AdminPluginSetting, "hint" | "description">) => string | null;
40
+ /** The description a page header shows in its info tooltip: when the summary is shown instead and differs. */
41
+ export declare const headerInfoText: (plugin: Pick<AdminPluginFeatures, "summary" | "description">) => string | null;
42
+ /** "default" is the normal case and not worth a line under every field. */
43
+ export declare const showsSourceHint: (source: PluginSettingSource) => boolean;
44
+ /** The plain-language range line ("Zwischen 8 und 128.") is only a separate line when no `hint` explains the field. */
45
+ export declare const showsBoundsLine: (setting: Pick<AdminPluginSetting, "hint">) => boolean;
46
+ /** The plugins in hub order: those that cannot be switched off first, then the server's order. */
47
+ export declare const hubOrder: <T extends {
48
+ switchable: boolean;
49
+ }>(plugins: readonly T[]) => T[];
@@ -0,0 +1,72 @@
1
+ /** Configured feature values (what the base stores), keyed by feature key. */
2
+ export const configuredFeatures = (plugin) => Object.fromEntries(plugin.features.map((feature) => [feature.key, feature.enabled]));
3
+ /** Labels of the required settings that have no value, "A, B". */
4
+ export const missingLabels = (plugin) => plugin.missing
5
+ .map((key) => plugin.settings.find((setting) => setting.key === key)?.label ?? key)
6
+ .join(", ");
7
+ /** The plugin has settings that must be filled for it to count as configured. */
8
+ export const hasRequiredSettings = (plugin) => plugin.settings.some((setting) => setting.required);
9
+ /** The plugin is not configured: something required is missing. */
10
+ export const isUnconfigured = (plugin) => !plugin.configured && hasRequiredSettings(plugin);
11
+ /**
12
+ * Every top-level feature is switched off (as configured, regardless of the
13
+ * plugin switch). `false` for a plugin without features.
14
+ */
15
+ export const allTopLevelFeaturesOff = (plugin) => {
16
+ const topLevel = plugin.features.filter((feature) => feature.parent_key === null);
17
+ return topLevel.length > 0 && topLevel.every((feature) => !feature.enabled);
18
+ };
19
+ /**
20
+ * The feature is the only enabled top-level feature of a plugin that requires
21
+ * one (`require_enabled_feature`): switching it off would be rejected by the
22
+ * server, so the Admin locks it.
23
+ */
24
+ export const isLastRequiredFeature = (plugin, feature) => plugin.require_enabled_feature &&
25
+ feature.parent_key === null &&
26
+ feature.enabled &&
27
+ plugin.features.every((other) => other.key === feature.key || other.parent_key !== null || !other.enabled);
28
+ /** The feature's parent when that parent is off, else `undefined`. */
29
+ export const disabledParent = (features, feature) => {
30
+ const parent = features.find((candidate) => candidate.key === feature.parent_key);
31
+ return parent && !parent.enabled ? parent : undefined;
32
+ };
33
+ /**
34
+ * Labels of the settings whose change deletes the given secret (reverse of
35
+ * `invalidates`), in the order the settings are declared.
36
+ */
37
+ export const invalidatedByLabels = (settings, secretKey) => settings
38
+ .filter((setting) => setting.invalidates.includes(secretKey))
39
+ .map((setting) => setting.label);
40
+ /** Whether a settings group is dimmed: its required feature exists and is not effective. */
41
+ export const isGroupDimmed = (features, requiresFeature) => requiresFeature !== null &&
42
+ features.find((feature) => feature.key === requiresFeature)
43
+ ?.effective_enabled === false;
44
+ /**
45
+ * Labels of the secrets that a change of `setting` deletes (forward
46
+ * `invalidates`), in the setting's order; unknown keys fall back to the key.
47
+ */
48
+ export const invalidatesLabels = (settings, setting) => setting.invalidates.map((key) => settings.find((candidate) => candidate.key === key)?.label ?? key);
49
+ /**
50
+ * The description a setting shows in its info tooltip: only when a `hint`
51
+ * takes the place under the field and the description says something else.
52
+ */
53
+ export const settingInfoText = (setting) => setting.hint !== null &&
54
+ setting.description !== null &&
55
+ setting.description !== setting.hint
56
+ ? setting.description
57
+ : null;
58
+ /** The description a page header shows in its info tooltip: when the summary is shown instead and differs. */
59
+ export const headerInfoText = (plugin) => plugin.summary !== null &&
60
+ plugin.description !== null &&
61
+ plugin.description !== plugin.summary
62
+ ? plugin.description
63
+ : null;
64
+ /** "default" is the normal case and not worth a line under every field. */
65
+ export const showsSourceHint = (source) => source !== "default";
66
+ /** The plain-language range line ("Zwischen 8 und 128.") is only a separate line when no `hint` explains the field. */
67
+ export const showsBoundsLine = (setting) => setting.hint === null;
68
+ /** The plugins in hub order: those that cannot be switched off first, then the server's order. */
69
+ export const hubOrder = (plugins) => [
70
+ ...plugins.filter((plugin) => !plugin.switchable),
71
+ ...plugins.filter((plugin) => plugin.switchable),
72
+ ];
@@ -12,17 +12,6 @@ export declare const initialSettingsDraft: (settings: readonly AdminPluginSettin
12
12
  export declare const isHexColor: (value: string) => boolean;
13
13
  /** Colors are typed and sent lowercase; surrounding spaces are dropped. */
14
14
  export declare const normalizeColorInput: (value: string) => string;
15
- export type SettingSection = {
16
- /** Section heading; `null` = no heading. */
17
- group: string | null;
18
- settings: AdminPluginSetting[];
19
- };
20
- /**
21
- * Splits the settings (in their given order) into consecutive runs of the
22
- * same `group`; a new section starts whenever the group differs from the
23
- * previous setting's group.
24
- */
25
- export declare const groupSettings: (settings: readonly AdminPluginSetting[]) => SettingSection[];
26
15
  /**
27
16
  * Keys of number fields whose input the browser could not parse (e.g. "1e"):
28
17
  * the input then reports `""`, which must not be read as "cleared".
@@ -30,7 +19,7 @@ export declare const groupSettings: (settings: readonly AdminPluginSetting[]) =>
30
19
  export type UnparsableKeys = readonly string[];
31
20
  /**
32
21
  * Keys whose draft value cannot be sent: unparsable, not a number or
33
- * outside min/max, or a color that is not `#rrggbb`. Saving is disabled while any key is listed.
22
+ * outside min/max, a fraction for an integer setting, or a color that is not `#rrggbb`. Saving is disabled while any key is listed.
34
23
  */
35
24
  export declare const invalidDraftKeys: (settings: readonly AdminPluginSetting[], draft: SettingsDraft, unparsable?: UnparsableKeys) => string[];
36
25
  /**
@@ -13,24 +13,6 @@ const HEX_COLOR = /^#[0-9a-fA-F]{6}$/;
13
13
  export const isHexColor = (value) => HEX_COLOR.test(value);
14
14
  /** Colors are typed and sent lowercase; surrounding spaces are dropped. */
15
15
  export const normalizeColorInput = (value) => value.trim().toLowerCase();
16
- /**
17
- * Splits the settings (in their given order) into consecutive runs of the
18
- * same `group`; a new section starts whenever the group differs from the
19
- * previous setting's group.
20
- */
21
- export const groupSettings = (settings) => {
22
- const sections = [];
23
- for (const setting of settings) {
24
- const last = sections[sections.length - 1];
25
- if (last && last.group === setting.group) {
26
- last.settings.push(setting);
27
- }
28
- else {
29
- sections.push({ group: setting.group, settings: [setting] });
30
- }
31
- }
32
- return sections;
33
- };
34
16
  const outsideBounds = (setting, value) => (setting.min !== null && value < setting.min) ||
35
17
  (setting.max !== null && value > setting.max);
36
18
  const numberEntryValue = (entry) => {
@@ -39,7 +21,7 @@ const numberEntryValue = (entry) => {
39
21
  };
40
22
  /**
41
23
  * Keys whose draft value cannot be sent: unparsable, not a number or
42
- * outside min/max, or a color that is not `#rrggbb`. Saving is disabled while any key is listed.
24
+ * outside min/max, a fraction for an integer setting, or a color that is not `#rrggbb`. Saving is disabled while any key is listed.
43
25
  */
44
26
  export const invalidDraftKeys = (settings, draft, unparsable = []) => settings
45
27
  .filter((setting) => {
@@ -60,7 +42,9 @@ export const invalidDraftKeys = (settings, draft, unparsable = []) => settings
60
42
  return false;
61
43
  }
62
44
  const value = numberEntryValue(entry);
63
- return value === null || outsideBounds(setting, value);
45
+ return (value === null ||
46
+ outsideBounds(setting, value) ||
47
+ (setting.integer && !Number.isInteger(value)));
64
48
  })
65
49
  .map((setting) => setting.key);
66
50
  /**
@@ -0,0 +1,47 @@
1
+ import type { AdminPluginSetting, AdminPluginSettingGroup } from "@hartl-services/medusa-food-supplements-contracts/types/plugin-features-admin";
2
+ /** One row of fields: a full-width setting, or consecutive `half` settings sharing a row. */
3
+ export type SettingFieldRow = {
4
+ kind: "full";
5
+ setting: AdminPluginSetting;
6
+ } | {
7
+ kind: "half";
8
+ settings: AdminPluginSetting[];
9
+ };
10
+ /**
11
+ * A run of rows in a group. Boolean settings are switch rows of their own;
12
+ * all other settings between two switches (or two sub-headings) share one
13
+ * `fields` block. `heading` is the sub-heading that starts the block.
14
+ */
15
+ export type SettingBlock = {
16
+ kind: "fields";
17
+ heading: string | null;
18
+ rows: SettingFieldRow[];
19
+ } | {
20
+ kind: "switch";
21
+ heading: string | null;
22
+ setting: AdminPluginSetting;
23
+ };
24
+ /** One card of the settings form: a group with its metadata and blocks. */
25
+ export type SettingGroupView = {
26
+ /** Group name as in `setting.group`; `null` = the ungrouped settings. */
27
+ name: string | null;
28
+ /** Card heading (the group name, or the fallback title for ungrouped). */
29
+ title: string;
30
+ description: string | null;
31
+ note: string | null;
32
+ requiresFeature: string | null;
33
+ /** The group applies only while this setting's draft value equals `equals`. */
34
+ visibleWhen: AdminPluginSettingGroup["visible_when"];
35
+ settings: AdminPluginSetting[];
36
+ blocks: SettingBlock[];
37
+ };
38
+ /** Blocks of one group's settings (in their given order). */
39
+ export declare const buildSettingBlocks: (settings: readonly AdminPluginSetting[]) => SettingBlock[];
40
+ /**
41
+ * Groups the settings into cards, in order of the first appearance of each
42
+ * group; settings without a group form one card titled `ungroupedTitle`.
43
+ * `groups` supplies the description, note and required feature per group.
44
+ */
45
+ export declare const buildSettingGroups: (settings: readonly AdminPluginSetting[], groups: readonly AdminPluginSettingGroup[], ungroupedTitle: string) => SettingGroupView[];
46
+ /** Whether a group's `visible_when` holds for the current form values. */
47
+ export declare const isGroupVisible: (group: Pick<SettingGroupView, "visibleWhen">, draft: Readonly<Record<string, string | boolean | null>>) => boolean;