@hartl-services/medusa-base 2.7.0 → 2.9.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 (54) hide show
  1. package/.medusa/server/src/admin/admin-components/features/plugin-features/components/PluginSettingsForm.js +12 -9
  2. package/.medusa/server/src/admin/admin-components/features/plugin-features/hooks/usePluginFeatureEnabled.d.ts +5 -1
  3. package/.medusa/server/src/admin/admin-components/features/plugin-features/hooks/usePluginFeatures.d.ts +20 -4
  4. package/.medusa/server/src/admin/admin-components/features/plugin-features/hooks/usePluginSettingsForm.d.ts +5 -1
  5. package/.medusa/server/src/admin/admin-components/features/plugin-features/lib/plugin-features-admin-client.d.ts +20 -4
  6. package/.medusa/server/src/admin/admin-components/features/plugin-features/lib/plugin-view.d.ts +0 -5
  7. package/.medusa/server/src/admin/admin-components/features/plugin-features/lib/plugin-view.js +0 -5
  8. package/.medusa/server/src/admin/admin-components/features/plugin-features/lib/settings-layout.d.ts +4 -0
  9. package/.medusa/server/src/admin/admin-components/features/plugin-features/lib/settings-layout.js +4 -0
  10. package/.medusa/server/src/admin/admin-components/i18n/texts.d.ts +1 -2
  11. package/.medusa/server/src/admin/admin-components/i18n/texts.js +1 -2
  12. package/.medusa/server/src/admin/index.js +142 -87
  13. package/.medusa/server/src/admin/index.mjs +144 -89
  14. package/.medusa/server/src/api/admin/email/templates/[kind]/send-test/route.js +7 -1
  15. package/.medusa/server/src/customer-auth/plugin-features.js +10 -10
  16. package/.medusa/server/src/email/application/warn-credential-expiry.js +77 -0
  17. package/.medusa/server/src/email/config/index.js +8 -2
  18. package/.medusa/server/src/email/config/notification-module.js +28 -2
  19. package/.medusa/server/src/email/domain/business-keys.js +5 -2
  20. package/.medusa/server/src/email/domain/failure-classification.js +9 -1
  21. package/.medusa/server/src/email/plugin-features.js +123 -1
  22. package/.medusa/server/src/email/rendering/default-templates.js +16 -1
  23. package/.medusa/server/src/email/rendering/render-email.js +2 -1
  24. package/.medusa/server/src/email/types/email-kinds.js +2 -1
  25. package/.medusa/server/src/email/types/template-data.js +8 -1
  26. package/.medusa/server/src/jobs/email-credential-expiry.js +27 -0
  27. package/.medusa/server/src/modules/email/domain/message-state.js +3 -1
  28. package/.medusa/server/src/modules/email/migrations/Migration20261011120000.js +20 -0
  29. package/.medusa/server/src/modules/plugin-features/domain/plugin-settings.js +27 -6
  30. package/.medusa/server/src/modules/plugin-features/service.js +4 -3
  31. package/.medusa/server/src/providers/smtp/delivery-settings.js +75 -0
  32. package/.medusa/server/src/providers/smtp/graph-transport.js +150 -0
  33. package/.medusa/server/src/providers/smtp/service.js +105 -37
  34. package/.medusa/server/src/providers/smtp/types.js +7 -1
  35. package/.medusa/server/src/public/descriptor.js +24 -3
  36. package/.medusa/server/src/shared/lib/dates.js +8 -2
  37. package/.medusa/server/src/shop-config/build-food-shop-config.js +3 -5
  38. package/README.md +100 -65
  39. package/dist/customer-auth/plugin-features.js +9 -9
  40. package/dist/email/config/index.d.ts +6 -1
  41. package/dist/email/config/index.js +7 -1
  42. package/dist/email/config/notification-module.d.ts +25 -0
  43. package/dist/email/config/notification-module.js +27 -1
  44. package/dist/email/types/email-kinds.d.ts +2 -1
  45. package/dist/email/types/email-kinds.js +1 -0
  46. package/dist/email/types/template-data.d.ts +10 -0
  47. package/dist/email/types/template-data.js +7 -0
  48. package/dist/public/descriptor.js +23 -2
  49. package/dist/public/types.d.ts +14 -4
  50. package/dist/shared/lib/dates.d.ts +2 -0
  51. package/dist/shared/lib/dates.js +7 -1
  52. package/dist/shop-config/build-food-shop-config.d.ts +1 -1
  53. package/dist/shop-config/build-food-shop-config.js +2 -4
  54. package/package.json +2 -2
@@ -1,10 +1,10 @@
1
1
  import { jsx, jsxs, Fragment } from "react/jsx-runtime";
2
2
  import { defineWidgetConfig, defineRouteConfig } from "@medusajs/admin-sdk";
3
- import { Container, IconBadge, Heading, Text, Tooltip, IconButton, toast, StatusBadge, Button, clx, usePrompt, Label, Switch, Hint, Input, Select, Alert, I18nProvider, DatePicker, FocusModal, DropdownMenu, Badge, Table, Prompt } from "@medusajs/ui";
3
+ import { Container, IconBadge, Heading, Text, Tooltip, IconButton, toast, StatusBadge, Button, clx, usePrompt, Label, Switch, I18nProvider, DatePicker, Hint, Input, Select, Alert, FocusModal, DropdownMenu, Badge, Table, Prompt } from "@medusajs/ui";
4
4
  import { useQuery, useQueryClient, useMutation, keepPreviousData, skipToken } from "@tanstack/react-query";
5
5
  import { emailAdminPaths } from "@hartl-services/medusa-food-supplements-contracts/paths/email";
6
6
  import Medusa from "@medusajs/js-sdk";
7
- import { ArrowLongLeft, InformationCircle, Users, TruckFast, Tag, SquaresPlus, ShoppingCart, ShieldCheck, ReceiptPercent, Envelope, DocumentText, CreditCard, CogSixTooth, ClockSolid, Buildings, BuildingStorefront, ArrowPath, ArchiveBox, ArrowUpTray, TriangleRightMini, ChevronDownMini, PaperClip, User, ArrowDownTray } from "@medusajs/icons";
7
+ import { ArrowLongLeft, InformationCircle, Users, TruckFast, Tag, SquaresPlus, ShoppingCart, ShieldCheck, ReceiptPercent, Envelope, DocumentText, CreditCard, CogSixTooth, ClockSolid, Buildings, BuildingStorefront, ArrowPath, ArchiveBox, ArrowUpTray, TriangleRightMini, ChevronDownMini, PaperPlane, PaperClip, User, ArrowDownTray } from "@medusajs/icons";
8
8
  import { Link, useLocation, useSearchParams, useParams } from "react-router-dom";
9
9
  import { pluginFeaturesAdminPaths } from "@hartl-services/medusa-food-supplements-contracts/paths/plugin-features";
10
10
  import { useRef, useEffect, useState, useMemo, Fragment as Fragment$1, useCallback, useLayoutEffect, useId, forwardRef, useImperativeHandle } from "react";
@@ -22,7 +22,8 @@ const texts = {
22
22
  },
23
23
  breadcrumbs: {
24
24
  hub: "Plugins",
25
- emailAttachments: "Anhänge"
25
+ emailAttachments: "Anhänge",
26
+ emailDelivery: "Versand"
26
27
  },
