@gorgo/medusa-integration 0.1.3 → 0.1.5

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 (29) hide show
  1. package/.medusa/server/src/admin/index.js +218 -39
  2. package/.medusa/server/src/admin/index.mjs +219 -40
  3. package/.medusa/server/src/lib/__tests__/catalog-fallback.unit.spec.js +10 -5
  4. package/.medusa/server/src/lib/__tests__/catalog.unit.spec.js +64 -1
  5. package/.medusa/server/src/lib/catalog.generated.js +37 -21
  6. package/.medusa/server/src/lib/catalog.js +46 -2
  7. package/.medusa/server/src/lib/markdown/__tests__/inline.unit.spec.d.ts +1 -0
  8. package/.medusa/server/src/lib/markdown/__tests__/inline.unit.spec.js +90 -0
  9. package/.medusa/server/src/lib/markdown/__tests__/no-raw-html.unit.spec.d.ts +1 -0
  10. package/.medusa/server/src/lib/markdown/__tests__/no-raw-html.unit.spec.js +20 -0
  11. package/.medusa/server/src/lib/markdown/__tests__/parse.unit.spec.d.ts +1 -0
  12. package/.medusa/server/src/lib/markdown/__tests__/parse.unit.spec.js +91 -0
  13. package/.medusa/server/src/lib/markdown/href.d.ts +9 -0
  14. package/.medusa/server/src/lib/markdown/href.js +20 -0
  15. package/.medusa/server/src/lib/markdown/inline.d.ts +2 -0
  16. package/.medusa/server/src/lib/markdown/inline.js +51 -0
  17. package/.medusa/server/src/lib/markdown/parse.d.ts +12 -0
  18. package/.medusa/server/src/lib/markdown/parse.js +97 -0
  19. package/.medusa/server/src/lib/markdown/types.d.ts +39 -0
  20. package/.medusa/server/src/lib/markdown/types.js +3 -0
  21. package/.medusa/server/src/modules/integration/descriptor/__tests__/build-zod.unit.spec.js +30 -1
  22. package/.medusa/server/src/modules/integration/descriptor/__tests__/define.unit.spec.js +34 -1
  23. package/.medusa/server/src/modules/integration/descriptor/build-zod.js +11 -3
  24. package/.medusa/server/src/modules/integration/descriptor/define.js +13 -1
  25. package/.medusa/server/src/modules/integration/descriptor/option.d.ts +2 -2
  26. package/.medusa/server/src/types/http/integration/admin/entities.d.ts +11 -3
  27. package/.medusa/server/src/types/integration/common.d.ts +1 -1
  28. package/README.md +5 -5
  29. package/package.json +3 -2
@@ -1957,15 +1957,25 @@ function renderControl(field, f, secretConfigured, t) {
1957
1957
  switch (field.control) {
1958
1958
  case "switch":
1959
1959
  return /* @__PURE__ */ jsxRuntime.jsx(ui.Switch, { checked: !!f.value, onCheckedChange: f.onChange, disabled });
1960
- case "select":
1961
- return /* @__PURE__ */ jsxRuntime.jsxs(ui.Select, { value: f.value ?? "", onValueChange: f.onChange, disabled, children: [
1962
- /* @__PURE__ */ jsxRuntime.jsx(ui.Select.Trigger, { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Select.Value, { placeholder }) }),
1963
- /* @__PURE__ */ jsxRuntime.jsx(ui.Select.Content, { children: (field.options ?? []).map((o) => {
1964
- var _a;
1965
- const labelKey = (_a = field.optionLabels) == null ? void 0 : _a[o];
1966
- return /* @__PURE__ */ jsxRuntime.jsx(ui.Select.Item, { value: o, children: labelKey ? t(labelKey) : o }, o);
1967
- }) })
1968
- ] });
1960
+ case "select": {
1961
+ const declared = field.options ?? [];
1962
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1963
+ ui.Select,
1964
+ {
1965
+ value: f.value == null ? "" : String(f.value),
1966
+ onValueChange: (next) => f.onChange(declared.find((o) => String(o) === next) ?? next),
1967
+ disabled,
1968
+ children: [
1969
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Select.Trigger, { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Select.Value, { placeholder }) }),
1970
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Select.Content, { children: declared.map((o) => {
1971
+ var _a;
1972
+ const labelKey = (_a = field.optionLabels) == null ? void 0 : _a[String(o)];
1973
+ return /* @__PURE__ */ jsxRuntime.jsx(ui.Select.Item, { value: String(o), children: labelKey ? t(labelKey) : String(o) }, String(o));
1974
+ }) })
1975
+ ]
1976
+ }
1977
+ );
1978
+ }
1969
1979
  case "number":
