@gorgo/medusa-integration 0.0.2 → 0.0.4

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 (52) hide show
  1. package/.medusa/server/src/admin/index.js +35 -21
  2. package/.medusa/server/src/admin/index.mjs +35 -21
  3. package/.medusa/server/src/api/admin/integrations/__tests__/helpers.unit.spec.d.ts +1 -0
  4. package/.medusa/server/src/api/admin/integrations/__tests__/helpers.unit.spec.js +30 -0
  5. package/.medusa/server/src/api/admin/integrations/_helpers.d.ts +3 -3
  6. package/.medusa/server/src/api/admin/integrations/_helpers.js +8 -8
  7. package/.medusa/server/src/index.d.ts +1 -1
  8. package/.medusa/server/src/jobs/__tests__/test-integration-connections.unit.spec.d.ts +1 -0
  9. package/.medusa/server/src/jobs/__tests__/test-integration-connections.unit.spec.js +27 -0
  10. package/.medusa/server/src/jobs/test-integration-connections.d.ts +7 -0
  11. package/.medusa/server/src/jobs/test-integration-connections.js +19 -6
  12. package/.medusa/server/src/modules/integration/descriptor/__tests__/build-zod.unit.spec.js +43 -1
  13. package/.medusa/server/src/modules/integration/descriptor/__tests__/define.unit.spec.js +3 -3
  14. package/.medusa/server/src/modules/integration/descriptor/__tests__/introspect.unit.spec.js +3 -3
  15. package/.medusa/server/src/modules/integration/descriptor/__tests__/section-write.unit.spec.d.ts +1 -0
  16. package/.medusa/server/src/modules/integration/descriptor/__tests__/section-write.unit.spec.js +64 -0
  17. package/.medusa/server/src/modules/integration/descriptor/__tests__/validate.unit.spec.js +28 -2
  18. package/.medusa/server/src/modules/integration/descriptor/build-zod.js +7 -1
  19. package/.medusa/server/src/modules/integration/descriptor/define.d.ts +12 -5
  20. package/.medusa/server/src/modules/integration/descriptor/define.js +2 -2
  21. package/.medusa/server/src/modules/integration/descriptor/introspect.d.ts +1 -1
  22. package/.medusa/server/src/modules/integration/descriptor/introspect.js +4 -4
  23. package/.medusa/server/src/modules/integration/descriptor/meta.d.ts +1 -1
  24. package/.medusa/server/src/modules/integration/descriptor/section-write.d.ts +10 -0
  25. package/.medusa/server/src/modules/integration/descriptor/section-write.js +24 -0
  26. package/.medusa/server/src/modules/integration/loaders/load-providers.js +2 -2
  27. package/.medusa/server/src/modules/integration/migrations/Migration20260720130920.d.ts +5 -0
  28. package/.medusa/server/src/modules/integration/migrations/Migration20260720130920.js +18 -0
  29. package/.medusa/server/src/modules/integration/models/integration.d.ts +1 -1
  30. package/.medusa/server/src/modules/integration/models/integration.js +3 -3
  31. package/.medusa/server/src/modules/integration/services/__tests__/integration-module.unit.spec.d.ts +1 -0
  32. package/.medusa/server/src/modules/integration/services/__tests__/integration-module.unit.spec.js +240 -0
  33. package/.medusa/server/src/modules/integration/services/__tests__/integration-provider.unit.spec.js +3 -4
  34. package/.medusa/server/src/modules/integration/services/integration-module.d.ts +5 -5
  35. package/.medusa/server/src/modules/integration/services/integration-module.js +11 -12
  36. package/.medusa/server/src/modules/integration/utils/abstract-integration-provider.d.ts +5 -8
  37. package/.medusa/server/src/modules/integration/utils/abstract-integration-provider.js +4 -5
  38. package/.medusa/server/src/modules/integration/utils/integration.d.ts +3 -3
  39. package/.medusa/server/src/modules/integration/utils/integration.js +4 -4
  40. package/.medusa/server/src/subscribers/__tests__/invalidate-options-cache.unit.spec.d.ts +1 -0
  41. package/.medusa/server/src/subscribers/__tests__/invalidate-options-cache.unit.spec.js +53 -0
  42. package/.medusa/server/src/types/http/integration/admin/entities.d.ts +5 -4
  43. package/.medusa/server/src/types/integration/common.d.ts +3 -3
  44. package/.medusa/server/src/workflows/integration/steps/apply-integration-section.d.ts +1 -1
  45. package/.medusa/server/src/workflows/integration/steps/apply-integration-section.js +13 -20
  46. package/.medusa/server/src/workflows/integration/steps/set-integration-enabled.d.ts +1 -1
  47. package/.medusa/server/src/workflows/integration/steps/upsert-integration-record.d.ts +2 -2
  48. package/.medusa/server/src/workflows/integration/workflows/set-integration-enabled.d.ts +1 -1
  49. package/.medusa/server/src/workflows/integration/workflows/upsert-integration.js +2 -2
  50. package/README.md +41 -2
  51. package/README.ru.md +85 -0
  52. package/package.json +1 -1
@@ -24,7 +24,7 @@ const IntegrationIcon = ({
24
24
  alt,
25
25
  size = "base"
26
26
  }) => {
27
- const dim = size === "small" ? "h-6 w-6" : "h-8 w-8";
27
+ const dim = size === "small" ? "h-6 w-6" : "h-10 w-10";
28
28
  return /* @__PURE__ */ jsxRuntime.jsx(
29
29
  "div",
30
30
  {
@@ -43,15 +43,15 @@ const IntegrationsPage = () => {
43
43
  queryFn: () => sdk.client.fetch("/admin/integrations")
44
44
  });
45
45
  const items = (data == null ? void 0 : data.integrations) ?? [];
46
- const byModule = items.reduce((acc, i) => {
46
+ const byCategory = items.reduce((acc, i) => {
47
47
  var _a;
48
- (acc[_a = i.module] ?? (acc[_a] = [])).push(i);
48
+ (acc[_a = i.category] ?? (acc[_a] = [])).push(i);
49
49
  return acc;
50
50
  }, {});
51
51
  return /* @__PURE__ */ jsxRuntime.jsxs(ui.Container, { className: "divide-y p-0", children: [
52
52
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-6 py-4", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { level: "h2", children: t("integration.list.title") }) }),
53
- isLoading ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-center px-6 py-8", children: /* @__PURE__ */ jsxRuntime.jsx(icons.Spinner, { className: "text-ui-fg-subtle animate-spin" }) }) : items.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-6 py-4", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "text-ui-fg-subtle", children: t("integration.list.empty") }) }) : Object.entries(byModule).map(([module2, group]) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "px-6 py-4", children: [
54
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", weight: "plus", children: t(`integration.modules.${module2}`) }),
53
+ isLoading ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-center px-6 py-8", children: /* @__PURE__ */ jsxRuntime.jsx(icons.Spinner, { className: "text-ui-fg-subtle animate-spin" }) }) : items.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-6 py-4", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "text-ui-fg-subtle", children: t("integration.list.empty") }) }) : Object.entries(byCategory).map(([category, group]) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "px-6 py-4", children: [
54
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", weight: "plus", children: t(`integration.categories.${category}`) }),
55
55
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-2 flex flex-col gap-2", children: group.map((i) => {
56
56
  const configured = i.is_configured && i.is_enabled;
57
57
  return /* @__PURE__ */ jsxRuntime.jsxs(
@@ -75,7 +75,7 @@ const IntegrationsPage = () => {
75
75
  i.provider_id
76
76
  );
77
77
  }) })
78
- ] }, module2))
78
+ ] }, category))
79
79
  ] });
80
80
  };