27
28
  page: {
28
29
  title: "Hartl Services Plugins",
@@ -88,8 +89,6 @@ const texts = {
88
89
  secretClearUndoLabel: (label) => `${label} nicht löschen`,
89
90
  /** Shown on a secret: the settings whose change deletes it ("A", "A oder B"). */
90
91
  invalidatedBy: (labels) => `Wird gelöscht, wenn ${labels.length > 1 ? `${labels.slice(0, -1).join(", ")} oder ${labels[labels.length - 1]}` : labels.join("")} sich ändert.`,
91
- /** Shown on the changing setting: the secrets its change deletes. */
92
- invalidates: (labels) => `Beim Ändern muss ${labels} neu eingegeben werden.`,
93
92
  invalidNumber: "Bitte eine gültige Zahl eingeben.",
94
93
  invalidColor: "Bitte eine Hex-Farbe wie #1a2b3c eingeben.",
95
94
  colorPlaceholder: "Standard",
@@ -390,9 +389,6 @@ const disabledParent = (features, feature) => {
390
389
  };
391
390
  const invalidatedByLabels = (settings, secretKey) => settings.filter((setting) => setting.invalidates.includes(secretKey)).map((setting) => setting.label);
392
391
  const isGroupDimmed = (features, requiresFeature) => requiresFeature !== null && features.find((feature) => feature.key === requiresFeature)?.effective_enabled === false;
393
- const invalidatesLabels = (settings, setting) => setting.invalidates.map(
394
- (key) => settings.find((candidate) => candidate.key === key)?.label ?? key
395
- );
396
392
  const settingInfoText = (setting) => setting.hint !== null && setting.description !== null && setting.description !== setting.hint ? setting.description : null;
397
393
  const headerInfoText = (plugin2) => plugin2.summary !== null && plugin2.description !== null && plugin2.description !== plugin2.summary ? plugin2.description : null;
398
394
  const showsSourceHint = (source) => source !== "default";
@@ -957,6 +953,35 @@ const changedSettingValues = (settings, draft, unparsable = []) => {
957
953
  }
958
954
  return values;
959
955
  };
956
+ const DATE_PATTERN = /^(\d{4})-(\d{2})-(\d{2})$/;
957
+ const DATE_TIME_PATTERN = /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2})$/;
958
+ const pad = (value, length = 2) => String(value).padStart(length, "0");
959
+ const build = ([year, month, day, hour = 0, minute = 0]) => {
960
+ const date = new Date(year, month - 1, day, hour, minute);
961
+ const matches = date.getFullYear() === year && date.getMonth() === month - 1 && date.getDate() === day && date.getHours() === hour && date.getMinutes() === minute;
962
+ return matches ? date : null;
963
+ };
964
+ const dateFromInputValue = (value) => {
965
+ const match = value ? DATE_PATTERN.exec(value) : null;
966
+ return match ? build(match.slice(1).map(Number)) : null;
967
+ };
968
+ const inputValueFromDate = (date) => {
969
+ if (!date || Number.isNaN(date.getTime())) {
970
+ return "";
971
+ }
972
+ return `${pad(date.getFullYear(), 4)}-${pad(date.getMonth() + 1)}-${pad(date.getDate())}`;
973
+ };
974
+ const dateTimeFromInputValue = (value) => {
975
+ const match = value ? DATE_TIME_PATTERN.exec(value) : null;
976
+ return match ? build(match.slice(1).map(Number)) : null;
977
+ };
978
+ const inputValueFromDateTime = (date) => {
979
+ if (!date || Number.isNaN(date.getTime())) {
980
+ return "";
981
+ }
982
+ return `${inputValueFromDate(date)}T${pad(date.getHours())}:${pad(date.getMinutes())}`;
983
+ };
984
+ const AdminDatePicker = (props) => /* @__PURE__ */ jsx(I18nProvider, { locale: ADMIN_LOCALE, children: /* @__PURE__ */ jsx(DatePicker, { ...props }) });
960
985
  const buildSettingBlocks = (settings) => {
961
986
  const blocks = [];
962
987
  let previousSection = null;
@@ -1008,11 +1033,13 @@ const buildSettingGroups = (settings, groups, ungroupedTitle) => {
1008
1033
  description: meta?.description ?? null,
1009
1034
  note: meta?.note ?? null,
1010
1035
  requiresFeature: meta?.requires_feature ?? null,
1036
+ visibleWhen: meta?.visible_when ?? null,
1011
1037
  settings: groupSettings,
1012
1038
  blocks: buildSettingBlocks(groupSettings)
1013
1039
  };
1014
1040
  });
1015
1041
  };
1042
+ const isGroupVisible = (group, draft) => group.visibleWhen === null || draft[group.visibleWhen.setting] === group.visibleWhen.equals;
1016
1043
  function usePluginSettingsForm(plugin2) {
1017
1044
  const mutation = useUpdatePluginSettings(plugin2.plugin_key);
1018
1045
  const [draft, setDraft] = useState(
@@ -1306,13 +1333,13 @@ const SettingField = ({
1306
1333
  pluginKey,
1307
1334
  setting,
1308
1335
  invalidatedBy,
1309
- invalidates,
1310
1336
  value,
1311
1337
  invalid,
1312
1338
  disabled,
1313
1339
  onChange
1314
1340
  }) => {
1315
1341
  const id = fieldId(pluginKey, setting.key);
1342
+ const labelId = `${id}-label`;
1316
1343
  const hintId = `${id}-hint`;
1317
1344
  const clearPending = setting.type === "secret" && value === null;
1318
1345
  const bounds = setting.type === "number" ? boundsText(setting) : void 0;
@@ -1320,13 +1347,13 @@ const SettingField = ({
1320
1347
  const info = settingInfoText(setting);
1321
1348
  const showBounds = Boolean(bounds) && showsBoundsLine(setting);
1322
1349
  const required = setting.required;
1323
- const hasHints = Boolean(hint) || clearPending || invalidatedBy.length > 0 || invalidates.length > 0 || showBounds || invalid;
1350
+ const hasHints = Boolean(hint) || clearPending || invalidatedBy.length > 0 || showBounds || invalid;
1324
1351
  const describedBy = hasHints ? hintId : void 0;
1325
1352
  const placeholder = setting.placeholder ?? void 0;
1326
1353
  return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-y-2", children: [
1327
1354
  /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-3", children: [
1328
1355
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-x-1", children: [
1329
- /* @__PURE__ */ jsx(Label, { htmlFor: id, size: "small", weight: "plus", children: labelText(setting) }),
1356
+ /* @__PURE__ */ jsx(Label, { id: labelId, htmlFor: id, size: "small", weight: "plus", children: labelText(setting) }),
1330
1357
  info && /* @__PURE__ */ jsx(InfoTooltip, { label: texts.info.label(setting.label), children: info })
1331
1358
  ] }),
1332
1359
  showsSourceHint(setting.source) && /* @__PURE__ */ jsx(Text, { size: "xsmall", className: "text-ui-fg-muted shrink-0", children: texts.settings.source[setting.source] })
@@ -1400,6 +1427,16 @@ const SettingField = ({
1400
1427
  disabled,
1401
1428
  onChange: (next) => onChange(next)
1402
1429
  }
1430
+ ) : setting.type === "date" ? /* @__PURE__ */ jsx(
1431
+ AdminDatePicker,
1432
+ {
1433
+ id,
1434
+ "aria-labelledby": labelId,
1435
+ "aria-describedby": describedBy,
1436
+ isDisabled: disabled,
1437
+ value: dateFromInputValue(typeof value === "string" ? value : ""),
1438
+ onChange: (date) => onChange(inputValueFromDate(date))
1439
+ }
1403
1440
  ) : setting.type === "number" ? /* @__PURE__ */ jsx(
1404
1441
  Input,
1405
1442
  {
@@ -1434,7 +1471,6 @@ const SettingField = ({
1434
1471
  hint && /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: hint }),
1435
1472
  clearPending && /* @__PURE__ */ jsx(Hint, { variant: "info", children: texts.settings.secretClearPending }),
1436
1473
  invalidatedBy.length > 0 && /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: texts.settings.invalidatedBy(invalidatedBy) }),
1437
- invalidates.length > 0 && /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: texts.settings.invalidates(invalidates.join(", ")) }),
1438
1474
  showBounds && !invalid && /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: bounds }),
1439
1475
  invalid && /* @__PURE__ */ jsx(Hint, { variant: "error", children: setting.type === "color" ? texts.settings.invalidColor : bounds ?? texts.settings.invalidNumber })
1440
1476
  ] })
@@ -1447,9 +1483,9 @@ const PluginSettingsForm = ({ plugin: plugin2 }) => {
1447
1483
  plugin2.settings,
1448
1484
  plugin2.setting_groups,
1449
1485
  texts.sections.settings
1450
- );
1486
+ ).filter((group) => isGroupVisible(group, form.draft));
1451
1487
  const hasTextFields = plugin2.settings.some(
1452
- (setting) => setting.type === "string" || setting.type === "url" || setting.type === "number" || setting.type === "color"
1488
+ (setting) => setting.type === "string" || setting.type === "url" || setting.type === "number" || setting.type === "color" || setting.type === "date"
1453
1489
  );