1970
1980
  return /* @__PURE__ */ jsxRuntime.jsx(
1971
1981
  ui.Input,
@@ -2300,38 +2310,205 @@ const IntegrationBreadcrumb = ({ params }) => {
2300
2310
  const handle$1 = {
2301
2311
  breadcrumb: ({ params }) => /* @__PURE__ */ jsxRuntime.jsx(IntegrationBreadcrumb, { params })
2302
2312
  };
2313
+ function isSafeHref(raw) {
2314
+ try {
2315
+ return new URL(raw).protocol === "https:";
2316
+ } catch {
2317
+ return false;
2318
+ }
2319
+ }
2320
+ const INLINE_RE = /`([^`\n]+)`|\[([^\]\n]*)\]\(([^)\s]+)\)|\*\*([^*\n]+)\*\*|\*([^*\n]+)\*|_([^_\n]+)_/;
2321
+ const MAX_DEPTH = 3;
2322
+ function parseInline(src, depth = 0) {
2323
+ if (!src) return [];
2324
+ if (depth >= MAX_DEPTH) return [{ type: "text", value: src }];
2325
+ const out = [];
2326
+ const re = new RegExp(INLINE_RE, "g");
2327
+ let last = 0;
2328
+ let m;
2329
+ while ((m = re.exec(src)) !== null) {
2330
+ const [full, code, linkText, linkHref, strong, star, underscore] = m;
2331
+ if (m.index > last) out.push({ type: "text", value: src.slice(last, m.index) });
2332
+ last = m.index + full.length;
2333
+ if (code !== void 0) {
2334
+ out.push({ type: "code", value: code });
2335
+ } else if (linkHref !== void 0) {
2336
+ const isImage = m.index > 0 && src[m.index - 1] === "!";
2337
+ if (!isImage && isSafeHref(linkHref)) {
2338
+ out.push({ type: "link", href: linkHref, children: parseInline(linkText, depth + 1) });
2339
+ } else {
2340
+ out.push({ type: "text", value: full });
2341
+ }
2342
+ } else if (strong !== void 0) {
2343
+ out.push({ type: "strong", children: parseInline(strong, depth + 1) });
2344
+ } else {
2345
+ out.push({ type: "em", children: parseInline(star ?? underscore, depth + 1) });
2346
+ }
2347
+ }
2348
+ if (last < src.length) out.push({ type: "text", value: src.slice(last) });
2349
+ return out;
2350
+ }
2351
+ const MD_MAX_CHARS = 8e3;
2352
+ const MD_MAX_BLOCKS = 200;
2353
+ const FENCE_RE = /^```(.*)$/;
2354
+ const HEADING_RE = /^(#{1,3})\s+(.*)$/;
2355
+ const HR_RE = /^-{3,}\s*$/;
2356
+ const UL_RE = /^[-*]\s+(.*)$/;
2357
+ const OL_RE = /^\d+\.\s+(.*)$/;
2358
+ function fenceLabel(info) {
2359
+ const first = info.trim().split(/\s+/)[0] ?? "";
2360
+ return first.replace(/[^a-zA-Z0-9._/-]/g, "").slice(0, 40) || null;
2361
+ }
2362
+ function parseMarkdown(src) {
2363
+ if (typeof src !== "string" || !src) return [];
2364
+ if (src.length > MD_MAX_CHARS) return [{ type: "truncated" }];
2365
+ const lines = src.replace(/\r\n?/g, "\n").split("\n");
2366
+ const blocks = [];
2367
+ let para = [];
2368
+ const flushPara = () => {
2369
+ if (!para.length) return;
2370
+ blocks.push({ type: "paragraph", children: parseInline(para.join(" ")) });
2371
+ para = [];
2372
+ };
2373
+ for (let i = 0; i < lines.length; i++) {
2374
+ const line = lines[i];
2375
+ const fence = FENCE_RE.exec(line);
2376
+ if (fence) {
2377
+ flushPara();
2378
+ const body = [];
2379
+ i++;
2380
+ while (i < lines.length && !FENCE_RE.test(lines[i])) body.push(lines[i++]);
2381
+ blocks.push({ type: "codeBlock", label: fenceLabel(fence[1]), value: body.join("\n") });
2382
+ continue;
2383
+ }
2384
+ if (!line.trim()) {
2385
+ flushPara();
2386
+ continue;
2387
+ }
2388
+ if (HR_RE.test(line)) {
2389
+ flushPara();
2390
+ blocks.push({ type: "hr" });
2391
+ continue;
2392
+ }
2393
+ const heading = HEADING_RE.exec(line);
2394
+ if (heading) {
2395
+ flushPara();
2396
+ blocks.push({
2397
+ type: "heading",
2398
+ level: heading[1].length + 1,
2399
+ children: parseInline(heading[2])
2400
+ });
2401
+ continue;
2402
+ }
2403
+ const ul = UL_RE.exec(line);
2404
+ const ol = ul ? null : OL_RE.exec(line);
2405
+ if (ul || ol) {
2406
+ flushPara();
2407
+ const ordered = !!ol;
2408
+ const itemRe = ordered ? OL_RE : UL_RE;
2409
+ const items = [];
2410
+ while (i < lines.length) {
2411
+ const item = itemRe.exec(lines[i]);
2412
+ if (!item) break;
2413
+ items.push(parseInline(item[1]));
2414
+ i++;
2415
+ }
2416
+ i--;
2417
+ blocks.push({ type: "list", ordered, items });
2418
+ continue;
2419
+ }
2420
+ para.push(line);
2421
+ }
2422
+ flushPara();
2423
+ const weight = blocks.reduce((n, b) => n + (b.type === "list" ? b.items.length : 1), 0);
2424
+ return weight > MD_MAX_BLOCKS ? [{ type: "truncated" }] : blocks;
2425
+ }
2426
+ const Inline = ({ nodes }) => /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: nodes.map((node, i) => {
2427
+ switch (node.type) {
2428
+ case "text":
2429
+ return /* @__PURE__ */ jsxRuntime.jsx("span", { children: node.value }, i);
2430
+ case "code":
2431
+ return /* @__PURE__ */ jsxRuntime.jsx("code", { className: "txt-compact-small bg-ui-bg-component rounded px-1 py-0.5", children: node.value }, i);
2432
+ case "strong":
2433
+ return /* @__PURE__ */ jsxRuntime.jsx("span", { className: "txt-compact-small-plus", children: /* @__PURE__ */ jsxRuntime.jsx(Inline, { nodes: node.children }) }, i);
2434
+ case "em":
2435
+ return /* @__PURE__ */ jsxRuntime.jsx("em", { children: /* @__PURE__ */ jsxRuntime.jsx(Inline, { nodes: node.children }) }, i);
2436
+ case "link":
2437
+ return /* @__PURE__ */ jsxRuntime.jsx(
2438
+ "a",
2439
+ {
2440
+ href: node.href,
2441
+ target: "_blank",
2442
+ rel: "noopener noreferrer",
2443
+ className: "text-ui-fg-interactive hover:underline",
2444
+ children: /* @__PURE__ */ jsxRuntime.jsx(Inline, { nodes: node.children })
2445
+ },
2446
+ i
2447
+ );
2448
+ }
2449
+ }) });
2450
+ const Block = ({ block, truncatedLabel }) => {
2451
+ switch (block.type) {
2452
+ case "heading":
2453
+ return /* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { level: block.level === 2 ? "h2" : "h3", children: /* @__PURE__ */ jsxRuntime.jsx(Inline, { nodes: block.children }) });
2454
+ case "paragraph":
2455
+ return /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "text-ui-fg-subtle", children: /* @__PURE__ */ jsxRuntime.jsx(Inline, { nodes: block.children }) });
2456
+ case "list": {
2457
+ const List = block.ordered ? "ol" : "ul";
2458
+ return /* @__PURE__ */ jsxRuntime.jsx(
2459
+ List,
2460
+ {
2461
+ className: `text-ui-fg-subtle txt-small flex flex-col gap-y-1 pl-5 ${block.ordered ? "list-decimal" : "list-disc"}`,
2462
+ children: block.items.map((item, i) => /* @__PURE__ */ jsxRuntime.jsx("li", { children: /* @__PURE__ */ jsxRuntime.jsx(Inline, { nodes: item }) }, i))
2463
+ }
2464
+ );
2465
+ }
2466
+ case "codeBlock":
2467
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bg-ui-bg-subtle flex flex-col gap-y-2 rounded-md px-3 pb-1 pt-2", children: [
2468
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between gap-x-2", children: [
2469
+ block.label ? /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "xsmall", weight: "plus", className: "text-ui-fg-subtle", children: block.label }) : /* @__PURE__ */ jsxRuntime.jsx("span", {}),
2470
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Copy, { content: block.value })
2471
+ ] }),
2472
+ /* @__PURE__ */ jsxRuntime.jsx("pre", { className: "txt-compact-small text-ui-fg-subtle overflow-x-auto whitespace-pre pb-2", children: block.value })
2473
+ ] });
2474
+ case "hr":
2475
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "border-ui-border-base border-t" });
2476
+ case "truncated":
2477
+ return /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "text-ui-fg-muted", children: truncatedLabel });
2478
+ }
2479
+ };
2480
+ const Markdown = ({
2481
+ source,
2482
+ truncatedLabel
2483
+ }) => {
2484
+ const blocks = React.useMemo(() => parseMarkdown(source), [source]);
2485
+ if (!blocks.length) return null;
2486
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-col gap-y-4", children: blocks.map((block, i) => /* @__PURE__ */ jsxRuntime.jsx(Block, { block, truncatedLabel }, i)) });
2487
+ };
2303
2488
  const PUBLISH_URL = "https://docs.gorgojs.com/medusa-modules/integration";