81
81
  const config = adminSdk.defineRouteConfig({
@@ -1683,7 +1683,7 @@ function useForm(props = {}) {
1683
1683
  _formControl.current.formState = getProxyFormState(formState, control);
1684
1684
  return _formControl.current;
1685
1685
  }
1686
- const jsonToText = (v) => v === void 0 || v === "" ? "" : JSON.stringify(v, null, 2);
1686
+ const jsonToText = (v) => v == null || v === "" ? "" : JSON.stringify(v, null, 2);
1687
1687
  const JsonField = ({ field, f }) => {
1688
1688
  const { t } = reactI18next.useTranslation();
1689
1689
  const [raw, setRaw] = React.useState(() => jsonToText(f.value));
@@ -1703,7 +1703,7 @@ const JsonField = ({ field, f }) => {
1703
1703
  setRaw(text);
1704
1704
  if (text.trim() === "") {
1705
1705
  setError(null);
1706
- f.onChange(void 0);
1706
+ f.onChange(null);
1707
1707
  return;
1708
1708
  }
1709
1709
  try {
@@ -1773,7 +1773,18 @@ function renderControl(field, f, secretConfigured, t) {
1773
1773
  placeholder,
1774
1774
  value: f.value ?? "",
1775
1775
  disabled,
1776
- onChange: (e) => f.onChange(e.target.value === "" ? void 0 : e.target.valueAsNumber)
1776
+ onChange: (e) => f.onChange(e.target.value === "" ? null : e.target.valueAsNumber)
1777
+ }
1778
+ );
1779
+ case "url":
1780
+ return /* @__PURE__ */ jsxRuntime.jsx(
1781
+ ui.Input,
1782
+ {
1783
+ type: "url",
1784
+ placeholder,
1785
+ value: f.value ?? "",
1786
+ disabled,
1787
+ onChange: f.onChange
1777
1788
  }
1778
1789
  );
1779
1790
  case "secret":
@@ -1784,7 +1795,8 @@ function renderControl(field, f, secretConfigured, t) {
1784
1795
  placeholder: secretConfigured ? t("integration.form.keepSecret") : placeholder ?? "",
1785
1796
  value: f.value ?? "",
1786
1797
  disabled,
1787
- onChange: f.onChange
1798
+ onChange: f.onChange,
1799
+ className: !f.value ? "[&~div]:hidden" : void 0
1788
1800
  }
1789
1801
  );
1790
1802
  case "json":
@@ -1822,10 +1834,11 @@ const EditSectionDrawer = ({
1822
1834
  providerId,
1823
1835
  section,
1824
1836
  values,
1825
- hasSecrets = false
1837
+ configuredSecrets = []
1826
1838
  }) => {
1827
1839
  const { t } = reactI18next.useTranslation();
1828
1840
  const qc = reactQuery.useQueryClient();
1841
+ const configured = new Set(configuredSecrets);
1829
1842
  const [defaults] = React.useState(() => sectionDefaults(section, values));
1830
1843
  const form = useForm({ values: defaults });
1831
1844
  const current = form.watch();
@@ -1852,7 +1865,7 @@ const EditSectionDrawer = ({
1852
1865
  {
1853
1866
  field: f,
1854
1867
  control: form.control,
1855
- secretConfigured: hasSecrets
1868
+ secretConfigured: configured.has(f.name)
1856
1869
  },
1857
1870
  f.name
1858
1871
  )) }),
@@ -1946,6 +1959,7 @@ const EditPage = () => {
1946
1959
  ] });
1947
1960
  }
1948
1961
  const editing = descriptor.sections.find((s) => s.id === editingSection) ?? null;
1962
+ const configuredSecrets = new Set((record == null ? void 0 : record.configured_secrets) ?? []);
1949
1963
  const sectionData = {
1950
1964
  providerId: provider_id,
1951
1965
  identifier: descriptor.identifier,
@@ -1970,7 +1984,7 @@ const EditPage = () => {
1970
1984
  {
1971
1985
  field: f,
1972
1986
  value: (_a = record == null ? void 0 : record.values) == null ? void 0 : _a[f.name],
1973
- secretConfigured: !!(record == null ? void 0 : record.has_secrets)
1987
+ secretConfigured: configuredSecrets.has(f.name)
1974
1988
  }
1975
1989
  ) }, f.name);
1976
1990
  })
@@ -2011,7 +2025,7 @@ const EditPage = () => {
2011
2025
  ] })
2012
2026
  ] }),
2013
2027
  /* @__PURE__ */ jsxRuntime.jsx(Row, { label: t("integration.labels.status"), children: !isConfigured ? /* @__PURE__ */ jsxRuntime.jsx(ui.StatusBadge, { color: "grey", children: t("integration.status.notConfigured") }) : !isComplete ? /* @__PURE__ */ jsxRuntime.jsx(ui.StatusBadge, { color: "orange", children: t("integration.status.incomplete") }) : /* @__PURE__ */ jsxRuntime.jsx(ui.StatusBadge, { color: record.is_enabled ? "green" : "grey", children: record.is_enabled ? t("integration.status.enabled") : t("integration.status.disabled") }) }),
2014
- /* @__PURE__ */ jsxRuntime.jsx(Row, { label: t("integration.labels.module"), children: /* @__PURE__ */ jsxRuntime.jsx(ui.Badge, { size: "2xsmall", color: "grey", children: t(`integration.modules.${descriptor.module}`) }) }),
2028
+ /* @__PURE__ */ jsxRuntime.jsx(Row, { label: t("integration.labels.category"), children: /* @__PURE__ */ jsxRuntime.jsx(ui.Badge, { size: "2xsmall", color: "grey", children: t(`integration.categories.${descriptor.category}`) }) }),
2015
2029
  /* @__PURE__ */ jsxRuntime.jsx(Row, { label: t("integration.labels.lastTest"), children: (record == null ? void 0 : record.last_test_status) ? /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: /* @__PURE__ */ jsxRuntime.jsx(ui.StatusBadge, { color: testColor(record.last_test_status), children: t(`integration.testStatus.${record.last_test_status}`) }) }) : /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", leading: "compact", className: "text-ui-fg-subtle", children: t("integration.labels.neverTested") }) })
2016
2030
  ] }) }),
2017
2031
  mainSections.map(renderSection),
@@ -2023,7 +2037,7 @@ const EditPage = () => {
2023
2037
  providerId: provider_id,
2024
2038
  section: editing,
2025
2039
  values: (record == null ? void 0 : record.values) ?? {},
2026
- hasSecrets: !!(record == null ? void 0 : record.has_secrets)
2040
+ configuredSecrets: (record == null ? void 0 : record.configured_secrets) ?? []
2027
2041
  },
2028
2042
  editing.id
2029
2043
  )
@@ -2072,11 +2086,11 @@ const integration$1 = {
2072
2086
  },
2073
2087
  labels: {
2074
2088
  status: "Status",
2075
- module: "Module",
2089
+ category: "Category",
2076
2090
  lastTest: "Last test",
2077
2091
  neverTested: "Never tested"
2078
2092
  },