1454
1490
  const renderField = (setting) => /* @__PURE__ */ jsx(
1455
1491
  SettingField,
@@ -1457,7 +1493,6 @@ const PluginSettingsForm = ({ plugin: plugin2 }) => {
1457
1493
  pluginKey: plugin2.plugin_key,
1458
1494
  setting,
1459
1495
  invalidatedBy: setting.type === "secret" ? invalidatedByLabels(plugin2.settings, setting.key) : [],
1460
- invalidates: invalidatesLabels(plugin2.settings, setting),
1461
1496
  value: form.draft[setting.key],
1462
1497
  invalid: form.invalid.includes(setting.key),
1463
1498
  disabled: pending,
@@ -1635,29 +1670,6 @@ const PluginFeatureDisabledNotice = ({
1635
1670
  ]
1636
1671
  }
1637
1672
  );
1638
- const DATE_TIME_PATTERN = /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2})$/;
1639
- const pad = (value, length = 2) => String(value).padStart(length, "0");
1640
- const build = ([year, month, day, hour = 0, minute = 0]) => {
1641
- const date = new Date(year, month - 1, day, hour, minute);
1642
- const matches = date.getFullYear() === year && date.getMonth() === month - 1 && date.getDate() === day && date.getHours() === hour && date.getMinutes() === minute;
1643
- return matches ? date : null;
1644
- };
1645
- const inputValueFromDate = (date) => {
1646
- if (!date || Number.isNaN(date.getTime())) {
1647
- return "";
1648
- }
1649
- return `${pad(date.getFullYear(), 4)}-${pad(date.getMonth() + 1)}-${pad(date.getDate())}`;
1650
- };
1651
- const dateTimeFromInputValue = (value) => {
1652
- const match = value ? DATE_TIME_PATTERN.exec(value) : null;
1653
- return match ? build(match.slice(1).map(Number)) : null;
1654
- };
1655
- const inputValueFromDateTime = (date) => {
1656
- if (!date || Number.isNaN(date.getTime())) {
1657
- return "";
1658
- }
1659
- return `${inputValueFromDate(date)}T${pad(date.getHours())}:${pad(date.getMinutes())}`;
1660
- };
1661
1673
  const fetchPdfObjectUrl = async (path) => {
1662
1674
  const response = await sdk.client.fetch(path, {
1663
1675
  headers: { accept: "application/pdf" }
@@ -1745,7 +1757,6 @@ const useDebouncedValue = (value, delayMs) => {
1745
1757
  }, [value, delayMs]);
1746
1758
  return debounced;
1747
1759
  };
1748
- const AdminDatePicker = (props) => /* @__PURE__ */ jsx(I18nProvider, { locale: ADMIN_LOCALE, children: /* @__PURE__ */ jsx(DatePicker, { ...props }) });
1749
1760
  const FocusModalShell = ({
1750
1761
  open,
1751
1762
  onOpenChange,
@@ -3504,7 +3515,7 @@ const PluginFeaturesSettingsPage = () => {
3504
3515
  const config = defineRouteConfig({
3505
3516
  label: texts.menu.label
3506
3517
  });
3507
- const handle$a = {
3518
+ const handle$b = {
3508
3519
  breadcrumb: () => texts.breadcrumbs.hub
3509
3520
  };
3510
3521
  const KINDS = [
@@ -3520,7 +3531,8 @@ const KINDS = [
3520
3531
  "auth.login_code",
3521
3532
  "affiliate.consignment_report_due",
3522
3533
  "affiliate.application_submitted.admin",
3523
- "user.invite"
3534
+ "user.invite",
3535
+ "system.credential_expiry.admin"
3524
3536
  ];
3525
3537
  const KIND_LABELS = {
3526
3538
  "order.received": "Bestellbestätigung (Kunde)",
@@ -3535,10 +3547,12 @@ const KIND_LABELS = {
3535
3547
  "auth.login_code": "Anmeldecode",
3536
3548
  "affiliate.consignment_report_due": "Affiliate-Meldung",
3537
3549
  "affiliate.application_submitted.admin": "Neue Partner-Bewerbung (Shop)",
3538
- "user.invite": "Admin-Einladung"
3550
+ "user.invite": "Admin-Einladung",
3551
+ "system.credential_expiry.admin": "Secret läuft ab (Shop)"
3539
3552
  };
3540
3553
  const EMAIL_PAGE_PATH = `${PLUGIN_HUB_PATH}/email`;
3541
3554
  const EMAIL_ATTACHMENTS_PAGE_PATH = `${EMAIL_PAGE_PATH}/attachments`;
3555
+ const EMAIL_DELIVERY_PAGE_PATH = `${EMAIL_PAGE_PATH}/delivery`;
3542
3556
  const emailAttachmentPagePath = (attachmentId) => `${EMAIL_ATTACHMENTS_PAGE_PATH}/${encodeURIComponent(attachmentId)}`;
3543
3557
  const NO_MAIL_ASSIGNED_LABEL = "keiner Mail zugeordnet";
3544
3558
  const MAIL_KIND_OPTIONS = EMAIL_ATTACHABLE_KINDS.map((kind) => ({
@@ -3796,52 +3810,61 @@ const LinkRow = ({
3796
3810
  description,
3797
3811
  to,
3798
3812
  disabled
3799
- }) => /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-4 px-6 py-3", children: [
3800
- /* @__PURE__ */ jsx(IconBadge, { children: icon }),
3801
- /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 flex-1 flex-col gap-y-0.5", children: [
3802
- /* @__PURE__ */ jsx(Text, { size: "small", leading: "compact", weight: "plus", children: title }),
3803
- /* @__PURE__ */ jsx(Text, { size: "small", leading: "compact", className: "text-ui-fg-subtle", children: description })
3804
- ] }),
3805
- disabled ? /* @__PURE__ */ jsx(
3806
- Button,
3807
- {
3808
- "aria-label": texts.plugin.openLabel(title),
3809
- disabled: true,
3810
- size: "small",
3811
- variant: "secondary",
3812
- children: texts.plugin.open
3813
- }
3814
- ) : /* @__PURE__ */ jsx(Button, { asChild: true, size: "small", variant: "secondary", children: /* @__PURE__ */ jsx(Link, { "aria-label": texts.plugin.openLabel(title), to, children: texts.plugin.open }) })
3815
- ] });
3816
- const EmailManagementSection = ({ disabled }) => /* @__PURE__ */ jsxs(
3817
- AdminSection,
3813
+ }) => /* @__PURE__ */ jsxs(
3814
+ "div",
3818
3815
  {
3819
- className: `transition-opacity ${disabled ? "opacity-50" : ""}`,
3820
- title: "Verwaltung",
3816
+ className: `flex items-center gap-4 px-6 py-3 transition-opacity ${disabled ? "opacity-50" : ""}`,
3821
3817
  children: [
3822
- /* @__PURE__ */ jsx(
3823
- LinkRow,
3824
- {
3825
- description: "PDFs an Kunden-Mails, z. B. AGB.",
3826
- disabled,
3827
- icon: /* @__PURE__ */ jsx(PaperClip, {}),
3828
- title: "Anhänge",
3829
- to: EMAIL_ATTACHMENTS_PAGE_PATH
3830
- }
3831
- ),
3832
- /* @__PURE__ */ jsx(
3833
- LinkRow,
3818
+ /* @__PURE__ */ jsx(IconBadge, { children: icon }),
3819
+ /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 flex-1 flex-col gap-y-0.5", children: [
3820
+ /* @__PURE__ */ jsx(Text, { size: "small", leading: "compact", weight: "plus", children: title }),
3821
+ /* @__PURE__ */ jsx(Text, { size: "small", leading: "compact", className: "text-ui-fg-subtle", children: description })
3822
+ ] }),
3823
+ disabled ? /* @__PURE__ */ jsx(
3824
+ Button,
3834
3825
  {
3835
- description: "Status und Zustellversuche.",
3836
- disabled,
3837
- icon: /* @__PURE__ */ jsx(ClockSolid, {}),
3838
- title: "E-Mail-Protokoll",
3839
- to: EMAIL_LOG_PAGE_PATH
3826
+ "aria-label": texts.plugin.openLabel(title),
3827
+ disabled: true,
3828
+ size: "small",
3829
+ variant: "secondary",
3830
+ children: texts.plugin.open
3840
3831
  }
3841
- )
3832
+ ) : /* @__PURE__ */ jsx(Button, { asChild: true, size: "small", variant: "secondary", children: /* @__PURE__ */ jsx(Link, { "aria-label": texts.plugin.openLabel(title), to, children: texts.plugin.open }) })
3842
3833
  ]
3843
3834
  }
3844
3835
  );