2304
2489
  const API_URL = "https://gorgojs.com";
2305
- const InstallModal = ({ item, onOpenChange }) => {
2306
- const { t } = reactI18next.useTranslation();
2490
+ const iconSrc = (icon) => icon.startsWith("data:") ? icon : API_URL + icon;
2491
+ const InstallModal = ({
2492
+ item,
2493
+ onOpenChange
2494
+ }) => {
2495
+ var _a, _b, _c;
2496
+ const { t, i18n } = reactI18next.useTranslation();
2497
+ const lang = i18n.language.split("-")[0] === "ru" ? "ru" : "en";
2498
+ const source = ((_a = item == null ? void 0 : item.docsSnippet) == null ? void 0 : _a[lang]) || ((_b = item == null ? void 0 : item.docsSnippet) == null ? void 0 : _b.en) || ((_c = item == null ? void 0 : item.docsSnippet) == null ? void 0 : _c.ru) || "";
2307
2499
  return /* @__PURE__ */ jsxRuntime.jsx(ui.Drawer, { open: !!item, onOpenChange, children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Drawer.Content, { children: [
2308
2500
  /* @__PURE__ */ jsxRuntime.jsx(ui.Drawer.Header, { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Drawer.Title, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-x-2", children: [
2309
- item && /* @__PURE__ */ jsxRuntime.jsx(IntegrationIcon, { src: API_URL + item.icon, alt: item.label, size: "small" }),
2501
+ item && /* @__PURE__ */ jsxRuntime.jsx(IntegrationIcon, { src: iconSrc(item.icon), alt: item.label, size: "small" }),
2310
2502
  /* @__PURE__ */ jsxRuntime.jsx("span", { children: item == null ? void 0 : item.label })
2311
2503
  ] }) }) }),
2312
- /* @__PURE__ */ jsxRuntime.jsx(ui.Drawer.Body, { className: "flex flex-1 flex-col gap-y-4 overflow-auto", children: item && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
2313
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "text-ui-fg-subtle", children: t("integration.browse.install_addToConfig") }),
2314
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bg-ui-bg-subtle flex items-center justify-between gap-x-2 rounded-md px-3 py-2", children: [
2315
- /* @__PURE__ */ jsxRuntime.jsx("code", { className: "txt-compact-small text-ui-fg-subtle", children: `yarn add @gorgo/medusa-integration ${item.npm}@beta` }),
2316
- /* @__PURE__ */ jsxRuntime.jsx(ui.Copy, { content: `yarn add @gorgo/medusa-integration ${item.npm}@beta` })
2317
- ] }),
2318
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bg-ui-bg-subtle flex items-center justify-between gap-x-2 rounded-md px-3 py-2", children: [
2319
- /* @__PURE__ */ jsxRuntime.jsx("code", { className: "txt-compact-small text-ui-fg-subtle", children: `npm install @gorgo/medusa-integration ${item.npm}@beta` }),
2320
- /* @__PURE__ */ jsxRuntime.jsx(ui.Copy, { content: `npm install @gorgo/medusa-integration ${item.npm}@beta` })
2321
- ] }),
2322
- item.configSnippet && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bg-ui-bg-subtle flex flex-col gap-y-2 rounded-md px-3 py-2", children: [
2323
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between gap-x-2", children: [
2324
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "xsmall", weight: "plus", className: "text-ui-fg-subtle", children: "medusa-config.ts" }),
2325
- /* @__PURE__ */ jsxRuntime.jsx(ui.Copy, { content: item.configSnippet })
2326
- ] }),
2327
- /* @__PURE__ */ jsxRuntime.jsx("pre", { className: "txt-compact-small text-ui-fg-subtle overflow-x-auto whitespace-pre", children: item.configSnippet })
2328
- ] }),
2329
- /* @__PURE__ */ jsxRuntime.jsxs("a", { href: item.docsUrl, target: "_blank", rel: "noreferrer", className: "text-ui-fg-base txt-small", children: [
2504
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Drawer.Body, { className: "flex flex-1 flex-col gap-y-4 overflow-auto", children: source.trim() ? /* @__PURE__ */ jsxRuntime.jsx(Markdown, { source, truncatedLabel: t("integration.browse.install_truncated") }) : /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "text-ui-fg-subtle", children: t("integration.browse.install_empty") }) }),
2505
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.Drawer.Footer, { children: [
2506
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Drawer.Close, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { size: "small", variant: "secondary", children: t("integration.actions.cancel") }) }),
2507
+ (item == null ? void 0 : item.docsUrl) && /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { size: "small", variant: "primary", asChild: true, children: /* @__PURE__ */ jsxRuntime.jsxs("a", { href: item.docsUrl, target: "_blank", rel: "noopener noreferrer", children: [
2330
2508
  t("integration.browse.install_docs"),
2331
- " →"
2332
- ] })
2333
- ] }) }),
2334
- /* @__PURE__ */ jsxRuntime.jsx(ui.Drawer.Footer, { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Drawer.Close, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { size: "small", variant: "secondary", children: t("integration.actions.cancel") }) }) })
2509
+ /* @__PURE__ */ jsxRuntime.jsx(icons.ArrowUpRightOnBox, {})
2510
+ ] }) })
2511
+ ] })
2335
2512
  ] }) });