2079
- modules: {
2093
+ categories: {
2080
2094
  payment: "Payment",
2081
2095
  fulfillment: "Fulfillment",
2082
2096
  marketplace: "Marketplace",
@@ -2109,7 +2123,7 @@ const integration$1 = {
2109
2123
  form: {
2110
2124
  required: "{{field}} is required",
2111
2125
  invalidJson: "Invalid JSON",
2112
- keepSecret: "•••••• — leave blank to keep",
2126
+ keepSecret: "•••••• – leave blank to keep",
2113
2127
  items: "{{count}} items"
2114
2128
  },
2115
2129
  toast: {
@@ -2145,11 +2159,11 @@ const integration = {
2145
2159
  },
2146
2160
  labels: {
2147
2161
  status: "Статус",
2148
- module: "Модуль",
2162
+ category: "Категория",
2149
2163
  lastTest: "Последняя проверка",
2150
2164
  neverTested: "Не проверялось"
2151
2165
  },
2152
- modules: {
2166
+ categories: {
2153
2167
  payment: "Платежи",
2154
2168
  fulfillment: "Доставка",
2155
2169
  marketplace: "Маркетплейс",
@@ -2182,7 +2196,7 @@ const integration = {
2182
2196
  form: {
2183
2197
  required: "Поле «{{field}}» обязательно",
2184
2198
  invalidJson: "Некорректный JSON",
2185
- keepSecret: "•••••• — оставьте пустым, чтобы не менять",
2199
+ keepSecret: "•••••• – оставьте пустым, чтобы не менять",
2186
2200
  items: "{{count}} шт."
2187
2201
  },
2188
2202
  toast: {
@@ -20,7 +20,7 @@ const IntegrationIcon = ({
20
20
  alt,
21
21
  size = "base"
22
22
  }) => {
23
- const dim = size === "small" ? "h-6 w-6" : "h-8 w-8";
23
+ const dim = size === "small" ? "h-6 w-6" : "h-10 w-10";
24
24
  return /* @__PURE__ */ jsx(
25
25
  "div",
26
26
  {
@@ -39,15 +39,15 @@ const IntegrationsPage = () => {
39
39
  queryFn: () => sdk.client.fetch("/admin/integrations")
40
40
  });
41
41
  const items = (data == null ? void 0 : data.integrations) ?? [];
42
- const byModule = items.reduce((acc, i) => {
42
+ const byCategory = items.reduce((acc, i) => {
43
43
  var _a;
44
- (acc[_a = i.module] ?? (acc[_a] = [])).push(i);
44
+ (acc[_a = i.category] ?? (acc[_a] = [])).push(i);
45
45
  return acc;
46
46
  }, {});
47
47
  return /* @__PURE__ */ jsxs(Container, { className: "divide-y p-0", children: [
48
48
  /* @__PURE__ */ jsx("div", { className: "px-6 py-4", children: /* @__PURE__ */ jsx(Heading, { level: "h2", children: t("integration.list.title") }) }),
49
- isLoading ? /* @__PURE__ */ jsx("div", { className: "flex items-center justify-center px-6 py-8", children: /* @__PURE__ */ jsx(Spinner, { className: "text-ui-fg-subtle animate-spin" }) }) : items.length === 0 ? /* @__PURE__ */ jsx("div", { className: "px-6 py-4", children: /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: t("integration.list.empty") }) }) : Object.entries(byModule).map(([module, group]) => /* @__PURE__ */ jsxs("div", { className: "px-6 py-4", children: [
50
- /* @__PURE__ */ jsx(Text, { size: "small", weight: "plus", children: t(`integration.modules.${module}`) }),
49
+ isLoading ? /* @__PURE__ */ jsx("div", { className: "flex items-center justify-center px-6 py-8", children: /* @__PURE__ */ jsx(Spinner, { className: "text-ui-fg-subtle animate-spin" }) }) : items.length === 0 ? /* @__PURE__ */ jsx("div", { className: "px-6 py-4", children: /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: t("integration.list.empty") }) }) : Object.entries(byCategory).map(([category, group]) => /* @__PURE__ */ jsxs("div", { className: "px-6 py-4", children: [
50
+ /* @__PURE__ */ jsx(Text, { size: "small", weight: "plus", children: t(`integration.categories.${category}`) }),
51
51
  /* @__PURE__ */ jsx("div", { className: "mt-2 flex flex-col gap-2", children: group.map((i) => {
52
52
  const configured = i.is_configured && i.is_enabled;
53
53
  return /* @__PURE__ */ jsxs(
@@ -71,7 +71,7 @@ const IntegrationsPage = () => {
71
71
  i.provider_id
72
72
  );
73
73
  }) })
74
- ] }, module))
74
+ ] }, category))
75
75
  ] });
76
76
  };
77
77
  const config = defineRouteConfig({
@@ -1679,7 +1679,7 @@ function useForm(props = {}) {
1679
1679
  _formControl.current.formState = getProxyFormState(formState, control);
1680
1680
  return _formControl.current;
1681
1681
  }
1682
- const jsonToText = (v) => v === void 0 || v === "" ? "" : JSON.stringify(v, null, 2);
1682
+ const jsonToText = (v) => v == null || v === "" ? "" : JSON.stringify(v, null, 2);
1683
1683
  const JsonField = ({ field, f }) => {
1684
1684
  const { t } = useTranslation();
1685
1685
  const [raw, setRaw] = useState(() => jsonToText(f.value));
@@ -1699,7 +1699,7 @@ const JsonField = ({ field, f }) => {
1699
1699
  setRaw(text);
1700
1700
  if (text.trim() === "") {
1701
1701
  setError(null);
1702
- f.onChange(void 0);
1702
+ f.onChange(null);
1703
1703
  return;
1704
1704
  }
1705
1705
  try {
@@ -1769,7 +1769,18 @@ function renderControl(field, f, secretConfigured, t) {
1769
1769
  placeholder,
1770
1770
  value: f.value ?? "",
1771
1771
  disabled,
1772
- onChange: (e) => f.onChange(e.target.value === "" ? void 0 : e.target.valueAsNumber)
1772
+ onChange: (e) => f.onChange(e.target.value === "" ? null : e.target.valueAsNumber)
1773
+ }
1774
+ );
1775
+ case "url":
1776
+ return /* @__PURE__ */ jsx(
1777
+ Input,
1778
+ {
1779
+ type: "url",
1780
+ placeholder,
1781
+ value: f.value ?? "",
1782
+ disabled,
1783
+ onChange: f.onChange
1773
1784
  }
1774
1785
  );
1775
1786
  case "secret":
@@ -1780,7 +1791,8 @@ function renderControl(field, f, secretConfigured, t) {
1780
1791
  placeholder: secretConfigured ? t("integration.form.keepSecret") : placeholder ?? "",
1781
1792
  value: f.value ?? "",
1782
1793
  disabled,
1783
- onChange: f.onChange
1794
+ onChange: f.onChange,
1795
+ className: !f.value ? "[&~div]:hidden" : void 0
1784
1796
  }
1785
1797
  );
1786
1798
  case "json":
@@ -1818,10 +1830,11 @@ const EditSectionDrawer = ({
1818
1830
  providerId,
1819
1831
  section,
1820
1832
  values,
1821
- hasSecrets = false
1833
+ configuredSecrets = []
1822
1834
  }) => {
1823
1835
  const { t } = useTranslation();
1824
1836
  const qc = useQueryClient();
1837
+ const configured = new Set(configuredSecrets);
1825
1838
  const [defaults] = useState(() => sectionDefaults(section, values));
1826
1839
  const form = useForm({ values: defaults });
1827
1840
  const current = form.watch();
@@ -1848,7 +1861,7 @@ const EditSectionDrawer = ({
1848
1861
  {
1849
1862
  field: f,
1850
1863
  control: form.control,
1851
- secretConfigured: hasSecrets
1864
+ secretConfigured: configured.has(f.name)
1852
1865
  },
1853
1866
  f.name
1854
1867
  )) }),
@@ -1942,6 +1955,7 @@ const EditPage = () => {
1942
1955
  ] });
1943
1956
  }
1944
1957
  const editing = descriptor.sections.find((s) => s.id === editingSection) ?? null;
1958
+ const configuredSecrets = new Set((record == null ? void 0 : record.configured_secrets) ?? []);
1945
1959
  const sectionData = {
1946
1960
  providerId: provider_id,
1947
1961
  identifier: descriptor.identifier,
@@ -1966,7 +1980,7 @@ const EditPage = () => {
1966
1980
  {
1967
1981
  field: f,
1968
1982
  value: (_a = record == null ? void 0 : record.values) == null ? void 0 : _a[f.name],
1969
- secretConfigured: !!(record == null ? void 0 : record.has_secrets)
1983
+ secretConfigured: configuredSecrets.has(f.name)
1970
1984
  }
1971
1985
  ) }, f.name);
1972
1986
  })
@@ -2007,7 +2021,7 @@ const EditPage = () => {
2007
2021
  ] })
2008
2022
  ] }),
2009
2023
  /* @__PURE__ */ jsx(Row, { label: t("integration.labels.status"), children: !isConfigured ? /* @__PURE__ */ jsx(StatusBadge, { color: "grey", children: t("integration.status.notConfigured") }) : !isComplete ? /* @__PURE__ */ jsx(StatusBadge, { color: "orange", children: t("integration.status.incomplete") }) : /* @__PURE__ */ jsx(StatusBadge, { color: record.is_enabled ? "green" : "grey", children: record.is_enabled ? t("integration.status.enabled") : t("integration.status.disabled") }) }),
