hermium 0.1.3 → 0.1.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 (149) hide show
  1. package/bin/hermium.mjs +4 -1
  2. package/dist/web-server/__23tanstack-start-plugin-adapters-Cwee5PKy.mjs +6 -0
  3. package/dist/web-server/_chunks/ssr-renderer.mjs +22 -0
  4. package/dist/web-server/_libs/babel__runtime.mjs +237 -0
  5. package/dist/web-server/_libs/bail.mjs +8 -0
  6. package/dist/web-server/_libs/base-ui__react.mjs +9554 -0
  7. package/dist/web-server/_libs/base-ui__utils.mjs +1101 -0
  8. package/dist/web-server/_libs/ccount.mjs +16 -0
  9. package/dist/web-server/_libs/character-entities-legacy.mjs +111 -0
  10. package/dist/web-server/_libs/character-entities.mjs +2130 -0
  11. package/dist/web-server/_libs/character-reference-invalid.mjs +33 -0
  12. package/dist/web-server/_libs/class-variance-authority.mjs +44 -0
  13. package/dist/web-server/_libs/clsx.mjs +16 -0
  14. package/dist/web-server/_libs/comma-separated-tokens.mjs +31 -0
  15. package/dist/web-server/_libs/cookie-es.mjs +44 -0
  16. package/dist/web-server/_libs/croner.mjs +1 -0
  17. package/dist/web-server/_libs/crossws.mjs +1 -0
  18. package/dist/web-server/_libs/decode-named-character-reference+[...].mjs +8 -0
  19. package/dist/web-server/_libs/devlop.mjs +8 -0
  20. package/dist/web-server/_libs/escape-string-regexp.mjs +9 -0
  21. package/dist/web-server/_libs/estree-util-is-identifier-name.mjs +11 -0
  22. package/dist/web-server/_libs/extend.mjs +97 -0
  23. package/dist/web-server/_libs/fault.mjs +1 -0
  24. package/dist/web-server/_libs/floating-ui__core.mjs +663 -0
  25. package/dist/web-server/_libs/floating-ui__dom.mjs +624 -0
  26. package/dist/web-server/_libs/floating-ui__react-dom.mjs +279 -0
  27. package/dist/web-server/_libs/floating-ui__utils.mjs +322 -0
  28. package/dist/web-server/_libs/format.mjs +1 -0
  29. package/dist/web-server/_libs/h3.mjs +408 -0
  30. package/dist/web-server/_libs/hast-util-parse-selector.mjs +39 -0
  31. package/dist/web-server/_libs/hast-util-to-jsx-runtime.mjs +388 -0
  32. package/dist/web-server/_libs/hast-util-whitespace.mjs +10 -0
  33. package/dist/web-server/_libs/hastscript.mjs +200 -0
  34. package/dist/web-server/_libs/highlight.js.mjs +1 -0
  35. package/dist/web-server/_libs/hookable.mjs +1 -0
  36. package/dist/web-server/_libs/html-url-attributes.mjs +26 -0
  37. package/dist/web-server/_libs/inline-style-parser.mjs +142 -0
  38. package/dist/web-server/_libs/is-alphabetical.mjs +7 -0
  39. package/dist/web-server/_libs/is-alphanumerical.mjs +8 -0
  40. package/dist/web-server/_libs/is-decimal.mjs +7 -0
  41. package/dist/web-server/_libs/is-hexadecimal.mjs +7 -0
  42. package/dist/web-server/_libs/is-plain-obj.mjs +10 -0
  43. package/dist/web-server/_libs/isbot.mjs +21 -0
  44. package/dist/web-server/_libs/longest-streak.mjs +25 -0
  45. package/dist/web-server/_libs/lowlight.mjs +1 -0
  46. package/dist/web-server/_libs/markdown-table.mjs +142 -0
  47. package/dist/web-server/_libs/mdast-util-find-and-replace.mjs +109 -0
  48. package/dist/web-server/_libs/mdast-util-from-markdown.mjs +717 -0
  49. package/dist/web-server/_libs/mdast-util-gfm-autolink-literal+[...].mjs +156 -0
  50. package/dist/web-server/_libs/mdast-util-gfm-footnote.mjs +117 -0
  51. package/dist/web-server/_libs/mdast-util-gfm-strikethrough.mjs +54 -0
  52. package/dist/web-server/_libs/mdast-util-gfm-table.mjs +157 -0
  53. package/dist/web-server/_libs/mdast-util-gfm-task-list-item.mjs +77 -0
  54. package/dist/web-server/_libs/mdast-util-gfm.mjs +29 -0
  55. package/dist/web-server/_libs/mdast-util-phrasing.mjs +30 -0
  56. package/dist/web-server/_libs/mdast-util-to-hast.mjs +710 -0
  57. package/dist/web-server/_libs/mdast-util-to-markdown.mjs +798 -0
  58. package/dist/web-server/_libs/mdast-util-to-string.mjs +38 -0
  59. package/dist/web-server/_libs/micromark-core-commonmark.mjs +2259 -0
  60. package/dist/web-server/_libs/micromark-extension-gfm-autolink-literal+[...].mjs +344 -0
  61. package/dist/web-server/_libs/micromark-extension-gfm-footnote+[...].mjs +279 -0
  62. package/dist/web-server/_libs/micromark-extension-gfm-strikethrough+[...].mjs +98 -0
  63. package/dist/web-server/_libs/micromark-extension-gfm-table.mjs +491 -0
  64. package/dist/web-server/_libs/micromark-extension-gfm-tagfilter+[...].mjs +1 -0
  65. package/dist/web-server/_libs/micromark-extension-gfm-task-list-item+[...].mjs +77 -0
  66. package/dist/web-server/_libs/micromark-extension-gfm.mjs +18 -0
  67. package/dist/web-server/_libs/micromark-factory-destination.mjs +94 -0
  68. package/dist/web-server/_libs/micromark-factory-label.mjs +63 -0
  69. package/dist/web-server/_libs/micromark-factory-space.mjs +24 -0
  70. package/dist/web-server/_libs/micromark-factory-title.mjs +65 -0
  71. package/dist/web-server/_libs/micromark-factory-whitespace.mjs +22 -0
  72. package/dist/web-server/_libs/micromark-util-character.mjs +44 -0
  73. package/dist/web-server/_libs/micromark-util-chunked.mjs +36 -0
  74. package/dist/web-server/_libs/micromark-util-classify-character+[...].mjs +12 -0
  75. package/dist/web-server/_libs/micromark-util-combine-extensions+[...].mjs +41 -0
  76. package/dist/web-server/_libs/micromark-util-decode-numeric-character-reference+[...].mjs +19 -0
  77. package/dist/web-server/_libs/micromark-util-decode-string.mjs +21 -0
  78. package/dist/web-server/_libs/micromark-util-encode.mjs +1 -0
  79. package/dist/web-server/_libs/micromark-util-html-tag-name.mjs +69 -0
  80. package/dist/web-server/_libs/micromark-util-normalize-identifier+[...].mjs +6 -0
  81. package/dist/web-server/_libs/micromark-util-resolve-all.mjs +15 -0
  82. package/dist/web-server/_libs/micromark-util-sanitize-uri.mjs +41 -0
  83. package/dist/web-server/_libs/micromark-util-subtokenize.mjs +346 -0
  84. package/dist/web-server/_libs/micromark.mjs +906 -0
  85. package/dist/web-server/_libs/ocache.mjs +1 -0
  86. package/dist/web-server/_libs/ohash.mjs +1 -0
  87. package/dist/web-server/_libs/parse-entities.mjs +245 -0
  88. package/dist/web-server/_libs/property-information.mjs +1210 -0
  89. package/dist/web-server/_libs/react-dom.mjs +10779 -0
  90. package/dist/web-server/_libs/react-markdown.mjs +147 -0
  91. package/dist/web-server/_libs/react-syntax-highlighter.mjs +941 -0
  92. package/dist/web-server/_libs/react.mjs +513 -0
  93. package/dist/web-server/_libs/refractor.mjs +2425 -0
  94. package/dist/web-server/_libs/remark-gfm.mjs +20 -0
  95. package/dist/web-server/_libs/remark-parse.mjs +19 -0
  96. package/dist/web-server/_libs/remark-rehype.mjs +21 -0
  97. package/dist/web-server/_libs/reselect.mjs +1 -0
  98. package/dist/web-server/_libs/rou3.mjs +8 -0
  99. package/dist/web-server/_libs/seroval-plugins.mjs +58 -0
  100. package/dist/web-server/_libs/seroval.mjs +1775 -0
  101. package/dist/web-server/_libs/space-separated-tokens.mjs +11 -0
  102. package/dist/web-server/_libs/srvx.mjs +781 -0
  103. package/dist/web-server/_libs/style-to-js.mjs +72 -0
  104. package/dist/web-server/_libs/style-to-object.mjs +38 -0
  105. package/dist/web-server/_libs/tabler__icons-react.mjs +224 -0
  106. package/dist/web-server/_libs/tanstack__history.mjs +204 -0
  107. package/dist/web-server/_libs/tanstack__query-core.mjs +2552 -0
  108. package/dist/web-server/_libs/tanstack__react-query.mjs +190 -0
  109. package/dist/web-server/_libs/tanstack__react-router.mjs +1120 -0
  110. package/dist/web-server/_libs/tanstack__react-store.mjs +2 -0
  111. package/dist/web-server/_libs/tanstack__router-core.mjs +4288 -0
  112. package/dist/web-server/_libs/tanstack__store.mjs +1 -0
  113. package/dist/web-server/_libs/trim-lines.mjs +41 -0
  114. package/dist/web-server/_libs/trough.mjs +85 -0
  115. package/dist/web-server/_libs/ufo.mjs +54 -0
  116. package/dist/web-server/_libs/unctx.mjs +1 -0
  117. package/dist/web-server/_libs/ungap__structured-clone.mjs +224 -0
  118. package/dist/web-server/_libs/unified.mjs +661 -0
  119. package/dist/web-server/_libs/unist-util-is.mjs +100 -0
  120. package/dist/web-server/_libs/unist-util-position.mjs +27 -0
  121. package/dist/web-server/_libs/unist-util-stringify-position.mjs +27 -0
  122. package/dist/web-server/_libs/unist-util-visit-parents.mjs +83 -0
  123. package/dist/web-server/_libs/unist-util-visit.mjs +24 -0
  124. package/dist/web-server/_libs/unstorage.mjs +1 -0
  125. package/dist/web-server/_libs/use-sync-external-store.mjs +139 -0
  126. package/dist/web-server/_libs/vfile-message.mjs +138 -0
  127. package/dist/web-server/_libs/vfile.mjs +467 -0
  128. package/dist/web-server/_libs/zod.mjs +3915 -0
  129. package/dist/web-server/_libs/zustand.mjs +343 -0
  130. package/dist/web-server/_libs/zwitch.mjs +1 -0
  131. package/dist/web-server/_ssr/index-BLK6uN4p.mjs +612 -0
  132. package/dist/web-server/_ssr/index-BkkxTg0a.mjs +1855 -0
  133. package/dist/web-server/_ssr/index-Bp9a_nTf.mjs +66 -0
  134. package/dist/web-server/_ssr/index-C8t8AZQG.mjs +513 -0
  135. package/dist/web-server/_ssr/index-DSIu0x-q.mjs +449 -0
  136. package/dist/web-server/_ssr/index-DqFrn6kj.mjs +278 -0
  137. package/dist/web-server/_ssr/index-EKE8NFy_.mjs +189 -0
  138. package/dist/web-server/_ssr/index-JzLhPyir.mjs +213 -0
  139. package/dist/web-server/_ssr/index-wTy_4MhH.mjs +369 -0
  140. package/dist/web-server/_ssr/index.mjs +1558 -0
  141. package/dist/web-server/_ssr/input-BQFduUUo.mjs +20 -0
  142. package/dist/web-server/_ssr/router-59cN5lqo.mjs +1998 -0
  143. package/dist/web-server/_ssr/start-HYkvq4Ni.mjs +4 -0
  144. package/dist/web-server/_ssr/switch-Bim4kX8N.mjs +33 -0
  145. package/dist/web-server/_ssr/syntax-highlighter-5vezNTce.mjs +62 -0
  146. package/dist/web-server/_ssr/textarea-CK0ROhfF.mjs +18 -0
  147. package/dist/web-server/_tanstack-start-manifest_v-DLw6M7p4.mjs +4 -0
  148. package/dist/web-server/index.mjs +120 -120
  149. package/package.json +1 -1