2336
2513
  };
2337
2514
  const BrowsePage = () => {
@@ -2380,7 +2557,7 @@ const BrowsePage = () => {
2380
2557
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-1 flex-col gap-y-3 p-4", children: [
2381
2558
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start justify-between gap-x-2", children: [
2382
2559
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-x-3", children: [
2383
- /* @__PURE__ */ jsxRuntime.jsx(IntegrationIcon, { src: API_URL + item.icon, alt: item.label }),
2560
+ /* @__PURE__ */ jsxRuntime.jsx(IntegrationIcon, { src: iconSrc(item.icon), alt: item.label }),
2384
2561
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col", children: [
2385
2562
  /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", weight: "plus", leading: "compact", children: item.label }),
2386
2563
  /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "xsmall", leading: "compact", className: "text-ui-fg-subtle", children: t("integration.browse.by", { author: item.authorLocalized }) })
@@ -2446,8 +2623,9 @@ const integration$1 = {
2446
2623
  notInstalled: "Not installed",
2447
2624
  add: "Add",
2448
2625
  settings: "Settings",
2449
- install_addToConfig: "Add this to your medusa-config.ts and restart the server.",
2450
- install_docs: "Documentation"
2626
+ install_docs: "Read docs",
2627
+ install_empty: "Setup instructions for this integration aren't available yet.",
2628
+ install_truncated: "These instructions are too long to show here — open the documentation."
2451
2629
  },