2010
- /* @__PURE__ */ jsx(Row, { label: t("integration.labels.module"), children: /* @__PURE__ */ jsx(Badge, { size: "2xsmall", color: "grey", children: t(`integration.modules.${descriptor.module}`) }) }),
2024
+ /* @__PURE__ */ jsx(Row, { label: t("integration.labels.category"), children: /* @__PURE__ */ jsx(Badge, { size: "2xsmall", color: "grey", children: t(`integration.categories.${descriptor.category}`) }) }),
2011
2025
  /* @__PURE__ */ jsx(Row, { label: t("integration.labels.lastTest"), children: (record == null ? void 0 : record.last_test_status) ? /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsx(StatusBadge, { color: testColor(record.last_test_status), children: t(`integration.testStatus.${record.last_test_status}`) }) }) : /* @__PURE__ */ jsx(Text, { size: "small", leading: "compact", className: "text-ui-fg-subtle", children: t("integration.labels.neverTested") }) })
2012
2026
  ] }) }),
2013
2027
  mainSections.map(renderSection),
@@ -2019,7 +2033,7 @@ const EditPage = () => {
2019
2033
  providerId: provider_id,
2020
2034
  section: editing,
2021
2035
  values: (record == null ? void 0 : record.values) ?? {},
2022
- hasSecrets: !!(record == null ? void 0 : record.has_secrets)
2036
+ configuredSecrets: (record == null ? void 0 : record.configured_secrets) ?? []
2023
2037
  },
2024
2038
  editing.id
2025
2039
  )
@@ -2068,11 +2082,11 @@ const integration$1 = {
2068
2082
  },
2069
2083
  labels: {
2070
2084
  status: "Status",
2071
- module: "Module",
2085
+ category: "Category",
2072
2086
  lastTest: "Last test",
2073
2087
  neverTested: "Never tested"
2074
2088
  },