@@ -0,0 +1,66 @@
1
+ import { r as reactExports, j as jsxRuntimeExports } from "../_libs/react.mjs";
2
+ import { d as useNavigate } from "../_libs/tanstack__react-router.mjs";
3
+ import { b as useChatStore, c as createSession } from "./router-59cN5lqo.mjs";
4
+ import "../_libs/tanstack__router-core.mjs";
5
+ import "../_libs/tanstack__history.mjs";
6
+ import "../_libs/cookie-es.mjs";
7
+ import "../_libs/seroval.mjs";
8
+ import "../_libs/seroval-plugins.mjs";
9
+ import "node:stream/web";
10
+ import "node:stream";
11
+ import "../_libs/react-dom.mjs";
12
+ import "util";
13
+ import "crypto";
14
+ import "async_hooks";
15
+ import "stream";
16
+ import "../_libs/isbot.mjs";
17
+ import "../_libs/tanstack__query-core.mjs";
18
+ import "../_libs/tanstack__react-query.mjs";
19
+ import "../_libs/clsx.mjs";
20
+ import "../_libs/class-variance-authority.mjs";
21
+ import "../_libs/zustand.mjs";
22
+ import "../_libs/tabler__icons-react.mjs";
23
+ import "../_libs/base-ui__react.mjs";
24
+ import "../_libs/base-ui__utils.mjs";
25
+ import "../_libs/use-sync-external-store.mjs";
26
+ import "../_libs/floating-ui__utils.mjs";
27
+ import "../_libs/floating-ui__react-dom.mjs";
28
+ import "../_libs/floating-ui__dom.mjs";
29
+ import "../_libs/floating-ui__core.mjs";
30
+ import "../_libs/zod.mjs";
31
+ function ChatIndexPage() {
32
+ const navigate = useNavigate();
33
+ const sessionsLoaded = useChatStore((s) => s.sessionsLoaded);
34
+ const sessions = useChatStore((s) => s.sessions);
35
+ const creatingRef = reactExports.useRef(false);
36
+ reactExports.useEffect(() => {
37
+ if (!sessionsLoaded) return;
38
+ if (sessions.length > 0) {
39
+ navigate({
40
+ to: "/chat/$sessionId",
41
+ params: {
42
+ sessionId: sessions[0].id
43
+ },
44
+ replace: true
45
+ });
46
+ } else {
47
+ if (creatingRef.current) return;
48
+ creatingRef.current = true;
49
+ createSession().then((data) => {
50
+ navigate({
51
+ to: "/chat/$sessionId",
52
+ params: {
53
+ sessionId: data.id
54
+ },
55
+ replace: true
56
+ });
57
+ }).catch(() => {
58
+ creatingRef.current = false;
59
+ });
60
+ }
61
+ }, [sessionsLoaded, sessions, navigate]);
62
+ return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex flex-1 items-center justify-center", children: /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-sm text-muted-foreground", children: "Loading conversations…" }) });
63
+ }
64
+ export {
65
+ ChatIndexPage as component
66
+ };
@@ -0,0 +1,513 @@
1
+ import { r as reactExports, j as jsxRuntimeExports } from "../_libs/react.mjs";
2
+ import { S as Switch } from "./switch-Bim4kX8N.mjs";
3
+ import { I as Input } from "./input-BQFduUUo.mjs";
4
+ import { u as useQueryClient, a as useQuery, b as useMutation } from "../_libs/tanstack__react-query.mjs";
5
+ import { a as cn, d as put, g as get } from "./router-59cN5lqo.mjs";
6
+ import { G as IconLoader2, O as IconSparkles, P as IconPlugConnected, Q as IconAlertTriangle, R as IconPlug, m as IconChevronDown, N as IconCheck } from "../_libs/tabler__icons-react.mjs";
7
+ import "../_libs/base-ui__react.mjs";
8
+ import "../_libs/base-ui__utils.mjs";
9
+ import "../_libs/use-sync-external-store.mjs";
10
+ import "../_libs/react-dom.mjs";
11
+ import "util";
12
+ import "crypto";
13
+ import "async_hooks";
14
+ import "stream";
15
+ import "../_libs/floating-ui__utils.mjs";
16
+ import "../_libs/floating-ui__react-dom.mjs";
17
+ import "../_libs/floating-ui__dom.mjs";
18
+ import "../_libs/floating-ui__core.mjs";
19
+ import "../_libs/tanstack__query-core.mjs";
20
+ import "../_libs/tanstack__react-router.mjs";
21
+ import "../_libs/tanstack__router-core.mjs";
22
+ import "../_libs/tanstack__history.mjs";
23
+ import "../_libs/cookie-es.mjs";
24
+ import "../_libs/seroval.mjs";
25
+ import "../_libs/seroval-plugins.mjs";
26
+ import "node:stream/web";
27
+ import "node:stream";
28
+ import "../_libs/isbot.mjs";
29
+ import "../_libs/clsx.mjs";
30
+ import "../_libs/class-variance-authority.mjs";
31
+ import "../_libs/zustand.mjs";
32
+ import "../_libs/zod.mjs";
33
+ async function fetchConfig() {
34
+ return get("/api/config");
35
+ }
36
+ async function fetchEnvVars() {
37
+ return get("/api/env");
38
+ }
39
+ async function updateConfig(config) {
40
+ return put("/api/config", { config });
41
+ }
42
+ async function updateEnvVar(key, value) {
43
+ return put("/api/env", { key, value });
44
+ }
45
+ function PlatformCard({
46
+ name,
47
+ icon,
48
+ color,
49
+ configured,
50
+ hasCreds,
51
+ exclusive,
52
+ children
53
+ }) {
54
+ const [expanded, setExpanded] = reactExports.useState(true);
55
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs(
56
+ "div",
57
+ {
58
+ className: cn(
59
+ "group relative rounded-xl border bg-card transition-all duration-200",
60
+ "hover:shadow-md hover:shadow-black/5 dark:hover:shadow-black/20",
61
+ "hover:border-border/80",
62
+ configured && hasCreds ? "border-emerald-500/30 dark:border-emerald-500/20 bg-emerald-500/[0.02]" : configured ? "border-amber-500/30 dark:border-amber-500/20 bg-amber-500/[0.02]" : "border-border"
63
+ ),
64
+ children: [
65
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
66
+ "div",
67
+ {
68
+ className: cn(
69
+ "absolute left-0 top-0 bottom-0 w-0.5 rounded-l-xl transition-colors",
70
+ configured && hasCreds ? "bg-emerald-500/50" : configured ? "bg-amber-500/50" : "bg-border"
71
+ )
72
+ }
73
+ ),
74
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(
75
+ "button",
76
+ {
77
+ onClick: () => setExpanded(!expanded),
78
+ className: "flex items-center justify-between w-full px-4 py-3.5 text-left",
79
+ children: [
80
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-3 min-w-0", children: [
81
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
82
+ "div",
83
+ {
84
+ className: cn(
85
+ "flex items-center justify-center size-9 rounded-lg shrink-0 transition-colors",
86
+ configured ? "bg-foreground/5 dark:bg-foreground/10" : "bg-muted"
87
+ ),
88
+ children: /* @__PURE__ */ jsxRuntimeExports.jsx(
89
+ "span",
90
+ {
91
+ className: cn(
92
+ "size-[18px] flex items-center justify-center",
93
+ configured ? "text-foreground/70" : "text-muted-foreground/50"
94
+ ),
95
+ dangerouslySetInnerHTML: { __html: icon }
96
+ }
97
+ )
98
+ }
99
+ ),
100
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "min-w-0", children: [
101
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex items-center gap-2", children: /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-sm font-semibold text-foreground truncate", children: name }) }),
102
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex items-center gap-1.5 mt-0.5", children: configured && hasCreds ? /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
103
+ /* @__PURE__ */ jsxRuntimeExports.jsx(IconPlugConnected, { className: "size-3 text-emerald-500" }),
104
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[11px] font-medium text-emerald-600 dark:text-emerald-400", children: "Connected" })
105
+ ] }) : configured ? /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
106
+ /* @__PURE__ */ jsxRuntimeExports.jsx(IconAlertTriangle, { className: "size-3 text-amber-500" }),
107
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[11px] font-medium text-amber-600 dark:text-amber-400", children: "Needs credentials" })
108
+ ] }) : /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
109
+ /* @__PURE__ */ jsxRuntimeExports.jsx(IconPlug, { className: "size-3 text-muted-foreground/50" }),
110
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[11px] font-medium text-muted-foreground", children: "Not connected" })
111
+ ] }) })
112
+ ] })
113
+ ] }),
114
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
115
+ IconChevronDown,
116
+ {
117
+ className: cn(
118
+ "size-4 text-muted-foreground/50 transition-transform duration-200",
119
+ expanded && "rotate-180"
120
+ )
121
+ }
122
+ )
123
+ ]
124
+ }
125
+ ),
126
+ expanded && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "px-4 pb-4 border-t border-border/40", children: [
127
+ exclusive && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "mt-3 flex items-start gap-2 rounded-lg bg-amber-500/5 border border-amber-500/20 px-3 py-2 text-[11px] text-amber-600 dark:text-amber-400 leading-relaxed", children: [
128
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(
129
+ "svg",
130
+ {
131
+ className: "size-3.5 shrink-0 mt-0.5",
132
+ viewBox: "0 0 24 24",
133
+ fill: "none",
134
+ stroke: "currentColor",
135
+ strokeWidth: "2",
136
+ children: [
137
+ /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z" }),
138
+ /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "12", y1: "9", x2: "12", y2: "13" }),
139
+ /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "12", y1: "17", x2: "12.01", y2: "17" })
140
+ ]
141
+ }
142
+ ),
143
+ "This platform requires an exclusive/shared token. Ensure only one bot instance uses this token."
144
+ ] }),
145
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "mt-3 space-y-0.5", children })
146
+ ] })
147
+ ]
148
+ }
149
+ );
150
+ }
151
+ function SettingRow({ label, hint, children }) {
152
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between py-2 px-2 -mx-2 rounded-lg hover:bg-muted/40 transition-colors", children: [
153
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex-1 mr-3 min-w-0", children: [
154
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[12px] font-medium text-foreground/80 block", children: label }),
155
+ hint && /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-[10px] text-muted-foreground mt-0.5 leading-snug", children: hint })
156
+ ] }),
157
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "shrink-0", children })
158
+ ] });
159
+ }
160
+ const PLATFORMS = [
161
+ {
162
+ key: "telegram",
163
+ name: "Telegram",
164
+ exclusive: true,
165
+ color: "#26A5E4",
166
+ icon: '<svg viewBox="0 0 24 24" fill="currentColor"><path d="M11.944 0A12 12 0 0 0 0 12a12 12 0 0 0 12 12 12 12 0 0 0 12-12A12 12 0 0 0 12 0a12 12 0 0 0-.056 0zm4.962 7.224c.1-.002.321.023.465.14a.506.506 0 0 1 .171.325c.016.093.036.306.02.472-.18 1.898-.962 6.502-1.36 8.627-.168.9-.499 1.201-.82 1.23-.696.065-1.225-.46-1.9-.902-1.056-.693-1.653-1.124-2.678-1.8-1.185-.78-.417-1.21.258-1.91.177-.184 3.247-2.977 3.307-3.23.007-.032.014-.15-.056-.212s-.174-.041-.249-.024c-.106.024-1.793 1.14-5.061 3.345-.479.33-.913.49-1.302.48-.428-.008-1.252-.241-1.865-.44-.752-.245-1.349-.374-1.297-.789.027-.216.325-.437.893-.663 3.498-1.524 5.83-2.529 6.998-3.014 3.332-1.386 4.025-1.627 4.476-1.635z"/></svg>',
167
+ primaryCred: "TELEGRAM_BOT_TOKEN",
168
+ envFields: [
169
+ { key: "TELEGRAM_BOT_TOKEN", label: "Bot Token", hint: "Get it from @BotFather", password: true },
170
+ { key: "TELEGRAM_ALLOWED_USERS", label: "Allowed Users", hint: "Comma-separated user IDs" },
171
+ { key: "TELEGRAM_PROXY", label: "Proxy", hint: "Optional proxy URL" }
172
+ ],
173
+ configFields: [
174
+ { key: "reactions", label: "Reactions", hint: "Add emoji reactions during processing", type: "switch" },
175
+ { key: "allowed_chats", label: "Allowed Chats", hint: "Comma-separated chat IDs (whitelist)", type: "input" }
176
+ ]
177
+ },
178
+ {
179
+ key: "discord",
180
+ name: "Discord",
181
+ exclusive: true,
182
+ color: "#5865F2",
183
+ icon: '<svg viewBox="0 0 24 24" fill="currentColor"><path d="M20.317 4.3698a19.7913 19.7913 0 00-4.8851-1.5152.0741.0741 0 00-.0785.0371c-.211.3753-.4447.8648-.6083 1.2495-1.8447-.2762-3.68-.2762-5.4868 0-.1636-.3933-.4058-.8742-.6177-1.2495a.077.077 0 00-.0785-.037 19.7363 19.7363 0 00-4.8852 1.515.0699.0699 0 00-.0321.0277C.5334 9.0458-.319 13.5799.0992 18.0578a.0824.0824 0 00.0312.0561c2.0528 1.5076 4.0413 2.4228 5.9929 3.0294a.0777.0777 0 00.0842-.0276c.4616-.6304.8731-1.2952 1.226-1.9942a.076.076 0 00-.0416-.1057c-.6528-.2476-1.2743-.5495-1.8722-.8923a.077.077 0 01-.0076-.1277c.1258-.0943.2517-.1923.3718-.2914a.0743.0743 0 01.0776-.0105c3.9278 1.7933 8.18 1.7933 12.0614 0a.0739.0739 0 01.0785.0095c.1202.099.246.1981.3728.2924a.077.077 0 01-.0066.1276 12.2986 12.2986 0 01-1.873.8914.0766.0766 0 00-.0407.1067c.3604.698.7719 1.3628 1.225 1.9932a.076.076 0 00.0842.0286c1.961-.6067 3.9495-1.5219 6.0023-3.0294a.077.077 0 00.0313-.0552c.5004-5.177-.8382-9.6739-3.5485-13.6604a.061.061 0 00-.0312-.0286zM8.02 15.3312c-1.1825 0-2.1569-1.0857-2.1569-2.419 0-1.3332.9555-2.4189 2.157-2.4189 1.2108 0 2.1757 1.0952 2.1568 2.419 0 1.3332-.9555 2.4189-2.1569 2.4189zm7.9748 0c-1.1825 0-2.1569-1.0857-2.1569-2.419 0-1.3332.9554-2.4189 2.1569-2.4189 1.2108 0 2.1757 1.0952 2.1568 2.419 0 1.3332-.946 2.4189-2.1568 2.4189z"/></svg>',
184
+ primaryCred: "DISCORD_BOT_TOKEN",
185
+ envFields: [
186
+ { key: "DISCORD_BOT_TOKEN", label: "Bot Token", hint: "From Discord Developer Portal", password: true },
187
+ { key: "DISCORD_ALLOWED_USERS", label: "Allowed Users", hint: "Comma-separated user IDs" },
188
+ { key: "DISCORD_REPLY_TO_MODE", label: "Reply Mode", hint: "off / first / all", type: "select", options: ["off", "first", "all"] }
189
+ ],
190
+ configFields: [
191
+ { key: "require_mention", label: "Require Mention", hint: "Only respond when @mentioned", type: "switch" },
192
+ { key: "auto_thread", label: "Auto-thread", hint: "Create threads for long conversations", type: "switch" },
193
+ { key: "reactions", label: "Reactions", hint: "Add emoji reactions during processing", type: "switch" },
194
+ { key: "free_response_channels", label: "Free-response Channels", hint: "Comma-separated channel IDs", type: "input" },
195
+ { key: "allowed_channels", label: "Allowed Channels", hint: "Comma-separated channel IDs (whitelist)", type: "input" }
196
+ ]
197
+ },
198
+ {
199
+ key: "slack",
200
+ name: "Slack",
201
+ exclusive: true,
202
+ color: "#4A154B",
203
+ icon: '<svg viewBox="0 0 24 24" fill="currentColor"><path d="M5.042 15.165a2.528 2.528 0 0 1-2.52 2.523A2.528 2.528 0 0 1 0 15.165a2.527 2.527 0 0 1 2.522-2.52h2.52v2.52zm1.271 0a2.527 2.527 0 0 1 2.521-2.52 2.527 2.527 0 0 1 2.521 2.52v6.313A2.528 2.528 0 0 1 8.834 24a2.528 2.528 0 0 1-2.521-2.522v-6.313zM8.834 5.042a2.528 2.528 0 0 1-2.521-2.52A2.528 2.528 0 0 1 8.834 0a2.528 2.528 0 0 1 2.521 2.522v2.52H8.834zm0 1.271a2.528 2.528 0 0 1 2.521 2.521 2.528 2.528 0 0 1-2.521 2.521H2.522A2.528 2.528 0 0 1 0 8.834a2.528 2.528 0 0 1 2.522-2.521h6.312zm10.122 0a2.528 2.528 0 0 1 2.522-2.521A2.528 2.528 0 0 1 24 8.834a2.528 2.528 0 0 1-2.522 2.521h-2.522V5.042zm-1.27 0a2.528 2.528 0 0 1-2.523 2.521 2.527 2.527 0 0 1-2.52-2.521V2.522A2.527 2.527 0 0 1 15.165 0a2.528 2.528 0 0 1 2.523 2.522v6.312zM15.165 18.956a2.528 2.528 0 0 1 2.523 2.522A2.528 2.528 0 0 1 15.165 24a2.527 2.527 0 0 1-2.52-2.522v-2.522h2.52zm0-1.27a2.527 2.527 0 0 1 2.523-2.52h6.313A2.528 2.528 0 0 1 24 18.956a2.528 2.528 0 0 1-2.522 2.523h-6.313z"/></svg>',
204
+ primaryCred: "SLACK_BOT_TOKEN",
205
+ envFields: [
206
+ { key: "SLACK_BOT_TOKEN", label: "Bot Token", hint: "xoxb-... from Slack API", password: true },
207
+ { key: "SLACK_APP_TOKEN", label: "App Token", hint: "xapp-... for Socket Mode", password: true },
208
+ { key: "SLACK_ALLOWED_USERS", label: "Allowed Users", hint: "Comma-separated user IDs" }
209
+ ],
210
+ configFields: [
211
+ { key: "require_mention", label: "Require Mention", hint: "Only respond when @mentioned", type: "switch" },
212
+ { key: "free_response_channels", label: "Free-response Channels", hint: "Comma-separated channel IDs", type: "input" },
213
+ { key: "allowed_channels", label: "Allowed Channels", hint: "Comma-separated channel IDs (whitelist)", type: "input" }
214
+ ]
215
+ },
216
+ {
217
+ key: "whatsapp",
218
+ name: "WhatsApp",
219
+ exclusive: true,
220
+ color: "#25D366",
221
+ icon: '<svg viewBox="0 0 24 24" fill="currentColor"><path d="M17.472 14.382c-.297-.149-1.758-.867-2.03-.967-.273-.099-.471-.148-.67.15-.197.297-.767.966-.94 1.164-.173.199-.347.223-.644.075-.297-.15-1.255-.463-2.39-1.475-.883-.788-1.48-1.761-1.653-2.059-.173-.297-.018-.458.13-.606.134-.133.298-.347.446-.52.149-.174.198-.298.298-.497.099-.198.05-.371-.025-.52-.075-.149-.669-1.612-.916-2.207-.242-.579-.487-.5-.669-.51-.173-.008-.371-.01-.57-.01-.198 0-.52.074-.792.372-.272.297-1.04 1.016-1.04 2.479 0 1.462 1.065 2.875 1.213 3.074.149.198 2.096 3.2 5.077 4.487.709.306 1.262.489 1.694.625.712.227 1.36.195 1.871.118.571-.085 1.758-.719 2.006-1.413.248-.694.248-1.289.173-1.413-.074-.124-.272-.198-.57-.347m-5.421 7.403h-.004a9.87 9.87 0 01-5.031-1.378l-.361-.214-3.741.982.998-3.648-.235-.374a9.86 9.86 0 01-1.51-5.26c.001-5.45 4.436-9.884 9.888-9.884 2.64 0 5.122 1.03 6.988 2.898a9.825 9.825 0 012.893 6.994c-.003 5.45-4.437 9.884-9.885 9.884m8.413-18.297A11.815 11.815 0 0012.05 0C5.495 0 .16 5.335.157 11.892c0 2.096.547 4.142 1.588 5.945L.057 24l6.305-1.654a11.882 11.882 0 005.683 1.448h.005c6.554 0 11.89-5.335 11.893-11.893a11.821 11.821 0 00-3.48-8.413z"/></svg>',
222
+ primaryCred: "WHATSAPP_ENABLED",
223
+ envFields: [
224
+ { key: "WHATSAPP_ENABLED", label: "Enabled", hint: "Set to true to enable WhatsApp", type: "select", options: ["true", "false"] },
225
+ { key: "WHATSAPP_MODE", label: "Mode", hint: "self-chat or bot", type: "select", options: ["self-chat", "bot"] },
226
+ { key: "WHATSAPP_ALLOWED_USERS", label: "Allowed Users", hint: "Comma-separated phone numbers" }
227
+ ],
228
+ configFields: [
229
+ { key: "require_mention", label: "Require Mention", hint: "Only respond when mentioned", type: "switch" },
230
+ { key: "free_response_chats", label: "Free-response Chats", hint: "Comma-separated chat IDs", type: "input" }
231
+ ]
232
+ },
233
+ {
234
+ key: "matrix",
235
+ name: "Matrix",
236
+ color: "#000000",
237
+ icon: '<svg viewBox="0 0 24 24" fill="currentColor"><path d="M.632.55v22.9H2.28V24H0V0h2.28v.55zm7.043 7.26v1.157h.033c.309-.443.683-.784 1.117-1.024.433-.245.936-.365 1.5-.365.54 0 1.033.107 1.48.324.448.217.786.619 1.017 1.205.24-.376.558-.702.956-.98.398-.277.872-.414 1.424-.414.41 0 .784.065 1.122.194.34.13.629.325.87.588.241.263.428.59.56.984.132.393.198.85.198 1.368v5.89h-2.49v-4.893c0-.268-.016-.525-.048-.77a1.627 1.627 0 00-.2-.63 1.028 1.028 0 00-.392-.426 1.294 1.294 0 00-.616-.134c-.277 0-.508.05-.693.15a1.043 1.043 0 00-.43.41 1.768 1.768 0 00-.214.616 4.15 4.15 0 00-.06.74v4.937H9.29v-4.937c0-.25-.01-.498-.032-.742a1.84 1.84 0 00-.166-.638.998.998 0 00-.363-.448 1.206 1.206 0 00-.624-.154c-.26 0-.483.048-.67.144a1.055 1.055 0 00-.436.402 1.744 1.744 0 00-.227.616 4.108 4.108 0 00-.063.74v4.937H5.21V7.81zm15.693 15.64V.55H21.72V0H24v24h-2.28v-.55z"/></svg>',
238
+ primaryCred: "MATRIX_ACCESS_TOKEN",
239
+ envFields: [
240
+ { key: "MATRIX_HOMESERVER", label: "Homeserver", hint: "e.g. https://matrix.org" },
241
+ { key: "MATRIX_ACCESS_TOKEN", label: "Access Token", hint: "From Element settings", password: true },
242
+ { key: "MATRIX_USER_ID", label: "User ID", hint: "e.g. @hermes:matrix.org" },
243
+ { key: "MATRIX_ALLOWED_USERS", label: "Allowed Users", hint: "Comma-separated user IDs" }
244
+ ],
245
+ configFields: [
246
+ { key: "require_mention", label: "Require Mention", hint: "Only respond when mentioned", type: "switch" },
247
+ { key: "free_response_rooms", label: "Free-response Rooms", hint: "Comma-separated room IDs", type: "input" },
248
+ { key: "allowed_rooms", label: "Allowed Rooms", hint: "Comma-separated room IDs (whitelist)", type: "input" }
249
+ ]
250
+ },
251
+ {
252
+ key: "feishu",
253
+ name: "Feishu",
254
+ exclusive: true,
255
+ color: "#3370FF",
256
+ icon: '<svg viewBox="0 0 24 24" fill="currentColor"><path d="M6.59 3.41a2.25 2.25 0 0 1 3.182 0L13.5 7.14l-3.182 3.182L6.59 7.59a2.25 2.25 0 0 1 0-3.182zm5.303 5.303L15.075 5.53a2.25 2.25 0 0 1 3.182 3.182L15.075 11.894 11.893 8.713zM3.41 6.59a2.25 2.25 0 0 1 3.182 0l3.182 3.182-3.182 3.182a2.25 2.25 0 0 1-3.182-3.182L3.41 6.59zm5.303 5.303L11.894 15.075a2.25 2.25 0 0 1-3.182 3.182L5.53 15.075 8.713 11.893zm5.303-5.303L17.478 9.778a2.25 2.25 0 0 1-3.182 3.182L10.53 10.075l3.182-3.182 0 .023z"/></svg>',
257
+ primaryCred: "FEISHU_APP_ID",
258
+ envFields: [
259
+ { key: "FEISHU_APP_ID", label: "App ID", hint: "From Feishu Open Platform" },
260
+ { key: "FEISHU_APP_SECRET", label: "App Secret", hint: "From Feishu Open Platform", password: true },
261
+ { key: "FEISHU_ENCRYPT_KEY", label: "Encrypt Key", hint: "Optional encrypt key", password: true },
262
+ { key: "FEISHU_VERIFICATION_TOKEN", label: "Verification Token", hint: "Optional verification token" }
263
+ ],
264
+ configFields: []
265
+ },
266
+ {
267
+ key: "weixin",
268
+ name: "WeChat",
269
+ exclusive: true,
270
+ color: "#07C160",
271
+ icon: '<svg viewBox="0 0 24 24" fill="currentColor"><path d="M8.691 2.188C3.891 2.188 0 5.476 0 9.53c0 2.212 1.17 4.203 3.002 5.55a.59.59 0 01.213.665l-.39 1.48c-.019.07-.048.141-.048.213 0 .163.13.295.29.295a.326.326 0 00.167-.054l1.903-1.114a.864.864 0 01.717-.098 10.16 10.16 0 002.837.403c.276 0 .543-.027.811-.05-.857-2.578.157-4.972 1.932-6.446 1.703-1.415 3.882-1.98 5.853-1.838-.576-3.583-4.196-6.348-8.596-6.348zM5.785 5.991c.642 0 1.162.529 1.162 1.18a1.17 1.17 0 01-1.162 1.178A1.17 1.17 0 014.623 7.17c0-.651.52-1.18 1.162-1.18zm5.813 0c.642 0 1.162.529 1.162 1.18a1.17 1.17 0 01-1.162 1.178 1.17 1.17 0 01-1.162-1.178c0-.651.52-1.18 1.162-1.18zm3.68 4.025c-3.694 0-6.69 2.462-6.69 5.496 0 3.034 2.996 5.496 6.69 5.496.753 0 1.477-.1 2.158-.28a.66.66 0 01.548.074l1.46.854a.25.25 0 00.127.041.224.224 0 00.221-.225c0-.055-.022-.109-.037-.162l-.298-1.131a.453.453 0 01.163-.509C21.81 18.613 22.77 16.973 22.77 15.512c0-3.034-2.996-5.496-6.69-5.496h.198zm-2.454 3.347c.491 0 .889.404.889.902a.896.896 0 01-.889.903.896.896 0 01-.889-.903c0-.498.398-.902.889-.902zm4.912 0c.491 0 .889.404.889.902a.896.896 0 01-.889.903.896.896 0 01-.889-.903c0-.498.398-.902.889-.902z"/></svg>',
272
+ primaryCred: "WEIXIN_TOKEN",
273
+ envFields: [
274
+ { key: "WEIXIN_ACCOUNT_ID", label: "Account ID", hint: "Official account ID" },
275
+ { key: "WEIXIN_TOKEN", label: "Token", hint: "WeChat verification token", password: true },
276
+ { key: "WEIXIN_BASE_URL", label: "Base URL", hint: "WeChat API base URL" },
277
+ { key: "WEIXIN_CDN_BASE_URL", label: "CDN Base URL", hint: "Optional CDN base URL" }
278
+ ],
279
+ configFields: []
280
+ },
281
+ {
282
+ key: "wecom",
283
+ name: "WeCom",
284
+ color: "#1677FF",
285
+ icon: '<svg viewBox="0 0 24 24" fill="currentColor"><path d="M8.691 2.188C3.891 2.188 0 5.476 0 9.53c0 2.212 1.17 4.203 3.002 5.55a.59.59 0 01.213.665l-.39 1.48c-.019.07-.048.141-.048.213 0 .163.13.295.29.295a.326.326 0 00.167-.054l1.903-1.114a.864.864 0 01.717-.098 10.16 10.16 0 002.837.403c.276 0 .543-.027.811-.05-.857-2.578.157-4.972 1.932-6.446 1.703-1.415 3.882-1.98 5.853-1.838-.576-3.583-4.196-6.348-8.596-6.348zM5.785 5.991c.642 0 1.162.529 1.162 1.18a1.17 1.17 0 01-1.162 1.178A1.17 1.17 0 014.623 7.17c0-.651.52-1.18 1.162-1.18zm5.813 0c.642 0 1.162.529 1.162 1.18a1.17 1.17 0 01-1.162 1.178 1.17 1.17 0 01-1.162-1.178c0-.651.52-1.18 1.162-1.18zm3.68 4.025c-3.694 0-6.69 2.462-6.69 5.496 0 3.034 2.996 5.496 6.69 5.496.753 0 1.477-.1 2.158-.28a.66.66 0 01.548.074l1.46.854a.25.25 0 00.127.041.224.224 0 00.221-.225c0-.055-.022-.109-.037-.162l-.298-1.131a.453.453 0 01.163-.509C21.81 18.613 22.77 16.973 22.77 15.512c0-3.034-2.996-5.496-6.69-5.496h.198zm-2.454 3.347c.491 0 .889.404.889.902a.896.896 0 01-.889.903.896.896 0 01-.889-.903c0-.498.398-.902.889-.902zm4.912 0c.491 0 .889.404.889.902a.896.896 0 01-.889.903.896.896 0 01-.889-.903c0-.498.398-.902.889-.902z"/></svg>',
286
+ primaryCred: "WECOM_BOT_ID",
287
+ envFields: [
288
+ { key: "WECOM_BOT_ID", label: "Bot ID", hint: "WeCom Bot identifier" },
289
+ { key: "WECOM_SECRET", label: "Secret", hint: "WeCom application secret", password: true }
290
+ ],
291
+ configFields: []
292
+ }
293
+ ];
294
+ function SaveStatus({ saving, saved }) {
295
+ if (saving) return /* @__PURE__ */ jsxRuntimeExports.jsx(IconLoader2, { className: "size-3 animate-spin text-muted-foreground" });
296
+ if (saved) return /* @__PURE__ */ jsxRuntimeExports.jsx(IconCheck, { className: "size-3 text-emerald-500" });
297
+ return null;
298
+ }
299
+ function ChannelsPage() {
300
+ const queryClient = useQueryClient();
301
+ const { data: config, isLoading: configLoading } = useQuery({
302
+ queryKey: ["config"],
303
+ queryFn: fetchConfig,
304
+ staleTime: 3e4
305
+ });
306
+ const { data: envVars, isLoading: envLoading } = useQuery({
307
+ queryKey: ["env-vars"],
308
+ queryFn: fetchEnvVars,
309
+ staleTime: 3e4
310
+ });
311
+ const [localEnv, setLocalEnv] = reactExports.useState({});
312
+ const [localConfig, setLocalConfig] = reactExports.useState({});
313
+ const [savingKeys, setSavingKeys] = reactExports.useState(/* @__PURE__ */ new Set());
314
+ const [savedKeys, setSavedKeys] = reactExports.useState(/* @__PURE__ */ new Set());
315
+ const markSaving = reactExports.useCallback((key) => {
316
+ setSavingKeys((prev) => new Set(prev).add(key));
317
+ setSavedKeys((prev) => {
318
+ const next = new Set(prev);
319
+ next.delete(key);
320
+ return next;
321
+ });
322
+ }, []);
323
+ const markSaved = reactExports.useCallback((key) => {
324
+ setSavingKeys((prev) => {
325
+ const next = new Set(prev);
326
+ next.delete(key);
327
+ return next;
328
+ });
329
+ setSavedKeys((prev) => new Set(prev).add(key));
330
+ setTimeout(() => {
331
+ setSavedKeys((prev) => {
332
+ const next = new Set(prev);
333
+ next.delete(key);
334
+ return next;
335
+ });
336
+ }, 2e3);
337
+ }, []);
338
+ const saveConfigMutation = useMutation({
339
+ mutationFn: async (nextConfig) => {
340
+ await updateConfig(nextConfig);
341
+ },
342
+ onSuccess: () => {
343
+ queryClient.invalidateQueries({ queryKey: ["config"] });
344
+ }
345
+ });
346
+ const saveEnvMutation = useMutation({
347
+ mutationFn: async ({ key, value }) => {
348
+ await updateEnvVar(key, value);
349
+ },
350
+ onSuccess: () => {
351
+ queryClient.invalidateQueries({ queryKey: ["env-vars"] });
352
+ }
353
+ });
354
+ const updateLocalConfig = reactExports.useCallback((platform, key, value) => {
355
+ setLocalConfig((prev) => ({
356
+ ...prev,
357
+ [platform]: { ...prev[platform] || {}, [key]: value }
358
+ }));
359
+ }, []);
360
+ const flushConfig = reactExports.useCallback(
361
+ (platform, key) => {
362
+ const saveKey = `cfg.${platform}.${key}`;
363
+ const currentConfig = queryClient.getQueryData(["config"]) || {};
364
+ const currentPlatform = currentConfig[platform] || {};
365
+ const localValue = localConfig[platform]?.[key];
366
+ if (localValue === void 0) return;
367
+ const nextPlatform = { ...currentPlatform, [key]: localValue };
368
+ const nextConfig = { ...currentConfig, [platform]: nextPlatform };
369
+ markSaving(saveKey);
370
+ saveConfigMutation.mutate(nextConfig, {
371
+ onSuccess: () => markSaved(saveKey),
372
+ onError: () => {
373
+ setSavingKeys((prev) => {
374
+ const next = new Set(prev);
375
+ next.delete(saveKey);
376
+ return next;
377
+ });
378
+ }
379
+ });
380
+ },
381
+ [localConfig, queryClient, saveConfigMutation, markSaving, markSaved]
382
+ );
383
+ const handleUpdateConfig = reactExports.useCallback(
384
+ (platform, key, value) => {
385
+ updateLocalConfig(platform, key, value);
386
+ flushConfig(platform, key);
387
+ },
388
+ [updateLocalConfig, flushConfig]
389
+ );
390
+ const handleSaveEnv = reactExports.useCallback(
391
+ (key) => {
392
+ const value = localEnv[key];
393
+ if (value === void 0) return;
394
+ const saveKey = `env.${key}`;
395
+ markSaving(saveKey);
396
+ saveEnvMutation.mutate(
397
+ { key, value },
398
+ {
399
+ onSuccess: () => markSaved(saveKey),
400
+ onError: () => {
401
+ setSavingKeys((prev) => {
402
+ const next = new Set(prev);
403
+ next.delete(saveKey);
404
+ return next;
405
+ });
406
+ }
407
+ }
408
+ );
409
+ },
410
+ [localEnv, saveEnvMutation, markSaving, markSaved]
411
+ );
412
+ const getConfigValue = reactExports.useCallback(
413
+ (platform, key) => {
414
+ return localConfig[platform]?.[key] ?? config?.[platform]?.[key];
415
+ },
416
+ [localConfig, config]
417
+ );
418
+ const isSaving = (key) => savingKeys.has(key);
419
+ const isSaved = (key) => savedKeys.has(key);
420
+ if (configLoading || envLoading) {
421
+ return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex items-center justify-center h-64", children: /* @__PURE__ */ jsxRuntimeExports.jsx(IconLoader2, { className: "size-5 animate-spin text-muted-foreground" }) });
422
+ }
423
+ const envMap = envVars || {};
424
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-1 flex-col h-full overflow-hidden", children: [
425
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "shrink-0 border-b px-6 py-4", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2.5", children: [
426
+ /* @__PURE__ */ jsxRuntimeExports.jsx(IconSparkles, { className: "size-5 text-muted-foreground" }),
427
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
428
+ /* @__PURE__ */ jsxRuntimeExports.jsx("h1", { className: "text-base font-semibold text-foreground", children: "Channels" }),
429
+ /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-[12px] text-muted-foreground mt-0.5", children: "Connect messaging platforms so Hermium can respond on Telegram, Discord, Slack, and more." })
430
+ ] })
431
+ ] }) }),
432
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex-1 overflow-y-auto", children: /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "p-6", children: /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "grid grid-cols-1 md:grid-cols-2 xl:grid-cols-3 gap-4", children: PLATFORMS.map((p) => {
433
+ const primaryVar = envMap[p.primaryCred];
434
+ const hasCreds = primaryVar?.is_set ?? false;
435
+ const platformConfig = config?.[p.key] || {};
436
+ const configured = hasCreds || Object.keys(platformConfig).length > 0;
437
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs(
438
+ PlatformCard,
439
+ {
440
+ name: p.name,
441
+ icon: p.icon,
442
+ color: p.color,
443
+ configured,
444
+ hasCreds,
445
+ exclusive: p.exclusive,
446
+ children: [
447
+ p.envFields.map((field) => {
448
+ const envInfo = envMap[field.key];
449
+ const isSet = envInfo?.is_set ?? false;
450
+ const saveKey = `env.${field.key}`;
451
+ const currentValue = localEnv[field.key] ?? "";
452
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(SettingRow, { label: field.label, hint: field.hint, children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2", children: [
453
+ field.type === "select" && field.options ? /* @__PURE__ */ jsxRuntimeExports.jsxs(
454
+ "select",
455
+ {
456
+ className: "w-[220px] h-8 text-xs rounded-md border border-input bg-background px-2",
457
+ value: currentValue || String(getConfigValue(p.key, field.key) ?? ""),
458
+ onChange: (e) => {
459
+ setLocalEnv((prev) => ({ ...prev, [field.key]: e.target.value }));
460
+ handleSaveEnv(field.key);
461
+ },
462
+ children: [
463
+ /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "", children: "— Select —" }),
464
+ field.options.map((opt) => /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: opt, children: opt }, opt))
465
+ ]
466
+ }
467
+ ) : /* @__PURE__ */ jsxRuntimeExports.jsx(
468
+ Input,
469
+ {
470
+ className: "w-[220px] h-8 text-xs font-mono",
471
+ type: field.password ? "password" : "text",
472
+ placeholder: isSet ? "Already set (enter to overwrite)" : field.hint,
473
+ value: currentValue,
474
+ onChange: (e) => setLocalEnv((prev) => ({ ...prev, [field.key]: e.target.value })),
475
+ onBlur: () => handleSaveEnv(field.key)
476
+ }
477
+ ),
478
+ /* @__PURE__ */ jsxRuntimeExports.jsx(SaveStatus, { saving: isSaving(saveKey), saved: isSaved(saveKey) })
479
+ ] }) }, field.key);
480
+ }),
481
+ p.configFields.map((field) => {
482
+ const saveKey = `cfg.${p.key}.${field.key}`;
483
+ const value = getConfigValue(p.key, field.key);
484
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(SettingRow, { label: field.label, hint: field.hint, children: field.type === "switch" ? /* @__PURE__ */ jsxRuntimeExports.jsx(
485
+ Switch,
486
+ {
487
+ checked: !!value,
488
+ onCheckedChange: (v) => handleUpdateConfig(p.key, field.key, v)
489
+ }
490
+ ) : /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2", children: [
491
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
492
+ Input,
493
+ {
494
+ className: "w-[220px] h-8 text-xs",
495
+ value: String(value ?? ""),
496
+ onChange: (e) => updateLocalConfig(p.key, field.key, e.target.value),
497
+ onBlur: () => flushConfig(p.key, field.key)
498
+ }
499
+ ),
500
+ /* @__PURE__ */ jsxRuntimeExports.jsx(SaveStatus, { saving: isSaving(saveKey), saved: isSaved(saveKey) })
501
+ ] }) }, field.key);
502
+ })
503
+ ]
504
+ },
505
+ p.key
506
+ );
507
+ }) }) }) })
508
+ ] });
509
+ }
510
+ const SplitComponent = ChannelsPage;
511
+ export {
512
+ SplitComponent as component
513
+ };