2452
2630
  columns: {
2453
2631
  integration: "Integration",
@@ -2549,8 +2727,9 @@ const integration = {
2549
2727
  notInstalled: "Не установлено",
2550
2728
  add: "Добавить",
2551
2729
  settings: "Настройки",
2552
- install_addToConfig: "Добавьте это в medusa-config.ts и перезапустите сервер.",
2553
- install_docs: "Документация"
2730
+ install_docs: "Читать документацию",
2731
+ install_empty: "Инструкция по настройке для этой интеграции пока недоступна.",
2732
+ install_truncated: "Инструкция слишком длинная для показа здесь — откройте документацию."
2554
2733
  },
2555
2734
  columns: {
2556
2735
  integration: "Интеграция",
@@ -1,6 +1,6 @@
1
1
  import { jsx, Fragment, jsxs } from "react/jsx-runtime";
2
2
  import { defineRouteConfig } from "@medusajs/admin-sdk";
3
- import { PuzzleSolid, CogSixTooth, Trash, Spinner, EllipsisHorizontal, PencilSquare, Plus } from "@medusajs/icons";
3
+ import { PuzzleSolid, CogSixTooth, Trash, Spinner, EllipsisHorizontal, PencilSquare, Plus, ArrowUpRightOnBox } from "@medusajs/icons";
4
4
  import { clx, createDataTableColumnHelper, usePrompt, toast, Text, Badge, useDataTable, Container, Heading, Button, DataTable, Tabs, StatusBadge, Label, Input, Select, Switch, Textarea, Drawer, DropdownMenu, IconButton, Copy } from "@medusajs/ui";
5
5
  import { useQueryClient, useQuery, keepPreviousData, useMutation } from "@tanstack/react-query";
6
6
  import React, { useState, useMemo } from "react";
@@ -1953,15 +1953,25 @@ function renderControl(field, f, secretConfigured, t) {
1953
1953
  switch (field.control) {
1954
1954
  case "switch":
1955
1955
  return /* @__PURE__ */ jsx(Switch, { checked: !!f.value, onCheckedChange: f.onChange, disabled });
1956
- case "select":
1957
- return /* @__PURE__ */ jsxs(Select, { value: f.value ?? "", onValueChange: f.onChange, disabled, children: [
1958
- /* @__PURE__ */ jsx(Select.Trigger, { children: /* @__PURE__ */ jsx(Select.Value, { placeholder }) }),
1959
- /* @__PURE__ */ jsx(Select.Content, { children: (field.options ?? []).map((o) => {
1960
- var _a;
1961
- const labelKey = (_a = field.optionLabels) == null ? void 0 : _a[o];
1962
- return /* @__PURE__ */ jsx(Select.Item, { value: o, children: labelKey ? t(labelKey) : o }, o);
1963
- }) })
1964
- ] });
1956
+ case "select": {
1957
+ const declared = field.options ?? [];
1958
+ return /* @__PURE__ */ jsxs(
1959
+ Select,
1960
+ {
1961
+ value: f.value == null ? "" : String(f.value),
1962
+ onValueChange: (next) => f.onChange(declared.find((o) => String(o) === next) ?? next),
1963
+ disabled,
1964
+ children: [
1965
+ /* @__PURE__ */ jsx(Select.Trigger, { children: /* @__PURE__ */ jsx(Select.Value, { placeholder }) }),
1966
+ /* @__PURE__ */ jsx(Select.Content, { children: declared.map((o) => {
1967
+ var _a;
1968
+ const labelKey = (_a = field.optionLabels) == null ? void 0 : _a[String(o)];
1969
+ return /* @__PURE__ */ jsx(Select.Item, { value: String(o), children: labelKey ? t(labelKey) : String(o) }, String(o));
1970
+ }) })
1971
+ ]
1972
+ }
1973
+ );
1974
+ }
1965
1975
  case "number":
1966
1976
  return /* @__PURE__ */ jsx(
1967
1977
  Input,
@@ -2296,38 +2306,205 @@ const IntegrationBreadcrumb = ({ params }) => {
2296
2306
  const handle$1 = {
2297
2307
  breadcrumb: ({ params }) => /* @__PURE__ */ jsx(IntegrationBreadcrumb, { params })
2298
2308
  };
2309
+ function isSafeHref(raw) {
2310
+ try {
2311
+ return new URL(raw).protocol === "https:";
2312
+ } catch {
2313
+ return false;
2314
+ }
2315
+ }
2316
+ const INLINE_RE = /`([^`\n]+)`|\[([^\]\n]*)\]\(([^)\s]+)\)|\*\*([^*\n]+)\*\*|\*([^*\n]+)\*|_([^_\n]+)_/;
2317
+ const MAX_DEPTH = 3;
2318
+ function parseInline(src, depth = 0) {
2319
+ if (!src) return [];
2320
+ if (depth >= MAX_DEPTH) return [{ type: "text", value: src }];
2321
+ const out = [];
2322
+ const re = new RegExp(INLINE_RE, "g");
2323
+ let last = 0;
2324
+ let m;
2325
+ while ((m = re.exec(src)) !== null) {
2326
+ const [full, code, linkText, linkHref, strong, star, underscore] = m;
2327
+ if (m.index > last) out.push({ type: "text", value: src.slice(last, m.index) });
2328
+ last = m.index + full.length;
2329
+ if (code !== void 0) {
2330
+ out.push({ type: "code", value: code });
2331
+ } else if (linkHref !== void 0) {
2332
+ const isImage = m.index > 0 && src[m.index - 1] === "!";
2333
+ if (!isImage && isSafeHref(linkHref)) {
2334
+ out.push({ type: "link", href: linkHref, children: parseInline(linkText, depth + 1) });
2335
+ } else {
2336
+ out.push({ type: "text", value: full });
2337
+ }
2338
+ } else if (strong !== void 0) {
2339
+ out.push({ type: "strong", children: parseInline(strong, depth + 1) });
2340
+ } else {
2341
+ out.push({ type: "em", children: parseInline(star ?? underscore, depth + 1) });
2342
+ }
2343
+ }
2344
+ if (last < src.length) out.push({ type: "text", value: src.slice(last) });
2345
+ return out;
2346
+ }
2347
+ const MD_MAX_CHARS = 8e3;
2348
+ const MD_MAX_BLOCKS = 200;
2349
+ const FENCE_RE = /^```(.*)$/;
2350
+ const HEADING_RE = /^(#{1,3})\s+(.*)$/;
2351
+ const HR_RE = /^-{3,}\s*$/;
2352
+ const UL_RE = /^[-*]\s+(.*)$/;
2353
+ const OL_RE = /^\d+\.\s+(.*)$/;
2354
+ function fenceLabel(info) {
2355
+ const first = info.trim().split(/\s+/)[0] ?? "";
2356
+ return first.replace(/[^a-zA-Z0-9._/-]/g, "").slice(0, 40) || null;
2357
+ }
2358
+ function parseMarkdown(src) {
2359
+ if (typeof src !== "string" || !src) return [];
2360
+ if (src.length > MD_MAX_CHARS) return [{ type: "truncated" }];
2361
+ const lines = src.replace(/\r\n?/g, "\n").split("\n");
2362
+ const blocks = [];
2363
+ let para = [];
2364
+ const flushPara = () => {
2365
+ if (!para.length) return;
2366
+ blocks.push({ type: "paragraph", children: parseInline(para.join(" ")) });
2367
+ para = [];
2368
+ };
2369
+ for (let i = 0; i < lines.length; i++) {
2370
+ const line = lines[i];
2371
+ const fence = FENCE_RE.exec(line);
2372
+ if (fence) {
2373
+ flushPara();
2374
+ const body = [];
2375
+ i++;
2376
+ while (i < lines.length && !FENCE_RE.test(lines[i])) body.push(lines[i++]);
2377
+ blocks.push({ type: "codeBlock", label: fenceLabel(fence[1]), value: body.join("\n") });
2378
+ continue;
2379
+ }
2380
+ if (!line.trim()) {
2381
+ flushPara();
2382
+ continue;
2383
+ }
2384
+ if (HR_RE.test(line)) {
2385
+ flushPara();
2386
+ blocks.push({ type: "hr" });
2387
+ continue;
2388
+ }
2389
+ const heading = HEADING_RE.exec(line);
2390
+ if (heading) {
2391
+ flushPara();
2392
+ blocks.push({
2393
+ type: "heading",
2394
+ level: heading[1].length + 1,
2395
+ children: parseInline(heading[2])
2396
+ });
2397
+ continue;
2398
+ }
2399
+ const ul = UL_RE.exec(line);
2400
+ const ol = ul ? null : OL_RE.exec(line);
2401
+ if (ul || ol) {
2402
+ flushPara();
2403
+ const ordered = !!ol;
2404
+ const itemRe = ordered ? OL_RE : UL_RE;
2405
+ const items = [];
2406
+ while (i < lines.length) {
2407
+ const item = itemRe.exec(lines[i]);
2408
+ if (!item) break;
2409
+ items.push(parseInline(item[1]));
2410
+ i++;
2411
+ }
2412
+ i--;
2413
+ blocks.push({ type: "list", ordered, items });
2414
+ continue;
2415
+ }
2416
+ para.push(line);
2417
+ }
2418
+ flushPara();
2419
+ const weight = blocks.reduce((n, b) => n + (b.type === "list" ? b.items.length : 1), 0);
2420
+ return weight > MD_MAX_BLOCKS ? [{ type: "truncated" }] : blocks;
2421
+ }
2422
+ const Inline = ({ nodes }) => /* @__PURE__ */ jsx(Fragment, { children: nodes.map((node, i) => {
2423
+ switch (node.type) {
2424
+ case "text":
2425
+ return /* @__PURE__ */ jsx("span", { children: node.value }, i);
2426
+ case "code":
2427
+ return /* @__PURE__ */ jsx("code", { className: "txt-compact-small bg-ui-bg-component rounded px-1 py-0.5", children: node.value }, i);
2428
+ case "strong":
2429
+ return /* @__PURE__ */ jsx("span", { className: "txt-compact-small-plus", children: /* @__PURE__ */ jsx(Inline, { nodes: node.children }) }, i);
2430
+ case "em":
2431
+ return /* @__PURE__ */ jsx("em", { children: /* @__PURE__ */ jsx(Inline, { nodes: node.children }) }, i);
2432
+ case "link":
2433
+ return /* @__PURE__ */ jsx(
2434
+ "a",
2435
+ {
2436
+ href: node.href,
2437
+ target: "_blank",
2438
+ rel: "noopener noreferrer",
2439
+ className: "text-ui-fg-interactive hover:underline",
2440
+ children: /* @__PURE__ */ jsx(Inline, { nodes: node.children })
2441
+ },
2442
+ i
2443
+ );
2444
+ }
2445
+ }) });
2446
+ const Block = ({ block, truncatedLabel }) => {
2447
+ switch (block.type) {
2448
+ case "heading":
2449
+ return /* @__PURE__ */ jsx(Heading, { level: block.level === 2 ? "h2" : "h3", children: /* @__PURE__ */ jsx(Inline, { nodes: block.children }) });
2450
+ case "paragraph":
2451
+ return /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: /* @__PURE__ */ jsx(Inline, { nodes: block.children }) });
2452
+ case "list": {
2453
+ const List = block.ordered ? "ol" : "ul";
2454
+ return /* @__PURE__ */ jsx(
2455
+ List,
2456
+ {
2457
+ className: `text-ui-fg-subtle txt-small flex flex-col gap-y-1 pl-5 ${block.ordered ? "list-decimal" : "list-disc"}`,
2458
+ children: block.items.map((item, i) => /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx(Inline, { nodes: item }) }, i))
2459
+ }
2460
+ );
2461
+ }
2462
+ case "codeBlock":
2463
+ return /* @__PURE__ */ jsxs("div", { className: "bg-ui-bg-subtle flex flex-col gap-y-2 rounded-md px-3 pb-1 pt-2", children: [
2464
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-x-2", children: [
2465
+ block.label ? /* @__PURE__ */ jsx(Text, { size: "xsmall", weight: "plus", className: "text-ui-fg-subtle", children: block.label }) : /* @__PURE__ */ jsx("span", {}),
2466
+ /* @__PURE__ */ jsx(Copy, { content: block.value })
2467
+ ] }),
2468
+ /* @__PURE__ */ jsx("pre", { className: "txt-compact-small text-ui-fg-subtle overflow-x-auto whitespace-pre pb-2", children: block.value })
2469
+ ] });
2470
+ case "hr":
2471
+ return /* @__PURE__ */ jsx("div", { className: "border-ui-border-base border-t" });
2472
+ case "truncated":
2473
+ return /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: truncatedLabel });
2474
+ }
2475
+ };
2476
+ const Markdown = ({
2477
+ source,
2478
+ truncatedLabel
2479
+ }) => {
2480
+ const blocks = useMemo(() => parseMarkdown(source), [source]);
2481
+ if (!blocks.length) return null;
2482
+ return /* @__PURE__ */ jsx("div", { className: "flex flex-col gap-y-4", children: blocks.map((block, i) => /* @__PURE__ */ jsx(Block, { block, truncatedLabel }, i)) });
2483
+ };
2299
2484
  const PUBLISH_URL = "https://docs.gorgojs.com/medusa-modules/integration";