2075
- modules: {
2089
+ categories: {
2076
2090
  payment: "Payment",
2077
2091
  fulfillment: "Fulfillment",
2078
2092
  marketplace: "Marketplace",
@@ -2105,7 +2119,7 @@ const integration$1 = {
2105
2119
  form: {
2106
2120
  required: "{{field}} is required",
2107
2121
  invalidJson: "Invalid JSON",
2108
- keepSecret: "•••••• — leave blank to keep",
2122
+ keepSecret: "•••••• – leave blank to keep",
2109
2123
  items: "{{count}} items"
2110
2124
  },
2111
2125
  toast: {
@@ -2141,11 +2155,11 @@ const integration = {
2141
2155
  },
2142
2156
  labels: {
2143
2157
  status: "Статус",
2144
- module: "Модуль",
2158
+ category: "Категория",
2145
2159
  lastTest: "Последняя проверка",
2146
2160
  neverTested: "Не проверялось"
2147
2161
  },
2148
- modules: {
2162
+ categories: {
2149
2163
  payment: "Платежи",
2150
2164
  fulfillment: "Доставка",
2151
2165
  marketplace: "Маркетплейс",
@@ -2178,7 +2192,7 @@ const integration = {
2178
2192
  form: {
2179
2193
  required: "Поле «{{field}}» обязательно",
2180
2194
  invalidJson: "Некорректный JSON",
2181
- keepSecret: "•••••• — оставьте пустым, чтобы не менять",
2195
+ keepSecret: "•••••• – оставьте пустым, чтобы не менять",
2182
2196
  items: "{{count}} шт."
2183
2197
  },
2184
2198
  toast: {
@@ -0,0 +1,30 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const globals_1 = require("@jest/globals");
4
+ const _helpers_1 = require("../_helpers");
5
+ const rec = (options) => ({
6
+ id: "int_x",
7
+ provider_id: "int_x",
8
+ category: "payment",
9
+ title: null,
10
+ is_enabled: true,
11
+ last_test_status: null,
12
+ options,
13
+ });
14
+ (0, globals_1.describe)("maskedView", () => {
15
+ (0, globals_1.it)("reports configured secrets per field — only those with a stored value", () => {
16
+ // apiKey has ciphertext, clientSecret is blank → only apiKey counts as configured.
17
+ const v = (0, _helpers_1.maskedView)(rec({ apiKey: "ct", clientSecret: "", terminalKey: "abc" }), ["apiKey", "clientSecret"]);
18
+ (0, globals_1.expect)(v.configured_secrets).toEqual(["apiKey"]);
19
+ });
20
+ (0, globals_1.it)("returns an empty list when no secret is set", () => {
21
+ const v = (0, _helpers_1.maskedView)(rec({ terminalKey: "abc" }), ["apiKey", "clientSecret"]);
22
+ (0, globals_1.expect)(v.configured_secrets).toEqual([]);
23
+ });
24
+ (0, globals_1.it)("never leaks secret ciphertext into values", () => {
25
+ const v = (0, _helpers_1.maskedView)(rec({ apiKey: "ct", terminalKey: "abc" }), ["apiKey"]);
26
+ (0, globals_1.expect)(v.values).toEqual({ terminalKey: "abc" });
27
+ (0, globals_1.expect)(Object.prototype.hasOwnProperty.call(v.values, "apiKey")).toBe(false);
28
+ });
29
+ });
30
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaGVscGVycy51bml0LnNwZWMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi8uLi9zcmMvYXBpL2FkbWluL2ludGVncmF0aW9ucy9fX3Rlc3RzX18vaGVscGVycy51bml0LnNwZWMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7QUFBQSwyQ0FBb0Q7QUFDcEQsMENBQXdDO0FBRXhDLE1BQU0sR0FBRyxHQUFHLENBQUMsT0FBZ0MsRUFBRSxFQUFFLENBQUMsQ0FBQztJQUNqRCxFQUFFLEVBQUUsT0FBTztJQUNYLFdBQVcsRUFBRSxPQUFPO0lBQ3BCLFFBQVEsRUFBRSxTQUFTO0lBQ25CLEtBQUssRUFBRSxJQUFJO0lBQ1gsVUFBVSxFQUFFLElBQUk7SUFDaEIsZ0JBQWdCLEVBQUUsSUFBSTtJQUN0QixPQUFPO0NBQ1IsQ0FBQyxDQUFBO0FBRUYsSUFBQSxrQkFBUSxFQUFDLFlBQVksRUFBRSxHQUFHLEVBQUU7SUFDMUIsSUFBQSxZQUFFLEVBQUMsdUVBQXVFLEVBQUUsR0FBRyxFQUFFO1FBQy9FLG1GQUFtRjtRQUNuRixNQUFNLENBQUMsR0FBRyxJQUFBLHFCQUFVLEVBQUMsR0FBRyxDQUFDLEVBQUUsTUFBTSxFQUFFLElBQUksRUFBRSxZQUFZLEVBQUUsRUFBRSxFQUFFLFdBQVcsRUFBRSxLQUFLLEVBQUUsQ0FBQyxFQUFFLENBQUMsUUFBUSxFQUFFLGNBQWMsQ0FBQyxDQUFDLENBQUE7UUFDN0csSUFBQSxnQkFBTSxFQUFDLENBQUMsQ0FBQyxrQkFBa0IsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxDQUFDLFFBQVEsQ0FBQyxDQUFDLENBQUE7SUFDbEQsQ0FBQyxDQUFDLENBQUE7SUFFRixJQUFBLFlBQUUsRUFBQyw2Q0FBNkMsRUFBRSxHQUFHLEVBQUU7UUFDckQsTUFBTSxDQUFDLEdBQUcsSUFBQSxxQkFBVSxFQUFDLEdBQUcsQ0FBQyxFQUFFLFdBQVcsRUFBRSxLQUFLLEVBQUUsQ0FBQyxFQUFFLENBQUMsUUFBUSxFQUFFLGNBQWMsQ0FBQyxDQUFDLENBQUE7UUFDN0UsSUFBQSxnQkFBTSxFQUFDLENBQUMsQ0FBQyxrQkFBa0IsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxFQUFFLENBQUMsQ0FBQTtJQUMxQyxDQUFDLENBQUMsQ0FBQTtJQUVGLElBQUEsWUFBRSxFQUFDLDJDQUEyQyxFQUFFLEdBQUcsRUFBRTtRQUNuRCxNQUFNLENBQUMsR0FBRyxJQUFBLHFCQUFVLEVBQUMsR0FBRyxDQUFDLEVBQUUsTUFBTSxFQUFFLElBQUksRUFBRSxXQUFXLEVBQUUsS0FBSyxFQUFFLENBQUMsRUFBRSxDQUFDLFFBQVEsQ0FBQyxDQUFDLENBQUE7UUFDM0UsSUFBQSxnQkFBTSxFQUFDLENBQUMsQ0FBQyxNQUFNLENBQUMsQ0FBQyxPQUFPLENBQUMsRUFBRSxXQUFXLEVBQUUsS0FBSyxFQUFFLENBQUMsQ0FBQTtRQUNoRCxJQUFBLGdCQUFNLEVBQUMsTUFBTSxDQUFDLFNBQVMsQ0FBQyxjQUFjLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxNQUFNLEVBQUUsUUFBUSxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUE7SUFDOUUsQ0FBQyxDQUFDLENBQUE7QUFDSixDQUFDLENBQUMsQ0FBQSJ9
@@ -9,8 +9,8 @@ export declare function service(req: MedusaRequest): IntegrationModuleService;
9
9
  export declare function requireProvider(svc: IntegrationModuleService, providerId: string): void;
10
10
  /**
11
11
  * Build the client-facing view of a record. Secret options live encrypted inside `options`;
12
- * they are stripped here so ciphertext never reaches the browser. `has_secrets` tells the UI
13
- * a secret is stored (so it can render a "leave blank to keep" hint). `values` holds only
14
- * the non-secret options.
12
+ * they are stripped here so ciphertext never reaches the browser. `configured_secrets` lists
13
+ * the secret keys that currently have a stored value (per field), so the UI can render a
14
+ * "leave blank to keep" hint on exactly those fields. `values` holds only the non-secret options.
15
15
  */
16
16
  export declare function maskedView(record: any, secretKeys: string[]): MaskedIntegration;
@@ -19,19 +19,19 @@ function requireProvider(svc, providerId) {
19
19
  }
20
20
  /**
21
21
  * Build the client-facing view of a record. Secret options live encrypted inside `options`;
22
- * they are stripped here so ciphertext never reaches the browser. `has_secrets` tells the UI
23
- * a secret is stored (so it can render a "leave blank to keep" hint). `values` holds only
24
- * the non-secret options.
22
+ * they are stripped here so ciphertext never reaches the browser. `configured_secrets` lists
23
+ * the secret keys that currently have a stored value (per field), so the UI can render a
24
+ * "leave blank to keep" hint on exactly those fields. `values` holds only the non-secret options.
25
25
  */
26
26
  function maskedView(record, secretKeys) {
27
27
  const secret = new Set(secretKeys);
28
28
  const stored = (record.options ?? {});
29
29
  const values = {};
30
- let has_secrets = false;
30
+ const configured_secrets = [];
31
31
  for (const [k, v] of Object.entries(stored)) {
32
32
  if (secret.has(k)) {
33
33
  if (v != null && v !== "")
34
- has_secrets = true;
34
+ configured_secrets.push(k);
35
35
  continue;
36
36
  }
37
37
  values[k] = v;
@@ -39,12 +39,12 @@ function maskedView(record, secretKeys) {
39
39
  return {
40
40
  id: record.id,
41
41
  provider_id: record.provider_id,
42
- module: record.module,
42
+ category: record.category,
43
43
  title: record.title ?? null,
44
44
  is_enabled: record.is_enabled,
45
- has_secrets,
45
+ configured_secrets,
46
46
  last_test_status: record.last_test_status ?? null,
47
47
  values,
48
48
  };
49
49
  }
50
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiX2hlbHBlcnMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi9zcmMvYXBpL2FkbWluL2ludGVncmF0aW9ucy9faGVscGVycy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQU1BLDBCQUVDO0FBTUQsMENBSUM7QUFRRCxnQ0FzQkM7QUEvQ0QscURBQXVEO0FBQ3ZELDhEQUFpRTtBQUlqRSxTQUFnQixPQUFPLENBQUMsR0FBa0I7SUFDeEMsT0FBTyxHQUFHLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FBQyxnQ0FBa0IsQ0FBQyxDQUFBO0FBQzlDLENBQUM7QUFFRDs7O0dBR0c7QUFDSCxTQUFnQixlQUFlLENBQUMsR0FBNkIsRUFBRSxVQUFrQjtJQUMvRSxJQUFJLENBQUMsR0FBRyxDQUFDLGFBQWEsQ0FBQyxVQUFVLENBQUMsRUFBRSxDQUFDO1FBQ25DLE1BQU0sSUFBSSxtQkFBVyxDQUFDLG1CQUFXLENBQUMsS0FBSyxDQUFDLFNBQVMsRUFBRSx3QkFBd0IsVUFBVSxHQUFHLENBQUMsQ0FBQTtJQUMzRixDQUFDO0FBQ0gsQ0FBQztBQUVEOzs7OztHQUtHO0FBQ0gsU0FBZ0IsVUFBVSxDQUFDLE1BQVcsRUFBRSxVQUFvQjtJQUMxRCxNQUFNLE1BQU0sR0FBRyxJQUFJLEdBQUcsQ0FBQyxVQUFVLENBQUMsQ0FBQTtJQUNsQyxNQUFNLE1BQU0sR0FBRyxDQUFDLE1BQU0sQ0FBQyxPQUFPLElBQUksRUFBRSxDQUE0QixDQUFBO0lBQ2hFLE1BQU0sTUFBTSxHQUE0QixFQUFFLENBQUE7SUFDMUMsSUFBSSxXQUFXLEdBQUcsS0FBSyxDQUFBO0lBQ3ZCLEtBQUssTUFBTSxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsSUFBSSxNQUFNLENBQUMsT0FBTyxDQUFDLE1BQU0sQ0FBQyxFQUFFLENBQUM7UUFDNUMsSUFBSSxNQUFNLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUM7WUFDbEIsSUFBSSxDQUFDLElBQUksSUFBSSxJQUFJLENBQUMsS0FBSyxFQUFFO2dCQUFFLFdBQVcsR0FBRyxJQUFJLENBQUE7WUFDN0MsU0FBUTtRQUNWLENBQUM7UUFDRCxNQUFNLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFBO0lBQ2YsQ0FBQztJQUNELE9BQU87UUFDTCxFQUFFLEVBQUUsTUFBTSxDQUFDLEVBQUU7UUFDYixXQUFXLEVBQUUsTUFBTSxDQUFDLFdBQVc7UUFDL0IsTUFBTSxFQUFFLE1BQU0sQ0FBQyxNQUFNO1FBQ3JCLEtBQUssRUFBRSxNQUFNLENBQUMsS0FBSyxJQUFJLElBQUk7UUFDM0IsVUFBVSxFQUFFLE1BQU0sQ0FBQyxVQUFVO1FBQzdCLFdBQVc7UUFDWCxnQkFBZ0IsRUFBRSxNQUFNLENBQUMsZ0JBQWdCLElBQUksSUFBSTtRQUNqRCxNQUFNO0tBQ1AsQ0FBQTtBQUNILENBQUMifQ==
50
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiX2hlbHBlcnMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi9zcmMvYXBpL2FkbWluL2ludGVncmF0aW9ucy9faGVscGVycy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQU1BLDBCQUVDO0FBTUQsMENBSUM7QUFRRCxnQ0FzQkM7QUEvQ0QscURBQXVEO0FBQ3ZELDhEQUFpRTtBQUlqRSxTQUFnQixPQUFPLENBQUMsR0FBa0I7SUFDeEMsT0FBTyxHQUFHLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FBQyxnQ0FBa0IsQ0FBQyxDQUFBO0FBQzlDLENBQUM7QUFFRDs7O0dBR0c7QUFDSCxTQUFnQixlQUFlLENBQUMsR0FBNkIsRUFBRSxVQUFrQjtJQUMvRSxJQUFJLENBQUMsR0FBRyxDQUFDLGFBQWEsQ0FBQyxVQUFVLENBQUMsRUFBRSxDQUFDO1FBQ25DLE1BQU0sSUFBSSxtQkFBVyxDQUFDLG1CQUFXLENBQUMsS0FBSyxDQUFDLFNBQVMsRUFBRSx3QkFBd0IsVUFBVSxHQUFHLENBQUMsQ0FBQTtJQUMzRixDQUFDO0FBQ0gsQ0FBQztBQUVEOzs7OztHQUtHO0FBQ0gsU0FBZ0IsVUFBVSxDQUFDLE1BQVcsRUFBRSxVQUFvQjtJQUMxRCxNQUFNLE1BQU0sR0FBRyxJQUFJLEdBQUcsQ0FBQyxVQUFVLENBQUMsQ0FBQTtJQUNsQyxNQUFNLE1BQU0sR0FBRyxDQUFDLE1BQU0sQ0FBQyxPQUFPLElBQUksRUFBRSxDQUE0QixDQUFBO0lBQ2hFLE1BQU0sTUFBTSxHQUE0QixFQUFFLENBQUE7SUFDMUMsTUFBTSxrQkFBa0IsR0FBYSxFQUFFLENBQUE7SUFDdkMsS0FBSyxNQUFNLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxJQUFJLE1BQU0sQ0FBQyxPQUFPLENBQUMsTUFBTSxDQUFDLEVBQUUsQ0FBQztRQUM1QyxJQUFJLE1BQU0sQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQztZQUNsQixJQUFJLENBQUMsSUFBSSxJQUFJLElBQUksQ0FBQyxLQUFLLEVBQUU7Z0JBQUUsa0JBQWtCLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFBO1lBQ3JELFNBQVE7UUFDVixDQUFDO1FBQ0QsTUFBTSxDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQTtJQUNmLENBQUM7SUFDRCxPQUFPO1FBQ0wsRUFBRSxFQUFFLE1BQU0sQ0FBQyxFQUFFO1FBQ2IsV0FBVyxFQUFFLE1BQU0sQ0FBQyxXQUFXO1FBQy9CLFFBQVEsRUFBRSxNQUFNLENBQUMsUUFBUTtRQUN6QixLQUFLLEVBQUUsTUFBTSxDQUFDLEtBQUssSUFBSSxJQUFJO1FBQzNCLFVBQVUsRUFBRSxNQUFNLENBQUMsVUFBVTtRQUM3QixrQkFBa0I7UUFDbEIsZ0JBQWdCLEVBQUUsTUFBTSxDQUFDLGdCQUFnQixJQUFJLElBQUk7UUFDakQsTUFBTTtLQUNQLENBQUE7QUFDSCxDQUFDIn0=
@@ -1,6 +1,6 @@
1
1
  export { defineIntegration, z } from "./modules/integration/descriptor/define";
2
2
  export { AbstractIntegrationProvider } from "./modules/integration/utils/abstract-integration-provider";
3
- export type { IntegrationDescriptor, IntegrationDescriptorInput, ModuleKind, OptionDef, OptionValidateContext, Settings, TestConnectionContext, TestConnectionResult, } from "./modules/integration/descriptor/define";
3
+ export type { IntegrationDescriptor, IntegrationDescriptorInput, CategoryKind, OptionDef, OptionValidateContext, Settings, TestConnectionContext, TestConnectionResult, } from "./modules/integration/descriptor/define";
4
4
  export type { FieldControl, I18nKey } from "./modules/integration/descriptor/meta";
5
5
  export { collectValidationIssues, isDescriptorComplete } from "./modules/integration/descriptor/validate";
6
6
  export type { IntegrationSectionData } from "./types";
@@ -0,0 +1,27 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const globals_1 = require("@jest/globals");
4
+ const test_integration_connections_1 = require("../test-integration-connections");
5
+ (0, globals_1.describe)("tallyOutcomes", () => {
6
+ (0, globals_1.it)("counts each status into its own bucket (statuses, not display labels)", () => {
7
+ (0, globals_1.expect)((0, test_integration_connections_1.tallyOutcomes)(["passed", "failed", "passed", "skipped", "errored"])).toEqual({
8
+ passed: 2,
9
+ failed: 1,
10
+ skipped: 1,
11
+ errored: 1,
12
+ });
13
+ });
14
+ (0, globals_1.it)("returns all-zero buckets for no outcomes", () => {
15
+ (0, globals_1.expect)((0, test_integration_connections_1.tallyOutcomes)([])).toEqual({ passed: 0, failed: 0, skipped: 0, errored: 0 });
16
+ });
17
+ });
18
+ (0, globals_1.describe)("formatConnectionTestSummary", () => {
19
+ (0, globals_1.it)("maps passed→ok and failed→fail in the summary line", () => {
20
+ const line = (0, test_integration_connections_1.formatConnectionTestSummary)({ passed: 2, failed: 1, skipped: 3, errored: 0 });
21
+ (0, globals_1.expect)(line).toContain("ok: 2");
22
+ (0, globals_1.expect)(line).toContain("fail: 1");
23
+ (0, globals_1.expect)(line).toContain("skipped: 3");
24
+ (0, globals_1.expect)(line).toContain("errored: 0");
25
+ });
26
+ });
27
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGVzdC1pbnRlZ3JhdGlvbi1jb25uZWN0aW9ucy51bml0LnNwZWMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi9zcmMvam9icy9fX3Rlc3RzX18vdGVzdC1pbnRlZ3JhdGlvbi1jb25uZWN0aW9ucy51bml0LnNwZWMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7QUFBQSwyQ0FBb0Q7QUFDcEQsa0ZBQTRGO0FBRTVGLElBQUEsa0JBQVEsRUFBQyxlQUFlLEVBQUUsR0FBRyxFQUFFO0lBQzdCLElBQUEsWUFBRSxFQUFDLHVFQUF1RSxFQUFFLEdBQUcsRUFBRTtRQUMvRSxJQUFBLGdCQUFNLEVBQUMsSUFBQSw0Q0FBYSxFQUFDLENBQUMsUUFBUSxFQUFFLFFBQVEsRUFBRSxRQUFRLEVBQUUsU0FBUyxFQUFFLFNBQVMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxPQUFPLENBQUM7WUFDbEYsTUFBTSxFQUFFLENBQUM7WUFDVCxNQUFNLEVBQUUsQ0FBQztZQUNULE9BQU8sRUFBRSxDQUFDO1lBQ1YsT0FBTyxFQUFFLENBQUM7U0FDWCxDQUFDLENBQUE7SUFDSixDQUFDLENBQUMsQ0FBQTtJQUVGLElBQUEsWUFBRSxFQUFDLDBDQUEwQyxFQUFFLEdBQUcsRUFBRTtRQUNsRCxJQUFBLGdCQUFNLEVBQUMsSUFBQSw0Q0FBYSxFQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsT0FBTyxDQUFDLEVBQUUsTUFBTSxFQUFFLENBQUMsRUFBRSxNQUFNLEVBQUUsQ0FBQyxFQUFFLE9BQU8sRUFBRSxDQUFDLEVBQUUsT0FBTyxFQUFFLENBQUMsRUFBRSxDQUFDLENBQUE7SUFDckYsQ0FBQyxDQUFDLENBQUE7QUFDSixDQUFDLENBQUMsQ0FBQTtBQUVGLElBQUEsa0JBQVEsRUFBQyw2QkFBNkIsRUFBRSxHQUFHLEVBQUU7SUFDM0MsSUFBQSxZQUFFLEVBQUMsb0RBQW9ELEVBQUUsR0FBRyxFQUFFO1FBQzVELE1BQU0sSUFBSSxHQUFHLElBQUEsMERBQTJCLEVBQUMsRUFBRSxNQUFNLEVBQUUsQ0FBQyxFQUFFLE1BQU0sRUFBRSxDQUFDLEVBQUUsT0FBTyxFQUFFLENBQUMsRUFBRSxPQUFPLEVBQUUsQ0FBQyxFQUFFLENBQUMsQ0FBQTtRQUMxRixJQUFBLGdCQUFNLEVBQUMsSUFBSSxDQUFDLENBQUMsU0FBUyxDQUFDLE9BQU8sQ0FBQyxDQUFBO1FBQy9CLElBQUEsZ0JBQU0sRUFBQyxJQUFJLENBQUMsQ0FBQyxTQUFTLENBQUMsU0FBUyxDQUFDLENBQUE7UUFDakMsSUFBQSxnQkFBTSxFQUFDLElBQUksQ0FBQyxDQUFDLFNBQVMsQ0FBQyxZQUFZLENBQUMsQ0FBQTtRQUNwQyxJQUFBLGdCQUFNLEVBQUMsSUFBSSxDQUFDLENBQUMsU0FBUyxDQUFDLFlBQVksQ0FBQyxDQUFBO0lBQ3RDLENBQUMsQ0FBQyxDQUFBO0FBQ0osQ0FBQyxDQUFDLENBQUEifQ==
@@ -1,4 +1,11 @@
1
1
  import type { MedusaContainer } from "@medusajs/framework/types";
2
+ /** A per-integration test result: the provider's `passed`/`failed`/`skipped`, or `errored` (threw). */
3
+ export type TestOutcome = "passed" | "failed" | "skipped" | "errored";
4
+ export type OutcomeCounts = Record<TestOutcome, number>;
5
+ /** Tally outcomes into per-status buckets. Buckets are keyed by the status itself — no mapping. */
6
+ export declare function tallyOutcomes(outcomes: Iterable<TestOutcome>): OutcomeCounts;
7
+ /** The end-of-run summary line. `passed`→"ok", `failed`→"fail" for human-readable output. */
8
+ export declare function formatConnectionTestSummary(counts: OutcomeCounts): string;
2
9
  /**
3
10
  * Daily health check: run the connection test for every configured & enabled integration
4
11
  * that exposes one. Each test runs through `testIntegrationConnectionWorkflow`, which
@@ -1,9 +1,23 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.config = void 0;
4
+ exports.tallyOutcomes = tallyOutcomes;
5
+ exports.formatConnectionTestSummary = formatConnectionTestSummary;
4
6
  exports.default = testIntegrationConnectionsJob;
5
7
  const integration_1 = require("../modules/integration");
6
8
  const integration_2 = require("../workflows/integration");
9
+ /** Tally outcomes into per-status buckets. Buckets are keyed by the status itself — no mapping. */
10
+ function tallyOutcomes(outcomes) {
11
+ const counts = { passed: 0, failed: 0, skipped: 0, errored: 0 };
12
+ for (const o of outcomes)
13
+ counts[o]++;
14
+ return counts;
15
+ }
16
+ /** The end-of-run summary line. `passed`→"ok", `failed`→"fail" for human-readable output. */
17
+ function formatConnectionTestSummary(counts) {
18
+ return (`[integration] connection-test job done — ok: ${counts.passed}, fail: ${counts.failed}, ` +
19
+ `skipped: ${counts.skipped}, errored: ${counts.errored}`);
20
+ }
7
21
  /**
8
22
  * Daily health check: run the connection test for every configured & enabled integration
9
23
  * that exposes one. Each test runs through `testIntegrationConnectionWorkflow`, which
@@ -24,13 +38,13 @@ async function testIntegrationConnectionsJob(container) {
24
38
  return;
25
39
  }
26
40
  logger.info(`[integration] connection-test job: testing ${targets.length} integration(s)`);
27
- const counts = { ok: 0, fail: 0, skipped: 0, errored: 0 };
41
+ const outcomes = [];
28
42
  for (const target of targets) {
29
43
  try {
30
44
  const { result } = await (0, integration_2.testIntegrationConnectionWorkflow)(container).run({
31
45
  input: { provider_id: target.provider_id },
32
46
  });
33
- counts[result.status]++;
47
+ outcomes.push(result.status);
34
48
  const line = `[integration] ${target.provider_id} → ${result.status}${result.message ? `: ${result.message}` : ""}`;
35
49
  if (result.status === "failed")
36
50
  logger.warn(line);
@@ -38,16 +52,15 @@ async function testIntegrationConnectionsJob(container) {
38
52
  logger.info(line);
39
53
  }
40
54
  catch (e) {
41
- counts.errored++;
55
+ outcomes.push("errored");
42
56
  logger.error(`[integration] ${target.provider_id} test errored: ${e?.message ?? e}`);
43
57
  }
44
58
  }
45
- logger.info(`[integration] connection-test job done — ok: ${counts.ok}, fail: ${counts.fail}, ` +
46
- `skipped: ${counts.skipped}, errored: ${counts.errored}`);
59
+ logger.info(formatConnectionTestSummary(tallyOutcomes(outcomes)));
47
60
  }
48
61
  exports.config = {
49
62
  name: "test-integration-connections-daily",
50
63
  // Once a day, off-peak (03:00). Cron: minute hour day-of-month month day-of-week.
51
64
  schedule: "0 3 * * *",
52
65
  };
53
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGVzdC1pbnRlZ3JhdGlvbi1jb25uZWN0aW9ucy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3NyYy9qb2JzL3Rlc3QtaW50ZWdyYXRpb24tY29ubmVjdGlvbnMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBZUEsZ0RBdUNDO0FBckRELHdEQUEyRDtBQUUzRCwwREFBNEU7QUFFNUU7Ozs7Ozs7OztHQVNHO0FBQ1ksS0FBSyxVQUFVLDZCQUE2QixDQUFDLFNBQTBCO0lBQ3BGLE1BQU0sTUFBTSxHQUFHLFNBQVMsQ0FBQyxPQUFPLENBQVMsUUFBUSxDQUFDLENBQUE7SUFDbEQsTUFBTSxPQUFPLEdBQTZCLFNBQVMsQ0FBQyxPQUFPLENBQUMsZ0NBQWtCLENBQUMsQ0FBQTtJQUUvRSxNQUFNLFFBQVEsR0FBRyxNQUFNLE9BQU8sQ0FBQyx3QkFBd0IsRUFBRSxDQUFBO0lBQ3pELE1BQU0sT0FBTyxHQUFHLFFBQVEsQ0FBQyxNQUFNLENBQzdCLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUMsYUFBYSxJQUFJLENBQUMsQ0FBQyxVQUFVLElBQUksQ0FBQyxDQUFDLG1CQUFtQixDQUNoRSxDQUFBO0lBRUQsSUFBSSxPQUFPLENBQUMsTUFBTSxLQUFLLENBQUMsRUFBRSxDQUFDO1FBQ3pCLE1BQU0sQ0FBQyxJQUFJLENBQUMsdUVBQXVFLENBQUMsQ0FBQTtRQUNwRixPQUFNO0lBQ1IsQ0FBQztJQUVELE1BQU0sQ0FBQyxJQUFJLENBQUMsOENBQThDLE9BQU8sQ0FBQyxNQUFNLGlCQUFpQixDQUFDLENBQUE7SUFFMUYsTUFBTSxNQUFNLEdBQUcsRUFBRSxFQUFFLEVBQUUsQ0FBQyxFQUFFLElBQUksRUFBRSxDQUFDLEVBQUUsT0FBTyxFQUFFLENBQUMsRUFBRSxPQUFPLEVBQUUsQ0FBQyxFQUFFLENBQUE7SUFFekQsS0FBSyxNQUFNLE1BQU0sSUFBSSxPQUFPLEVBQUUsQ0FBQztRQUM3QixJQUFJLENBQUM7WUFDSCxNQUFNLEVBQUUsTUFBTSxFQUFFLEdBQUcsTUFBTSxJQUFBLCtDQUFpQyxFQUFDLFNBQVMsQ0FBQyxDQUFDLEdBQUcsQ0FBQztnQkFDeEUsS0FBSyxFQUFFLEVBQUUsV0FBVyxFQUFFLE1BQU0sQ0FBQyxXQUFXLEVBQUU7YUFDM0MsQ0FBQyxDQUFBO1lBQ0YsTUFBTSxDQUFDLE1BQU0sQ0FBQyxNQUFNLENBQUMsRUFBRSxDQUFBO1lBQ3ZCLE1BQU0sSUFBSSxHQUFHLGlCQUFpQixNQUFNLENBQUMsV0FBVyxNQUFNLE1BQU0sQ0FBQyxNQUFNLEdBQ2pFLE1BQU0sQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLEtBQUssTUFBTSxDQUFDLE9BQU8sRUFBRSxDQUFDLENBQUMsQ0FBQyxFQUMzQyxFQUFFLENBQUE7WUFDRixJQUFJLE1BQU0sQ0FBQyxNQUFNLEtBQUssUUFBUTtnQkFBRSxNQUFNLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFBOztnQkFDNUMsTUFBTSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQTtRQUN4QixDQUFDO1FBQUMsT0FBTyxDQUFNLEVBQUUsQ0FBQztZQUNoQixNQUFNLENBQUMsT0FBTyxFQUFFLENBQUE7WUFDaEIsTUFBTSxDQUFDLEtBQUssQ0FBQyxpQkFBaUIsTUFBTSxDQUFDLFdBQVcsa0JBQWtCLENBQUMsRUFBRSxPQUFPLElBQUksQ0FBQyxFQUFFLENBQUMsQ0FBQTtRQUN0RixDQUFDO0lBQ0gsQ0FBQztJQUVELE1BQU0sQ0FBQyxJQUFJLENBQ1QsZ0RBQWdELE1BQU0sQ0FBQyxFQUFFLFdBQVcsTUFBTSxDQUFDLElBQUksSUFBSTtRQUNqRixZQUFZLE1BQU0sQ0FBQyxPQUFPLGNBQWMsTUFBTSxDQUFDLE9BQU8sRUFBRSxDQUMzRCxDQUFBO0FBQ0gsQ0FBQztBQUVZLFFBQUEsTUFBTSxHQUFHO0lBQ3BCLElBQUksRUFBRSxvQ0FBb0M7SUFDMUMsa0ZBQWtGO0lBQ2xGLFFBQVEsRUFBRSxXQUFXO0NBQ3RCLENBQUEifQ==
66
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGVzdC1pbnRlZ3JhdGlvbi1jb25uZWN0aW9ucy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3NyYy9qb2JzL3Rlc3QtaW50ZWdyYXRpb24tY29ubmVjdGlvbnMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBVUEsc0NBSUM7QUFHRCxrRUFLQztBQVlELGdEQW9DQztBQXJFRCx3REFBMkQ7QUFFM0QsMERBQTRFO0FBTTVFLG1HQUFtRztBQUNuRyxTQUFnQixhQUFhLENBQUMsUUFBK0I7SUFDM0QsTUFBTSxNQUFNLEdBQWtCLEVBQUUsTUFBTSxFQUFFLENBQUMsRUFBRSxNQUFNLEVBQUUsQ0FBQyxFQUFFLE9BQU8sRUFBRSxDQUFDLEVBQUUsT0FBTyxFQUFFLENBQUMsRUFBRSxDQUFBO0lBQzlFLEtBQUssTUFBTSxDQUFDLElBQUksUUFBUTtRQUFFLE1BQU0sQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFBO0lBQ3JDLE9BQU8sTUFBTSxDQUFBO0FBQ2YsQ0FBQztBQUVELDZGQUE2RjtBQUM3RixTQUFnQiwyQkFBMkIsQ0FBQyxNQUFxQjtJQUMvRCxPQUFPLENBQ0wsZ0RBQWdELE1BQU0sQ0FBQyxNQUFNLFdBQVcsTUFBTSxDQUFDLE1BQU0sSUFBSTtRQUN6RixZQUFZLE1BQU0sQ0FBQyxPQUFPLGNBQWMsTUFBTSxDQUFDLE9BQU8sRUFBRSxDQUN6RCxDQUFBO0FBQ0gsQ0FBQztBQUVEOzs7Ozs7Ozs7R0FTRztBQUNZLEtBQUssVUFBVSw2QkFBNkIsQ0FBQyxTQUEwQjtJQUNwRixNQUFNLE1BQU0sR0FBRyxTQUFTLENBQUMsT0FBTyxDQUFTLFFBQVEsQ0FBQyxDQUFBO0lBQ2xELE1BQU0sT0FBTyxHQUE2QixTQUFTLENBQUMsT0FBTyxDQUFDLGdDQUFrQixDQUFDLENBQUE7SUFFL0UsTUFBTSxRQUFRLEdBQUcsTUFBTSxPQUFPLENBQUMsd0JBQXdCLEVBQUUsQ0FBQTtJQUN6RCxNQUFNLE9BQU8sR0FBRyxRQUFRLENBQUMsTUFBTSxDQUM3QixDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDLGFBQWEsSUFBSSxDQUFDLENBQUMsVUFBVSxJQUFJLENBQUMsQ0FBQyxtQkFBbUIsQ0FDaEUsQ0FBQTtJQUVELElBQUksT0FBTyxDQUFDLE1BQU0sS0FBSyxDQUFDLEVBQUUsQ0FBQztRQUN6QixNQUFNLENBQUMsSUFBSSxDQUFDLHVFQUF1RSxDQUFDLENBQUE7UUFDcEYsT0FBTTtJQUNSLENBQUM7SUFFRCxNQUFNLENBQUMsSUFBSSxDQUFDLDhDQUE4QyxPQUFPLENBQUMsTUFBTSxpQkFBaUIsQ0FBQyxDQUFBO0lBRTFGLE1BQU0sUUFBUSxHQUFrQixFQUFFLENBQUE7SUFFbEMsS0FBSyxNQUFNLE1BQU0sSUFBSSxPQUFPLEVBQUUsQ0FBQztRQUM3QixJQUFJLENBQUM7WUFDSCxNQUFNLEVBQUUsTUFBTSxFQUFFLEdBQUcsTUFBTSxJQUFBLCtDQUFpQyxFQUFDLFNBQVMsQ0FBQyxDQUFDLEdBQUcsQ0FBQztnQkFDeEUsS0FBSyxFQUFFLEVBQUUsV0FBVyxFQUFFLE1BQU0sQ0FBQyxXQUFXLEVBQUU7YUFDM0MsQ0FBQyxDQUFBO1lBQ0YsUUFBUSxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsTUFBTSxDQUFDLENBQUE7WUFDNUIsTUFBTSxJQUFJLEdBQUcsaUJBQWlCLE1BQU0sQ0FBQyxXQUFXLE1BQU0sTUFBTSxDQUFDLE1BQU0sR0FDakUsTUFBTSxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsS0FBSyxNQUFNLENBQUMsT0FBTyxFQUFFLENBQUMsQ0FBQyxDQUFDLEVBQzNDLEVBQUUsQ0FBQTtZQUNGLElBQUksTUFBTSxDQUFDLE1BQU0sS0FBSyxRQUFRO2dCQUFFLE1BQU0sQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUE7O2dCQUM1QyxNQUFNLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFBO1FBQ3hCLENBQUM7UUFBQyxPQUFPLENBQU0sRUFBRSxDQUFDO1lBQ2hCLFFBQVEsQ0FBQyxJQUFJLENBQUMsU0FBUyxDQUFDLENBQUE7WUFDeEIsTUFBTSxDQUFDLEtBQUssQ0FBQyxpQkFBaUIsTUFBTSxDQUFDLFdBQVcsa0JBQWtCLENBQUMsRUFBRSxPQUFPLElBQUksQ0FBQyxFQUFFLENBQUMsQ0FBQTtRQUN0RixDQUFDO0lBQ0gsQ0FBQztJQUVELE1BQU0sQ0FBQyxJQUFJLENBQUMsMkJBQTJCLENBQUMsYUFBYSxDQUFDLFFBQVEsQ0FBQyxDQUFDLENBQUMsQ0FBQTtBQUNuRSxDQUFDO0FBRVksUUFBQSxNQUFNLEdBQUc7SUFDcEIsSUFBSSxFQUFFLG9DQUFvQztJQUMxQyxrRkFBa0Y7SUFDbEYsUUFBUSxFQUFFLFdBQVc7Q0FDdEIsQ0FBQSJ9