3836
+ const EmailManagementSection = ({ disabled }) => /* @__PURE__ */ jsxs(AdminSection, { title: "Verwaltung", children: [
3837
+ /* @__PURE__ */ jsx(
3838
+ LinkRow,
3839
+ {
3840
+ description: "SMTP oder Microsoft 365.",
3841
+ disabled: false,
3842
+ icon: /* @__PURE__ */ jsx(PaperPlane, {}),
3843
+ title: texts.breadcrumbs.emailDelivery,
3844
+ to: EMAIL_DELIVERY_PAGE_PATH
3845
+ }
3846
+ ),
3847
+ /* @__PURE__ */ jsx(
3848
+ LinkRow,
3849
+ {
3850
+ description: "PDFs an Kunden-Mails, z. B. AGB.",
3851
+ disabled,
3852
+ icon: /* @__PURE__ */ jsx(PaperClip, {}),
3853
+ title: "Anhänge",
3854
+ to: EMAIL_ATTACHMENTS_PAGE_PATH
3855
+ }
3856
+ ),
3857
+ /* @__PURE__ */ jsx(
3858
+ LinkRow,
3859
+ {
3860
+ description: "Status und Zustellversuche.",
3861
+ disabled,
3862
+ icon: /* @__PURE__ */ jsx(ClockSolid, {}),
3863
+ title: "E-Mail-Protokoll",
3864
+ to: EMAIL_LOG_PAGE_PATH
3865
+ }
3866
+ )
3867
+ ] });
3845
3868
  const EmailOverviewSections = () => {
3846
3869
  const plugin2 = usePluginFeature("email").data?.plugin;
3847
3870
  if (!plugin2) {
@@ -3853,7 +3876,7 @@ const EmailOverviewSections = () => {
3853
3876
  ] });
3854
3877
  };
3855
3878
  const EmailOverviewPage = () => /* @__PURE__ */ jsx(PluginPageShell, { pluginKey: "email", variant: "header", children: /* @__PURE__ */ jsx(EmailOverviewSections, {}) });
3856
- const handle$9 = {
3879
+ const handle$a = {
3857
3880
  breadcrumb: (_match) => /* @__PURE__ */ jsx(PluginLabelCrumb, { pluginKey: "email" })
3858
3881
  };
3859
3882
  const EMAIL_TEMPLATES_PATH = `${EMAIL_PAGE_PATH}/templates`;
@@ -3973,11 +3996,11 @@ const EmailTemplateGroupPage = ({
3973
3996
  ) })
3974
3997
  ] });
3975
3998
  };
3976
- const handle$8 = {
3999
+ const handle$9 = {
3977
4000
  breadcrumb: () => EMAIL_TEMPLATE_GROUPS.account.label
3978
4001
  };
3979
4002
  const EmailAccountMailsRoute = () => /* @__PURE__ */ jsx(PluginFeatureRoute, { pluginKey: "email", children: /* @__PURE__ */ jsx(EmailTemplateGroupPage, { group: "account" }) });
3980
- const handle$7 = {
4003
+ const handle$8 = {
3981
4004
  breadcrumb: () => EMAIL_TEMPLATE_GROUPS.affiliate.label
3982
4005
  };
3983
4006
  const EmailAffiliateMailsRoute = () => /* @__PURE__ */ jsx(PluginFeatureRoute, { pluginKey: "email", children: /* @__PURE__ */ jsx(EmailTemplateGroupPage, { group: "affiliate" }) });
@@ -4378,10 +4401,37 @@ const EmailAttachmentsPage = () => {
4378
4401
  /* @__PURE__ */ jsx(NewAttachmentModal, { onOpenChange: setNewOpen, open: newOpen })
4379
4402
  ] });
4380
4403
  };
4381
- const handle$6 = {
4404
+ const handle$7 = {
4382
4405
  breadcrumb: () => texts.breadcrumbs.emailAttachments
4383
4406
  };
4384
4407
  const EmailAttachmentsRoute = () => /* @__PURE__ */ jsx(PluginFeatureRoute, { pluginKey: "email", children: /* @__PURE__ */ jsx(EmailAttachmentsPage, {}) });
4408
+ const EmailDeliveryPage = () => {
4409
+ const query = usePluginFeature("email");
4410
+ const plugin2 = query.data?.plugin;
4411
+ return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-y-3", children: [
4412
+ /* @__PURE__ */ jsx(
4413
+ AdminPageHeader,
4414
+ {
4415
+ badges: plugin2 && /* @__PURE__ */ jsx(StatusBadge, { color: plugin2.configured ? "green" : "orange", children: plugin2.configured ? texts.chips.configured : texts.chips.notConfigured }),
4416
+ description: "SMTP oder Microsoft 365.",
4417
+ icon: /* @__PURE__ */ jsx(PaperPlane, {}),
4418
+ title: texts.breadcrumbs.emailDelivery
4419
+ }
4420
+ ),
4421
+ plugin2 ? /* @__PURE__ */ jsx(PluginSettingsForm, { plugin: plugin2 }) : /* @__PURE__ */ jsx(Container, { className: "p-0", children: /* @__PURE__ */ jsx(
4422
+ QueryState,
4423
+ {
4424
+ error: query.error,
4425
+ errorText: texts.states.error,
4426
+ isLoading: query.isPending,
4427
+ loadingText: texts.states.loading
4428
+ }
4429
+ ) })
4430
+ ] });
4431
+ };
4432
+ const handle$6 = {
4433
+ breadcrumb: () => texts.breadcrumbs.emailDelivery
4434
+ };
4385
4435
  const LOG_PAGE_SIZE = 20;
4386
4436
  const LOG_MAX_OFFSET = 1e4;
4387
4437
  const LOG_MAX_RESOURCE_ID_LENGTH = 255;
@@ -6681,26 +6731,31 @@ const routeModule = {
6681
6731
  {
6682
6732
  Component: PluginFeaturesSettingsPage,
6683
6733
  path: "/settings/hartl-services",
6684
- handle: { label: config.label, translationNs: config.translationNs, ...handle$a }
6734
+ handle: { label: config.label, translationNs: config.translationNs, ...handle$b }
6685
6735
  },
6686
6736
  {
6687
6737
  Component: EmailOverviewPage,
6688
6738
  path: "/settings/hartl-services/email",
6689
- handle: handle$9
6739
+ handle: handle$a
6690
6740
  },
6691
6741
  {
6692
6742
  Component: EmailAccountMailsRoute,
6693
6743
  path: "/settings/hartl-services/email/account",
6694
- handle: handle$8
6744
+ handle: handle$9
6695
6745
  },
6696
6746
  {
6697
6747
  Component: EmailAffiliateMailsRoute,
6698
6748
  path: "/settings/hartl-services/email/affiliate",
6699
- handle: handle$7
6749
+ handle: handle$8
6700
6750
  },
6701
6751
  {
6702
6752
  Component: EmailAttachmentsRoute,
6703
6753
  path: "/settings/hartl-services/email/attachments",
6754
+ handle: handle$7
6755
+ },
6756
+ {
6757
+ Component: EmailDeliveryPage,
6758
+ path: "/settings/hartl-services/email/delivery",
6704
6759
  handle: handle$6
6705
6760
  },
6706
6761
  {
@@ -16,6 +16,12 @@ const TEST_SUBJECT_PREFIX = "[Test] ";
16
16
  /** A German Admin message for a failed test send; the provider's own text never reaches the Admin. */
17
17
  const testSendFailure = (error) => {
18
18
  const { code } = (0, failure_classification_1.classifyNotificationFailure)(error);
19
+ if (code === "not_configured") {
20
+ return new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, "Der Versand ist nicht eingerichtet (E-Mail › Versand).");
21
+ }
22
+ if (code === "auth_failed") {
23
+ return new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, "Die Anmeldung beim Mailanbieter ist fehlgeschlagen. Zugangsdaten unter E-Mail › Versand prüfen.");
24
+ }
19
25
  if (code === "permanent_rejection") {
20
26
  return new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, "Der Mailserver hat die Adresse abgelehnt.");
21
27
  }