2300
2485
  const API_URL = "https://gorgojs.com";
2301
- const InstallModal = ({ item, onOpenChange }) => {
2302
- const { t } = useTranslation();
2486
+ const iconSrc = (icon) => icon.startsWith("data:") ? icon : API_URL + icon;
2487
+ const InstallModal = ({
2488
+ item,
2489
+ onOpenChange
2490
+ }) => {
2491
+ var _a, _b, _c;
2492
+ const { t, i18n } = useTranslation();
2493
+ const lang = i18n.language.split("-")[0] === "ru" ? "ru" : "en";
2494
+ const source = ((_a = item == null ? void 0 : item.docsSnippet) == null ? void 0 : _a[lang]) || ((_b = item == null ? void 0 : item.docsSnippet) == null ? void 0 : _b.en) || ((_c = item == null ? void 0 : item.docsSnippet) == null ? void 0 : _c.ru) || "";
2303
2495
  return /* @__PURE__ */ jsx(Drawer, { open: !!item, onOpenChange, children: /* @__PURE__ */ jsxs(Drawer.Content, { children: [
2304
2496
  /* @__PURE__ */ jsx(Drawer.Header, { children: /* @__PURE__ */ jsx(Drawer.Title, { asChild: true, children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-x-2", children: [
2305
- item && /* @__PURE__ */ jsx(IntegrationIcon, { src: API_URL + item.icon, alt: item.label, size: "small" }),
2497
+ item && /* @__PURE__ */ jsx(IntegrationIcon, { src: iconSrc(item.icon), alt: item.label, size: "small" }),
2306
2498
  /* @__PURE__ */ jsx("span", { children: item == null ? void 0 : item.label })
2307
2499
  ] }) }) }),
2308
- /* @__PURE__ */ jsx(Drawer.Body, { className: "flex flex-1 flex-col gap-y-4 overflow-auto", children: item && /* @__PURE__ */ jsxs(Fragment, { children: [
2309
- /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: t("integration.browse.install_addToConfig") }),
2310
- /* @__PURE__ */ jsxs("div", { className: "bg-ui-bg-subtle flex items-center justify-between gap-x-2 rounded-md px-3 py-2", children: [
2311
- /* @__PURE__ */ jsx("code", { className: "txt-compact-small text-ui-fg-subtle", children: `yarn add @gorgo/medusa-integration ${item.npm}@beta` }),
2312
- /* @__PURE__ */ jsx(Copy, { content: `yarn add @gorgo/medusa-integration ${item.npm}@beta` })
2313
- ] }),
2314
- /* @__PURE__ */ jsxs("div", { className: "bg-ui-bg-subtle flex items-center justify-between gap-x-2 rounded-md px-3 py-2", children: [
2315
- /* @__PURE__ */ jsx("code", { className: "txt-compact-small text-ui-fg-subtle", children: `npm install @gorgo/medusa-integration ${item.npm}@beta` }),
2316
- /* @__PURE__ */ jsx(Copy, { content: `npm install @gorgo/medusa-integration ${item.npm}@beta` })
2317
- ] }),
2318
- item.configSnippet && /* @__PURE__ */ jsxs("div", { className: "bg-ui-bg-subtle flex flex-col gap-y-2 rounded-md px-3 py-2", children: [
2319
- /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-x-2", children: [
2320
- /* @__PURE__ */ jsx(Text, { size: "xsmall", weight: "plus", className: "text-ui-fg-subtle", children: "medusa-config.ts" }),
2321
- /* @__PURE__ */ jsx(Copy, { content: item.configSnippet })
2322
- ] }),
2323
- /* @__PURE__ */ jsx("pre", { className: "txt-compact-small text-ui-fg-subtle overflow-x-auto whitespace-pre", children: item.configSnippet })
2324
- ] }),
2325
- /* @__PURE__ */ jsxs("a", { href: item.docsUrl, target: "_blank", rel: "noreferrer", className: "text-ui-fg-base txt-small", children: [
2500
+ /* @__PURE__ */ jsx(Drawer.Body, { className: "flex flex-1 flex-col gap-y-4 overflow-auto", children: source.trim() ? /* @__PURE__ */ jsx(Markdown, { source, truncatedLabel: t("integration.browse.install_truncated") }) : /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: t("integration.browse.install_empty") }) }),
2501
+ /* @__PURE__ */ jsxs(Drawer.Footer, { children: [
2502
+ /* @__PURE__ */ jsx(Drawer.Close, { asChild: true, children: /* @__PURE__ */ jsx(Button, { size: "small", variant: "secondary", children: t("integration.actions.cancel") }) }),
2503
+ (item == null ? void 0 : item.docsUrl) && /* @__PURE__ */ jsx(Button, { size: "small", variant: "primary", asChild: true, children: /* @__PURE__ */ jsxs("a", { href: item.docsUrl, target: "_blank", rel: "noopener noreferrer", children: [
2326
2504
  t("integration.browse.install_docs"),
2327
- " →"
2328
- ] })
2329
- ] }) }),
2330
- /* @__PURE__ */ jsx(Drawer.Footer, { children: /* @__PURE__ */ jsx(Drawer.Close, { asChild: true, children: /* @__PURE__ */ jsx(Button, { size: "small", variant: "secondary", children: t("integration.actions.cancel") }) }) })
2505
+ /* @__PURE__ */ jsx(ArrowUpRightOnBox, {})
2506
+ ] }) })
2507
+ ] })
2331
2508
  ] }) });
