@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.
- package/.medusa/server/src/admin/admin-components/features/plugin-features/components/ImageSettingInput.d.ts +3 -2
- package/.medusa/server/src/admin/admin-components/features/plugin-features/components/ImageSettingInput.js +4 -4
- package/.medusa/server/src/admin/admin-components/features/plugin-features/components/PluginActionsSection.js +4 -4
- package/.medusa/server/src/admin/admin-components/features/plugin-features/components/PluginBreadcrumb.d.ts +16 -0
- package/.medusa/server/src/admin/admin-components/features/plugin-features/components/PluginBreadcrumb.js +25 -0
- package/.medusa/server/src/admin/admin-components/features/plugin-features/components/PluginDetailPage.js +1 -1
- package/.medusa/server/src/admin/admin-components/features/plugin-features/components/PluginFeatureSections.d.ts +5 -4
- package/.medusa/server/src/admin/admin-components/features/plugin-features/components/PluginFeatureSections.js +8 -5
- package/.medusa/server/src/admin/admin-components/features/plugin-features/components/PluginFeaturesCard.d.ts +4 -4
- package/.medusa/server/src/admin/admin-components/features/plugin-features/components/PluginFeaturesCard.js +24 -27
- package/.medusa/server/src/admin/admin-components/features/plugin-features/components/PluginFeaturesSettingsPage.d.ts +2 -2
- package/.medusa/server/src/admin/admin-components/features/plugin-features/components/PluginFeaturesSettingsPage.js +9 -9
- package/.medusa/server/src/admin/admin-components/features/plugin-features/components/PluginHubCard.d.ts +5 -1
- package/.medusa/server/src/admin/admin-components/features/plugin-features/components/PluginHubCard.js +11 -15
- package/.medusa/server/src/admin/admin-components/features/plugin-features/components/PluginPageShell.d.ts +10 -4
- package/.medusa/server/src/admin/admin-components/features/plugin-features/components/PluginPageShell.js +10 -5
- package/.medusa/server/src/admin/admin-components/features/plugin-features/components/PluginSettingsForm.d.ts +0 -1
- package/.medusa/server/src/admin/admin-components/features/plugin-features/components/PluginSettingsForm.js +77 -26
- package/.medusa/server/src/admin/admin-components/features/plugin-features/components/PluginStatusChips.d.ts +5 -1
- package/.medusa/server/src/admin/admin-components/features/plugin-features/components/PluginStatusChips.js +8 -6
- package/.medusa/server/src/admin/admin-components/features/plugin-features/components/ShopMasterDataBanner.d.ts +11 -0
- package/.medusa/server/src/admin/admin-components/features/plugin-features/components/ShopMasterDataBanner.js +15 -0
- package/.medusa/server/src/admin/admin-components/features/plugin-features/hooks/usePluginFeatureEnabled.d.ts +40 -5
- package/.medusa/server/src/admin/admin-components/features/plugin-features/hooks/usePluginFeatures.d.ts +160 -20
- package/.medusa/server/src/admin/admin-components/features/plugin-features/hooks/usePluginSettingsForm.d.ts +40 -5
- package/.medusa/server/src/admin/admin-components/features/plugin-features/hooks/usePluginSwitch.d.ts +15 -0
- package/.medusa/server/src/admin/admin-components/features/plugin-features/hooks/usePluginSwitch.js +66 -0
- package/.medusa/server/src/admin/admin-components/features/plugin-features/lib/plugin-features-admin-client.d.ts +160 -20
- package/.medusa/server/src/admin/admin-components/features/plugin-features/lib/plugin-view.d.ts +49 -0
- package/.medusa/server/src/admin/admin-components/features/plugin-features/lib/plugin-view.js +72 -0
- package/.medusa/server/src/admin/admin-components/features/plugin-features/lib/settings-draft.d.ts +1 -12
- package/.medusa/server/src/admin/admin-components/features/plugin-features/lib/settings-draft.js +4 -20
- package/.medusa/server/src/admin/admin-components/features/plugin-features/lib/settings-layout.d.ts +47 -0
- package/.medusa/server/src/admin/admin-components/features/plugin-features/lib/settings-layout.js +70 -0
- package/.medusa/server/src/admin/admin-components/i18n/texts.d.ts +22 -2
- package/.medusa/server/src/admin/admin-components/i18n/texts.js +29 -7
- package/.medusa/server/src/admin/admin-components/index.d.ts +12 -0
- package/.medusa/server/src/admin/admin-components/index.js +11 -0
- package/.medusa/server/src/admin/admin-components/shared/ui/AdminPageHeader.d.ts +22 -0
- package/.medusa/server/src/admin/admin-components/shared/ui/AdminPageHeader.js +8 -0
- package/.medusa/server/src/admin/admin-components/shared/ui/AdminSection.d.ts +26 -0
- package/.medusa/server/src/admin/admin-components/shared/ui/AdminSection.js +12 -0
- package/.medusa/server/src/admin/admin-components/shared/ui/BreadcrumbTrail.d.ts +23 -0
- package/.medusa/server/src/admin/admin-components/shared/ui/BreadcrumbTrail.js +20 -0
- package/.medusa/server/src/admin/admin-components/shared/ui/FileDropField.d.ts +21 -0
- package/.medusa/server/src/admin/admin-components/shared/ui/FileDropField.js +33 -0
- package/.medusa/server/src/admin/admin-components/shared/ui/FocusModalShell.d.ts +27 -0
- package/.medusa/server/src/admin/admin-components/shared/ui/FocusModalShell.js +13 -0
- package/.medusa/server/src/admin/admin-components/shared/ui/InfoTooltip.d.ts +13 -0
- package/.medusa/server/src/admin/admin-components/shared/ui/InfoTooltip.js +8 -0
- package/.medusa/server/src/admin/admin-components/shared/ui/MultiSelectDropdown.d.ts +22 -0
- package/.medusa/server/src/admin/admin-components/shared/ui/MultiSelectDropdown.js +14 -0
- package/.medusa/server/src/admin/admin-components/shared/ui/PluginIcon.d.ts +10 -0
- package/.medusa/server/src/admin/admin-components/shared/ui/PluginIcon.js +10 -0
- package/.medusa/server/src/admin/admin-components/shared/ui/SwitchRow.d.ts +27 -0
- package/.medusa/server/src/admin/admin-components/shared/ui/SwitchRow.js +15 -0
- package/.medusa/server/src/admin/admin-components/shared/ui/WidgetHeader.d.ts +15 -0
- package/.medusa/server/src/admin/admin-components/shared/ui/WidgetHeader.js +8 -0
- package/.medusa/server/src/admin/admin-components/shared/ui/file-drop.d.ts +13 -0
- package/.medusa/server/src/admin/admin-components/shared/ui/file-drop.js +16 -0
- package/.medusa/server/src/admin/admin-components/shared/ui/multi-select.d.ts +13 -0
- package/.medusa/server/src/admin/admin-components/shared/ui/multi-select.js +11 -0
- package/.medusa/server/src/admin/admin-components/shared/ui/plugin-icon.d.ts +12 -0
- package/.medusa/server/src/admin/admin-components/shared/ui/plugin-icon.js +29 -0
- package/.medusa/server/src/admin/index.js +3155 -2039
- package/.medusa/server/src/admin/index.mjs +3158 -2042
- package/.medusa/server/src/api/admin-first-login-password-policy.js +56 -0
- package/.medusa/server/src/api/answer-actor-type-casing-not-found.js +26 -0
- package/.medusa/server/src/api/answer-code-provider-route-not-found.js +34 -0
- package/.medusa/server/src/api/code-account-password-routes.js +92 -0
- package/.medusa/server/src/api/middlewares.js +82 -17
- package/.medusa/server/src/api/password-policy.js +55 -10
- package/.medusa/server/src/api/require-login-code-customer-email.js +40 -0
- package/.medusa/server/src/api/store/customer-auth/login-code/route.js +17 -0
- package/.medusa/server/src/api/store/customer-auth/password-policy/route.js +19 -0
- package/.medusa/server/src/customer-auth/application/prepare-code-account-password-reset.js +111 -0
- package/.medusa/server/src/customer-auth/application/request-login-code.js +145 -0
- package/.medusa/server/src/customer-auth/customer-auth-methods-snapshot.js +55 -0
- package/.medusa/server/src/customer-auth/customer-password-policy.js +40 -0
- package/.medusa/server/src/customer-auth/domain/account-linking.js +53 -0
- package/.medusa/server/src/customer-auth/domain/auth-methods.js +32 -0
- package/.medusa/server/src/customer-auth/domain/login-code.js +39 -0
- package/.medusa/server/src/customer-auth/login-code-accounts.js +146 -0
- package/.medusa/server/src/customer-auth/login-code-state.js +139 -0
- package/.medusa/server/src/customer-auth/plugin-features.js +80 -0
- package/.medusa/server/src/customer-auth/remove-provider-identity.js +18 -0
- package/.medusa/server/src/customer-auth/start-customer-auth-methods.js +20 -0
- package/.medusa/server/src/documents/plugin-features.js +8 -2
- package/.medusa/server/src/email/application/deliver-ephemeral-auth-mail.js +186 -0
- package/.medusa/server/src/email/application/deliver-login-code.js +89 -0
- package/.medusa/server/src/email/application/handle-customer-verification-event.js +29 -168
- package/.medusa/server/src/email/application/handle-password-reset-event.js +27 -166
- package/.medusa/server/src/email/customer-verification-snapshot.js +20 -108
- package/.medusa/server/src/email/domain/business-keys.js +15 -2
- package/.medusa/server/src/email/plugin-features.js +8 -3
- package/.medusa/server/src/email/rendering/default-templates.js +2 -1
- package/.medusa/server/src/email/templates/blocks/dynamic-blocks.js +19 -1
- package/.medusa/server/src/email/templates/defaults/documents.js +7 -1
- package/.medusa/server/src/email/templates/defaults/subjects.js +3 -1
- package/.medusa/server/src/email/templates/defaults/texts.js +5 -2
- package/.medusa/server/src/email/templates/render.js +2 -1
- package/.medusa/server/src/email/templates/sample-data.js +2 -1
- package/.medusa/server/src/email/templates/validate.js +8 -3
- package/.medusa/server/src/email/types/email-kinds.js +4 -2
- package/.medusa/server/src/email/types/template-data.js +9 -1
- package/.medusa/server/src/modules/customer-auth/index.js +14 -0
- package/.medusa/server/src/modules/customer-auth/service.js +35 -0
- package/.medusa/server/src/modules/email/migrations/Migration20261010090000.js +20 -0
- package/.medusa/server/src/modules/plugin-features/domain/plugin-settings.js +30 -6
- package/.medusa/server/src/modules/plugin-features/service.js +29 -3
- package/.medusa/server/src/providers/email-otp/index.js +8 -0
- package/.medusa/server/src/providers/email-otp/service.js +96 -0
- package/.medusa/server/src/public/descriptor.js +138 -5
- package/.medusa/server/src/public/effective-features.js +22 -1
- package/.medusa/server/src/public/index.js +4 -2
- package/.medusa/server/src/public/plugin-icons.js +28 -0
- package/.medusa/server/src/public/shop-master-data.js +33 -14
- package/.medusa/server/src/shared/lib/dates.js +8 -2
- package/.medusa/server/src/shared/lib/index.js +2 -1
- package/.medusa/server/src/shared/lib/refreshing-snapshot.js +122 -0
- package/.medusa/server/src/shop-config/build-food-shop-config.js +38 -1
- package/README.md +436 -87
- package/dist/customer-auth/customer-auth-methods-snapshot.d.ts +25 -0
- package/dist/customer-auth/customer-auth-methods-snapshot.js +54 -0
- package/dist/customer-auth/domain/auth-methods.d.ts +16 -0
- package/dist/customer-auth/domain/auth-methods.js +31 -0
- package/dist/customer-auth/plugin-features.d.ts +2 -0
- package/dist/customer-auth/plugin-features.js +79 -0
- package/dist/email/customer-verification-snapshot.d.ts +3 -15
- package/dist/email/customer-verification-snapshot.js +19 -107
- package/dist/email/types/email-kinds.d.ts +4 -3
- package/dist/email/types/email-kinds.js +3 -1
- package/dist/email/types/template-data.d.ts +8 -0
- package/dist/email/types/template-data.js +8 -0
- package/dist/public/descriptor.js +137 -4
- package/dist/public/effective-features.d.ts +10 -0
- package/dist/public/effective-features.js +21 -0
- package/dist/public/index.d.ts +2 -1
- package/dist/public/index.js +3 -1
- package/dist/public/plugin-icons.d.ts +7 -0
- package/dist/public/plugin-icons.js +27 -0
- package/dist/public/shop-master-data.js +32 -13
- package/dist/public/types.d.ts +74 -2
- package/dist/shared/lib/dates.d.ts +2 -0
- package/dist/shared/lib/dates.js +7 -1
- package/dist/shared/lib/index.d.ts +1 -0
- package/dist/shared/lib/index.js +1 -0
- package/dist/shared/lib/refreshing-snapshot.d.ts +52 -0
- package/dist/shared/lib/refreshing-snapshot.js +121 -0
- package/dist/shop-config/build-food-shop-config.js +37 -0
- package/package.json +8 -3
|
@@ -4,6 +4,7 @@ exports.validatePluginFeatureDescriptor = validatePluginFeatureDescriptor;
|
|
|
4
4
|
exports.definePluginFeatures = definePluginFeatures;
|
|
5
5
|
const utils_1 = require("@medusajs/framework/utils");
|
|
6
6
|
const lib_1 = require("../shared/lib");
|
|
7
|
+
const plugin_icons_1 = require("./plugin-icons");
|
|
7
8
|
const KEY_PATTERN = /^[a-z][a-z0-9_]{0,62}$/;
|
|
8
9
|
const SETTING_TYPES = new Set([
|
|
9
10
|
"string",
|
|
@@ -14,12 +15,17 @@ const SETTING_TYPES = new Set([
|
|
|
14
15
|
"select",
|
|
15
16
|
"image",
|
|
16
17
|
"color",
|
|
18
|
+
"date",
|
|
17
19
|
]);
|
|
18
20
|
const HEX_COLOR_PATTERN = /^#[0-9a-f]{6}$/;
|
|
19
21
|
const ACTION_MODES = new Set(["sync", "background"]);
|
|
20
22
|
const ADMIN_PAGE_PREFIX = "/settings/hartl-services/";
|
|
21
23
|
const BASE_PAGE_PREFIX = "/settings/hartl-services/plugin/";
|
|
22
24
|
const ADMIN_PAGE_PATTERN = /^\/settings\/hartl-services(\/[a-z0-9][a-z0-9_-]*)+$/;
|
|
25
|
+
const ICON_NAMES = new Set(plugin_icons_1.PLUGIN_ICON_NAMES);
|
|
26
|
+
const SETTING_WIDTHS = new Set(["full", "half"]);
|
|
27
|
+
/** Types an input placeholder makes no sense for. */
|
|
28
|
+
const NO_PLACEHOLDER_TYPES = new Set(["boolean", "select", "image", "color", "date"]);
|
|
23
29
|
const invalid = (pluginKey, message) => new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, `Ungültige Funktionsschalter für Plugin "${pluginKey}": ${message}`);
|
|
24
30
|
const defaultMatchesType = (setting) => {
|
|
25
31
|
const value = setting.default;
|
|
@@ -31,8 +37,12 @@ const defaultMatchesType = (setting) => {
|
|
|
31
37
|
return typeof value === "string" && (0, lib_1.isHttpUrl)(value);
|
|
32
38
|
case "color":
|
|
33
39
|
return typeof value === "string" && HEX_COLOR_PATTERN.test(value);
|
|
40
|
+
case "date":
|
|
41
|
+
return typeof value === "string" && (0, lib_1.isCalendarDate)(value);
|
|
34
42
|
case "number":
|
|
35
|
-
return typeof value === "number" &&
|
|
43
|
+
return (typeof value === "number" &&
|
|
44
|
+
Number.isFinite(value) &&
|
|
45
|
+
(setting.integer !== true || Number.isInteger(value)));
|
|
36
46
|
case "boolean":
|
|
37
47
|
return typeof value === "boolean";
|
|
38
48
|
case "select":
|
|
@@ -46,7 +56,10 @@ const withinBounds = (setting) => typeof setting.default !== "number" ||
|
|
|
46
56
|
((setting.min === undefined || setting.default >= setting.min) &&
|
|
47
57
|
(setting.max === undefined || setting.default <= setting.max));
|
|
48
58
|
const isFiniteNumber = (value) => typeof value === "number" && Number.isFinite(value);
|
|
49
|
-
/**
|
|
59
|
+
/**
|
|
60
|
+
* `options` only (and required) for select, `min`/`max`/`integer` only for
|
|
61
|
+
* number.
|
|
62
|
+
*/
|
|
50
63
|
const validateTypeExtras = (pluginKey, setting) => {
|
|
51
64
|
if (setting.type === "select") {
|
|
52
65
|
const options = setting.options;
|
|
@@ -68,11 +81,16 @@ const validateTypeExtras = (pluginKey, setting) => {
|
|
|
68
81
|
throw invalid(pluginKey, `Einstellung "${setting.key}": options gibt es nur bei "select".`);
|
|
69
82
|
}
|
|
70
83
|
if (setting.type !== "number") {
|
|
71
|
-
if (setting.min !== undefined ||
|
|
72
|
-
|
|
84
|
+
if (setting.min !== undefined ||
|
|
85
|
+
setting.max !== undefined ||
|
|
86
|
+
setting.integer !== undefined) {
|
|
87
|
+
throw invalid(pluginKey, `Einstellung "${setting.key}": min/max/integer gibt es nur bei "number".`);
|
|
73
88
|
}
|
|
74
89
|
return;
|
|
75
90
|
}
|
|
91
|
+
if (setting.integer !== undefined && typeof setting.integer !== "boolean") {
|
|
92
|
+
throw invalid(pluginKey, `Einstellung "${setting.key}": integer muss boolean sein.`);
|
|
93
|
+
}
|
|
76
94
|
for (const [name, bound] of [
|
|
77
95
|
["min", setting.min],
|
|
78
96
|
["max", setting.max],
|
|
@@ -111,6 +129,28 @@ const validateInvalidates = (pluginKey, setting, settings) => {
|
|
|
111
129
|
seen.add(key);
|
|
112
130
|
}
|
|
113
131
|
};
|
|
132
|
+
/** `hint`, `placeholder`, `section` and `width` of one setting. */
|
|
133
|
+
const validateDisplayFields = (pluginKey, setting) => {
|
|
134
|
+
for (const name of ["hint", "placeholder", "section"]) {
|
|
135
|
+
const value = setting[name];
|
|
136
|
+
if (value !== undefined && !(0, lib_1.isNonEmptyString)(value)) {
|
|
137
|
+
throw invalid(pluginKey, `Einstellung "${setting.key}": ${name} muss ein nicht-leerer Text sein.`);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
if (setting.placeholder !== undefined && NO_PLACEHOLDER_TYPES.has(setting.type)) {
|
|
141
|
+
throw invalid(pluginKey, `Einstellung "${setting.key}": placeholder gibt es nicht bei "${setting.type}".`);
|
|
142
|
+
}
|
|
143
|
+
const width = setting.width;
|
|
144
|
+
if (width === undefined) {
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
if (typeof width !== "string" || !SETTING_WIDTHS.has(width)) {
|
|
148
|
+
throw invalid(pluginKey, `Einstellung "${setting.key}": width muss "full" oder "half" sein.`);
|
|
149
|
+
}
|
|
150
|
+
if (setting.type === "boolean") {
|
|
151
|
+
throw invalid(pluginKey, `Einstellung "${setting.key}": width gibt es nicht bei "boolean".`);
|
|
152
|
+
}
|
|
153
|
+
};
|
|
114
154
|
const validateSettings = (pluginKey, settings) => {
|
|
115
155
|
const seen = new Set();
|
|
116
156
|
for (const setting of settings) {
|
|
@@ -134,6 +174,7 @@ const validateSettings = (pluginKey, settings) => {
|
|
|
134
174
|
throw invalid(pluginKey, `Einstellung "${setting.key}": required muss boolean sein.`);
|
|
135
175
|
}
|
|
136
176
|
validateTypeExtras(pluginKey, setting);
|
|
177
|
+
validateDisplayFields(pluginKey, setting);
|
|
137
178
|
validateInvalidates(pluginKey, setting, settings);
|
|
138
179
|
if (setting.default === undefined) {
|
|
139
180
|
continue;
|
|
@@ -184,6 +225,96 @@ const validateAdminPage = (pluginKey, path) => {
|
|
|
184
225
|
throw invalid(pluginKey, `admin_page "${String(path)}" muss unter "${ADMIN_PAGE_PREFIX}<plugin>" liegen und darf nicht mit "${BASE_PAGE_PREFIX}" beginnen.`);
|
|
185
226
|
}
|
|
186
227
|
};
|
|
228
|
+
/**
|
|
229
|
+
* `visible_when` points at a select or boolean setting outside the group and
|
|
230
|
+
* `equals` is one of its possible values.
|
|
231
|
+
*/
|
|
232
|
+
const validateVisibleWhen = (pluginKey, groupName, condition, settings) => {
|
|
233
|
+
if (condition === undefined) {
|
|
234
|
+
return;
|
|
235
|
+
}
|
|
236
|
+
const { setting: key, equals } = (condition ?? {});
|
|
237
|
+
const target = settings.find((setting) => setting.key === key);
|
|
238
|
+
const fits = target?.type === "select"
|
|
239
|
+
? (target.options ?? []).some((option) => option.value === equals)
|
|
240
|
+
: target?.type === "boolean" && typeof equals === "boolean";
|
|
241
|
+
if (!target || target.group === groupName || !fits) {
|
|
242
|
+
throw invalid(pluginKey, `Einstellungsgruppe "${groupName}": visible_when muss auf eine Auswahl oder einen Schalter außerhalb der Gruppe mit einem ihrer Werte zeigen.`);
|
|
243
|
+
}
|
|
244
|
+
};
|
|
245
|
+
/**
|
|
246
|
+
* Metadata per settings group: unique names, each used by a setting's
|
|
247
|
+
* `group`, `requires_feature` a declared feature key, `visible_when` valid.
|
|
248
|
+
*/
|
|
249
|
+
const validateSettingGroups = (pluginKey, groups, settings, featureKeys) => {
|
|
250
|
+
if (groups === undefined) {
|
|
251
|
+
return;
|
|
252
|
+
}
|
|
253
|
+
if (!Array.isArray(groups)) {
|
|
254
|
+
throw invalid(pluginKey, "setting_groups muss eine Liste sein.");
|
|
255
|
+
}
|
|
256
|
+
const usedGroups = new Set(settings.map((setting) => setting.group));
|
|
257
|
+
const seen = new Set();
|
|
258
|
+
for (const group of groups) {
|
|
259
|
+
if (!(0, lib_1.isNonEmptyString)(group?.name)) {
|
|
260
|
+
throw invalid(pluginKey, "Eine Einstellungsgruppe hat keinen name.");
|
|
261
|
+
}
|
|
262
|
+
if (seen.has(group.name)) {
|
|
263
|
+
throw invalid(pluginKey, `Einstellungsgruppe "${group.name}" ist doppelt.`);
|
|
264
|
+
}
|
|
265
|
+
seen.add(group.name);
|
|
266
|
+
if (!usedGroups.has(group.name)) {
|
|
267
|
+
throw invalid(pluginKey, `Einstellungsgruppe "${group.name}" wird von keiner Einstellung verwendet.`);
|
|
268
|
+
}
|
|
269
|
+
for (const name of ["description", "note"]) {
|
|
270
|
+
if (group[name] !== undefined && !(0, lib_1.isNonEmptyString)(group[name])) {
|
|
271
|
+
throw invalid(pluginKey, `Einstellungsgruppe "${group.name}": ${name} muss ein nicht-leerer Text sein.`);
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
if (group.requires_feature !== undefined &&
|
|
275
|
+
!featureKeys.has(group.requires_feature)) {
|
|
276
|
+
throw invalid(pluginKey, `Einstellungsgruppe "${group.name}": requires_feature "${String(group.requires_feature)}" ist kein Feature dieses Plugins.`);
|
|
277
|
+
}
|
|
278
|
+
validateVisibleWhen(pluginKey, group.name, group.visible_when, settings);
|
|
279
|
+
}
|
|
280
|
+
};
|
|
281
|
+
/** Optional texts and icon of the plugin's Admin page. */
|
|
282
|
+
const validatePresentation = (pluginKey, descriptor) => {
|
|
283
|
+
const icon = descriptor.icon;
|
|
284
|
+
if (icon !== undefined && (typeof icon !== "string" || !ICON_NAMES.has(icon))) {
|
|
285
|
+
throw invalid(pluginKey, `icon "${String(icon)}" ist kein bekannter Icon-Name.`);
|
|
286
|
+
}
|
|
287
|
+
for (const name of [
|
|
288
|
+
"summary",
|
|
289
|
+
"disable_hint",
|
|
290
|
+
"disable_confirm",
|
|
291
|
+
"features_heading",
|
|
292
|
+
"features_note",
|
|
293
|
+
"all_off_warning",
|
|
294
|
+
]) {
|
|
295
|
+
const value = descriptor[name];
|
|
296
|
+
if (value !== undefined && !(0, lib_1.isNonEmptyString)(value)) {
|
|
297
|
+
throw invalid(pluginKey, `${name} muss ein nicht-leerer Text sein.`);
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
if (descriptor.switchable === false &&
|
|
301
|
+
(descriptor.disable_hint !== undefined ||
|
|
302
|
+
descriptor.disable_confirm !== undefined)) {
|
|
303
|
+
throw invalid(pluginKey, "disable_hint und disable_confirm gibt es nur bei abschaltbaren Plugins.");
|
|
304
|
+
}
|
|
305
|
+
if (descriptor.all_off_warning !== undefined && descriptor.features.length === 0) {
|
|
306
|
+
throw invalid(pluginKey, "all_off_warning braucht mindestens ein Feature.");
|
|
307
|
+
}
|
|
308
|
+
const requireEnabled = descriptor.require_enabled_feature;
|
|
309
|
+
if (requireEnabled !== undefined) {
|
|
310
|
+
if (requireEnabled !== true) {
|
|
311
|
+
throw invalid(pluginKey, "require_enabled_feature muss true sein.");
|
|
312
|
+
}
|
|
313
|
+
if (!descriptor.features.some((feature) => feature.parent_key === undefined && feature.default_enabled)) {
|
|
314
|
+
throw invalid(pluginKey, "require_enabled_feature braucht mindestens ein Feature ohne parent_key mit default_enabled: true.");
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
};
|
|
187
318
|
/**
|
|
188
319
|
* Checks key format, unique feature keys, existing parents and the single
|
|
189
320
|
* allowed nesting level, plus the optional settings, actions and Admin page.
|
|
@@ -236,7 +367,9 @@ function validatePluginFeatureDescriptor(descriptor) {
|
|
|
236
367
|
throw invalid(pluginKey, `Feature "${feature.key}" ist zu tief verschachtelt; erlaubt ist eine Ebene.`);
|
|
237
368
|
}
|
|
238
369
|
}
|
|
370
|
+
validatePresentation(pluginKey, descriptor);
|
|
239
371
|
validateSettings(pluginKey, descriptor.settings ?? []);
|
|
372
|
+
validateSettingGroups(pluginKey, descriptor.setting_groups, descriptor.settings ?? [], new Set(byKey.keys()));
|
|
240
373
|
validateActions(pluginKey, descriptor.actions ?? []);
|
|
241
374
|
validateAdminPage(pluginKey, descriptor.admin_page);
|
|
242
375
|
}
|
|
@@ -27,3 +27,13 @@ export declare function resolveEffectivePluginFeatures(descriptor: PluginFeature
|
|
|
27
27
|
* default).
|
|
28
28
|
*/
|
|
29
29
|
export declare function validateFeatureUpdate(descriptor: PluginFeatureDescriptor, features: Record<string, boolean>): Record<string, boolean>;
|
|
30
|
+
/**
|
|
31
|
+
* For a descriptor with `require_enabled_feature`: rejects (`INVALID_DATA`)
|
|
32
|
+
* an update that switches off the last enabled top-level feature. `features`
|
|
33
|
+
* are the values to persist (`validateFeatureUpdate`; a key without a value
|
|
34
|
+
* counts by its default), `current` the configured values before the update
|
|
35
|
+
* (`resolvePluginFeatureStates`). An update that does not reduce the enabled
|
|
36
|
+
* set is always allowed, so an already stored all-off state can be left and
|
|
37
|
+
* the plugin switch can be flipped with unchanged features.
|
|
38
|
+
*/
|
|
39
|
+
export declare function assertRequiredFeatureEnabled(descriptor: PluginFeatureDescriptor, features: Record<string, boolean>, current: Record<string, boolean>): void;
|
|
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.resolvePluginFeatureStates = resolvePluginFeatureStates;
|
|
4
4
|
exports.resolveEffectivePluginFeatures = resolveEffectivePluginFeatures;
|
|
5
5
|
exports.validateFeatureUpdate = validateFeatureUpdate;
|
|
6
|
+
exports.assertRequiredFeatureEnabled = assertRequiredFeatureEnabled;
|
|
6
7
|
const utils_1 = require("@medusajs/framework/utils");
|
|
7
8
|
/**
|
|
8
9
|
* Configured and effective values of every declared feature. A descriptor
|
|
@@ -75,3 +76,23 @@ function validateFeatureUpdate(descriptor, features) {
|
|
|
75
76
|
}
|
|
76
77
|
return result;
|
|
77
78
|
}
|
|
79
|
+
/**
|
|
80
|
+
* For a descriptor with `require_enabled_feature`: rejects (`INVALID_DATA`)
|
|
81
|
+
* an update that switches off the last enabled top-level feature. `features`
|
|
82
|
+
* are the values to persist (`validateFeatureUpdate`; a key without a value
|
|
83
|
+
* counts by its default), `current` the configured values before the update
|
|
84
|
+
* (`resolvePluginFeatureStates`). An update that does not reduce the enabled
|
|
85
|
+
* set is always allowed, so an already stored all-off state can be left and
|
|
86
|
+
* the plugin switch can be flipped with unchanged features.
|
|
87
|
+
*/
|
|
88
|
+
function assertRequiredFeatureEnabled(descriptor, features, current) {
|
|
89
|
+
if (descriptor.require_enabled_feature !== true) {
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
const topLevel = descriptor.features.filter((feature) => feature.parent_key === undefined);
|
|
93
|
+
const anyOnAfter = topLevel.some((feature) => (features[feature.key] ?? feature.default_enabled) === true);
|
|
94
|
+
const anyOnBefore = topLevel.some((feature) => current[feature.key] === true);
|
|
95
|
+
if (!anyOnAfter && anyOnBefore) {
|
|
96
|
+
throw new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, "Mindestens eine Funktion muss eingeschaltet bleiben.");
|
|
97
|
+
}
|
|
98
|
+
}
|
package/dist/public/index.d.ts
CHANGED
|
@@ -3,8 +3,9 @@ export { definePluginFeatures } from "./descriptor";
|
|
|
3
3
|
export { resolveEffectivePluginFeatures } from "./effective-features";
|
|
4
4
|
export { isOwnPluginEvent, isPluginFeatureEnabled, isPluginFeatureEnabledByKey, pluginFeatureGate, requirePluginFeature, } from "./enforcement";
|
|
5
5
|
export { isBasePluginRegistered, resolveBaseModule } from "./module-access";
|
|
6
|
+
export { PLUGIN_ICON_NAMES } from "./plugin-icons";
|
|
6
7
|
export { getPluginSettings } from "./settings";
|
|
7
8
|
export { getShopAppearance, getShopMasterData, shopMasterDataDescriptor, type ResolvedShopMasterData, type ShopAppearance, type ShopAppearanceColors, type ShopMasterData, type ShopMasterDataKey, } from "./shop-master-data";
|
|
8
9
|
export { reportPluginActionProgress, type PluginActionProgress, } from "./action-progress";
|
|
9
|
-
export type { BasePluginOptions, EffectivePluginFeatures, PluginActionDefinition, PluginActionMode, PluginActionProgressInput, PluginActionWorkflowInput, PluginFeatureDefinition, PluginFeatureDescriptor, PluginFeatureProvider, PluginSettingDefinition, PluginSettingOption, PluginSettingsFallback, PluginSettingType, PluginSettingValue, ResolvedPluginSettings, } from "./types";
|
|
10
|
+
export type { BasePluginOptions, EffectivePluginFeatures, PluginActionDefinition, PluginActionMode, PluginActionProgressInput, PluginActionWorkflowInput, PluginFeatureDefinition, PluginFeatureDescriptor, PluginFeatureProvider, PluginIconName, PluginSettingDefinition, PluginSettingGroupDefinition, PluginSettingOption, PluginSettingsFallback, PluginSettingType, PluginSettingValue, ResolvedPluginSettings, } from "./types";
|
|
10
11
|
export type { CompleteCartHookDeclarations, CompleteCartHookName, CompleteCartOrderCreatedInput, CompleteCartParticipant, CompleteCartParticipantStep, CompleteCartValidateInput, } from "./complete-cart";
|
package/dist/public/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.reportPluginActionProgress = exports.shopMasterDataDescriptor = exports.getShopMasterData = exports.getShopAppearance = exports.getPluginSettings = exports.resolveBaseModule = exports.isBasePluginRegistered = exports.requirePluginFeature = exports.pluginFeatureGate = exports.isPluginFeatureEnabledByKey = exports.isPluginFeatureEnabled = exports.isOwnPluginEvent = exports.resolveEffectivePluginFeatures = exports.definePluginFeatures = exports.PLUGIN_FEATURES_MODULE = void 0;
|
|
3
|
+
exports.reportPluginActionProgress = exports.shopMasterDataDescriptor = exports.getShopMasterData = exports.getShopAppearance = exports.getPluginSettings = exports.PLUGIN_ICON_NAMES = exports.resolveBaseModule = exports.isBasePluginRegistered = exports.requirePluginFeature = exports.pluginFeatureGate = exports.isPluginFeatureEnabledByKey = exports.isPluginFeatureEnabled = exports.isOwnPluginEvent = exports.resolveEffectivePluginFeatures = exports.definePluginFeatures = exports.PLUGIN_FEATURES_MODULE = void 0;
|
|
4
4
|
var constants_1 = require("./constants");
|
|
5
5
|
Object.defineProperty(exports, "PLUGIN_FEATURES_MODULE", { enumerable: true, get: function () { return constants_1.PLUGIN_FEATURES_MODULE; } });
|
|
6
6
|
var descriptor_1 = require("./descriptor");
|
|
@@ -16,6 +16,8 @@ Object.defineProperty(exports, "requirePluginFeature", { enumerable: true, get:
|
|
|
16
16
|
var module_access_1 = require("./module-access");
|
|
17
17
|
Object.defineProperty(exports, "isBasePluginRegistered", { enumerable: true, get: function () { return module_access_1.isBasePluginRegistered; } });
|
|
18
18
|
Object.defineProperty(exports, "resolveBaseModule", { enumerable: true, get: function () { return module_access_1.resolveBaseModule; } });
|
|
19
|
+
var plugin_icons_1 = require("./plugin-icons");
|
|
20
|
+
Object.defineProperty(exports, "PLUGIN_ICON_NAMES", { enumerable: true, get: function () { return plugin_icons_1.PLUGIN_ICON_NAMES; } });
|
|
19
21
|
var settings_1 = require("./settings");
|
|
20
22
|
Object.defineProperty(exports, "getPluginSettings", { enumerable: true, get: function () { return settings_1.getPluginSettings; } });
|
|
21
23
|
var shop_master_data_1 = require("./shop-master-data");
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Names of `@medusajs/icons` components a plugin descriptor may use as `icon`.
|
|
3
|
+
* A plain list so the server needs no icon package; the Admin maps the name to
|
|
4
|
+
* the component and falls back to a default icon for an unknown one. Every
|
|
5
|
+
* name is an export of `@medusajs/icons`.
|
|
6
|
+
*/
|
|
7
|
+
export declare const PLUGIN_ICON_NAMES: readonly ["ArchiveBox", "ArrowPath", "BuildingStorefront", "Buildings", "ClockSolid", "CogSixTooth", "CreditCard", "DocumentText", "Envelope", "ReceiptPercent", "ShieldCheck", "ShoppingCart", "SquaresPlus", "Tag", "TruckFast", "Users"];
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.PLUGIN_ICON_NAMES = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Names of `@medusajs/icons` components a plugin descriptor may use as `icon`.
|
|
6
|
+
* A plain list so the server needs no icon package; the Admin maps the name to
|
|
7
|
+
* the component and falls back to a default icon for an unknown one. Every
|
|
8
|
+
* name is an export of `@medusajs/icons`.
|
|
9
|
+
*/
|
|
10
|
+
exports.PLUGIN_ICON_NAMES = [
|
|
11
|
+
"ArchiveBox",
|
|
12
|
+
"ArrowPath",
|
|
13
|
+
"BuildingStorefront",
|
|
14
|
+
"Buildings",
|
|
15
|
+
"ClockSolid",
|
|
16
|
+
"CogSixTooth",
|
|
17
|
+
"CreditCard",
|
|
18
|
+
"DocumentText",
|
|
19
|
+
"Envelope",
|
|
20
|
+
"ReceiptPercent",
|
|
21
|
+
"ShieldCheck",
|
|
22
|
+
"ShoppingCart",
|
|
23
|
+
"SquaresPlus",
|
|
24
|
+
"Tag",
|
|
25
|
+
"TruckFast",
|
|
26
|
+
"Users",
|
|
27
|
+
];
|
|
@@ -7,6 +7,10 @@ const descriptor_1 = require("./descriptor");
|
|
|
7
7
|
const settings_1 = require("./settings");
|
|
8
8
|
const COMPANY = "Firmendaten";
|
|
9
9
|
const APPEARANCE = "Erscheinungsbild";
|
|
10
|
+
const ADDRESS = "Adresse";
|
|
11
|
+
const TAX_CONTACT = "Steuer und Kontakt";
|
|
12
|
+
const BANK_REGISTER = "Bank und Firmenbuch";
|
|
13
|
+
const COLORS = "Farben";
|
|
10
14
|
const DEFAULT_COLOR_HINT = "Leer lassen für die Standardfarbe von E-Mails und Dokumenten.";
|
|
11
15
|
/**
|
|
12
16
|
* The base's own descriptor: the shop's master data (Firmenangaben) and its
|
|
@@ -18,18 +22,22 @@ exports.shopMasterDataDescriptor = (0, descriptor_1.definePluginFeatures)({
|
|
|
18
22
|
plugin_key: "shop",
|
|
19
23
|
label: "Shop-Stammdaten",
|
|
20
24
|
description: "Firmenangaben des Shops für E-Mails, Rechnungen, Dokumente und Steuerprüfungen sowie Logo und Farben von E-Mails und Dokumenten.",
|
|
25
|
+
summary: "Firmenangaben, Logo und Farben für E-Mails, Rechnungen, Dokumente und Steuerprüfungen.",
|
|
26
|
+
icon: "Buildings",
|
|
21
27
|
switchable: false,
|
|
22
28
|
features: [],
|
|
23
29
|
settings: [
|
|
24
|
-
{ key: "legal_name", group: COMPANY, label: "Firmenname", type: "string", required: true },
|
|
25
|
-
{ key: "address_line1", group: COMPANY, label: "Adresse", type: "string", required: true },
|
|
26
|
-
{ key: "address_line2", group: COMPANY, label: "Adresszusatz", type: "string" },
|
|
27
|
-
{ key: "postal_code", group: COMPANY, label: "Postleitzahl", type: "string", required: true },
|
|
28
|
-
{ key: "city", group: COMPANY, label: "Ort", type: "string", required: true },
|
|
30
|
+
{ key: "legal_name", group: COMPANY, section: ADDRESS, label: "Firmenname", type: "string", required: true },
|
|
31
|
+
{ key: "address_line1", group: COMPANY, section: ADDRESS, width: "half", label: "Adresse", type: "string", required: true },
|
|
32
|
+
{ key: "address_line2", group: COMPANY, section: ADDRESS, width: "half", label: "Adresszusatz", type: "string" },
|
|
33
|
+
{ key: "postal_code", group: COMPANY, section: ADDRESS, width: "half", label: "Postleitzahl", type: "string", required: true },
|
|
34
|
+
{ key: "city", group: COMPANY, section: ADDRESS, width: "half", label: "Ort", type: "string", required: true },
|
|
29
35
|
{
|
|
30
36
|
key: "country_code",
|
|
31
37
|
group: COMPANY,
|
|
32
38
|
label: "Land",
|
|
39
|
+
section: ADDRESS,
|
|
40
|
+
width: "half",
|
|
33
41
|
type: "select",
|
|
34
42
|
required: true,
|
|
35
43
|
// EU-27 plus CH, GB, NO, IS, LI (ISO 3166-1 alpha-2, lowercase),
|
|
@@ -69,24 +77,27 @@ exports.shopMasterDataDescriptor = (0, descriptor_1.definePluginFeatures)({
|
|
|
69
77
|
{ value: "cy", label: "Zypern" },
|
|
70
78
|
],
|
|
71
79
|
},
|
|
72
|
-
{ key: "vat_number", group: COMPANY, label: "UID-Nummer", type: "string", required: true },
|
|
73
|
-
{ key: "email", group: COMPANY, label: "E-Mail", type: "string" },
|
|
74
|
-
{ key: "phone", group: COMPANY, label: "Telefon", type: "string" },
|
|
75
|
-
{ key: "website", group: COMPANY, label: "Website", type: "url" },
|
|
76
|
-
{ key: "iban", group: COMPANY, label: "IBAN", type: "string" },
|
|
77
|
-
{ key: "bic", group: COMPANY, label: "BIC", type: "string" },
|
|
78
|
-
{ key: "company_register_number", group: COMPANY, label: "Firmenbuchnummer", type: "string" },
|
|
79
|
-
{ key: "company_register_court", group: COMPANY, label: "Firmenbuchgericht", type: "string" },
|
|
80
|
+
{ key: "vat_number", group: COMPANY, section: TAX_CONTACT, width: "half", label: "UID-Nummer", type: "string", required: true },
|
|
81
|
+
{ key: "email", group: COMPANY, section: TAX_CONTACT, width: "half", label: "E-Mail", type: "string" },
|
|
82
|
+
{ key: "phone", group: COMPANY, section: TAX_CONTACT, width: "half", label: "Telefon", type: "string" },
|
|
83
|
+
{ key: "website", group: COMPANY, section: TAX_CONTACT, width: "half", label: "Website", type: "url" },
|
|
84
|
+
{ key: "iban", group: COMPANY, section: BANK_REGISTER, width: "half", label: "IBAN", type: "string" },
|
|
85
|
+
{ key: "bic", group: COMPANY, section: BANK_REGISTER, width: "half", label: "BIC", type: "string" },
|
|
86
|
+
{ key: "company_register_number", group: COMPANY, section: BANK_REGISTER, width: "half", label: "Firmenbuchnummer", type: "string" },
|
|
87
|
+
{ key: "company_register_court", group: COMPANY, section: BANK_REGISTER, width: "half", label: "Firmenbuchgericht", type: "string" },
|
|
80
88
|
{
|
|
81
89
|
key: "logo",
|
|
82
90
|
group: APPEARANCE,
|
|
83
91
|
label: "Logo",
|
|
84
92
|
description: "PNG oder JPG, erscheint oben in den E-Mails und auf Rechnungen und Lieferscheinen. Ohne Logo steht dort der Firmenname bzw. Shopname.",
|
|
93
|
+
hint: "PNG oder JPG, ohne Logo erscheint der Firmenname.",
|
|
85
94
|
type: "image",
|
|
86
95
|
},
|
|
87
96
|
{
|
|
88
97
|
key: "color_accent",
|
|
89
98
|
group: APPEARANCE,
|
|
99
|
+
section: COLORS,
|
|
100
|
+
width: "half",
|
|
90
101
|
label: "Akzentfarbe",
|
|
91
102
|
description: `Buttons, Überschriften und Links. ${DEFAULT_COLOR_HINT}`,
|
|
92
103
|
type: "color",
|
|
@@ -94,6 +105,8 @@ exports.shopMasterDataDescriptor = (0, descriptor_1.definePluginFeatures)({
|
|
|
94
105
|
{
|
|
95
106
|
key: "color_text",
|
|
96
107
|
group: APPEARANCE,
|
|
108
|
+
section: COLORS,
|
|
109
|
+
width: "half",
|
|
97
110
|
label: "Textfarbe",
|
|
98
111
|
description: `Fließtext und Beträge. ${DEFAULT_COLOR_HINT}`,
|
|
99
112
|
type: "color",
|
|
@@ -101,6 +114,8 @@ exports.shopMasterDataDescriptor = (0, descriptor_1.definePluginFeatures)({
|
|
|
101
114
|
{
|
|
102
115
|
key: "color_muted",
|
|
103
116
|
group: APPEARANCE,
|
|
117
|
+
section: COLORS,
|
|
118
|
+
width: "half",
|
|
104
119
|
label: "Nebentextfarbe",
|
|
105
120
|
description: `Beschriftungen, Hinweise und Fußzeilen. ${DEFAULT_COLOR_HINT}`,
|
|
106
121
|
type: "color",
|
|
@@ -108,6 +123,8 @@ exports.shopMasterDataDescriptor = (0, descriptor_1.definePluginFeatures)({
|
|
|
108
123
|
{
|
|
109
124
|
key: "color_line",
|
|
110
125
|
group: APPEARANCE,
|
|
126
|
+
section: COLORS,
|
|
127
|
+
width: "half",
|
|
111
128
|
label: "Linienfarbe",
|
|
112
129
|
description: `Rahmen und Trennlinien. ${DEFAULT_COLOR_HINT}`,
|
|
113
130
|
type: "color",
|
|
@@ -115,6 +132,8 @@ exports.shopMasterDataDescriptor = (0, descriptor_1.definePluginFeatures)({
|
|
|
115
132
|
{
|
|
116
133
|
key: "color_surface",
|
|
117
134
|
group: APPEARANCE,
|
|
135
|
+
section: COLORS,
|
|
136
|
+
width: "half",
|
|
118
137
|
label: "Flächenfarbe",
|
|
119
138
|
description: `Hinterlegte Flächen wie Infoboxen und Tabellenköpfe. ${DEFAULT_COLOR_HINT}`,
|
|
120
139
|
type: "color",
|
package/dist/public/types.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { DocumentPluginOptions } from "../modules/documents/domain/options";
|
|
2
2
|
import type { EmailPluginOptions } from "../email/types";
|
|
3
3
|
import type { FilesPluginOptions } from "../files/types";
|
|
4
|
+
import type { PLUGIN_ICON_NAMES } from "./plugin-icons";
|
|
4
5
|
/**
|
|
5
6
|
* Options of the base plugin (`plugins: [{ resolve, options }]`). Medusa hands
|
|
6
7
|
* the same options object to every module of the plugin; each module service
|
|
@@ -23,6 +24,8 @@ export type BasePluginOptions = {
|
|
|
23
24
|
/** `/files` gateway signing; set from `createS3CacheStorageConfig`. */
|
|
24
25
|
readonly files?: FilesPluginOptions;
|
|
25
26
|
};
|
|
27
|
+
/** `@medusajs/icons` component name a plugin may use as its icon. */
|
|
28
|
+
export type PluginIconName = (typeof PLUGIN_ICON_NAMES)[number];
|
|
26
29
|
export type PluginFeatureDefinition<K extends string = string> = {
|
|
27
30
|
readonly key: K;
|
|
28
31
|
readonly label: string;
|
|
@@ -33,8 +36,9 @@ export type PluginFeatureDefinition<K extends string = string> = {
|
|
|
33
36
|
/**
|
|
34
37
|
* `image`: public http(s) URL of an image the Admin uploads (PNG/JPEG).
|
|
35
38
|
* `color`: lowercase hex color `#rrggbb`.
|
|
39
|
+
* `date`: calendar day `YYYY-MM-DD`.
|
|
36
40
|
*/
|
|
37
|
-
export type PluginSettingType = "string" | "url" | "number" | "boolean" | "secret" | "select" | "image" | "color";
|
|
41
|
+
export type PluginSettingType = "string" | "url" | "number" | "boolean" | "secret" | "select" | "image" | "color" | "date";
|
|
38
42
|
/** One allowed value of a `"select"` setting. */
|
|
39
43
|
export type PluginSettingOption = {
|
|
40
44
|
readonly value: string;
|
|
@@ -53,7 +57,7 @@ export type PluginSettingDefinition<S extends string = string> = {
|
|
|
53
57
|
readonly type: PluginSettingType;
|
|
54
58
|
/** `false` when omitted. */
|
|
55
59
|
readonly required?: boolean;
|
|
56
|
-
/** Never for `"secret"`; must match `type` (and `options`/`min`/`max`). */
|
|
60
|
+
/** Never for `"secret"`; must match `type` (and `options`/`min`/`max`/`integer`). */
|
|
57
61
|
readonly default?: PluginSettingValue;
|
|
58
62
|
/** Required for `"select"` (non-empty, unique values); only there. */
|
|
59
63
|
readonly options?: readonly PluginSettingOption[];
|
|
@@ -61,12 +65,53 @@ export type PluginSettingDefinition<S extends string = string> = {
|
|
|
61
65
|
readonly min?: number;
|
|
62
66
|
/** Inclusive upper bound; only for `"number"`. */
|
|
63
67
|
readonly max?: number;
|
|
68
|
+
/** Only whole numbers are accepted; only for `"number"`. */
|
|
69
|
+
readonly integer?: boolean;
|
|
64
70
|
/**
|
|
65
71
|
* Secret settings of the same plugin whose stored values are deleted when
|
|
66
72
|
* this setting's stored value changes (also when it is cleared), e.g. an
|
|
67
73
|
* API key that must not be sent to a new URL.
|
|
68
74
|
*/
|
|
69
75
|
readonly invalidates?: readonly S[];
|
|
76
|
+
/**
|
|
77
|
+
* Short text under the field; the Admin shows `hint ?? description`.
|
|
78
|
+
*/
|
|
79
|
+
readonly hint?: string;
|
|
80
|
+
/** Input placeholder; not for boolean, select, image, color and date. */
|
|
81
|
+
readonly placeholder?: string;
|
|
82
|
+
/**
|
|
83
|
+
* `"half"`: consecutive half-width settings share one two-column row.
|
|
84
|
+
* `"full"` when omitted. Not for boolean (always a full-width switch row).
|
|
85
|
+
*/
|
|
86
|
+
readonly width?: "full" | "half";
|
|
87
|
+
/**
|
|
88
|
+
* Sub-heading inside the group; consecutive settings with the same section
|
|
89
|
+
* share one sub-heading.
|
|
90
|
+
*/
|
|
91
|
+
readonly section?: string;
|
|
92
|
+
};
|
|
93
|
+
/** Metadata of one settings group, keyed by the `group` name of its settings. */
|
|
94
|
+
export type PluginSettingGroupDefinition<K extends string = string, S extends string = string> = {
|
|
95
|
+
/** Equals the `group` of at least one setting; unique per plugin. */
|
|
96
|
+
readonly name: string;
|
|
97
|
+
/** Explanatory text under the group heading. */
|
|
98
|
+
readonly description?: string;
|
|
99
|
+
/** Short note shown on the right of the group heading. */
|
|
100
|
+
readonly note?: string;
|
|
101
|
+
/**
|
|
102
|
+
* Feature that must be on for the group to apply; the Admin dims the group
|
|
103
|
+
* (still editable) while the feature is not effectively enabled.
|
|
104
|
+
*/
|
|
105
|
+
readonly requires_feature?: K;
|
|
106
|
+
/**
|
|
107
|
+
* The group applies only while the select or boolean setting `setting`
|
|
108
|
+
* (of another group) resolves to `equals`. Otherwise the Admin hides it and
|
|
109
|
+
* its required settings do not count as missing; stored values are kept.
|
|
110
|
+
*/
|
|
111
|
+
readonly visible_when?: {
|
|
112
|
+
readonly setting: S;
|
|
113
|
+
readonly equals: string | boolean;
|
|
114
|
+
};
|
|
70
115
|
};
|
|
71
116
|
export type PluginActionMode = "sync" | "background";
|
|
72
117
|
export type PluginActionDefinition<A extends string = string> = {
|
|
@@ -100,6 +145,33 @@ export type PluginFeatureDescriptor<K extends string = string, S extends string
|
|
|
100
145
|
* omitted).
|
|
101
146
|
*/
|
|
102
147
|
readonly admin_page?: string;
|
|
148
|
+
/** `@medusajs/icons` component name for the hub card and the page header. */
|
|
149
|
+
readonly icon?: PluginIconName;
|
|
150
|
+
/** One short sentence: hub card text and page subtitle (Admin falls back to `description`). */
|
|
151
|
+
readonly summary?: string;
|
|
152
|
+
/** Line under the plugin switch, e.g. what stops working when it is off. Only when switchable. */
|
|
153
|
+
readonly disable_hint?: string;
|
|
154
|
+
/** Body of the confirmation shown before the plugin is switched off. Only when switchable. */
|
|
155
|
+
readonly disable_confirm?: string;
|
|
156
|
+
/** Heading of the features card; "Funktionen" when omitted. */
|
|
157
|
+
readonly features_heading?: string;
|
|
158
|
+
/** Note on the right of the features card header. */
|
|
159
|
+
readonly features_note?: string;
|
|
160
|
+
/** Warning shown while every top-level feature is off. Needs at least one feature. */
|
|
161
|
+
readonly all_off_warning?: string;
|
|
162
|
+
/**
|
|
163
|
+
* `true`: at least one top-level feature (without `parent_key`) must stay
|
|
164
|
+
* enabled; an update that would switch all of them off is rejected with
|
|
165
|
+
* `INVALID_DATA` and the Admin locks the last enabled switch. Needs at least
|
|
166
|
+
* one top-level feature with `default_enabled: true`. Only an update that
|
|
167
|
+
* switches off the last enabled one is rejected: a stored state that already
|
|
168
|
+
* violates the rule (everything off) can still be read and left, and an
|
|
169
|
+
* update that does not reduce the enabled set (e.g. the plugin switch) is
|
|
170
|
+
* always allowed.
|
|
171
|
+
*/
|
|
172
|
+
readonly require_enabled_feature?: true;
|
|
173
|
+
/** Metadata for the groups used in `settings[].group`. */
|
|
174
|
+
readonly setting_groups?: readonly PluginSettingGroupDefinition<K, S>[];
|
|
103
175
|
};
|
|
104
176
|
/** Values a plugin received from medusa-config; the base shows them as source "config". */
|
|
105
177
|
export type PluginSettingsFallback<S extends string = string> = Partial<Record<S, PluginSettingValue | null | undefined>>;
|
|
@@ -10,3 +10,5 @@ export declare const toWireDate: (value: Date | string) => string;
|
|
|
10
10
|
export declare const toOptionalWireDate: (value: Date | string | null | undefined) => string | null;
|
|
11
11
|
/** Whether the value is an IANA time zone this runtime knows ("Europe/Vienna"). */
|
|
12
12
|
export declare const isValidTimeZone: (value: unknown) => value is string;
|
|
13
|
+
/** Whether the value is an existing calendar day written `yyyy-mm-dd`. */
|
|
14
|
+
export declare const isCalendarDate: (value: unknown) => value is string;
|
package/dist/shared/lib/dates.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.isValidTimeZone = exports.toOptionalWireDate = exports.toWireDate = exports.toIsoDate = exports.startOfUtcDate = exports.toValidDate = void 0;
|
|
3
|
+
exports.isCalendarDate = exports.isValidTimeZone = exports.toOptionalWireDate = exports.toWireDate = exports.toIsoDate = exports.startOfUtcDate = exports.toValidDate = void 0;
|
|
4
4
|
const utils_1 = require("@medusajs/framework/utils");
|
|
5
5
|
/** A valid `Date`; throws `INVALID_DATA` for an unparsable value. */
|
|
6
6
|
const toValidDate = (value, message = "Invalid date.") => {
|
|
@@ -40,3 +40,9 @@ const isValidTimeZone = (value) => {
|
|
|
40
40
|
}
|
|
41
41
|
};
|
|
42
42
|
exports.isValidTimeZone = isValidTimeZone;
|
|
43
|
+
/** Whether the value is an existing calendar day written `yyyy-mm-dd`. */
|
|
44
|
+
const isCalendarDate = (value) => typeof value === "string" &&
|
|
45
|
+
/^\d{4}-\d{2}-\d{2}$/.test(value) &&
|
|
46
|
+
!Number.isNaN(Date.parse(`${value}T00:00:00Z`)) &&
|
|
47
|
+
new Date(`${value}T00:00:00Z`).toISOString().slice(0, 10) === value;
|
|
48
|
+
exports.isCalendarDate = isCalendarDate;
|
package/dist/shared/lib/index.js
CHANGED
|
@@ -23,6 +23,7 @@ __exportStar(require("./errors"), exports);
|
|
|
23
23
|
__exportStar(require("./hash"), exports);
|
|
24
24
|
__exportStar(require("./logging"), exports);
|
|
25
25
|
__exportStar(require("./money"), exports);
|
|
26
|
+
__exportStar(require("./refreshing-snapshot"), exports);
|
|
26
27
|
__exportStar(require("./text"), exports);
|
|
27
28
|
__exportStar(require("./transaction"), exports);
|
|
28
29
|
__exportStar(require("./wire-response"), exports);
|