@@ -176,4 +182,4 @@ const POST = async (req, res) => {
176
182
  }));
177
183
  };
178
184
  exports.POST = POST;
179
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicm91dGUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi9zcmMvYXBpL2FkbWluL2VtYWlsL3RlbXBsYXRlcy9ba2luZF0vc2VuZC10ZXN0L3JvdXRlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQUlBLHFEQUFpRTtBQUtqRSwyRkFHeUU7QUFRekUsMkdBS3NFO0FBQ3RFLDJHQUlzRTtBQUN0RSxnRkFJc0Q7QUFDdEQsa0dBQW9HO0FBQ3BHLHVHQUFpRztBQUNqRyxpRUFBMEU7QUFFMUUsMkRBQStEO0FBQy9ELGtGQUkyRDtBQUUzRCxvRkFBMkU7QUFFM0UsTUFBTSxtQkFBbUIsR0FBRyxTQUFTLENBQUM7QUFFdEMsc0dBQXNHO0FBQ3RHLE1BQU0sZUFBZSxHQUFHLENBQUMsS0FBYyxFQUFlLEVBQUU7SUFDdEQsTUFBTSxFQUFFLElBQUksRUFBRSxHQUFHLElBQUEsb0RBQTJCLEVBQUMsS0FBSyxDQUFDLENBQUM7SUFDcEQsSUFBSSxJQUFJLEtBQUsscUJBQXFCLEVBQUUsQ0FBQztRQUNuQyxPQUFPLElBQUksbUJBQVcsQ0FDcEIsbUJBQVcsQ0FBQyxLQUFLLENBQUMsWUFBWSxFQUM5QiwyQ0FBMkMsQ0FDNUMsQ0FBQztJQUNKLENBQUM7SUFDRCxJQUNFLElBQUksS0FBSyxtQkFBbUI7UUFDNUIsSUFBSSxLQUFLLHFCQUFxQjtRQUM5QixJQUFJLEtBQUssc0JBQXNCLEVBQy9CLENBQUM7UUFDRCxPQUFPLElBQUksbUJBQVcsQ0FDcEIsbUJBQVcsQ0FBQyxLQUFLLENBQUMsZ0JBQWdCLEVBQ2xDLDRFQUE0RSxDQUM3RSxDQUFDO0lBQ0osQ0FBQztJQUNELE9BQU8sSUFBSSxtQkFBVyxDQUNwQixtQkFBVyxDQUFDLEtBQUssQ0FBQyxnQkFBZ0IsRUFDbEMsNkNBQTZDLENBQzlDLENBQUM7QUFDSixDQUFDLENBQUM7QUFFRixNQUFNLGdCQUFnQixHQUFHLENBQUMsSUFBWSxFQUErQixFQUFFLENB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
185
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicm91dGUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi9zcmMvYXBpL2FkbWluL2VtYWlsL3RlbXBsYXRlcy9ba2luZF0vc2VuZC10ZXN0L3JvdXRlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQUlBLHFEQUFpRTtBQUtqRSwyRkFHeUU7QUFRekUsMkdBS3NFO0FBQ3RFLDJHQUlzRTtBQUN0RSxnRkFJc0Q7QUFDdEQsa0dBQW9HO0FBQ3BHLHVHQUFpRztBQUNqRyxpRUFBMEU7QUFFMUUsMkRBQStEO0FBQy9ELGtGQUkyRDtBQUUzRCxvRkFBMkU7QUFFM0UsTUFBTSxtQkFBbUIsR0FBRyxTQUFTLENBQUM7QUFFdEMsc0dBQXNHO0FBQ3RHLE1BQU0sZUFBZSxHQUFHLENBQUMsS0FBYyxFQUFlLEVBQUU7SUFDdEQsTUFBTSxFQUFFLElBQUksRUFBRSxHQUFHLElBQUEsb0RBQTJCLEVBQUMsS0FBSyxDQUFDLENBQUM7SUFDcEQsSUFBSSxJQUFJLEtBQUssZ0JBQWdCLEVBQUUsQ0FBQztRQUM5QixPQUFPLElBQUksbUJBQVcsQ0FDcEIsbUJBQVcsQ0FBQyxLQUFLLENBQUMsWUFBWSxFQUM5Qix3REFBd0QsQ0FDekQsQ0FBQztJQUNKLENBQUM7SUFDRCxJQUFJLElBQUksS0FBSyxhQUFhLEVBQUUsQ0FBQztRQUMzQixPQUFPLElBQUksbUJBQVcsQ0FDcEIsbUJBQVcsQ0FBQyxLQUFLLENBQUMsWUFBWSxFQUM5QixpR0FBaUcsQ0FDbEcsQ0FBQztJQUNKLENBQUM7SUFDRCxJQUFJLElBQUksS0FBSyxxQkFBcUIsRUFBRSxDQUFDO1FBQ25DLE9BQU8sSUFBSSxtQkFBVyxDQUNwQixtQkFBVyxDQUFDLEtBQUssQ0FBQyxZQUFZLEVBQzlCLDJDQUEyQyxDQUM1QyxDQUFDO0lBQ0osQ0FBQztJQUNELElBQ0UsSUFBSSxLQUFLLG1CQUFtQjtRQUM1QixJQUFJLEtBQUsscUJBQXFCO1FBQzlCLElBQUksS0FB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
@@ -7,32 +7,32 @@ const PASSWORD_RULES = "Passwort-Regeln";
7
7
  exports.customerAuthPluginFeatures = (0, descriptor_1.definePluginFeatures)({
8
8
  plugin_key: customer_auth_1.CUSTOMER_AUTH_PLUGIN_KEY,
9
9
  label: "Kunden-Login",
10
- description: "Welche Anmeldemethoden Kunden im Shop nutzen können. Mindestens eine Methode muss eingeschaltet bleiben, sonst kann sich niemand mehr anmelden; Admin-Benutzer melden sich unabhängig davon mit E-Mail und Passwort an. Eine Änderung wirkt innerhalb von etwa 30 Sekunden im Backend, die Storefront übernimmt sie nach ihrem Zwischenspeicher (etwa eine Minute). Die Passwort-Regeln gelten nur für Kunden, solange „E-Mail + Passwort“ eingeschaltet ist; Admin-Benutzer behalten mindestens 15 Zeichen, die bei der ersten Anmeldung eines noch nicht angelegten Admin-Benutzers (Einladung) geprüft werden.",
10
+ description: "Wie sich Kunden anmelden. Mindestens eine Methode bleibt eingeschaltet; Admin-Benutzer melden sich immer mit E-Mail und Passwort an.",
11
11
  summary: "Anmeldemethoden und Passwort-Regeln für Kunden.",
12
12
  icon: "ShieldCheck",
13
13
  switchable: false,
14
14
  features_heading: "Anmeldemethoden",
15
- features_note: "Wirkt nach ca. 30 Sekunden im Backend, in der Storefront nach ca. 1 Minute.",
15
+ features_note: "Wirkt nach ca. 1 Minute.",
16
16
  all_off_warning: "Keine Methode eingeschaltet: Kunden können sich nicht mehr anmelden.",
17
17
  require_enabled_feature: true,
18
18
  features: [
19
19
  {
20
20
  key: customer_auth_1.CUSTOMER_AUTH_FEATURES.emailPassword,
21
21
  label: "E-Mail + Passwort",
22
- description: "Anmeldung, Registrierung und Passwort-Zurücksetzen. Aus: Das Backend lehnt diese Wege für Kunden ab; bestehende Konten melden sich dann nur noch mit den anderen eingeschalteten Methoden an.",
22
+ description: "Anmeldung, Registrierung und Passwort zurücksetzen.",
23
23
  default_enabled: true,
24
24
  },
25
25
  {
26
26
  key: customer_auth_1.CUSTOMER_AUTH_FEATURES.emailOtp,
27
27
  label: "Anmeldecode per E-Mail",
28
- description: "Kunden fordern einen sechsstelligen Code an, der 10 Minuten gültig ist, und melden sich damit an; für neue Adressen entsteht dabei ein Kundenkonto. Ein bestehendes Passwort-Konto derselben Adresse wird nur verknüpft, wenn die Passwort-Anmeldung aus ist oder die Adresse bestätigt wurde. Die Code-Mail geht unabhängig von den Schaltern des E-Mail-Plugins hinaus. Aus: Code-Anfrage und Code-Anmeldung sind nicht möglich.",
28
+ description: "Anmeldung mit einem 6-stelligen Code per E-Mail; für neue Adressen entsteht ein Konto.",
29
29
  default_enabled: false,
30
30
  },
31
31
  ],
32
32
  setting_groups: [
33
33
  {
34
34
  name: PASSWORD_RULES,
35
- description: "Gelten nur für Kunden mit „E-Mail + Passwort“, bei Registrierung und Passwort-Zurücksetzen. Admin-Benutzer behalten mindestens 15 Zeichen.",
35
+ description: "Für Kunden mit „E-Mail + Passwort“. Admin-Benutzer: mindestens 15 Zeichen.",
36
36
  requires_feature: customer_auth_1.CUSTOMER_AUTH_FEATURES.emailPassword,
37
37
  },
38
38
  ],
@@ -40,8 +40,8 @@ exports.customerAuthPluginFeatures = (0, descriptor_1.definePluginFeatures)({
40
40
  {
41
41
  key: "password_min_length",
42
42
  label: "Mindestlänge",
43
- description: "Wie viele Zeichen ein Kundenpasswort mindestens haben muss (8 bis 128). NIST SP 800-63B Rev. 4, die US-Richtlinie für digitale Identität, empfiehlt mindestens 15 Zeichen, wenn das Passwort der einzige Faktor ist. Die Regeln gelten nur, solange „E-Mail + Passwort“ eingeschaltet ist, und nur für Kunden; Admin-Benutzer behalten mindestens 15 Zeichen. Bestehende Passwörter bleiben gültig, die Regeln greifen bei Registrierung und Passwort-Zurücksetzen. Grenze: Wer sich über den Admin-Weg registriert, kann 15 Zeichen ohne Zusammensetzungsregeln wählen, auch wenn der Shop mehr verlangt; das schwächt nur das eigene Passwort.",
44
- hint: "8 bis 128 Zeichen. Empfohlen: mindestens 15 (NIST SP 800-63B).",
43
+ description: "Gilt bei Registrierung und Passwort-Zurücksetzen; bestehende Passwörter bleiben gültig.",
44
+ hint: "8 bis 128 Zeichen. Empfohlen: 15 (NIST SP 800-63B).",
45
45
  group: PASSWORD_RULES,
46
46
  width: "half",
47
47
  type: "number",
@@ -54,7 +54,7 @@ exports.customerAuthPluginFeatures = (0, descriptor_1.definePluginFeatures)({
54
54
  key: "password_require_mixed_case",
55
55
  label: "Groß- und Kleinbuchstaben verlangen",
56
56
  description: "Mindestens ein Groß- und ein Kleinbuchstabe.",
57
- hint: "NIST rät von Zusammensetzungsregeln ab: Sie führen zu vorhersehbaren Passwörtern wie „Passwort1!“. Länge schützt besser.",
57
+ hint: "NIST rät von Zeichenregeln ab, Länge schützt besser.",
58
58
  group: PASSWORD_RULES,
59
59
  type: "boolean",
60
60
  default: false,
@@ -70,11 +70,11 @@ exports.customerAuthPluginFeatures = (0, descriptor_1.definePluginFeatures)({
70
70
  {
71
71
  key: "password_require_symbol",
72
72
  label: "Sonderzeichen verlangen",
73
- description: "Mindestens ein Sonderzeichen (kein Buchstabe, keine Ziffer, kein Leerzeichen).",
73
+ description: "Mindestens ein Sonderzeichen.",
74
74
  group: PASSWORD_RULES,
75
75
  type: "boolean",
76
76
  default: false,
77
77
  },
78
78
  ],
79
79
  });
80
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicGx1Z2luLWZlYXR1cmVzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vc3JjL2N1c3RvbWVyLWF1dGgvcGx1Z2luLWZlYXR1cmVzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQUFBLDJHQUdnRjtBQUVoRixxREFBMkQ7QUFFM0QsTUFBTSxjQUFjLEdBQUcsaUJBQWlCLENBQUE7QUFFM0IsUUFBQSwwQkFBMEIsR0FBRyxJQUFBLGlDQUFvQixFQUFDO0lBQzdELFVBQVUsRUFBRSx3Q0FBd0I7SUFDcEMsS0FBSyxFQUFFLGNBQWM7SUFDckIsV0FBVyxFQUNULG1sQkFBbWxCO0lBQ3JsQixPQUFPLEVBQUUsaURBQWlEO0lBQzFELElBQUksRUFBRSxhQUFhO0lBQ25CLFVBQVUsRUFBRSxLQUFLO0lBQ2pCLGdCQUFnQixFQUFFLGlCQUFpQjtJQUNuQyxhQUFhLEVBQ1gsNkVBQTZFO0lBQy9FLGVBQWUsRUFDYixzRUFBc0U7SUFDeEUsdUJBQXVCLEVBQUUsSUFBSTtJQUM3QixRQUFRLEVBQUU7UUFDUjtZQUNFLEdBQUcsRUFBRSxzQ0FBc0IsQ0FBQyxhQUFhO1lBQ3pDLEtBQUssRUFBRSxtQkFBbUI7WUFDMUIsV0FBVyxFQUNULCtMQUErTDtZQUNqTSxlQUFlLEVBQUUsSUFBSTtTQUN0QjtRQUNEO1lBQ0UsR0FBRyxFQUFFLHNDQUFzQixDQUFDLFFBQVE7WUFDcEMsS0FBSyxFQUFFLHdCQUF3QjtZQUMvQixXQUFXLEVBQ1Qsb2FBQW9hO1lBQ3RhLGVBQWUsRUFBRSxLQUFLO1NBQ3ZCO0tBQ0Y7SUFDRCxjQUFjLEVBQUU7UUFDZDtZQUNFLElBQUksRUFBRSxjQUFjO1lBQ3BCLFdBQVcsRUFDVCw0SUFBNEk7WUFDOUksZ0JBQWdCLEVBQUUsc0NBQXNCLENBQUMsYUFBYTtTQUN2RDtLQUNGO0lBQ0QsUUFBUSxFQUFFO1FBQ1I7WUFDRSxHQUFHLEVBQUUscUJBQXFCO1lBQzFCLEtBQUssRUFBRSxjQUFjO1lBQ3JCLFdBQVcsRUFDVCxrbkJBQWtuQjtZQUNwbkIsSUFBSSxFQUFFLGdFQUFnRTtZQUN0RSxLQUFLLEVBQUUsY0FBYztZQUNyQixLQUFLLEVBQUUsTUFBTTtZQUNiLElBQUksRUFBRSxRQUFRO1lBQ2QsR0FBRyxFQUFFLENBQUM7WUFDTixHQUFHLEVBQUUsR0FBRztZQUNSLE9BQU8sRUFBRSxJQUFJO1lBQ2IsT0FBTyxFQUFFLEVBQUU7U0FDWjtRQUNEO1lBQ0UsR0FBRyxFQUFFLDZCQUE2QjtZQUNsQyxLQUFLLEVBQUUscUNBQXFDO1lBQzVDLFdBQVcsRUFBRSw4Q0FBOEM7WUFDM0QsSUFBSSxFQUFFLDBIQUEwSDtZQUNoSSxLQUFLLEVBQUUsY0FBYztZQUNyQixJQUFJLEVBQUUsU0FBUztZQUNmLE9BQU8sRUFBRSxLQUFLO1NBQ2Y7UUFDRDtZQUNFLEdBQUcsRUFBRSx3QkFBd0I7WUFDN0IsS0FBSyxFQUFFLGtCQUFrQjtZQUN6QixXQUFXLEVBQUUseUJBQXlCO1lBQ3RDLEtBQUssRUFBRSxjQUFjO1lBQ3JCLElBQUksRUFBRSxTQUFTO1lBQ2YsT0FBTyxFQUFFLEtBQUs7U0FDZjtRQUNEO1lBQ0UsR0FBRyxFQUFFLHlCQUF5QjtZQUM5QixLQUFLLEVBQUUseUJBQXlCO1lBQ2hDLFdBQVcsRUFBRSxnRkFBZ0Y7WUFDN0YsS0FBSyxFQUFFLGNBQWM7WUFDckIsSUFBSSxFQUFFLFNBQVM7WUFDZixPQUFPLEVBQUUsS0FBSztTQUNmO0tBQ0Y7Q0FDRixDQUFDLENBQUEifQ==
80
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicGx1Z2luLWZlYXR1cmVzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vc3JjL2N1c3RvbWVyLWF1dGgvcGx1Z2luLWZlYXR1cmVzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQUFBLDJHQUdnRjtBQUVoRixxREFBMkQ7QUFFM0QsTUFBTSxjQUFjLEdBQUcsaUJBQWlCLENBQUE7QUFFM0IsUUFBQSwwQkFBMEIsR0FBRyxJQUFBLGlDQUFvQixFQUFDO0lBQzdELFVBQVUsRUFBRSx3Q0FBd0I7SUFDcEMsS0FBSyxFQUFFLGNBQWM7SUFDckIsV0FBVyxFQUNULHNJQUFzSTtJQUN4SSxPQUFPLEVBQUUsaURBQWlEO0lBQzFELElBQUksRUFBRSxhQUFhO0lBQ25CLFVBQVUsRUFBRSxLQUFLO0lBQ2pCLGdCQUFnQixFQUFFLGlCQUFpQjtJQUNuQyxhQUFhLEVBQUUsMEJBQTBCO0lBQ3pDLGVBQWUsRUFDYixzRUFBc0U7SUFDeEUsdUJBQXVCLEVBQUUsSUFBSTtJQUM3QixRQUFRLEVBQUU7UUFDUjtZQUNFLEdBQUcsRUFBRSxzQ0FBc0IsQ0FBQyxhQUFhO1lBQ3pDLEtBQUssRUFBRSxtQkFBbUI7WUFDMUIsV0FBVyxFQUNULHFEQUFxRDtZQUN2RCxlQUFlLEVBQUUsSUFBSTtTQUN0QjtRQUNEO1lBQ0UsR0FBRyxFQUFFLHNDQUFzQixDQUFDLFFBQVE7WUFDcEMsS0FBSyxFQUFFLHdCQUF3QjtZQUMvQixXQUFXLEVBQ1Qsd0ZBQXdGO1lBQzFGLGVBQWUsRUFBRSxLQUFLO1NBQ3ZCO0tBQ0Y7SUFDRCxjQUFjLEVBQUU7UUFDZDtZQUNFLElBQUksRUFBRSxjQUFjO1lBQ3BCLFdBQVcsRUFDVCw0RUFBNEU7WUFDOUUsZ0JBQWdCLEVBQUUsc0NBQXNCLENBQUMsYUFBYTtTQUN2RDtLQUNGO0lBQ0QsUUFBUSxFQUFFO1FBQ1I7WUFDRSxHQUFHLEVBQUUscUJBQXFCO1lBQzFCLEtBQUssRUFBRSxjQUFjO1lBQ3JCLFdBQVcsRUFDVCx5RkFBeUY7WUFDM0YsSUFBSSxFQUFFLHFEQUFxRDtZQUMzRCxLQUFLLEVBQUUsY0FBYztZQUNyQixLQUFLLEVBQUUsTUFBTTtZQUNiLElBQUksRUFBRSxRQUFRO1lBQ2QsR0FBRyxFQUFFLENBQUM7WUFDTixHQUFHLEVBQUUsR0FBRztZQUNSLE9BQU8sRUFBRSxJQUFJO1lBQ2IsT0FBTyxFQUFFLEVBQUU7U0FDWjtRQUNEO1lBQ0UsR0FBRyxFQUFFLDZCQUE2QjtZQUNsQyxLQUFLLEVBQUUscUNBQXFDO1lBQzVDLFdBQVcsRUFBRSw4Q0FBOEM7WUFDM0QsSUFBSSxFQUFFLHNEQUFzRDtZQUM1RCxLQUFLLEVBQUUsY0FBYztZQUNyQixJQUFJLEVBQUUsU0FBUztZQUNmLE9BQU8sRUFBRSxLQUFLO1NBQ2Y7UUFDRDtZQUNFLEdBQUcsRUFBRSx3QkFBd0I7WUFDN0IsS0FBSyxFQUFFLGtCQUFrQjtZQUN6QixXQUFXLEVBQUUseUJBQXlCO1lBQ3RDLEtBQUssRUFBRSxjQUFjO1lBQ3JCLElBQUksRUFBRSxTQUFTO1lBQ2YsT0FBTyxFQUFFLEtBQUs7U0FDZjtRQUNEO1lBQ0UsR0FBRyxFQUFFLHlCQUF5QjtZQUM5QixLQUFLLEVBQUUseUJBQXlCO1lBQ2hDLFdBQVcsRUFBRSwrQkFBK0I7WUFDNUMsS0FBSyxFQUFFLGNBQWM7WUFDckIsSUFBSSxFQUFFLFNBQVM7WUFDZixPQUFPLEVBQUUsS0FBSztTQUNmO0tBQ0Y7Q0FDRixDQUFDLENBQUEifQ==
@@ -0,0 +1,77 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.warnCredentialExpiry = exports.isCredentialExpiryDue = exports.calendarDateIn = exports.CREDENTIAL_EXPIRY_WARNING_DAYS = void 0;
4
+ const utils_1 = require("@medusajs/framework/utils");
5
+ const settings_1 = require("../../public/settings");
6
+ const shop_master_data_1 = require("../../public/shop-master-data");
7
+ const lib_1 = require("../../shared/lib");
8
+ const email_1 = require("../../modules/email");
9
+ const dispatch_email_message_1 = require("../../workflows/email/dispatch-email-message");
10
+ const business_keys_1 = require("../domain/business-keys");
11
+ const plugin_features_1 = require("../plugin-features");
12
+ /** The warning goes out this many days before the secret expires. */
13
+ exports.CREDENTIAL_EXPIRY_WARNING_DAYS = 7;
14
+ const DAY_MS = 86_400_000;
15
+ /** `YYYY-MM-DD` of `now` in `timeZone`. */
16
+ const calendarDateIn = (now, timeZone) => new Intl.DateTimeFormat("en-CA", {
17
+ day: "2-digit",
18
+ month: "2-digit",
19
+ timeZone,
20
+ year: "numeric",
21
+ }).format(now);
22
+ exports.calendarDateIn = calendarDateIn;
23
+ /** From seven days before the expiry up to the expiry day itself. */
24
+ const isCredentialExpiryDue = (expiresOn, today) => {
25
+ const days = (Date.parse(`${expiresOn}T00:00:00Z`) - Date.parse(`${today}T00:00:00Z`)) /
26
+ DAY_MS;
27
+ return days >= 0 && days <= exports.CREDENTIAL_EXPIRY_WARNING_DAYS;
28
+ };
29
+ exports.isCredentialExpiryDue = isCredentialExpiryDue;
30
+ /**
31
+ * Warns the shop (e-mail of the Shop-Stammdaten) that the Microsoft 365
32
+ * client secret expires soon. The business key holds client id and expiry
33
+ * date, so each secret is warned about once; a new date warns again.
34
+ */
35
+ const warnCredentialExpiry = async (container, now = new Date()) => {
36
+ const { values } = await (0, settings_1.getPluginSettings)(container, plugin_features_1.emailPluginFeatures);
37
+ const expiresOn = values.microsoft_client_secret_expires_on;
38
+ const clientId = values.microsoft_client_id;
39
+ if (values.provider !== "microsoft365" ||
40
+ !(0, lib_1.isCalendarDate)(expiresOn) ||
41
+ typeof clientId !== "string") {
42
+ return "not_due";
43
+ }
44
+ const email = container.resolve(email_1.EMAIL_MODULE);
45
+ const timeZone = email.getDispatchConfiguration().timeZone ?? "Europe/Vienna";
46
+ if (!(0, exports.isCredentialExpiryDue)(expiresOn, (0, exports.calendarDateIn)(now, timeZone))) {
47
+ return "not_due";
48
+ }
49
+ const recipient = (await (0, shop_master_data_1.getShopMasterData)(container)).values.email;
50
+ if (!recipient) {
51
+ container
52
+ .resolve(utils_1.ContainerRegistrationKeys.LOGGER)
53
+ .warn("email: the client secret expires soon, but the Shop-Stammdaten have no e-mail to warn");
54
+ return "no_recipient";
55
+ }
56
+ const message = await email.upsertMessageFact({
57
+ kind: "system.credential_expiry.admin",
58
+ business_key: (0, business_keys_1.credentialExpiryBusinessKey)(clientId, expiresOn),
59
+ resource_type: "email_provider",
60
+ resource_id: clientId,
61
+ recipient,
62
+ required_facts: ["due"],
63
+ fact: "due",
64
+ template_data: {
65
+ provider: "microsoft365",
66
+ client_id: clientId,
67
+ expires_on: expiresOn,
68
+ },
69
+ suppression_code: null,
70
+ });
71
+ await (0, dispatch_email_message_1.dispatchEmailMessageWorkflow)(container).run({
72
+ input: { message_id: message.id },
73
+ });
74
+ return "dispatched";
75
+ };
76
+ exports.warnCredentialExpiry = warnCredentialExpiry;
77
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoid2Fybi1jcmVkZW50aWFsLWV4cGlyeS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uL3NyYy9lbWFpbC9hcHBsaWNhdGlvbi93YXJuLWNyZWRlbnRpYWwtZXhwaXJ5LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQUNBLHFEQUFzRTtBQUV0RSxvREFBMEQ7QUFDMUQsb0VBQWtFO0FBQ2xFLDBDQUFrRDtBQUNsRCwrQ0FBbUQ7QUFFbkQseUZBQTRGO0FBQzVGLDJEQUFzRTtBQUN0RSx3REFBeUQ7QUFFekQscUVBQXFFO0FBQ3hELFFBQUEsOEJBQThCLEdBQUcsQ0FBQyxDQUFDO0FBRWhELE1BQU0sTUFBTSxHQUFHLFVBQVUsQ0FBQztBQUUxQiwyQ0FBMkM7QUFDcEMsTUFBTSxjQUFjLEdBQUcsQ0FBQyxHQUFTLEVBQUUsUUFBZ0IsRUFBVSxFQUFFLENBQ3BFLElBQUksSUFBSSxDQUFDLGNBQWMsQ0FBQyxPQUFPLEVBQUU7SUFDL0IsR0FBRyxFQUFFLFNBQVM7SUFDZCxLQUFLLEVBQUUsU0FBUztJQUNoQixRQUFRO0lBQ1IsSUFBSSxFQUFFLFNBQVM7Q0FDaEIsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxHQUFHLENBQUMsQ0FBQztBQU5KLFFBQUEsY0FBYyxrQkFNVjtBQUVqQixxRUFBcUU7QUFDOUQsTUFBTSxxQkFBcUIsR0FBRyxDQUNuQyxTQUFpQixFQUNqQixLQUFhLEVBQ0osRUFBRTtJQUNYLE1BQU0sSUFBSSxHQUNSLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxHQUFHLFNBQVMsWUFBWSxDQUFDLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxHQUFHLEtBQUssWUFBWSxDQUFDLENBQUM7UUFDekUsTUFBTSxDQUFDO0lBQ1QsT0FBTyxJQUFJLElBQUksQ0FBQyxJQUFJLElBQUksSUFBSSxzQ0FBOEIsQ0FBQztBQUM3RCxDQUFDLENBQUM7QUFSVyxRQUFBLHFCQUFxQix5QkFRaEM7QUFPRjs7OztHQUlHO0FBQ0ksTUFBTSxvQkFBb0IsR0FBRyxLQUFLLEVBQ3ZDLFNBQTBCLEVBQzFCLE1BQVksSUFBSSxJQUFJLEVBQUUsRUFDa0IsRUFBRTtJQUMxQyxNQUFNLEVBQUUsTUFBTSxFQUFFLEdBQUcsTUFBTSxJQUFBLDRCQUFpQixFQUFDLFNBQVMsRUFBRSxxQ0FBbUIsQ0FBQyxDQUFDO0lBQzNFLE1BQU0sU0FBUyxHQUFHLE1BQU0sQ0FBQyxrQ0FBa0MsQ0FBQztJQUM1RCxNQUFNLFFBQVEsR0FBRyxNQUFNLENBQUMsbUJBQW1CLENBQUM7SUFDNUMsSUFDRSxNQUFNLENBQUMsUUFBUSxLQUFLLGNBQWM7UUFDbEMsQ0FBQyxJQUFBLG9CQUFjLEVBQUMsU0FBUyxDQUFDO1FBQzFCLE9BQU8sUUFBUSxLQUFLLFFBQVEsRUFDNUIsQ0FBQztRQUNELE9BQU8sU0FBUyxDQUFDO0lBQ25CLENBQUM7SUFFRCxNQUFNLEtBQUssR0FBRyxTQUFTLENBQUMsT0FBTyxDQUFxQixvQkFBWSxDQUFDLENBQUM7SUFDbEUsTUFBTSxRQUFRLEdBQUcsS0FBSyxDQUFDLHdCQUF3QixFQUFFLENBQUMsUUFBUSxJQUFJLGVBQWUsQ0FBQztJQUM5RSxJQUFJLENBQUMsSUFBQSw2QkFBcUIsRUFBQyxTQUFTLEVBQUUsSUFBQSxzQkFBYyxFQUFDLEdBQUcsRUFBRSxRQUFRLENBQUMsQ0FBQyxFQUFFLENBQUM7UUFDckUsT0FBTyxTQUFTLENBQUM7SUFDbkIsQ0FBQztJQUVELE1BQU0sU0FBUyxHQUFHLENBQUMsTUFBTSxJQUFBLG9DQUFpQixFQUFDLFNBQVMsQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQztJQUNwRSxJQUFJLENBQUMsU0FBUyxFQUFFLENBQUM7UUFDZixTQUFTO2FBQ04sT0FBTyxDQUFTLGlDQUF5QixDQUFDLE1BQU0sQ0FBQzthQUNqRCxJQUFJLENBQ0gsdUZBQXVGLENBQ3hGLENBQUM7UUFDSixPQUFPLGNBQWMsQ0FBQztJQUN4QixDQUFDO0lBRUQsTUFBTSxPQUFPLEdBQUcsTUFBTSxLQUFLLENBQUMsaUJBQWlCLENBQUM7UUFDNUMsSUFBSSxFQUFFLGdDQUFnQztRQUN0QyxZQUFZLEVBQUUsSUFBQSwyQ0FBMkIsRUFBQyxRQUFRLEVBQUUsU0FBUyxDQUFDO1FBQzlELGFBQWEsRUFBRSxnQkFBZ0I7UUFDL0IsV0FBVyxFQUFFLFFBQVE7UUFDckIsU0FBUztRQUNULGNBQWMsRUFBRSxDQUFDLEtBQUssQ0FBQztRQUN2QixJQUFJLEVBQUUsS0FBSztRQUNYLGFBQWEsRUFBRTtZQUNiLFFBQVEsRUFBRSxjQUFjO1lBQ3hCLFNBQVMsRUFBRSxRQUFRO1lBQ25CLFVBQVUsRUFBRSxTQUFTO1NBQ3RCO1FBQ0QsZ0JBQWdCLEVBQUUsSUFBSTtLQUN2QixDQUFDLENBQUM7SUFDSCxNQUFNLElBQUEscURBQTRCLEVBQUMsU0FBUyxDQUFDLENBQUMsR0FBRyxDQUFDO1FBQ2hELEtBQUssRUFBRSxFQUFFLFVBQVUsRUFBRSxPQUFPLENBQUMsRUFBRSxFQUFFO0tBQ2xDLENBQUMsQ0FBQztJQUNILE9BQU8sWUFBWSxDQUFDO0FBQ3RCLENBQUMsQ0FBQztBQWxEVyxRQUFBLG9CQUFvQix3QkFrRC9CIn0=