2332
2509
  };
2333
2510
  const BrowsePage = () => {
@@ -2376,7 +2553,7 @@ const BrowsePage = () => {
2376
2553
  /* @__PURE__ */ jsxs("div", { className: "flex flex-1 flex-col gap-y-3 p-4", children: [
2377
2554
  /* @__PURE__ */ jsxs("div", { className: "flex items-start justify-between gap-x-2", children: [
2378
2555
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-x-3", children: [
2379
- /* @__PURE__ */ jsx(IntegrationIcon, { src: API_URL + item.icon, alt: item.label }),
2556
+ /* @__PURE__ */ jsx(IntegrationIcon, { src: iconSrc(item.icon), alt: item.label }),
2380
2557
  /* @__PURE__ */ jsxs("div", { className: "flex flex-col", children: [
2381
2558
  /* @__PURE__ */ jsx(Text, { size: "small", weight: "plus", leading: "compact", children: item.label }),
2382
2559
  /* @__PURE__ */ jsx(Text, { size: "xsmall", leading: "compact", className: "text-ui-fg-subtle", children: t("integration.browse.by", { author: item.authorLocalized }) })
@@ -2442,8 +2619,9 @@ const integration$1 = {
2442
2619
  notInstalled: "Not installed",
2443
2620
  add: "Add",
2444
2621
  settings: "Settings",
2445
- install_addToConfig: "Add this to your medusa-config.ts and restart the server.",
2446
- install_docs: "Documentation"
2622
+ install_docs: "Read docs",
2623
+ install_empty: "Setup instructions for this integration aren't available yet.",
2624
+ install_truncated: "These instructions are too long to show here — open the documentation."
2447
2625
  },
2448
2626
  columns: {
2449
2627
  integration: "Integration",
@@ -2545,8 +2723,9 @@ const integration = {
2545
2723
  notInstalled: "Не установлено",
2546
2724
  add: "Добавить",
2547
2725
  settings: "Настройки",
2548
- install_addToConfig: "Добавьте это в medusa-config.ts и перезапустите сервер.",
2549
- install_docs: "Документация"
2726
+ install_docs: "Читать документацию",
2727
+ install_empty: "Инструкция по настройке для этой интеграции пока недоступна.",
2728
+ install_truncated: "Инструкция слишком длинная для показа здесь — откройте документацию."
2550
2729
  },
2551
2730
  columns: {
2552
2731
  integration: "Интеграция",