@xopcai/xopc 0.0.53 → 0.0.54

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 (162) hide show
  1. package/dist/extensions/dingtalk/src/plugin.js +1 -1
  2. package/dist/extensions/feishu/src/outbound/media-load.js +1 -1
  3. package/dist/extensions/telegram/src/plugin.js +1 -1
  4. package/dist/extensions/telegram/src/routing-integration.js +2 -2
  5. package/dist/extensions/telegram/xopc.extension.json +1 -1
  6. package/dist/extensions/weixin/src/api/api.js +2 -2
  7. package/dist/extensions/weixin/src/auth/accounts.js +1 -1
  8. package/dist/extensions/weixin/src/cdn/upload.js +1 -1
  9. package/dist/extensions/weixin/src/media/data-url.js +1 -1
  10. package/dist/extensions/weixin/src/messaging/debug-mode.js +1 -1
  11. package/dist/extensions/weixin/src/messaging/inbound.js +1 -1
  12. package/dist/extensions/weixin/src/messaging/process-message.js +1 -1
  13. package/dist/extensions/weixin/src/plugin.js +1 -1
  14. package/dist/extensions/weixin/src/storage/sync-buf.js +1 -1
  15. package/dist/gateway/static/root/assets/{agents-Dk8idifM.js → agents-Cccit5xQ.js} +2 -2
  16. package/dist/gateway/static/root/assets/{agents-Dk8idifM.js.map → agents-Cccit5xQ.js.map} +1 -1
  17. package/dist/gateway/static/root/assets/{apps-page-C4_ekFnF.js → apps-page-JMpsr3yK.js} +2 -2
  18. package/dist/gateway/static/root/assets/{apps-page-C4_ekFnF.js.map → apps-page-JMpsr3yK.js.map} +1 -1
  19. package/dist/gateway/static/root/assets/{channels-settings-BoRUNSby.js → channels-settings-jJX9xOyE.js} +2 -2
  20. package/dist/gateway/static/root/assets/{channels-settings-BoRUNSby.js.map → channels-settings-jJX9xOyE.js.map} +1 -1
  21. package/dist/gateway/static/root/assets/{cron-dreaming-jobs-DjK4YEV9.js → cron-dreaming-jobs-DousYqF2.js} +2 -2
  22. package/dist/gateway/static/root/assets/{cron-dreaming-jobs-DjK4YEV9.js.map → cron-dreaming-jobs-DousYqF2.js.map} +1 -1
  23. package/dist/gateway/static/root/assets/{cron-page-wQAlt7WL.js → cron-page-CdYb690n.js} +2 -2
  24. package/dist/gateway/static/root/assets/{cron-page-wQAlt7WL.js.map → cron-page-CdYb690n.js.map} +1 -1
  25. package/dist/gateway/static/root/assets/{dist-DfWs1l6V.js → dist-D8QibYZR.js} +2 -2
  26. package/dist/gateway/static/root/assets/{dist-DfWs1l6V.js.map → dist-D8QibYZR.js.map} +1 -1
  27. package/dist/gateway/static/root/assets/{extension-debug-page-DKpIM74M.js → extension-debug-page-DJ-puhUh.js} +2 -2
  28. package/dist/gateway/static/root/assets/{extension-debug-page-DKpIM74M.js.map → extension-debug-page-DJ-puhUh.js.map} +1 -1
  29. package/dist/gateway/static/root/assets/{extension-page-DR980mtQ.js → extension-page-DgDGH7uc.js} +2 -2
  30. package/dist/gateway/static/root/assets/{extension-page-DR980mtQ.js.map → extension-page-DgDGH7uc.js.map} +1 -1
  31. package/dist/gateway/static/root/assets/{extension-settings-page-CZWcC3OA.js → extension-settings-page-BnQ2f4Fq.js} +2 -2
  32. package/dist/gateway/static/root/assets/{extension-settings-page-CZWcC3OA.js.map → extension-settings-page-BnQ2f4Fq.js.map} +1 -1
  33. package/dist/gateway/static/root/assets/{heartbeat-config-api-D4vLbsOG.js → heartbeat-config-api-B9hxMalj.js} +2 -2
  34. package/dist/gateway/static/root/assets/{heartbeat-config-api-D4vLbsOG.js.map → heartbeat-config-api-B9hxMalj.js.map} +1 -1
  35. package/dist/gateway/static/root/assets/{index-DZLKmP08.js → index-8IFT6i7x.js} +4 -4
  36. package/dist/gateway/static/root/assets/{index-DZLKmP08.js.map → index-8IFT6i7x.js.map} +1 -1
  37. package/dist/gateway/static/root/assets/{logs-page-f_viqgaf.js → logs-page-DNHn8mTk.js} +2 -2
  38. package/dist/gateway/static/root/assets/{logs-page-f_viqgaf.js.map → logs-page-DNHn8mTk.js.map} +1 -1
  39. package/dist/gateway/static/root/assets/{sessions-page-DW2-c8fv.js → sessions-page-D3kE1tob.js} +2 -2
  40. package/dist/gateway/static/root/assets/{sessions-page-DW2-c8fv.js.map → sessions-page-D3kE1tob.js.map} +1 -1
  41. package/dist/gateway/static/root/assets/{settings-page-D7-piKSc.js → settings-page-B4tuVOtd.js} +2 -2
  42. package/dist/gateway/static/root/assets/{settings-page-D7-piKSc.js.map → settings-page-B4tuVOtd.js.map} +1 -1
  43. package/dist/gateway/static/root/assets/{skills-page-ChpOJZM1.js → skills-page-Dgd20nUt.js} +2 -2
  44. package/dist/gateway/static/root/assets/{skills-page-ChpOJZM1.js.map → skills-page-Dgd20nUt.js.map} +1 -1
  45. package/dist/gateway/static/root/assets/{use-image-provider-credentials-131rA-SV.js → use-image-provider-credentials-CqMkyIiU.js} +2 -2
  46. package/dist/gateway/static/root/assets/{use-image-provider-credentials-131rA-SV.js.map → use-image-provider-credentials-CqMkyIiU.js.map} +1 -1
  47. package/dist/gateway/static/root/index.html +1 -1
  48. package/dist/package.js +1 -1
  49. package/dist/src/agent/agent-manager.js +6 -6
  50. package/dist/src/agent/context/workspace-seed.js +2 -2
  51. package/dist/src/agent/goals/post-turn.js +1 -1
  52. package/dist/src/agent/image/load-image-media.js +1 -1
  53. package/dist/src/agent/ipc/bus.js +1 -1
  54. package/dist/src/agent/ipc/inbox.js +2 -2
  55. package/dist/src/agent/ipc/socket.js +1 -1
  56. package/dist/src/agent/memory/builtin-memory-store.js +1 -1
  57. package/dist/src/agent/memory/dreaming/deep-promotion.js +1 -1
  58. package/dist/src/agent/memory/dreaming/events.js +1 -1
  59. package/dist/src/agent/memory/dreaming/last-run.js +1 -1
  60. package/dist/src/agent/memory/dreaming/light-sweep.js +1 -1
  61. package/dist/src/agent/memory/dreaming/preview.js +1 -1
  62. package/dist/src/agent/memory/dreaming/rem-patterns.js +1 -1
  63. package/dist/src/agent/memory/dreaming/short-term-store.js +1 -1
  64. package/dist/src/agent/memory/dreaming/utils.js +1 -1
  65. package/dist/src/agent/memory/plugin-discovery.js +1 -1
  66. package/dist/src/agent/models/manager.js +1 -1
  67. package/dist/src/agent/prompt/service-prompt-builder.js +2 -2
  68. package/dist/src/agent/service.js +5 -5
  69. package/dist/src/agent/skills/config.js +1 -1
  70. package/dist/src/agent/skills/hub-hash.js +2 -2
  71. package/dist/src/agent/skills/hub-lock.js +1 -1
  72. package/dist/src/agent/skills/hub-pull.js +1 -1
  73. package/dist/src/agent/skills/index.js +1 -1
  74. package/dist/src/agent/skills/managed-store.js +1 -1
  75. package/dist/src/agent/skills/scanner.js +1 -1
  76. package/dist/src/agent/skills/skill-manage-ops.js +1 -1
  77. package/dist/src/agent/skills/skill-manager.js +1 -1
  78. package/dist/src/agent/tools/dreaming-tool.js +1 -1
  79. package/dist/src/agent/tools/factory.js +1 -1
  80. package/dist/src/agent/tools/image-generate-tool.js +1 -1
  81. package/dist/src/agent/tools/send-media.js +1 -1
  82. package/dist/src/agent/tools/skill-manage-tool.js +1 -1
  83. package/dist/src/agent/tools/write.js +1 -1
  84. package/dist/src/auth/credentials.js +3 -3
  85. package/dist/src/auth/profiles/store.js +1 -1
  86. package/dist/src/auth/sync-provider-auth.js +1 -1
  87. package/dist/src/channels/attachments/inbound-persist.js +1 -1
  88. package/dist/src/channels/attachments/outbound-tts-persist.js +1 -1
  89. package/dist/src/channels/outbound/persist-store.js +1 -1
  90. package/dist/src/channels/pairing/allow-from-file.js +1 -1
  91. package/dist/src/channels/pairing/pairing-store.js +2 -2
  92. package/dist/src/chat-commands/builtins/config.js +2 -2
  93. package/dist/src/chat-commands/context.js +1 -1
  94. package/dist/src/cli/commands/agent.js +1 -1
  95. package/dist/src/cli/commands/config.js +1 -1
  96. package/dist/src/cli/commands/doctor/checks/config-health.js +1 -1
  97. package/dist/src/cli/commands/doctor/checks/provider-auth.js +1 -1
  98. package/dist/src/cli/commands/doctor/checks/session-integrity.js +1 -1
  99. package/dist/src/cli/commands/doctor/checks/state-integrity.js +1 -1
  100. package/dist/src/cli/commands/doctor/checks/workspace-status.js +1 -1
  101. package/dist/src/cli/commands/extension-dev.js +1 -1
  102. package/dist/src/cli/commands/extension-marketplace.js +1 -1
  103. package/dist/src/cli/commands/extension-pack.js +1 -1
  104. package/dist/src/cli/commands/image.js +1 -1
  105. package/dist/src/cli/commands/init.js +4 -4
  106. package/dist/src/cli/utils/init-workspace.js +2 -2
  107. package/dist/src/config/index.js +3 -3
  108. package/dist/src/config/loader.js +2 -2
  109. package/dist/src/config/models-json.js +2 -2
  110. package/dist/src/config/profile.js +2 -2
  111. package/dist/src/cron/executor.js +2 -2
  112. package/dist/src/cron/persistence.js +1 -1
  113. package/dist/src/cron/run-log-store.js +1 -1
  114. package/dist/src/daemon/launchd.js +2 -2
  115. package/dist/src/daemon/systemd.js +2 -2
  116. package/dist/src/extensions/health.js +1 -1
  117. package/dist/src/extensions/loader.js +1 -1
  118. package/dist/src/extensions/lockfile.js +2 -2
  119. package/dist/src/gateway/agents-admin.js +2 -2
  120. package/dist/src/gateway/hono/lib/extension-store.js +1 -1
  121. package/dist/src/gateway/hono/lib/static-ui.js +1 -1
  122. package/dist/src/gateway/hono/oauth.js +1 -1
  123. package/dist/src/gateway/hono/routes/auth-registry-extensions.js +1 -1
  124. package/dist/src/gateway/hono/routes/config.js +1 -1
  125. package/dist/src/gateway/hono/routes/dreaming.js +1 -1
  126. package/dist/src/gateway/hono/routes/host-fs.js +1 -1
  127. package/dist/src/gateway/hono/routes/models.js +1 -1
  128. package/dist/src/gateway/hono/routes/workspace.js +3 -3
  129. package/dist/src/gateway/hono/sse.js +2 -2
  130. package/dist/src/gateway/lock.js +2 -2
  131. package/dist/src/gateway/security/csp.d.ts +1 -0
  132. package/dist/src/gateway/security/csp.js +2 -0
  133. package/dist/src/gateway/security/csp.js.map +1 -1
  134. package/dist/src/gateway/service/run-gateway-agent.js +2 -2
  135. package/dist/src/gateway/service.js +5 -5
  136. package/dist/src/gateway/workspace-fs-file-list.js +1 -1
  137. package/dist/src/gateway/workspace-heartbeat-path.js +1 -1
  138. package/dist/src/infra/update-check.js +1 -1
  139. package/dist/src/infra/update-lock.js +3 -3
  140. package/dist/src/infra/update-runner.js +1 -1
  141. package/dist/src/infra/update-startup.js +2 -2
  142. package/dist/src/infra/write-file-atomic.js +2 -2
  143. package/dist/src/providers/auth-runtime/auth-profile-store.js +1 -1
  144. package/dist/src/providers/index.js +2 -2
  145. package/dist/src/providers/model-registry.js +1 -1
  146. package/dist/src/session/config-store.js +2 -2
  147. package/dist/src/session/parity/jsonl-transcript-io.js +2 -2
  148. package/dist/src/session/parity/sessions-json-file.js +1 -1
  149. package/dist/src/session/parity/transcript-file-lock.js +2 -2
  150. package/dist/src/session/parity/transcript-paths.js +1 -1
  151. package/dist/src/session/search-index-cache.js +1 -1
  152. package/dist/src/session/search-index.js +1 -1
  153. package/dist/src/session/session-title.js +1 -1
  154. package/dist/src/session/store.js +4 -4
  155. package/dist/src/tui/backends/embedded-backend.js +1 -1
  156. package/dist/src/tui/tui.js +1 -1
  157. package/dist/src/utils/logger/audit.js +1 -1
  158. package/dist/src/utils/logger/log-store.js +1 -1
  159. package/dist/src/utils/logger/rotation.js +1 -1
  160. package/dist/src/voice/tts/audio.js +1 -1
  161. package/dist/src/voice/tts/providers/edge-speech.js +1 -1
  162. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"extension-page-DR980mtQ.js","names":[],"sources":["../../../../../web/src/features/extensions/extension-page.tsx"],"sourcesContent":["/**\n * ExtensionPage — renders a full-page extension UI via ExtensionIframeHost.\n *\n * Mounted at /apps/:extensionId (or /apps/:extensionId/:pageId for multi-page extensions).\n */\n\nimport { useLayoutEffect } from 'react';\nimport { useParams } from 'react-router-dom';\n\nimport { usePageHeaderStore } from '@/stores/page-header-store';\n\nimport { ExtensionIframeHost } from './extension-iframe-host';\nimport { extensionShellUiReachable, useExtensions } from './extension-provider';\n\nexport function ExtensionPage() {\n const { extensionId, pageId } = useParams<{ extensionId: string; pageId?: string }>();\n const extensions = useExtensions();\n const setPageHeader = usePageHeaderStore((s) => s.setPageHeader);\n const clearPageHeader = usePageHeaderStore((s) => s.clearPageHeader);\n\n const extension = extensionId\n ? extensions.find((ext) => ext.id === extensionId && extensionShellUiReachable(ext))\n : undefined;\n const pages = extension?.ui?.contributions?.pages;\n const page =\n extensionId && pages?.length\n ? pageId\n ? pages.find((p) => p.id === pageId || p.id === `${extensionId}.${pageId}`)\n : pages[0]\n : undefined;\n\n useLayoutEffect(() => {\n if (!extensionId || !extension || !page) {\n clearPageHeader();\n return () => clearPageHeader();\n }\n const headline = page.title?.trim() || extension.name || extensionId;\n setPageHeader({\n startExtra: null,\n main: (\n <div className=\"w-full min-w-0 px-3 sm:px-5 xl:px-6\">\n <h1\n className=\"min-w-0 truncate text-base font-semibold tracking-tight text-fg\"\n title={headline}\n >\n {headline}\n </h1>\n </div>\n ),\n end: null,\n });\n return () => clearPageHeader();\n }, [clearPageHeader, extension, extensionId, page, setPageHeader]);\n\n if (!extensionId) {\n return <ExtensionPageNotFound message=\"No extension ID provided.\" />;\n }\n\n if (!extension) {\n return (\n <ExtensionPageNotFound message={`Extension \"${extensionId}\" not found or has no UI.`} />\n );\n }\n\n if (!pages?.length) {\n return (\n <ExtensionPageNotFound message={`Extension \"${extensionId}\" has no page contributions.`} />\n );\n }\n\n if (!page) {\n return (\n <ExtensionPageNotFound message={`Page \"${pageId}\" not found in extension \"${extensionId}\".`} />\n );\n }\n\n return (\n <div className=\"flex min-h-0 flex-1 flex-col\">\n <ExtensionIframeHost\n extensionId={extensionId}\n extensionName={extension.name}\n entrypoint={page.entrypoint}\n permissions={extension.ui?.permissions}\n title={page.title}\n className=\"min-h-0 flex-1\"\n fixedHeight={undefined}\n maxHeight={99999}\n />\n </div>\n );\n}\n\nfunction ExtensionPageNotFound({ message }: { message: string }) {\n return (\n <div className=\"flex min-h-[min(40vh,16rem)] flex-1 items-center justify-center\">\n <div className=\"text-center\">\n <p className=\"text-sm text-fg-muted\">{message}</p>\n </div>\n </div>\n );\n}\n"],"mappings":"sMAcA,SAAgB,GAAgB,CAC9B,GAAM,CAAE,cAAa,UAAW,GAAqD,CAC/E,EAAa,GAAe,CAC5B,EAAgB,EAAoB,GAAM,EAAE,cAAc,CAC1D,EAAkB,EAAoB,GAAM,EAAE,gBAAgB,CAE9D,EAAY,EACd,EAAW,KAAM,GAAQ,EAAI,KAAO,GAAe,EAA0B,EAAI,CAAC,CAClF,IAAA,GACE,EAAQ,GAAW,IAAI,eAAe,MACtC,EACJ,GAAe,GAAO,OAClB,EACE,EAAM,KAAM,GAAM,EAAE,KAAO,GAAU,EAAE,KAAO,GAAG,EAAY,GAAG,IAAS,CACzE,EAAM,GACR,IAAA,GA+CN,OA7CA,EAAA,EAAA,qBAAsB,CACpB,GAAI,CAAC,GAAe,CAAC,GAAa,CAAC,EAEjC,OADA,GAAiB,KACJ,GAAiB,CAEhC,IAAM,EAAW,EAAK,OAAO,MAAM,EAAI,EAAU,MAAQ,EAezD,OAdA,EAAc,CACZ,WAAY,KACZ,MACE,EAAA,EAAA,KAAC,MAAD,CAAK,UAAU,gDACb,EAAA,EAAA,KAAC,KAAD,CACE,UAAU,kEACV,MAAO,WAEN,EACE,CAAA,CACD,CAAA,CAER,IAAK,KACN,CAAC,KACW,GAAiB,EAC7B,CAAC,EAAiB,EAAW,EAAa,EAAM,EAAc,CAAC,CAE7D,EAIA,EAMA,GAAO,OAMP,GAOH,EAAA,EAAA,KAAC,MAAD,CAAK,UAAU,yCACb,EAAA,EAAA,KAAC,EAAD,CACe,cACb,cAAe,EAAU,KACzB,WAAY,EAAK,WACjB,YAAa,EAAU,IAAI,YAC3B,MAAO,EAAK,MACZ,UAAU,iBACV,YAAa,IAAA,GACb,UAAW,MACX,CAAA,CACE,CAAA,EAhBJ,EAAA,EAAA,KAAC,EAAD,CAAuB,QAAS,SAAS,EAAO,4BAA4B,EAAY,IAAO,CAAA,EAN/F,EAAA,EAAA,KAAC,EAAD,CAAuB,QAAS,cAAc,EAAY,8BAAiC,CAAA,EAN3F,EAAA,EAAA,KAAC,EAAD,CAAuB,QAAS,cAAc,EAAY,2BAA8B,CAAA,EALnF,EAAA,EAAA,KAAC,EAAD,CAAuB,QAAQ,4BAA8B,CAAA,CAqCxE,SAAS,EAAsB,CAAE,WAAgC,CAC/D,OACE,EAAA,EAAA,KAAC,MAAD,CAAK,UAAU,4EACb,EAAA,EAAA,KAAC,MAAD,CAAK,UAAU,wBACb,EAAA,EAAA,KAAC,IAAD,CAAG,UAAU,iCAAyB,EAAY,CAAA,CAC9C,CAAA,CACF,CAAA"}
1
+ {"version":3,"file":"extension-page-DgDGH7uc.js","names":[],"sources":["../../../../../web/src/features/extensions/extension-page.tsx"],"sourcesContent":["/**\n * ExtensionPage — renders a full-page extension UI via ExtensionIframeHost.\n *\n * Mounted at /apps/:extensionId (or /apps/:extensionId/:pageId for multi-page extensions).\n */\n\nimport { useLayoutEffect } from 'react';\nimport { useParams } from 'react-router-dom';\n\nimport { usePageHeaderStore } from '@/stores/page-header-store';\n\nimport { ExtensionIframeHost } from './extension-iframe-host';\nimport { extensionShellUiReachable, useExtensions } from './extension-provider';\n\nexport function ExtensionPage() {\n const { extensionId, pageId } = useParams<{ extensionId: string; pageId?: string }>();\n const extensions = useExtensions();\n const setPageHeader = usePageHeaderStore((s) => s.setPageHeader);\n const clearPageHeader = usePageHeaderStore((s) => s.clearPageHeader);\n\n const extension = extensionId\n ? extensions.find((ext) => ext.id === extensionId && extensionShellUiReachable(ext))\n : undefined;\n const pages = extension?.ui?.contributions?.pages;\n const page =\n extensionId && pages?.length\n ? pageId\n ? pages.find((p) => p.id === pageId || p.id === `${extensionId}.${pageId}`)\n : pages[0]\n : undefined;\n\n useLayoutEffect(() => {\n if (!extensionId || !extension || !page) {\n clearPageHeader();\n return () => clearPageHeader();\n }\n const headline = page.title?.trim() || extension.name || extensionId;\n setPageHeader({\n startExtra: null,\n main: (\n <div className=\"w-full min-w-0 px-3 sm:px-5 xl:px-6\">\n <h1\n className=\"min-w-0 truncate text-base font-semibold tracking-tight text-fg\"\n title={headline}\n >\n {headline}\n </h1>\n </div>\n ),\n end: null,\n });\n return () => clearPageHeader();\n }, [clearPageHeader, extension, extensionId, page, setPageHeader]);\n\n if (!extensionId) {\n return <ExtensionPageNotFound message=\"No extension ID provided.\" />;\n }\n\n if (!extension) {\n return (\n <ExtensionPageNotFound message={`Extension \"${extensionId}\" not found or has no UI.`} />\n );\n }\n\n if (!pages?.length) {\n return (\n <ExtensionPageNotFound message={`Extension \"${extensionId}\" has no page contributions.`} />\n );\n }\n\n if (!page) {\n return (\n <ExtensionPageNotFound message={`Page \"${pageId}\" not found in extension \"${extensionId}\".`} />\n );\n }\n\n return (\n <div className=\"flex min-h-0 flex-1 flex-col\">\n <ExtensionIframeHost\n extensionId={extensionId}\n extensionName={extension.name}\n entrypoint={page.entrypoint}\n permissions={extension.ui?.permissions}\n title={page.title}\n className=\"min-h-0 flex-1\"\n fixedHeight={undefined}\n maxHeight={99999}\n />\n </div>\n );\n}\n\nfunction ExtensionPageNotFound({ message }: { message: string }) {\n return (\n <div className=\"flex min-h-[min(40vh,16rem)] flex-1 items-center justify-center\">\n <div className=\"text-center\">\n <p className=\"text-sm text-fg-muted\">{message}</p>\n </div>\n </div>\n );\n}\n"],"mappings":"sMAcA,SAAgB,GAAgB,CAC9B,GAAM,CAAE,cAAa,UAAW,GAAqD,CAC/E,EAAa,GAAe,CAC5B,EAAgB,EAAoB,GAAM,EAAE,cAAc,CAC1D,EAAkB,EAAoB,GAAM,EAAE,gBAAgB,CAE9D,EAAY,EACd,EAAW,KAAM,GAAQ,EAAI,KAAO,GAAe,EAA0B,EAAI,CAAC,CAClF,IAAA,GACE,EAAQ,GAAW,IAAI,eAAe,MACtC,EACJ,GAAe,GAAO,OAClB,EACE,EAAM,KAAM,GAAM,EAAE,KAAO,GAAU,EAAE,KAAO,GAAG,EAAY,GAAG,IAAS,CACzE,EAAM,GACR,IAAA,GA+CN,OA7CA,EAAA,EAAA,qBAAsB,CACpB,GAAI,CAAC,GAAe,CAAC,GAAa,CAAC,EAEjC,OADA,GAAiB,KACJ,GAAiB,CAEhC,IAAM,EAAW,EAAK,OAAO,MAAM,EAAI,EAAU,MAAQ,EAezD,OAdA,EAAc,CACZ,WAAY,KACZ,MACE,EAAA,EAAA,KAAC,MAAD,CAAK,UAAU,gDACb,EAAA,EAAA,KAAC,KAAD,CACE,UAAU,kEACV,MAAO,WAEN,EACE,CAAA,CACD,CAAA,CAER,IAAK,KACN,CAAC,KACW,GAAiB,EAC7B,CAAC,EAAiB,EAAW,EAAa,EAAM,EAAc,CAAC,CAE7D,EAIA,EAMA,GAAO,OAMP,GAOH,EAAA,EAAA,KAAC,MAAD,CAAK,UAAU,yCACb,EAAA,EAAA,KAAC,EAAD,CACe,cACb,cAAe,EAAU,KACzB,WAAY,EAAK,WACjB,YAAa,EAAU,IAAI,YAC3B,MAAO,EAAK,MACZ,UAAU,iBACV,YAAa,IAAA,GACb,UAAW,MACX,CAAA,CACE,CAAA,EAhBJ,EAAA,EAAA,KAAC,EAAD,CAAuB,QAAS,SAAS,EAAO,4BAA4B,EAAY,IAAO,CAAA,EAN/F,EAAA,EAAA,KAAC,EAAD,CAAuB,QAAS,cAAc,EAAY,8BAAiC,CAAA,EAN3F,EAAA,EAAA,KAAC,EAAD,CAAuB,QAAS,cAAc,EAAY,2BAA8B,CAAA,EALnF,EAAA,EAAA,KAAC,EAAD,CAAuB,QAAQ,4BAA8B,CAAA,CAqCxE,SAAS,EAAsB,CAAE,WAAgC,CAC/D,OACE,EAAA,EAAA,KAAC,MAAD,CAAK,UAAU,4EACb,EAAA,EAAA,KAAC,MAAD,CAAK,UAAU,wBACb,EAAA,EAAA,KAAC,IAAD,CAAG,UAAU,iCAAyB,EAAY,CAAA,CAC9C,CAAA,CACF,CAAA"}
@@ -1,2 +1,2 @@
1
- import{i as e}from"./rolldown-runtime-DWdDZTNf.js";import{i as t,t as n}from"./vendor-react-DbimaAId.js";import{i as r}from"./vendor-swr-B5fPo7KK.js";import{Ai as i,An as a,Ar as o,Ei as s,In as c,Sn as l,_n as u,cn as d,hn as f,jn as p,mn as m,n as h,un as g}from"./index-DZLKmP08.js";import{i as _,n as v,r as y,t as b}from"./use-image-provider-credentials-131rA-SV.js";var x=e(t(),1),S=n(),C=()=>g(_);function w(e){return{credentialsIntro:e.credentialsIntro,regionHint:e.regionHint,endpointPresetsHint:e.endpointPresetsHint,apiKeyLabel:e.apiKeyLabel,optionalPlaceholder:e.optionalPlaceholder,regionLabel:e.regionLabel,baseUrlLabel:e.baseUrlLabel,imageBaseUrlLabel:e.imageBaseUrlLabel,saveCredentials:e.saveCredentials,savingCredentials:e.savingCredentials,credentialsSaved:e.credentialsSaved,discardCredentials:e.discardCredentials,credentialsNothingToSave:e.credentialsNothingToSave,credentialsSaveError:e.credentialsSaveError,regionPresetDefault:e.regionPresetDefault,regionPresetCustom:e.regionPresetCustom,baseUrlPresetDefault:e.baseUrlPresetDefault,baseUrlPresetCustom:e.baseUrlPresetCustom,openExtensionSettings:e.openExtensionSettings,openImageModelsPage:e.openImageModelsPage,extensionSettingsLinkTitle:e.extensionSettingsLinkTitle,imageModelsLinkTitle:e.imageModelsLinkTitle,configured:e.configured,missingKey:e.missingKey,defaultModel:e.defaultModel,modelsLabel:e.modelsLabel,imageBaseUrlPresetHint:e.imageBaseUrlPresetHint,dashscopeRegion_beijing:e.dashscopeRegion_beijing,dashscopeRegion_singapore:e.dashscopeRegion_singapore,dashscopeRegion_us:e.dashscopeRegion_us,apiKeyMaskedHelp:e.apiKeyMaskedHelp,apiKeyCopy:e.apiKeyCopy,apiKeyCopied:e.apiKeyCopied,apiKeyShow:e.apiKeyShow,apiKeyHide:e.apiKeyHide,apiKeyNotInConfigFile:e.apiKeyNotInConfigFile,apiKeyRevealFailed:e.apiKeyRevealFailed,minimaxClusterLabel:e.minimaxClusterLabel,minimaxClusterHint:e.minimaxClusterHint,falQueueBaseLabel:e.falQueueBaseLabel,falQueueBaseHint:e.falQueueBaseHint}}function T({extensionId:e}){let t=l(e=>e.language),n=a(t),i=n.imageModelsSettings,s=u(e=>!!e.token),{data:c=[],isLoading:d}=r(s?C():null,y,{revalidateOnFocus:!1}),f=(0,x.useMemo)(()=>c.filter(t=>t.id===e),[c,e]),p=b(f),m=(0,x.useMemo)(()=>w(i),[i]),h=(0,x.useMemo)(()=>({getApiKey:n.providersSettings.getApiKey,getApiKeyIntl:n.providersSettings.getApiKeyIntl,getApiKeyCn:n.providersSettings.getApiKeyCn}),[n.providersSettings]);return s?d?(0,S.jsxs)(`div`,{className:`flex items-center gap-2 py-6 text-sm text-fg-muted`,children:[(0,S.jsx)(o,{className:`size-4 animate-spin`}),`…`]}):f.length===0?(0,S.jsx)(`p`,{className:`text-sm text-fg-muted`,children:t===`zh`?`网关未注册该图像 Provider,或扩展已被禁用。`:`This image provider is not registered on the gateway, or the extension is disabled.`}):(0,S.jsx)(v,{summaries:f,credDraft:p.credDraft,credDirty:p.credDirty,credSaving:p.credSaving,credError:p.credError,credSavedFlash:p.credSavedFlash,credNoopFlash:p.credNoopFlash,updateCredRow:p.updateCredRow,onDiscardCredentials:p.onDiscardCredentials,onSaveCredentials:()=>void p.saveCredentials(i.credentialsSaveError),extensionIds:new Set,showExtensionLinks:!1,showImageModelsLink:!1,language:t,apiKeyLinkLabels:h,messages:m}):null}function E(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function D(e){let t=e[`x-order`];return typeof t==`number`&&!Number.isNaN(t)?t:999}function O(e){let t=e[`x-group`];return typeof t==`string`&&t.length>0?t:``}function k(e){return e[`x-hidden`]===!0}function A(e){let t=e.properties;if(!E(t))return[];let n=[];for(let[e,r]of Object.entries(t))E(r)&&(k(r)||n.push({key:e,sub:r,order:D(r),group:O(r),hidden:!1}));return n.sort((e,t)=>e.order-t.order||e.key.localeCompare(t.key)),n}function j(e){let t=new Map;for(let n of e){let e=n.group;t.has(e)||t.set(e,[]),t.get(e).push(n)}return t}function M({name:e,s:t,value:n,onChange:r,disabled:i}){let a=typeof t.description==`string`?t.description:void 0,o=(typeof t[`x-placeholder`]==`string`?t[`x-placeholder`]:null)||a,s=t.format;return Array.isArray(t.enum)&&t.enum.every(e=>typeof e==`string`)?(0,S.jsxs)(`div`,{className:`flex flex-col gap-1.5`,children:[a?(0,S.jsx)(`label`,{className:`text-xs text-fg-muted`,children:a}):null,(0,S.jsx)(`select`,{name:e,className:`ui-input h-9 rounded-md border border-edge bg-surface-base px-2 text-sm text-fg`,value:n,disabled:i,onChange:e=>r(e.target.value),children:t.enum.map(e=>(0,S.jsx)(`option`,{value:e,children:e},e))})]}):(0,S.jsxs)(`div`,{className:`flex flex-col gap-1.5`,children:[a?(0,S.jsx)(`label`,{className:`text-xs text-fg-muted`,children:a}):null,(0,S.jsx)(`input`,{name:e,type:s===`password`?`password`:`text`,className:`ui-input h-9 rounded-md border border-edge bg-surface-base px-2.5 text-sm text-fg placeholder:text-fg-muted/70`,value:n,placeholder:o,disabled:i,onChange:e=>r(e.target.value)})]})}function N({s:e,value:t,onChange:n,disabled:r}){let i=typeof e.description==`string`?e.description:void 0;return(0,S.jsxs)(`div`,{className:`flex flex-col gap-1.5`,children:[i?(0,S.jsx)(`label`,{className:`text-xs text-fg-muted`,children:i}):null,(0,S.jsx)(`input`,{type:`number`,className:`ui-input h-9 rounded-md border border-edge bg-surface-base px-2.5 text-sm text-fg`,value:Number.isFinite(t)?t:0,disabled:r,onChange:e=>n(Number(e.target.value))})]})}function P({s:e,value:t,onChange:n,disabled:r}){let i=(typeof e.description==`string`?e.description:void 0)??(typeof e.title==`string`&&e.title.length>0?e.title:`Enable`);return(0,S.jsxs)(`label`,{className:`flex items-center gap-2 text-sm text-fg`,children:[(0,S.jsx)(`input`,{type:`checkbox`,className:`h-4 w-4 rounded border border-edge`,checked:t,disabled:r,onChange:e=>n(e.target.checked)}),(0,S.jsx)(`span`,{children:i})]})}function F({s:e,value:t,onChange:n,disabled:r}){let i=typeof e.description==`string`?e.description:void 0,a=e.items;if(!(E(a)&&a.type===`string`))return(0,S.jsx)(`p`,{className:`text-xs text-fg-muted`,children:`Unsupported array type`});let o=e=>{let r=e.trim();!r||t.includes(r)||n([...t,r])};return(0,S.jsxs)(`div`,{className:`flex flex-col gap-1.5`,children:[i?(0,S.jsx)(`label`,{className:`text-xs text-fg-muted`,children:i}):null,(0,S.jsx)(`div`,{className:`flex flex-wrap gap-1`,children:t.map(e=>(0,S.jsxs)(`span`,{className:`inline-flex items-center gap-1 rounded-md border border-edge bg-surface-panel px-2 py-0.5 text-sm`,children:[e,(0,S.jsx)(`button`,{type:`button`,className:`text-fg-muted hover:text-fg`,disabled:r,onClick:()=>n(t.filter(t=>t!==e)),children:`×`})]},e))}),(0,S.jsx)(`input`,{className:`ui-input h-9 rounded-md border border-edge bg-surface-base px-2.5 text-sm`,disabled:r,placeholder:`Add and press Enter`,onKeyDown:e=>{e.key===`Enter`&&(e.preventDefault(),o(e.target.value),e.target.value=``)}})]})}function I({k:e,sub:t,value:n,onValue:r,disabled:i}){let a=t.type,o=(typeof t.title==`string`&&t.title.length>0?t.title:null)??e;if(a===`boolean`)return(0,S.jsxs)(`div`,{className:`space-y-1.5`,children:[(0,S.jsx)(`p`,{className:`text-sm font-medium text-fg`,children:o}),(0,S.jsx)(P,{s:t,value:n===!0,disabled:i,onChange:e=>r(e)})]});if(a===`number`||a===`integer`)return(0,S.jsxs)(`div`,{className:`space-y-1.5`,children:[(0,S.jsx)(`p`,{className:`text-sm font-medium text-fg`,children:o}),(0,S.jsx)(N,{s:t,value:typeof n==`number`?n:0,disabled:i,onChange:r})]});if(a===`string`)return(0,S.jsxs)(`div`,{className:`space-y-1.5`,children:[(0,S.jsx)(`p`,{className:`text-sm font-medium text-fg`,children:o}),(0,S.jsx)(M,{name:e,s:t,value:typeof n==`string`?n:``,disabled:i,onChange:r})]});if(a===`array`){let e=t.items;if(E(e)&&e.type===`string`)return(0,S.jsxs)(`div`,{className:`space-y-1.5`,children:[(0,S.jsx)(`p`,{className:`text-sm font-medium text-fg`,children:o}),(0,S.jsx)(F,{s:t,value:Array.isArray(n)&&n.every(e=>typeof e==`string`)?n:[],disabled:i,onChange:r})]})}return(0,S.jsxs)(`p`,{className:`text-xs text-fg-muted`,children:[o,`: unsupported field type`,typeof a==`string`?` (${a})`:``]})}function L({schema:e,values:t,onChange:n,disabled:r=!1,className:i}){let a=(0,x.useMemo)(()=>e.type===`object`?A(e):[],[e]),o=(0,x.useMemo)(()=>a.length===0?new Map:j(a),[a]),s=(0,x.useCallback)((e,r)=>{n({...t,[e]:r})},[n,t]);if(e.type!==`object`||!E(e.properties)||a.length===0)return null;let l=Array.from(o.keys()).sort((e,t)=>e===``?-1:t===``?1:e.localeCompare(t));return(0,S.jsx)(`div`,{className:c(`flex flex-col gap-4`,i),children:l.map(e=>{let n=(o.get(e)??[]).map(e=>(0,S.jsx)(I,{k:e.key,sub:e.sub,value:t[e.key],onValue:t=>s(e.key,t),disabled:r},e.key));return e===``?(0,S.jsx)(`div`,{children:n},`default`):(0,S.jsxs)(`details`,{className:`group rounded-lg border border-edge bg-surface-panel/40 open:bg-surface-base`,open:!0,children:[(0,S.jsx)(`summary`,{className:`cursor-pointer select-none px-3 py-2 text-sm font-medium text-fg group-open:rounded-b-none`,children:e}),(0,S.jsx)(`div`,{className:`space-y-4 border-t border-edge p-3`,children:n})]},e)})})}function R(e){let t={};if(e.type!==`object`||!E(e.properties))return t;for(let[n,r]of Object.entries(e.properties))E(r)&&Object.prototype.hasOwnProperty.call(r,`default`)&&(t[n]=r.default);return t}function z({extensionId:e}){let t=a(l(e=>e.language)).agentSettings,n=u(e=>!!e.token),{data:i,error:o}=r(n&&e?`ext-detail-${e}`:null,()=>f(g(`/api/extensions/${encodeURIComponent(e)}`))),{data:s,mutate:c,error:d}=r(n&&e?`ext-cfg-${e}`:null,()=>f(g(`/api/extensions/${encodeURIComponent(e)}/config`))),h=i?.manifest?.configSchema,_=(0,x.useMemo)(()=>h&&h.type===`object`?R(h):{},[h]),v=(0,x.useMemo)(()=>({..._,...s??{}}),[_,s]),[y,b]=(0,x.useState)({}),[C,w]=(0,x.useState)(!1),[T,E]=(0,x.useState)(!1),[D,O]=(0,x.useState)(null),[k,A]=(0,x.useState)(!1);(0,x.useEffect)(()=>{C||b(v)},[C,v]);let j=(0,x.useCallback)(e=>{b(e),w(!0),O(null)},[]),M=(0,x.useCallback)(()=>{b(v),w(!1),O(null)},[v]),N=(0,x.useCallback)(()=>{!h||h.type!==`object`||(b({...R(h)}),w(!0),O(null))},[h]),P=(0,x.useCallback)(async()=>{if(e){E(!0),O(null);try{let t=await m(g(`/api/extensions/${encodeURIComponent(e)}/config`),{method:`PATCH`,body:JSON.stringify(y)});if(!t.ok){let e=await t.json().catch(()=>({}));throw Error(e.error?.message??t.statusText)}await c(y,!1),w(!1),A(!0),window.setTimeout(()=>A(!1),3e3)}catch(e){O(e instanceof Error?e.message:String(e))}finally{E(!1)}}},[e,y,c]);if(!n)return null;if(o||d){let e=o??d;return(0,S.jsxs)(`p`,{className:`text-sm text-fg-muted`,children:[`Could not load extension settings: `,e instanceof Error?e.message:String(e)]})}return!h||h.type!==`object`?null:(0,S.jsxs)(`div`,{className:`mb-6 flex flex-col gap-3 rounded-xl border border-edge bg-surface-base p-4`,children:[(0,S.jsxs)(`div`,{className:`flex flex-wrap items-center justify-between gap-2`,children:[(0,S.jsx)(`h2`,{className:`text-sm font-semibold text-fg`,children:`Configuration`}),(0,S.jsxs)(`div`,{className:`flex flex-wrap items-center gap-2`,children:[k?(0,S.jsx)(`span`,{className:`text-xs text-emerald-600 dark:text-emerald-400`,children:t.saved}):null,D?(0,S.jsx)(`span`,{className:`text-xs text-red-600 dark:text-red-400`,children:D}):null,(0,S.jsx)(p,{type:`button`,variant:`ghost`,className:`h-8 text-xs`,disabled:!C,onClick:M,children:t.discard}),(0,S.jsx)(p,{type:`button`,variant:`ghost`,className:`h-8 text-xs`,onClick:N,children:`Reset to defaults`}),(0,S.jsx)(p,{type:`button`,variant:`primary`,className:`h-8 text-xs`,disabled:!C||T,onClick:()=>void P(),children:T?t.saving:t.save})]})]}),(0,S.jsx)(L,{schema:h,values:y,onChange:j,disabled:T})]})}function B(){let e=a(l(e=>e.language)),t=e.extensionImageGen,{extensionId:n,panelId:r}=i(),o=d();if(!n)return(0,S.jsx)(V,{message:`No extension ID provided.`});let c=o.find(e=>e.id===n);if(!c)return(0,S.jsx)(V,{message:`Extension "${n}" not found or is not available in this workspace.`});let u=c.ui?.contributions?.settingsPanels,f=r?u?.find(e=>e.id===r||e.id===`${n}.${r}`):u?.[0],p=!!(f&&c.ui),m=!!c.hasConfigSchema,g=c.kind===`image-generation`;return!m&&!p&&!g?(0,S.jsx)(V,{message:`Extension "${n}" has no settings panels or config schema.`}):(0,S.jsxs)(`div`,{className:`mx-auto flex w-full max-w-app-main flex-col gap-3 px-4 py-8`,children:[(0,S.jsx)(`h1`,{className:`text-lg font-semibold text-fg`,children:f?.title??`${c.name} Settings`}),g?(0,S.jsxs)(`div`,{className:`flex flex-col gap-2 rounded-lg border border-edge-subtle bg-surface-base px-4 py-3 text-sm`,children:[(0,S.jsx)(`p`,{className:`leading-relaxed text-fg-muted`,children:t.banner}),(0,S.jsx)(s,{to:`/settings/image-models`,className:`w-fit font-medium text-accent hover:underline`,title:e.imageModelsSettings.imageModelsLinkTitle,children:t.openImageModels})]}):null,g?(0,S.jsx)(T,{extensionId:n}):null,m?(0,S.jsx)(z,{extensionId:n}):null,p&&f&&c.ui?(0,S.jsx)(`div`,{className:`overflow-hidden rounded-xl border border-edge bg-surface-base`,children:(0,S.jsx)(h,{extensionId:n,extensionName:c.name,entrypoint:f.entrypoint,permissions:c.ui?.permissions,title:f.title,className:`w-full`,minHeight:120,maxHeight:2e3})}):null]})}function V({message:e}){return(0,S.jsx)(`div`,{className:`mx-auto flex w-full max-w-app-main flex-col gap-3 px-4 py-8`,children:(0,S.jsx)(`p`,{className:`text-sm text-fg-muted`,children:e})})}export{B as ExtensionSettingsPage};
2
- //# sourceMappingURL=extension-settings-page-CZWcC3OA.js.map
1
+ import{i as e}from"./rolldown-runtime-DWdDZTNf.js";import{i as t,t as n}from"./vendor-react-DbimaAId.js";import{i as r}from"./vendor-swr-B5fPo7KK.js";import{Ai as i,An as a,Ar as o,Ei as s,In as c,Sn as l,_n as u,cn as d,hn as f,jn as p,mn as m,n as h,un as g}from"./index-8IFT6i7x.js";import{i as _,n as v,r as y,t as b}from"./use-image-provider-credentials-CqMkyIiU.js";var x=e(t(),1),S=n(),C=()=>g(_);function w(e){return{credentialsIntro:e.credentialsIntro,regionHint:e.regionHint,endpointPresetsHint:e.endpointPresetsHint,apiKeyLabel:e.apiKeyLabel,optionalPlaceholder:e.optionalPlaceholder,regionLabel:e.regionLabel,baseUrlLabel:e.baseUrlLabel,imageBaseUrlLabel:e.imageBaseUrlLabel,saveCredentials:e.saveCredentials,savingCredentials:e.savingCredentials,credentialsSaved:e.credentialsSaved,discardCredentials:e.discardCredentials,credentialsNothingToSave:e.credentialsNothingToSave,credentialsSaveError:e.credentialsSaveError,regionPresetDefault:e.regionPresetDefault,regionPresetCustom:e.regionPresetCustom,baseUrlPresetDefault:e.baseUrlPresetDefault,baseUrlPresetCustom:e.baseUrlPresetCustom,openExtensionSettings:e.openExtensionSettings,openImageModelsPage:e.openImageModelsPage,extensionSettingsLinkTitle:e.extensionSettingsLinkTitle,imageModelsLinkTitle:e.imageModelsLinkTitle,configured:e.configured,missingKey:e.missingKey,defaultModel:e.defaultModel,modelsLabel:e.modelsLabel,imageBaseUrlPresetHint:e.imageBaseUrlPresetHint,dashscopeRegion_beijing:e.dashscopeRegion_beijing,dashscopeRegion_singapore:e.dashscopeRegion_singapore,dashscopeRegion_us:e.dashscopeRegion_us,apiKeyMaskedHelp:e.apiKeyMaskedHelp,apiKeyCopy:e.apiKeyCopy,apiKeyCopied:e.apiKeyCopied,apiKeyShow:e.apiKeyShow,apiKeyHide:e.apiKeyHide,apiKeyNotInConfigFile:e.apiKeyNotInConfigFile,apiKeyRevealFailed:e.apiKeyRevealFailed,minimaxClusterLabel:e.minimaxClusterLabel,minimaxClusterHint:e.minimaxClusterHint,falQueueBaseLabel:e.falQueueBaseLabel,falQueueBaseHint:e.falQueueBaseHint}}function T({extensionId:e}){let t=l(e=>e.language),n=a(t),i=n.imageModelsSettings,s=u(e=>!!e.token),{data:c=[],isLoading:d}=r(s?C():null,y,{revalidateOnFocus:!1}),f=(0,x.useMemo)(()=>c.filter(t=>t.id===e),[c,e]),p=b(f),m=(0,x.useMemo)(()=>w(i),[i]),h=(0,x.useMemo)(()=>({getApiKey:n.providersSettings.getApiKey,getApiKeyIntl:n.providersSettings.getApiKeyIntl,getApiKeyCn:n.providersSettings.getApiKeyCn}),[n.providersSettings]);return s?d?(0,S.jsxs)(`div`,{className:`flex items-center gap-2 py-6 text-sm text-fg-muted`,children:[(0,S.jsx)(o,{className:`size-4 animate-spin`}),`…`]}):f.length===0?(0,S.jsx)(`p`,{className:`text-sm text-fg-muted`,children:t===`zh`?`网关未注册该图像 Provider,或扩展已被禁用。`:`This image provider is not registered on the gateway, or the extension is disabled.`}):(0,S.jsx)(v,{summaries:f,credDraft:p.credDraft,credDirty:p.credDirty,credSaving:p.credSaving,credError:p.credError,credSavedFlash:p.credSavedFlash,credNoopFlash:p.credNoopFlash,updateCredRow:p.updateCredRow,onDiscardCredentials:p.onDiscardCredentials,onSaveCredentials:()=>void p.saveCredentials(i.credentialsSaveError),extensionIds:new Set,showExtensionLinks:!1,showImageModelsLink:!1,language:t,apiKeyLinkLabels:h,messages:m}):null}function E(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function D(e){let t=e[`x-order`];return typeof t==`number`&&!Number.isNaN(t)?t:999}function O(e){let t=e[`x-group`];return typeof t==`string`&&t.length>0?t:``}function k(e){return e[`x-hidden`]===!0}function A(e){let t=e.properties;if(!E(t))return[];let n=[];for(let[e,r]of Object.entries(t))E(r)&&(k(r)||n.push({key:e,sub:r,order:D(r),group:O(r),hidden:!1}));return n.sort((e,t)=>e.order-t.order||e.key.localeCompare(t.key)),n}function j(e){let t=new Map;for(let n of e){let e=n.group;t.has(e)||t.set(e,[]),t.get(e).push(n)}return t}function M({name:e,s:t,value:n,onChange:r,disabled:i}){let a=typeof t.description==`string`?t.description:void 0,o=(typeof t[`x-placeholder`]==`string`?t[`x-placeholder`]:null)||a,s=t.format;return Array.isArray(t.enum)&&t.enum.every(e=>typeof e==`string`)?(0,S.jsxs)(`div`,{className:`flex flex-col gap-1.5`,children:[a?(0,S.jsx)(`label`,{className:`text-xs text-fg-muted`,children:a}):null,(0,S.jsx)(`select`,{name:e,className:`ui-input h-9 rounded-md border border-edge bg-surface-base px-2 text-sm text-fg`,value:n,disabled:i,onChange:e=>r(e.target.value),children:t.enum.map(e=>(0,S.jsx)(`option`,{value:e,children:e},e))})]}):(0,S.jsxs)(`div`,{className:`flex flex-col gap-1.5`,children:[a?(0,S.jsx)(`label`,{className:`text-xs text-fg-muted`,children:a}):null,(0,S.jsx)(`input`,{name:e,type:s===`password`?`password`:`text`,className:`ui-input h-9 rounded-md border border-edge bg-surface-base px-2.5 text-sm text-fg placeholder:text-fg-muted/70`,value:n,placeholder:o,disabled:i,onChange:e=>r(e.target.value)})]})}function N({s:e,value:t,onChange:n,disabled:r}){let i=typeof e.description==`string`?e.description:void 0;return(0,S.jsxs)(`div`,{className:`flex flex-col gap-1.5`,children:[i?(0,S.jsx)(`label`,{className:`text-xs text-fg-muted`,children:i}):null,(0,S.jsx)(`input`,{type:`number`,className:`ui-input h-9 rounded-md border border-edge bg-surface-base px-2.5 text-sm text-fg`,value:Number.isFinite(t)?t:0,disabled:r,onChange:e=>n(Number(e.target.value))})]})}function P({s:e,value:t,onChange:n,disabled:r}){let i=(typeof e.description==`string`?e.description:void 0)??(typeof e.title==`string`&&e.title.length>0?e.title:`Enable`);return(0,S.jsxs)(`label`,{className:`flex items-center gap-2 text-sm text-fg`,children:[(0,S.jsx)(`input`,{type:`checkbox`,className:`h-4 w-4 rounded border border-edge`,checked:t,disabled:r,onChange:e=>n(e.target.checked)}),(0,S.jsx)(`span`,{children:i})]})}function F({s:e,value:t,onChange:n,disabled:r}){let i=typeof e.description==`string`?e.description:void 0,a=e.items;if(!(E(a)&&a.type===`string`))return(0,S.jsx)(`p`,{className:`text-xs text-fg-muted`,children:`Unsupported array type`});let o=e=>{let r=e.trim();!r||t.includes(r)||n([...t,r])};return(0,S.jsxs)(`div`,{className:`flex flex-col gap-1.5`,children:[i?(0,S.jsx)(`label`,{className:`text-xs text-fg-muted`,children:i}):null,(0,S.jsx)(`div`,{className:`flex flex-wrap gap-1`,children:t.map(e=>(0,S.jsxs)(`span`,{className:`inline-flex items-center gap-1 rounded-md border border-edge bg-surface-panel px-2 py-0.5 text-sm`,children:[e,(0,S.jsx)(`button`,{type:`button`,className:`text-fg-muted hover:text-fg`,disabled:r,onClick:()=>n(t.filter(t=>t!==e)),children:`×`})]},e))}),(0,S.jsx)(`input`,{className:`ui-input h-9 rounded-md border border-edge bg-surface-base px-2.5 text-sm`,disabled:r,placeholder:`Add and press Enter`,onKeyDown:e=>{e.key===`Enter`&&(e.preventDefault(),o(e.target.value),e.target.value=``)}})]})}function I({k:e,sub:t,value:n,onValue:r,disabled:i}){let a=t.type,o=(typeof t.title==`string`&&t.title.length>0?t.title:null)??e;if(a===`boolean`)return(0,S.jsxs)(`div`,{className:`space-y-1.5`,children:[(0,S.jsx)(`p`,{className:`text-sm font-medium text-fg`,children:o}),(0,S.jsx)(P,{s:t,value:n===!0,disabled:i,onChange:e=>r(e)})]});if(a===`number`||a===`integer`)return(0,S.jsxs)(`div`,{className:`space-y-1.5`,children:[(0,S.jsx)(`p`,{className:`text-sm font-medium text-fg`,children:o}),(0,S.jsx)(N,{s:t,value:typeof n==`number`?n:0,disabled:i,onChange:r})]});if(a===`string`)return(0,S.jsxs)(`div`,{className:`space-y-1.5`,children:[(0,S.jsx)(`p`,{className:`text-sm font-medium text-fg`,children:o}),(0,S.jsx)(M,{name:e,s:t,value:typeof n==`string`?n:``,disabled:i,onChange:r})]});if(a===`array`){let e=t.items;if(E(e)&&e.type===`string`)return(0,S.jsxs)(`div`,{className:`space-y-1.5`,children:[(0,S.jsx)(`p`,{className:`text-sm font-medium text-fg`,children:o}),(0,S.jsx)(F,{s:t,value:Array.isArray(n)&&n.every(e=>typeof e==`string`)?n:[],disabled:i,onChange:r})]})}return(0,S.jsxs)(`p`,{className:`text-xs text-fg-muted`,children:[o,`: unsupported field type`,typeof a==`string`?` (${a})`:``]})}function L({schema:e,values:t,onChange:n,disabled:r=!1,className:i}){let a=(0,x.useMemo)(()=>e.type===`object`?A(e):[],[e]),o=(0,x.useMemo)(()=>a.length===0?new Map:j(a),[a]),s=(0,x.useCallback)((e,r)=>{n({...t,[e]:r})},[n,t]);if(e.type!==`object`||!E(e.properties)||a.length===0)return null;let l=Array.from(o.keys()).sort((e,t)=>e===``?-1:t===``?1:e.localeCompare(t));return(0,S.jsx)(`div`,{className:c(`flex flex-col gap-4`,i),children:l.map(e=>{let n=(o.get(e)??[]).map(e=>(0,S.jsx)(I,{k:e.key,sub:e.sub,value:t[e.key],onValue:t=>s(e.key,t),disabled:r},e.key));return e===``?(0,S.jsx)(`div`,{children:n},`default`):(0,S.jsxs)(`details`,{className:`group rounded-lg border border-edge bg-surface-panel/40 open:bg-surface-base`,open:!0,children:[(0,S.jsx)(`summary`,{className:`cursor-pointer select-none px-3 py-2 text-sm font-medium text-fg group-open:rounded-b-none`,children:e}),(0,S.jsx)(`div`,{className:`space-y-4 border-t border-edge p-3`,children:n})]},e)})})}function R(e){let t={};if(e.type!==`object`||!E(e.properties))return t;for(let[n,r]of Object.entries(e.properties))E(r)&&Object.prototype.hasOwnProperty.call(r,`default`)&&(t[n]=r.default);return t}function z({extensionId:e}){let t=a(l(e=>e.language)).agentSettings,n=u(e=>!!e.token),{data:i,error:o}=r(n&&e?`ext-detail-${e}`:null,()=>f(g(`/api/extensions/${encodeURIComponent(e)}`))),{data:s,mutate:c,error:d}=r(n&&e?`ext-cfg-${e}`:null,()=>f(g(`/api/extensions/${encodeURIComponent(e)}/config`))),h=i?.manifest?.configSchema,_=(0,x.useMemo)(()=>h&&h.type===`object`?R(h):{},[h]),v=(0,x.useMemo)(()=>({..._,...s??{}}),[_,s]),[y,b]=(0,x.useState)({}),[C,w]=(0,x.useState)(!1),[T,E]=(0,x.useState)(!1),[D,O]=(0,x.useState)(null),[k,A]=(0,x.useState)(!1);(0,x.useEffect)(()=>{C||b(v)},[C,v]);let j=(0,x.useCallback)(e=>{b(e),w(!0),O(null)},[]),M=(0,x.useCallback)(()=>{b(v),w(!1),O(null)},[v]),N=(0,x.useCallback)(()=>{!h||h.type!==`object`||(b({...R(h)}),w(!0),O(null))},[h]),P=(0,x.useCallback)(async()=>{if(e){E(!0),O(null);try{let t=await m(g(`/api/extensions/${encodeURIComponent(e)}/config`),{method:`PATCH`,body:JSON.stringify(y)});if(!t.ok){let e=await t.json().catch(()=>({}));throw Error(e.error?.message??t.statusText)}await c(y,!1),w(!1),A(!0),window.setTimeout(()=>A(!1),3e3)}catch(e){O(e instanceof Error?e.message:String(e))}finally{E(!1)}}},[e,y,c]);if(!n)return null;if(o||d){let e=o??d;return(0,S.jsxs)(`p`,{className:`text-sm text-fg-muted`,children:[`Could not load extension settings: `,e instanceof Error?e.message:String(e)]})}return!h||h.type!==`object`?null:(0,S.jsxs)(`div`,{className:`mb-6 flex flex-col gap-3 rounded-xl border border-edge bg-surface-base p-4`,children:[(0,S.jsxs)(`div`,{className:`flex flex-wrap items-center justify-between gap-2`,children:[(0,S.jsx)(`h2`,{className:`text-sm font-semibold text-fg`,children:`Configuration`}),(0,S.jsxs)(`div`,{className:`flex flex-wrap items-center gap-2`,children:[k?(0,S.jsx)(`span`,{className:`text-xs text-emerald-600 dark:text-emerald-400`,children:t.saved}):null,D?(0,S.jsx)(`span`,{className:`text-xs text-red-600 dark:text-red-400`,children:D}):null,(0,S.jsx)(p,{type:`button`,variant:`ghost`,className:`h-8 text-xs`,disabled:!C,onClick:M,children:t.discard}),(0,S.jsx)(p,{type:`button`,variant:`ghost`,className:`h-8 text-xs`,onClick:N,children:`Reset to defaults`}),(0,S.jsx)(p,{type:`button`,variant:`primary`,className:`h-8 text-xs`,disabled:!C||T,onClick:()=>void P(),children:T?t.saving:t.save})]})]}),(0,S.jsx)(L,{schema:h,values:y,onChange:j,disabled:T})]})}function B(){let e=a(l(e=>e.language)),t=e.extensionImageGen,{extensionId:n,panelId:r}=i(),o=d();if(!n)return(0,S.jsx)(V,{message:`No extension ID provided.`});let c=o.find(e=>e.id===n);if(!c)return(0,S.jsx)(V,{message:`Extension "${n}" not found or is not available in this workspace.`});let u=c.ui?.contributions?.settingsPanels,f=r?u?.find(e=>e.id===r||e.id===`${n}.${r}`):u?.[0],p=!!(f&&c.ui),m=!!c.hasConfigSchema,g=c.kind===`image-generation`;return!m&&!p&&!g?(0,S.jsx)(V,{message:`Extension "${n}" has no settings panels or config schema.`}):(0,S.jsxs)(`div`,{className:`mx-auto flex w-full max-w-app-main flex-col gap-3 px-4 py-8`,children:[(0,S.jsx)(`h1`,{className:`text-lg font-semibold text-fg`,children:f?.title??`${c.name} Settings`}),g?(0,S.jsxs)(`div`,{className:`flex flex-col gap-2 rounded-lg border border-edge-subtle bg-surface-base px-4 py-3 text-sm`,children:[(0,S.jsx)(`p`,{className:`leading-relaxed text-fg-muted`,children:t.banner}),(0,S.jsx)(s,{to:`/settings/image-models`,className:`w-fit font-medium text-accent hover:underline`,title:e.imageModelsSettings.imageModelsLinkTitle,children:t.openImageModels})]}):null,g?(0,S.jsx)(T,{extensionId:n}):null,m?(0,S.jsx)(z,{extensionId:n}):null,p&&f&&c.ui?(0,S.jsx)(`div`,{className:`overflow-hidden rounded-xl border border-edge bg-surface-base`,children:(0,S.jsx)(h,{extensionId:n,extensionName:c.name,entrypoint:f.entrypoint,permissions:c.ui?.permissions,title:f.title,className:`w-full`,minHeight:120,maxHeight:2e3})}):null]})}function V({message:e}){return(0,S.jsx)(`div`,{className:`mx-auto flex w-full max-w-app-main flex-col gap-3 px-4 py-8`,children:(0,S.jsx)(`p`,{className:`text-sm text-fg-muted`,children:e})})}export{B as ExtensionSettingsPage};
2
+ //# sourceMappingURL=extension-settings-page-BnQ2f4Fq.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"extension-settings-page-CZWcC3OA.js","names":[],"sources":["../../../../../web/src/features/settings/extension-image-provider-settings.tsx","../../../../../web/src/components/ui/schema-form.tsx","../../../../../web/src/features/extensions/extension-auto-settings.tsx","../../../../../web/src/features/extensions/extension-settings-page.tsx"],"sourcesContent":["import { Loader2 } from 'lucide-react';\nimport { useMemo } from 'react';\nimport useSWR from 'swr';\n\nimport { fetchImageProvidersList } from '@/features/settings/fetch-image-providers';\nimport {\n ImageProviderCredentialsPanel,\n type ImageProviderCredentialsPanelMessages,\n} from '@/features/settings/image-provider-credentials-panel';\nimport { IMAGE_PROVIDERS_SWR_KEY } from '@/features/settings/image-providers-swr-key';\nimport { useImageProviderCredentials } from '@/features/settings/use-image-provider-credentials';\nimport { apiUrl } from '@/lib/url';\nimport { messages, type MessageBundle } from '@/i18n/messages';\nimport { useGatewayStore } from '@/stores/gateway-store';\nimport { useLocaleStore } from '@/stores/locale-store';\n\nconst imageProvidersSwrKey = () => apiUrl(IMAGE_PROVIDERS_SWR_KEY);\n\nfunction panelMessagesFromBundle(t: MessageBundle['imageModelsSettings']): ImageProviderCredentialsPanelMessages {\n return {\n credentialsIntro: t.credentialsIntro,\n regionHint: t.regionHint,\n endpointPresetsHint: t.endpointPresetsHint,\n apiKeyLabel: t.apiKeyLabel,\n optionalPlaceholder: t.optionalPlaceholder,\n regionLabel: t.regionLabel,\n baseUrlLabel: t.baseUrlLabel,\n imageBaseUrlLabel: t.imageBaseUrlLabel,\n saveCredentials: t.saveCredentials,\n savingCredentials: t.savingCredentials,\n credentialsSaved: t.credentialsSaved,\n discardCredentials: t.discardCredentials,\n credentialsNothingToSave: t.credentialsNothingToSave,\n credentialsSaveError: t.credentialsSaveError,\n regionPresetDefault: t.regionPresetDefault,\n regionPresetCustom: t.regionPresetCustom,\n baseUrlPresetDefault: t.baseUrlPresetDefault,\n baseUrlPresetCustom: t.baseUrlPresetCustom,\n openExtensionSettings: t.openExtensionSettings,\n openImageModelsPage: t.openImageModelsPage,\n extensionSettingsLinkTitle: t.extensionSettingsLinkTitle,\n imageModelsLinkTitle: t.imageModelsLinkTitle,\n configured: t.configured,\n missingKey: t.missingKey,\n defaultModel: t.defaultModel,\n modelsLabel: t.modelsLabel,\n imageBaseUrlPresetHint: t.imageBaseUrlPresetHint,\n dashscopeRegion_beijing: t.dashscopeRegion_beijing,\n dashscopeRegion_singapore: t.dashscopeRegion_singapore,\n dashscopeRegion_us: t.dashscopeRegion_us,\n apiKeyMaskedHelp: t.apiKeyMaskedHelp,\n apiKeyCopy: t.apiKeyCopy,\n apiKeyCopied: t.apiKeyCopied,\n apiKeyShow: t.apiKeyShow,\n apiKeyHide: t.apiKeyHide,\n apiKeyNotInConfigFile: t.apiKeyNotInConfigFile,\n apiKeyRevealFailed: t.apiKeyRevealFailed,\n minimaxClusterLabel: t.minimaxClusterLabel,\n minimaxClusterHint: t.minimaxClusterHint,\n falQueueBaseLabel: t.falQueueBaseLabel,\n falQueueBaseHint: t.falQueueBaseHint,\n };\n}\n\nexport function ExtensionImageProviderSettings({ extensionId }: { extensionId: string }) {\n const language = useLocaleStore((s) => s.language);\n const m = messages(language);\n const t = m.imageModelsSettings;\n const hasToken = useGatewayStore((s) => Boolean(s.token));\n\n const { data: all = [], isLoading } = useSWR(\n hasToken ? imageProvidersSwrKey() : null,\n fetchImageProvidersList,\n { revalidateOnFocus: false },\n );\n\n const summaries = useMemo(\n () => all.filter((p) => p.id === extensionId),\n [all, extensionId],\n );\n\n const cred = useImageProviderCredentials(summaries);\n const panelMsg = useMemo(() => panelMessagesFromBundle(t), [t]);\n const apiKeyLinkLabels = useMemo(\n () => ({\n getApiKey: m.providersSettings.getApiKey,\n getApiKeyIntl: m.providersSettings.getApiKeyIntl,\n getApiKeyCn: m.providersSettings.getApiKeyCn,\n }),\n [m.providersSettings],\n );\n\n if (!hasToken) {\n return null;\n }\n\n if (isLoading) {\n return (\n <div className=\"flex items-center gap-2 py-6 text-sm text-fg-muted\">\n <Loader2 className=\"size-4 animate-spin\" />\n …\n </div>\n );\n }\n\n if (summaries.length === 0) {\n return (\n <p className=\"text-sm text-fg-muted\">\n {language === 'zh'\n ? '网关未注册该图像 Provider,或扩展已被禁用。'\n : 'This image provider is not registered on the gateway, or the extension is disabled.'}\n </p>\n );\n }\n\n return (\n <ImageProviderCredentialsPanel\n summaries={summaries}\n credDraft={cred.credDraft}\n credDirty={cred.credDirty}\n credSaving={cred.credSaving}\n credError={cred.credError}\n credSavedFlash={cred.credSavedFlash}\n credNoopFlash={cred.credNoopFlash}\n updateCredRow={cred.updateCredRow}\n onDiscardCredentials={cred.onDiscardCredentials}\n onSaveCredentials={() => void cred.saveCredentials(t.credentialsSaveError)}\n extensionIds={new Set()}\n showExtensionLinks={false}\n showImageModelsLink={false}\n language={language}\n apiKeyLinkLabels={apiKeyLinkLabels}\n messages={panelMsg}\n />\n );\n}\n","import { useCallback, useMemo } from 'react';\n\nimport { cn } from '@/lib/cn';\n\nexport type JsonSchema = Record<string, unknown>;\n\ntype SchemaFormProps = {\n schema: JsonSchema;\n values: Record<string, unknown>;\n onChange: (values: Record<string, unknown>) => void;\n disabled?: boolean;\n className?: string;\n};\n\nfunction isRecord(x: unknown): x is Record<string, unknown> {\n return typeof x === 'object' && x !== null && !Array.isArray(x);\n}\n\ntype FieldDef = {\n key: string;\n sub: JsonSchema;\n order: number;\n group: string;\n hidden: boolean;\n};\n\nfunction getXOrder(s: JsonSchema): number {\n const v = s['x-order'];\n return typeof v === 'number' && !Number.isNaN(v) ? v : 999;\n}\n\nfunction getXGroup(s: JsonSchema): string {\n const v = s['x-group'];\n return typeof v === 'string' && v.length > 0 ? v : '';\n}\n\nfunction isHidden(s: JsonSchema): boolean {\n return s['x-hidden'] === true;\n}\n\nfunction sortedFields(schema: JsonSchema): FieldDef[] {\n const props = schema.properties;\n if (!isRecord(props)) return [];\n const out: FieldDef[] = [];\n for (const [key, sub] of Object.entries(props)) {\n if (!isRecord(sub)) continue;\n if (isHidden(sub)) continue;\n out.push({\n key,\n sub: sub,\n order: getXOrder(sub),\n group: getXGroup(sub),\n hidden: false,\n });\n }\n out.sort((a, b) => a.order - b.order || a.key.localeCompare(b.key));\n return out;\n}\n\nfunction groupFields(fields: FieldDef[]): Map<string, FieldDef[]> {\n const m = new Map<string, FieldDef[]>();\n for (const f of fields) {\n const g = f.group;\n if (!m.has(g)) m.set(g, []);\n m.get(g)!.push(f);\n }\n return m;\n}\n\nfunction StringField({\n name,\n s,\n value,\n onChange,\n disabled,\n}: {\n name: string;\n s: JsonSchema;\n value: string;\n onChange: (v: string) => void;\n disabled: boolean;\n}) {\n const desc = typeof s.description === 'string' ? s.description : undefined;\n const placeholder =\n (typeof s['x-placeholder'] === 'string' ? s['x-placeholder'] : null) || desc;\n const fmt = s.format;\n if (Array.isArray(s.enum) && s.enum.every((x) => typeof x === 'string')) {\n return (\n <div className=\"flex flex-col gap-1.5\">\n {desc ? <label className=\"text-xs text-fg-muted\">{desc}</label> : null}\n <select\n name={name}\n className=\"ui-input h-9 rounded-md border border-edge bg-surface-base px-2 text-sm text-fg\"\n value={value}\n disabled={disabled}\n onChange={(e) => onChange(e.target.value)}\n >\n {(s.enum).map((op) => (\n <option key={op} value={op}>\n {op}\n </option>\n ))}\n </select>\n </div>\n );\n }\n const inputType = fmt === 'password' ? 'password' : 'text';\n return (\n <div className=\"flex flex-col gap-1.5\">\n {desc ? <label className=\"text-xs text-fg-muted\">{desc}</label> : null}\n <input\n name={name}\n type={inputType}\n className=\"ui-input h-9 rounded-md border border-edge bg-surface-base px-2.5 text-sm text-fg placeholder:text-fg-muted/70\"\n value={value}\n placeholder={placeholder}\n disabled={disabled}\n onChange={(e) => onChange(e.target.value)}\n />\n </div>\n );\n}\n\nfunction NumberField({\n s,\n value,\n onChange,\n disabled,\n}: {\n s: JsonSchema;\n value: number;\n onChange: (v: number) => void;\n disabled: boolean;\n}) {\n const desc = typeof s.description === 'string' ? s.description : undefined;\n return (\n <div className=\"flex flex-col gap-1.5\">\n {desc ? <label className=\"text-xs text-fg-muted\">{desc}</label> : null}\n <input\n type=\"number\"\n className=\"ui-input h-9 rounded-md border border-edge bg-surface-base px-2.5 text-sm text-fg\"\n value={Number.isFinite(value) ? value : 0}\n disabled={disabled}\n onChange={(e) => onChange(Number(e.target.value))}\n />\n </div>\n );\n}\n\nfunction BooleanField({\n s,\n value,\n onChange,\n disabled,\n}: {\n s: JsonSchema;\n value: boolean;\n onChange: (v: boolean) => void;\n disabled: boolean;\n}) {\n const desc = typeof s.description === 'string' ? s.description : undefined;\n const labelText =\n desc ?? (typeof s.title === 'string' && s.title.length > 0 ? s.title : 'Enable');\n return (\n <label className=\"flex items-center gap-2 text-sm text-fg\">\n <input\n type=\"checkbox\"\n className=\"h-4 w-4 rounded border border-edge\"\n checked={value}\n disabled={disabled}\n onChange={(e) => onChange(e.target.checked)}\n />\n <span>{labelText}</span>\n </label>\n );\n}\n\nfunction ArrayStringField({\n s,\n value,\n onChange,\n disabled,\n}: {\n s: JsonSchema;\n value: string[];\n onChange: (v: string[]) => void;\n disabled: boolean;\n}) {\n const desc = typeof s.description === 'string' ? s.description : undefined;\n const items = s.items;\n const isStringItems = isRecord(items) && items.type === 'string';\n if (!isStringItems) {\n return <p className=\"text-xs text-fg-muted\">Unsupported array type</p>;\n }\n const add = (t: string) => {\n const n = t.trim();\n if (!n || value.includes(n)) return;\n onChange([...value, n]);\n };\n return (\n <div className=\"flex flex-col gap-1.5\">\n {desc ? <label className=\"text-xs text-fg-muted\">{desc}</label> : null}\n <div className=\"flex flex-wrap gap-1\">\n {value.map((t) => (\n <span\n key={t}\n className=\"inline-flex items-center gap-1 rounded-md border border-edge bg-surface-panel px-2 py-0.5 text-sm\"\n >\n {t}\n <button\n type=\"button\"\n className=\"text-fg-muted hover:text-fg\"\n disabled={disabled}\n onClick={() => onChange(value.filter((x) => x !== t))}\n >\n ×\n </button>\n </span>\n ))}\n </div>\n <input\n className=\"ui-input h-9 rounded-md border border-edge bg-surface-base px-2.5 text-sm\"\n disabled={disabled}\n placeholder=\"Add and press Enter\"\n onKeyDown={(e) => {\n if (e.key === 'Enter') {\n e.preventDefault();\n add((e.target as HTMLInputElement).value);\n (e.target as HTMLInputElement).value = '';\n }\n }}\n />\n </div>\n );\n}\n\nfunction FieldRow({\n k,\n sub,\n value,\n onValue,\n disabled,\n}: {\n k: string;\n sub: JsonSchema;\n value: unknown;\n onValue: (next: unknown) => void;\n disabled: boolean;\n}) {\n const t = sub.type;\n const title =\n (typeof sub.title === 'string' && sub.title.length > 0 ? sub.title : null) ?? k;\n if (t === 'boolean') {\n return (\n <div className=\"space-y-1.5\">\n <p className=\"text-sm font-medium text-fg\">{title}</p>\n <BooleanField\n s={sub}\n value={value === true}\n disabled={disabled}\n onChange={(b) => onValue(b)}\n />\n </div>\n );\n }\n if (t === 'number' || t === 'integer') {\n return (\n <div className=\"space-y-1.5\">\n <p className=\"text-sm font-medium text-fg\">{title}</p>\n <NumberField\n s={sub}\n value={typeof value === 'number' ? value : 0}\n disabled={disabled}\n onChange={onValue}\n />\n </div>\n );\n }\n if (t === 'string') {\n return (\n <div className=\"space-y-1.5\">\n <p className=\"text-sm font-medium text-fg\">{title}</p>\n <StringField\n name={k}\n s={sub}\n value={typeof value === 'string' ? value : ''}\n disabled={disabled}\n onChange={onValue}\n />\n </div>\n );\n }\n if (t === 'array') {\n const items = sub.items;\n if (isRecord(items) && items.type === 'string') {\n return (\n <div className=\"space-y-1.5\">\n <p className=\"text-sm font-medium text-fg\">{title}</p>\n <ArrayStringField\n s={sub}\n value={Array.isArray(value) && value.every((x) => typeof x === 'string') ? value : []}\n disabled={disabled}\n onChange={onValue}\n />\n </div>\n );\n }\n }\n return (\n <p className=\"text-xs text-fg-muted\">\n {title}: unsupported field type\n {typeof t === 'string' ? ` (${t})` : ''}\n </p>\n );\n}\n\n/**\n * Renders a JSON Schema (type: object) as a form using Gateway Console design tokens.\n */\nexport function SchemaForm({ schema, values, onChange, disabled = false, className }: SchemaFormProps) {\n const fields = useMemo(() => {\n if (schema.type !== 'object') return [];\n return sortedFields(schema);\n }, [schema]);\n\n const grouped = useMemo(() => {\n if (fields.length === 0) return new Map<string, FieldDef[]>();\n return groupFields(fields);\n }, [fields]);\n\n const setKey = useCallback(\n (key: string, next: unknown) => {\n onChange({ ...values, [key]: next });\n },\n [onChange, values],\n );\n\n if (schema.type !== 'object' || !isRecord(schema.properties) || fields.length === 0) {\n return null;\n }\n\n const groupKeys = Array.from(grouped.keys()).sort((a, b) => {\n if (a === '') return -1;\n if (b === '') return 1;\n return a.localeCompare(b);\n });\n\n return (\n <div className={cn('flex flex-col gap-4', className)}>\n {groupKeys.map((gk) => {\n const list = grouped.get(gk) ?? [];\n const block = list.map((f) => (\n <FieldRow\n key={f.key}\n k={f.key}\n sub={f.sub}\n value={values[f.key]}\n onValue={(v) => setKey(f.key, v)}\n disabled={disabled}\n />\n ));\n if (gk === '') {\n return <div key=\"default\">{block}</div>;\n }\n return (\n <details\n key={gk}\n className=\"group rounded-lg border border-edge bg-surface-panel/40 open:bg-surface-base\"\n open\n >\n <summary className=\"cursor-pointer select-none px-3 py-2 text-sm font-medium text-fg group-open:rounded-b-none\">\n {gk}\n </summary>\n <div className=\"space-y-4 border-t border-edge p-3\">{block}</div>\n </details>\n );\n })}\n </div>\n );\n}\n\n/** Extract per-key defaults from a JSON object schema for \"Reset\" actions. */\nexport function extractObjectDefaults(\n schema: JsonSchema,\n): Record<string, unknown> {\n const out: Record<string, unknown> = {};\n if (schema.type !== 'object' || !isRecord(schema.properties)) {\n return out;\n }\n for (const [k, sub] of Object.entries(schema.properties)) {\n if (!isRecord(sub)) continue;\n if (Object.prototype.hasOwnProperty.call(sub, 'default')) {\n out[k] = sub.default;\n }\n }\n return out;\n}\n","import { useCallback, useEffect, useMemo, useState } from 'react';\nimport useSWR from 'swr';\n\nimport { Button } from '@/components/ui/button';\nimport { extractObjectDefaults, SchemaForm, type JsonSchema } from '@/components/ui/schema-form';\nimport { apiFetch, fetchJson } from '@/lib/fetch';\nimport { apiUrl } from '@/lib/url';\nimport { messages } from '@/i18n/messages';\nimport { useGatewayStore } from '@/stores/gateway-store';\nimport { useLocaleStore } from '@/stores/locale-store';\n\ntype ExtensionDetailResponse = {\n manifest: { configSchema?: JsonSchema };\n};\n\nexport function ExtensionAutoSettings({ extensionId }: { extensionId: string }) {\n const language = useLocaleStore((s) => s.language);\n const a = messages(language).agentSettings;\n const hasToken = useGatewayStore((s) => Boolean(s.token));\n const { data: detail, error: detailError } = useSWR(\n hasToken && extensionId ? `ext-detail-${extensionId}` : null,\n () => fetchJson<ExtensionDetailResponse>(apiUrl(`/api/extensions/${encodeURIComponent(extensionId)}`)),\n );\n\n const { data: remoteConfig, mutate: mutateConfig, error: configError } = useSWR(\n hasToken && extensionId ? `ext-cfg-${extensionId}` : null,\n () =>\n fetchJson<Record<string, unknown>>(\n apiUrl(`/api/extensions/${encodeURIComponent(extensionId)}/config`),\n ),\n );\n\n const schema = detail?.manifest?.configSchema;\n const defaults = useMemo(\n () => (schema && schema.type === 'object' ? extractObjectDefaults(schema) : {}),\n [schema],\n );\n\n const savedValues = useMemo(\n () => ({ ...defaults, ...(remoteConfig ?? {}) }),\n [defaults, remoteConfig],\n );\n\n const [localValues, setLocalValues] = useState<Record<string, unknown>>({});\n const [isDirty, setIsDirty] = useState(false);\n const [saving, setSaving] = useState(false);\n const [saveError, setSaveError] = useState<string | null>(null);\n const [saveSuccess, setSaveSuccess] = useState(false);\n\n useEffect(() => {\n if (isDirty) return;\n setLocalValues(savedValues);\n }, [isDirty, savedValues]);\n\n const onChange = useCallback((next: Record<string, unknown>) => {\n setLocalValues(next);\n setIsDirty(true);\n setSaveError(null);\n }, []);\n\n const handleDiscard = useCallback(() => {\n setLocalValues(savedValues);\n setIsDirty(false);\n setSaveError(null);\n }, [savedValues]);\n\n const handleResetDefaults = useCallback(() => {\n if (!schema || schema.type !== 'object') return;\n setLocalValues({ ...extractObjectDefaults(schema) });\n setIsDirty(true);\n setSaveError(null);\n }, [schema]);\n\n const handleSave = useCallback(async () => {\n if (!extensionId) return;\n setSaving(true);\n setSaveError(null);\n try {\n const res = await apiFetch(\n apiUrl(`/api/extensions/${encodeURIComponent(extensionId)}/config`),\n { method: 'PATCH', body: JSON.stringify(localValues) },\n );\n if (!res.ok) {\n const body = (await res.json().catch(() => ({}))) as { error?: { message?: string } };\n throw new Error(body.error?.message ?? res.statusText);\n }\n await mutateConfig(localValues, false);\n setIsDirty(false);\n setSaveSuccess(true);\n window.setTimeout(() => setSaveSuccess(false), 3000);\n } catch (e) {\n setSaveError(e instanceof Error ? e.message : String(e));\n } finally {\n setSaving(false);\n }\n }, [extensionId, localValues, mutateConfig]);\n\n if (!hasToken) {\n return null;\n }\n\n if (detailError || configError) {\n const err = (detailError ?? configError) as Error;\n return (\n <p className=\"text-sm text-fg-muted\">\n Could not load extension settings: {err instanceof Error ? err.message : String(err)}\n </p>\n );\n }\n\n if (!schema || schema.type !== 'object') {\n return null;\n }\n\n return (\n <div className=\"mb-6 flex flex-col gap-3 rounded-xl border border-edge bg-surface-base p-4\">\n <div className=\"flex flex-wrap items-center justify-between gap-2\">\n <h2 className=\"text-sm font-semibold text-fg\">Configuration</h2>\n <div className=\"flex flex-wrap items-center gap-2\">\n {saveSuccess ? (\n <span className=\"text-xs text-emerald-600 dark:text-emerald-400\">{a.saved}</span>\n ) : null}\n {saveError ? <span className=\"text-xs text-red-600 dark:text-red-400\">{saveError}</span> : null}\n <Button\n type=\"button\"\n variant=\"ghost\"\n className=\"h-8 text-xs\"\n disabled={!isDirty}\n onClick={handleDiscard}\n >\n {a.discard}\n </Button>\n <Button\n type=\"button\"\n variant=\"ghost\"\n className=\"h-8 text-xs\"\n onClick={handleResetDefaults}\n >\n Reset to defaults\n </Button>\n <Button\n type=\"button\"\n variant=\"primary\"\n className=\"h-8 text-xs\"\n disabled={!isDirty || saving}\n onClick={() => void handleSave()}\n >\n {saving ? a.saving : a.save}\n </Button>\n </div>\n </div>\n <SchemaForm schema={schema} values={localValues} onChange={onChange} disabled={saving} />\n </div>\n );\n}\n","/**\n * Extension settings: auto-generated config form (configSchema) + optional iframe (settingsPanels).\n *\n * Routes: /settings/ext/:extensionId, /settings/ext/:extensionId/:panelId\n */\n\nimport { Link, useParams } from 'react-router-dom';\n\nimport { ExtensionImageProviderSettings } from '@/features/settings/extension-image-provider-settings';\nimport { messages } from '@/i18n/messages';\nimport { useLocaleStore } from '@/stores/locale-store';\n\nimport { ExtensionAutoSettings } from './extension-auto-settings';\nimport { ExtensionIframeHost } from './extension-iframe-host';\nimport { useExtensions } from './extension-provider';\n\nexport function ExtensionSettingsPage() {\n const language = useLocaleStore((s) => s.language);\n const m = messages(language);\n const xm = m.extensionImageGen;\n const { extensionId, panelId } = useParams<{ extensionId: string; panelId?: string }>();\n const extensions = useExtensions();\n\n if (!extensionId) {\n return <SettingsPanelNotFound message=\"No extension ID provided.\" />;\n }\n\n const extension = extensions.find((ext) => ext.id === extensionId);\n if (!extension) {\n return (\n <SettingsPanelNotFound\n message={`Extension \"${extensionId}\" not found or is not available in this workspace.`}\n />\n );\n }\n\n const panels = extension.ui?.contributions?.settingsPanels;\n const panel = panelId\n ? panels?.find((p) => p.id === panelId || p.id === `${extensionId}.${panelId}`)\n : panels?.[0];\n\n const hasIframe = Boolean(panel && extension.ui);\n const hasAutoForm = Boolean(extension.hasConfigSchema);\n const isImageGeneration = extension.kind === 'image-generation';\n\n if (!hasAutoForm && !hasIframe && !isImageGeneration) {\n return (\n <SettingsPanelNotFound\n message={`Extension \"${extensionId}\" has no settings panels or config schema.`}\n />\n );\n }\n\n const title = panel?.title ?? `${extension.name} Settings`;\n\n return (\n <div className=\"mx-auto flex w-full max-w-app-main flex-col gap-3 px-4 py-8\">\n <h1 className=\"text-lg font-semibold text-fg\">{title}</h1>\n {isImageGeneration ? (\n <div className=\"flex flex-col gap-2 rounded-lg border border-edge-subtle bg-surface-base px-4 py-3 text-sm\">\n <p className=\"leading-relaxed text-fg-muted\">{xm.banner}</p>\n <Link\n to=\"/settings/image-models\"\n className=\"w-fit font-medium text-accent hover:underline\"\n title={m.imageModelsSettings.imageModelsLinkTitle}\n >\n {xm.openImageModels}\n </Link>\n </div>\n ) : null}\n {isImageGeneration ? <ExtensionImageProviderSettings extensionId={extensionId} /> : null}\n {hasAutoForm ? <ExtensionAutoSettings extensionId={extensionId} /> : null}\n {hasIframe && panel && extension.ui ? (\n <div className=\"overflow-hidden rounded-xl border border-edge bg-surface-base\">\n <ExtensionIframeHost\n extensionId={extensionId}\n extensionName={extension.name}\n entrypoint={panel.entrypoint}\n permissions={extension.ui?.permissions}\n title={panel.title}\n className=\"w-full\"\n minHeight={120}\n maxHeight={2000}\n />\n </div>\n ) : null}\n </div>\n );\n}\n\nfunction SettingsPanelNotFound({ message }: { message: string }) {\n return (\n <div className=\"mx-auto flex w-full max-w-app-main flex-col gap-3 px-4 py-8\">\n <p className=\"text-sm text-fg-muted\">{message}</p>\n </div>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"extension-settings-page-BnQ2f4Fq.js","names":[],"sources":["../../../../../web/src/features/settings/extension-image-provider-settings.tsx","../../../../../web/src/components/ui/schema-form.tsx","../../../../../web/src/features/extensions/extension-auto-settings.tsx","../../../../../web/src/features/extensions/extension-settings-page.tsx"],"sourcesContent":["import { Loader2 } from 'lucide-react';\nimport { useMemo } from 'react';\nimport useSWR from 'swr';\n\nimport { fetchImageProvidersList } from '@/features/settings/fetch-image-providers';\nimport {\n ImageProviderCredentialsPanel,\n type ImageProviderCredentialsPanelMessages,\n} from '@/features/settings/image-provider-credentials-panel';\nimport { IMAGE_PROVIDERS_SWR_KEY } from '@/features/settings/image-providers-swr-key';\nimport { useImageProviderCredentials } from '@/features/settings/use-image-provider-credentials';\nimport { apiUrl } from '@/lib/url';\nimport { messages, type MessageBundle } from '@/i18n/messages';\nimport { useGatewayStore } from '@/stores/gateway-store';\nimport { useLocaleStore } from '@/stores/locale-store';\n\nconst imageProvidersSwrKey = () => apiUrl(IMAGE_PROVIDERS_SWR_KEY);\n\nfunction panelMessagesFromBundle(t: MessageBundle['imageModelsSettings']): ImageProviderCredentialsPanelMessages {\n return {\n credentialsIntro: t.credentialsIntro,\n regionHint: t.regionHint,\n endpointPresetsHint: t.endpointPresetsHint,\n apiKeyLabel: t.apiKeyLabel,\n optionalPlaceholder: t.optionalPlaceholder,\n regionLabel: t.regionLabel,\n baseUrlLabel: t.baseUrlLabel,\n imageBaseUrlLabel: t.imageBaseUrlLabel,\n saveCredentials: t.saveCredentials,\n savingCredentials: t.savingCredentials,\n credentialsSaved: t.credentialsSaved,\n discardCredentials: t.discardCredentials,\n credentialsNothingToSave: t.credentialsNothingToSave,\n credentialsSaveError: t.credentialsSaveError,\n regionPresetDefault: t.regionPresetDefault,\n regionPresetCustom: t.regionPresetCustom,\n baseUrlPresetDefault: t.baseUrlPresetDefault,\n baseUrlPresetCustom: t.baseUrlPresetCustom,\n openExtensionSettings: t.openExtensionSettings,\n openImageModelsPage: t.openImageModelsPage,\n extensionSettingsLinkTitle: t.extensionSettingsLinkTitle,\n imageModelsLinkTitle: t.imageModelsLinkTitle,\n configured: t.configured,\n missingKey: t.missingKey,\n defaultModel: t.defaultModel,\n modelsLabel: t.modelsLabel,\n imageBaseUrlPresetHint: t.imageBaseUrlPresetHint,\n dashscopeRegion_beijing: t.dashscopeRegion_beijing,\n dashscopeRegion_singapore: t.dashscopeRegion_singapore,\n dashscopeRegion_us: t.dashscopeRegion_us,\n apiKeyMaskedHelp: t.apiKeyMaskedHelp,\n apiKeyCopy: t.apiKeyCopy,\n apiKeyCopied: t.apiKeyCopied,\n apiKeyShow: t.apiKeyShow,\n apiKeyHide: t.apiKeyHide,\n apiKeyNotInConfigFile: t.apiKeyNotInConfigFile,\n apiKeyRevealFailed: t.apiKeyRevealFailed,\n minimaxClusterLabel: t.minimaxClusterLabel,\n minimaxClusterHint: t.minimaxClusterHint,\n falQueueBaseLabel: t.falQueueBaseLabel,\n falQueueBaseHint: t.falQueueBaseHint,\n };\n}\n\nexport function ExtensionImageProviderSettings({ extensionId }: { extensionId: string }) {\n const language = useLocaleStore((s) => s.language);\n const m = messages(language);\n const t = m.imageModelsSettings;\n const hasToken = useGatewayStore((s) => Boolean(s.token));\n\n const { data: all = [], isLoading } = useSWR(\n hasToken ? imageProvidersSwrKey() : null,\n fetchImageProvidersList,\n { revalidateOnFocus: false },\n );\n\n const summaries = useMemo(\n () => all.filter((p) => p.id === extensionId),\n [all, extensionId],\n );\n\n const cred = useImageProviderCredentials(summaries);\n const panelMsg = useMemo(() => panelMessagesFromBundle(t), [t]);\n const apiKeyLinkLabels = useMemo(\n () => ({\n getApiKey: m.providersSettings.getApiKey,\n getApiKeyIntl: m.providersSettings.getApiKeyIntl,\n getApiKeyCn: m.providersSettings.getApiKeyCn,\n }),\n [m.providersSettings],\n );\n\n if (!hasToken) {\n return null;\n }\n\n if (isLoading) {\n return (\n <div className=\"flex items-center gap-2 py-6 text-sm text-fg-muted\">\n <Loader2 className=\"size-4 animate-spin\" />\n …\n </div>\n );\n }\n\n if (summaries.length === 0) {\n return (\n <p className=\"text-sm text-fg-muted\">\n {language === 'zh'\n ? '网关未注册该图像 Provider,或扩展已被禁用。'\n : 'This image provider is not registered on the gateway, or the extension is disabled.'}\n </p>\n );\n }\n\n return (\n <ImageProviderCredentialsPanel\n summaries={summaries}\n credDraft={cred.credDraft}\n credDirty={cred.credDirty}\n credSaving={cred.credSaving}\n credError={cred.credError}\n credSavedFlash={cred.credSavedFlash}\n credNoopFlash={cred.credNoopFlash}\n updateCredRow={cred.updateCredRow}\n onDiscardCredentials={cred.onDiscardCredentials}\n onSaveCredentials={() => void cred.saveCredentials(t.credentialsSaveError)}\n extensionIds={new Set()}\n showExtensionLinks={false}\n showImageModelsLink={false}\n language={language}\n apiKeyLinkLabels={apiKeyLinkLabels}\n messages={panelMsg}\n />\n );\n}\n","import { useCallback, useMemo } from 'react';\n\nimport { cn } from '@/lib/cn';\n\nexport type JsonSchema = Record<string, unknown>;\n\ntype SchemaFormProps = {\n schema: JsonSchema;\n values: Record<string, unknown>;\n onChange: (values: Record<string, unknown>) => void;\n disabled?: boolean;\n className?: string;\n};\n\nfunction isRecord(x: unknown): x is Record<string, unknown> {\n return typeof x === 'object' && x !== null && !Array.isArray(x);\n}\n\ntype FieldDef = {\n key: string;\n sub: JsonSchema;\n order: number;\n group: string;\n hidden: boolean;\n};\n\nfunction getXOrder(s: JsonSchema): number {\n const v = s['x-order'];\n return typeof v === 'number' && !Number.isNaN(v) ? v : 999;\n}\n\nfunction getXGroup(s: JsonSchema): string {\n const v = s['x-group'];\n return typeof v === 'string' && v.length > 0 ? v : '';\n}\n\nfunction isHidden(s: JsonSchema): boolean {\n return s['x-hidden'] === true;\n}\n\nfunction sortedFields(schema: JsonSchema): FieldDef[] {\n const props = schema.properties;\n if (!isRecord(props)) return [];\n const out: FieldDef[] = [];\n for (const [key, sub] of Object.entries(props)) {\n if (!isRecord(sub)) continue;\n if (isHidden(sub)) continue;\n out.push({\n key,\n sub: sub,\n order: getXOrder(sub),\n group: getXGroup(sub),\n hidden: false,\n });\n }\n out.sort((a, b) => a.order - b.order || a.key.localeCompare(b.key));\n return out;\n}\n\nfunction groupFields(fields: FieldDef[]): Map<string, FieldDef[]> {\n const m = new Map<string, FieldDef[]>();\n for (const f of fields) {\n const g = f.group;\n if (!m.has(g)) m.set(g, []);\n m.get(g)!.push(f);\n }\n return m;\n}\n\nfunction StringField({\n name,\n s,\n value,\n onChange,\n disabled,\n}: {\n name: string;\n s: JsonSchema;\n value: string;\n onChange: (v: string) => void;\n disabled: boolean;\n}) {\n const desc = typeof s.description === 'string' ? s.description : undefined;\n const placeholder =\n (typeof s['x-placeholder'] === 'string' ? s['x-placeholder'] : null) || desc;\n const fmt = s.format;\n if (Array.isArray(s.enum) && s.enum.every((x) => typeof x === 'string')) {\n return (\n <div className=\"flex flex-col gap-1.5\">\n {desc ? <label className=\"text-xs text-fg-muted\">{desc}</label> : null}\n <select\n name={name}\n className=\"ui-input h-9 rounded-md border border-edge bg-surface-base px-2 text-sm text-fg\"\n value={value}\n disabled={disabled}\n onChange={(e) => onChange(e.target.value)}\n >\n {(s.enum).map((op) => (\n <option key={op} value={op}>\n {op}\n </option>\n ))}\n </select>\n </div>\n );\n }\n const inputType = fmt === 'password' ? 'password' : 'text';\n return (\n <div className=\"flex flex-col gap-1.5\">\n {desc ? <label className=\"text-xs text-fg-muted\">{desc}</label> : null}\n <input\n name={name}\n type={inputType}\n className=\"ui-input h-9 rounded-md border border-edge bg-surface-base px-2.5 text-sm text-fg placeholder:text-fg-muted/70\"\n value={value}\n placeholder={placeholder}\n disabled={disabled}\n onChange={(e) => onChange(e.target.value)}\n />\n </div>\n );\n}\n\nfunction NumberField({\n s,\n value,\n onChange,\n disabled,\n}: {\n s: JsonSchema;\n value: number;\n onChange: (v: number) => void;\n disabled: boolean;\n}) {\n const desc = typeof s.description === 'string' ? s.description : undefined;\n return (\n <div className=\"flex flex-col gap-1.5\">\n {desc ? <label className=\"text-xs text-fg-muted\">{desc}</label> : null}\n <input\n type=\"number\"\n className=\"ui-input h-9 rounded-md border border-edge bg-surface-base px-2.5 text-sm text-fg\"\n value={Number.isFinite(value) ? value : 0}\n disabled={disabled}\n onChange={(e) => onChange(Number(e.target.value))}\n />\n </div>\n );\n}\n\nfunction BooleanField({\n s,\n value,\n onChange,\n disabled,\n}: {\n s: JsonSchema;\n value: boolean;\n onChange: (v: boolean) => void;\n disabled: boolean;\n}) {\n const desc = typeof s.description === 'string' ? s.description : undefined;\n const labelText =\n desc ?? (typeof s.title === 'string' && s.title.length > 0 ? s.title : 'Enable');\n return (\n <label className=\"flex items-center gap-2 text-sm text-fg\">\n <input\n type=\"checkbox\"\n className=\"h-4 w-4 rounded border border-edge\"\n checked={value}\n disabled={disabled}\n onChange={(e) => onChange(e.target.checked)}\n />\n <span>{labelText}</span>\n </label>\n );\n}\n\nfunction ArrayStringField({\n s,\n value,\n onChange,\n disabled,\n}: {\n s: JsonSchema;\n value: string[];\n onChange: (v: string[]) => void;\n disabled: boolean;\n}) {\n const desc = typeof s.description === 'string' ? s.description : undefined;\n const items = s.items;\n const isStringItems = isRecord(items) && items.type === 'string';\n if (!isStringItems) {\n return <p className=\"text-xs text-fg-muted\">Unsupported array type</p>;\n }\n const add = (t: string) => {\n const n = t.trim();\n if (!n || value.includes(n)) return;\n onChange([...value, n]);\n };\n return (\n <div className=\"flex flex-col gap-1.5\">\n {desc ? <label className=\"text-xs text-fg-muted\">{desc}</label> : null}\n <div className=\"flex flex-wrap gap-1\">\n {value.map((t) => (\n <span\n key={t}\n className=\"inline-flex items-center gap-1 rounded-md border border-edge bg-surface-panel px-2 py-0.5 text-sm\"\n >\n {t}\n <button\n type=\"button\"\n className=\"text-fg-muted hover:text-fg\"\n disabled={disabled}\n onClick={() => onChange(value.filter((x) => x !== t))}\n >\n ×\n </button>\n </span>\n ))}\n </div>\n <input\n className=\"ui-input h-9 rounded-md border border-edge bg-surface-base px-2.5 text-sm\"\n disabled={disabled}\n placeholder=\"Add and press Enter\"\n onKeyDown={(e) => {\n if (e.key === 'Enter') {\n e.preventDefault();\n add((e.target as HTMLInputElement).value);\n (e.target as HTMLInputElement).value = '';\n }\n }}\n />\n </div>\n );\n}\n\nfunction FieldRow({\n k,\n sub,\n value,\n onValue,\n disabled,\n}: {\n k: string;\n sub: JsonSchema;\n value: unknown;\n onValue: (next: unknown) => void;\n disabled: boolean;\n}) {\n const t = sub.type;\n const title =\n (typeof sub.title === 'string' && sub.title.length > 0 ? sub.title : null) ?? k;\n if (t === 'boolean') {\n return (\n <div className=\"space-y-1.5\">\n <p className=\"text-sm font-medium text-fg\">{title}</p>\n <BooleanField\n s={sub}\n value={value === true}\n disabled={disabled}\n onChange={(b) => onValue(b)}\n />\n </div>\n );\n }\n if (t === 'number' || t === 'integer') {\n return (\n <div className=\"space-y-1.5\">\n <p className=\"text-sm font-medium text-fg\">{title}</p>\n <NumberField\n s={sub}\n value={typeof value === 'number' ? value : 0}\n disabled={disabled}\n onChange={onValue}\n />\n </div>\n );\n }\n if (t === 'string') {\n return (\n <div className=\"space-y-1.5\">\n <p className=\"text-sm font-medium text-fg\">{title}</p>\n <StringField\n name={k}\n s={sub}\n value={typeof value === 'string' ? value : ''}\n disabled={disabled}\n onChange={onValue}\n />\n </div>\n );\n }\n if (t === 'array') {\n const items = sub.items;\n if (isRecord(items) && items.type === 'string') {\n return (\n <div className=\"space-y-1.5\">\n <p className=\"text-sm font-medium text-fg\">{title}</p>\n <ArrayStringField\n s={sub}\n value={Array.isArray(value) && value.every((x) => typeof x === 'string') ? value : []}\n disabled={disabled}\n onChange={onValue}\n />\n </div>\n );\n }\n }\n return (\n <p className=\"text-xs text-fg-muted\">\n {title}: unsupported field type\n {typeof t === 'string' ? ` (${t})` : ''}\n </p>\n );\n}\n\n/**\n * Renders a JSON Schema (type: object) as a form using Gateway Console design tokens.\n */\nexport function SchemaForm({ schema, values, onChange, disabled = false, className }: SchemaFormProps) {\n const fields = useMemo(() => {\n if (schema.type !== 'object') return [];\n return sortedFields(schema);\n }, [schema]);\n\n const grouped = useMemo(() => {\n if (fields.length === 0) return new Map<string, FieldDef[]>();\n return groupFields(fields);\n }, [fields]);\n\n const setKey = useCallback(\n (key: string, next: unknown) => {\n onChange({ ...values, [key]: next });\n },\n [onChange, values],\n );\n\n if (schema.type !== 'object' || !isRecord(schema.properties) || fields.length === 0) {\n return null;\n }\n\n const groupKeys = Array.from(grouped.keys()).sort((a, b) => {\n if (a === '') return -1;\n if (b === '') return 1;\n return a.localeCompare(b);\n });\n\n return (\n <div className={cn('flex flex-col gap-4', className)}>\n {groupKeys.map((gk) => {\n const list = grouped.get(gk) ?? [];\n const block = list.map((f) => (\n <FieldRow\n key={f.key}\n k={f.key}\n sub={f.sub}\n value={values[f.key]}\n onValue={(v) => setKey(f.key, v)}\n disabled={disabled}\n />\n ));\n if (gk === '') {\n return <div key=\"default\">{block}</div>;\n }\n return (\n <details\n key={gk}\n className=\"group rounded-lg border border-edge bg-surface-panel/40 open:bg-surface-base\"\n open\n >\n <summary className=\"cursor-pointer select-none px-3 py-2 text-sm font-medium text-fg group-open:rounded-b-none\">\n {gk}\n </summary>\n <div className=\"space-y-4 border-t border-edge p-3\">{block}</div>\n </details>\n );\n })}\n </div>\n );\n}\n\n/** Extract per-key defaults from a JSON object schema for \"Reset\" actions. */\nexport function extractObjectDefaults(\n schema: JsonSchema,\n): Record<string, unknown> {\n const out: Record<string, unknown> = {};\n if (schema.type !== 'object' || !isRecord(schema.properties)) {\n return out;\n }\n for (const [k, sub] of Object.entries(schema.properties)) {\n if (!isRecord(sub)) continue;\n if (Object.prototype.hasOwnProperty.call(sub, 'default')) {\n out[k] = sub.default;\n }\n }\n return out;\n}\n","import { useCallback, useEffect, useMemo, useState } from 'react';\nimport useSWR from 'swr';\n\nimport { Button } from '@/components/ui/button';\nimport { extractObjectDefaults, SchemaForm, type JsonSchema } from '@/components/ui/schema-form';\nimport { apiFetch, fetchJson } from '@/lib/fetch';\nimport { apiUrl } from '@/lib/url';\nimport { messages } from '@/i18n/messages';\nimport { useGatewayStore } from '@/stores/gateway-store';\nimport { useLocaleStore } from '@/stores/locale-store';\n\ntype ExtensionDetailResponse = {\n manifest: { configSchema?: JsonSchema };\n};\n\nexport function ExtensionAutoSettings({ extensionId }: { extensionId: string }) {\n const language = useLocaleStore((s) => s.language);\n const a = messages(language).agentSettings;\n const hasToken = useGatewayStore((s) => Boolean(s.token));\n const { data: detail, error: detailError } = useSWR(\n hasToken && extensionId ? `ext-detail-${extensionId}` : null,\n () => fetchJson<ExtensionDetailResponse>(apiUrl(`/api/extensions/${encodeURIComponent(extensionId)}`)),\n );\n\n const { data: remoteConfig, mutate: mutateConfig, error: configError } = useSWR(\n hasToken && extensionId ? `ext-cfg-${extensionId}` : null,\n () =>\n fetchJson<Record<string, unknown>>(\n apiUrl(`/api/extensions/${encodeURIComponent(extensionId)}/config`),\n ),\n );\n\n const schema = detail?.manifest?.configSchema;\n const defaults = useMemo(\n () => (schema && schema.type === 'object' ? extractObjectDefaults(schema) : {}),\n [schema],\n );\n\n const savedValues = useMemo(\n () => ({ ...defaults, ...(remoteConfig ?? {}) }),\n [defaults, remoteConfig],\n );\n\n const [localValues, setLocalValues] = useState<Record<string, unknown>>({});\n const [isDirty, setIsDirty] = useState(false);\n const [saving, setSaving] = useState(false);\n const [saveError, setSaveError] = useState<string | null>(null);\n const [saveSuccess, setSaveSuccess] = useState(false);\n\n useEffect(() => {\n if (isDirty) return;\n setLocalValues(savedValues);\n }, [isDirty, savedValues]);\n\n const onChange = useCallback((next: Record<string, unknown>) => {\n setLocalValues(next);\n setIsDirty(true);\n setSaveError(null);\n }, []);\n\n const handleDiscard = useCallback(() => {\n setLocalValues(savedValues);\n setIsDirty(false);\n setSaveError(null);\n }, [savedValues]);\n\n const handleResetDefaults = useCallback(() => {\n if (!schema || schema.type !== 'object') return;\n setLocalValues({ ...extractObjectDefaults(schema) });\n setIsDirty(true);\n setSaveError(null);\n }, [schema]);\n\n const handleSave = useCallback(async () => {\n if (!extensionId) return;\n setSaving(true);\n setSaveError(null);\n try {\n const res = await apiFetch(\n apiUrl(`/api/extensions/${encodeURIComponent(extensionId)}/config`),\n { method: 'PATCH', body: JSON.stringify(localValues) },\n );\n if (!res.ok) {\n const body = (await res.json().catch(() => ({}))) as { error?: { message?: string } };\n throw new Error(body.error?.message ?? res.statusText);\n }\n await mutateConfig(localValues, false);\n setIsDirty(false);\n setSaveSuccess(true);\n window.setTimeout(() => setSaveSuccess(false), 3000);\n } catch (e) {\n setSaveError(e instanceof Error ? e.message : String(e));\n } finally {\n setSaving(false);\n }\n }, [extensionId, localValues, mutateConfig]);\n\n if (!hasToken) {\n return null;\n }\n\n if (detailError || configError) {\n const err = (detailError ?? configError) as Error;\n return (\n <p className=\"text-sm text-fg-muted\">\n Could not load extension settings: {err instanceof Error ? err.message : String(err)}\n </p>\n );\n }\n\n if (!schema || schema.type !== 'object') {\n return null;\n }\n\n return (\n <div className=\"mb-6 flex flex-col gap-3 rounded-xl border border-edge bg-surface-base p-4\">\n <div className=\"flex flex-wrap items-center justify-between gap-2\">\n <h2 className=\"text-sm font-semibold text-fg\">Configuration</h2>\n <div className=\"flex flex-wrap items-center gap-2\">\n {saveSuccess ? (\n <span className=\"text-xs text-emerald-600 dark:text-emerald-400\">{a.saved}</span>\n ) : null}\n {saveError ? <span className=\"text-xs text-red-600 dark:text-red-400\">{saveError}</span> : null}\n <Button\n type=\"button\"\n variant=\"ghost\"\n className=\"h-8 text-xs\"\n disabled={!isDirty}\n onClick={handleDiscard}\n >\n {a.discard}\n </Button>\n <Button\n type=\"button\"\n variant=\"ghost\"\n className=\"h-8 text-xs\"\n onClick={handleResetDefaults}\n >\n Reset to defaults\n </Button>\n <Button\n type=\"button\"\n variant=\"primary\"\n className=\"h-8 text-xs\"\n disabled={!isDirty || saving}\n onClick={() => void handleSave()}\n >\n {saving ? a.saving : a.save}\n </Button>\n </div>\n </div>\n <SchemaForm schema={schema} values={localValues} onChange={onChange} disabled={saving} />\n </div>\n );\n}\n","/**\n * Extension settings: auto-generated config form (configSchema) + optional iframe (settingsPanels).\n *\n * Routes: /settings/ext/:extensionId, /settings/ext/:extensionId/:panelId\n */\n\nimport { Link, useParams } from 'react-router-dom';\n\nimport { ExtensionImageProviderSettings } from '@/features/settings/extension-image-provider-settings';\nimport { messages } from '@/i18n/messages';\nimport { useLocaleStore } from '@/stores/locale-store';\n\nimport { ExtensionAutoSettings } from './extension-auto-settings';\nimport { ExtensionIframeHost } from './extension-iframe-host';\nimport { useExtensions } from './extension-provider';\n\nexport function ExtensionSettingsPage() {\n const language = useLocaleStore((s) => s.language);\n const m = messages(language);\n const xm = m.extensionImageGen;\n const { extensionId, panelId } = useParams<{ extensionId: string; panelId?: string }>();\n const extensions = useExtensions();\n\n if (!extensionId) {\n return <SettingsPanelNotFound message=\"No extension ID provided.\" />;\n }\n\n const extension = extensions.find((ext) => ext.id === extensionId);\n if (!extension) {\n return (\n <SettingsPanelNotFound\n message={`Extension \"${extensionId}\" not found or is not available in this workspace.`}\n />\n );\n }\n\n const panels = extension.ui?.contributions?.settingsPanels;\n const panel = panelId\n ? panels?.find((p) => p.id === panelId || p.id === `${extensionId}.${panelId}`)\n : panels?.[0];\n\n const hasIframe = Boolean(panel && extension.ui);\n const hasAutoForm = Boolean(extension.hasConfigSchema);\n const isImageGeneration = extension.kind === 'image-generation';\n\n if (!hasAutoForm && !hasIframe && !isImageGeneration) {\n return (\n <SettingsPanelNotFound\n message={`Extension \"${extensionId}\" has no settings panels or config schema.`}\n />\n );\n }\n\n const title = panel?.title ?? `${extension.name} Settings`;\n\n return (\n <div className=\"mx-auto flex w-full max-w-app-main flex-col gap-3 px-4 py-8\">\n <h1 className=\"text-lg font-semibold text-fg\">{title}</h1>\n {isImageGeneration ? (\n <div className=\"flex flex-col gap-2 rounded-lg border border-edge-subtle bg-surface-base px-4 py-3 text-sm\">\n <p className=\"leading-relaxed text-fg-muted\">{xm.banner}</p>\n <Link\n to=\"/settings/image-models\"\n className=\"w-fit font-medium text-accent hover:underline\"\n title={m.imageModelsSettings.imageModelsLinkTitle}\n >\n {xm.openImageModels}\n </Link>\n </div>\n ) : null}\n {isImageGeneration ? <ExtensionImageProviderSettings extensionId={extensionId} /> : null}\n {hasAutoForm ? <ExtensionAutoSettings extensionId={extensionId} /> : null}\n {hasIframe && panel && extension.ui ? (\n <div className=\"overflow-hidden rounded-xl border border-edge bg-surface-base\">\n <ExtensionIframeHost\n extensionId={extensionId}\n extensionName={extension.name}\n entrypoint={panel.entrypoint}\n permissions={extension.ui?.permissions}\n title={panel.title}\n className=\"w-full\"\n minHeight={120}\n maxHeight={2000}\n />\n </div>\n ) : null}\n </div>\n );\n}\n\nfunction SettingsPanelNotFound({ message }: { message: string }) {\n return (\n <div className=\"mx-auto flex w-full max-w-app-main flex-col gap-3 px-4 py-8\">\n <p className=\"text-sm text-fg-muted\">{message}</p>\n </div>\n );\n}\n"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- import{o as e}from"./vendor-swr-B5fPo7KK.js";import{hn as t,un as n,xt as r}from"./index-DZLKmP08.js";function i(){return n(`/api/workspace/heartbeat-md`)}async function a(){let e=await t(i());return typeof e.payload?.content==`string`?e.payload.content:``}function o(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function s(e){let t=o(e)?e:{},n=o(t.gateway)?t.gateway:{},r=o(n.heartbeat)?n.heartbeat:{},i=r.activeHours,a=o(i)?i:null,s=a&&typeof a.start==`string`&&typeof a.end==`string`&&a.start&&a.end?{start:a.start,end:a.end,timezone:typeof a.timezone==`string`?a.timezone:``}:null;return{enabled:!!(r.enabled??!0),intervalMs:typeof r.intervalMs==`number`&&Number.isFinite(r.intervalMs)?r.intervalMs:18e5,target:typeof r.target==`string`?r.target:``,targetChatId:typeof r.targetChatId==`string`?r.targetChatId:``,prompt:typeof r.prompt==`string`?r.prompt:``,ackMaxChars:typeof r.ackMaxChars==`number`&&Number.isFinite(r.ackMaxChars)?r.ackMaxChars:``,isolatedSession:!!r.isolatedSession,activeHours:s}}function c(e){let t={enabled:e.enabled,intervalMs:e.intervalMs};return e.target.trim()?t.target=e.target.trim():t.target=null,e.targetChatId.trim()?t.targetChatId=e.targetChatId.trim():t.targetChatId=null,e.prompt.trim()?t.prompt=e.prompt.trim():t.prompt=null,e.ackMaxChars===``||e.ackMaxChars===void 0?t.ackMaxChars=null:t.ackMaxChars=e.ackMaxChars,e.isolatedSession?t.isolatedSession=!0:t.isolatedSession=null,e.activeHours?.start?.trim()&&e.activeHours?.end?.trim()?t.activeHours={start:e.activeHours.start.trim(),end:e.activeHours.end.trim(),...e.activeHours.timezone.trim()?{timezone:e.activeHours.timezone.trim()}:{}}:t.activeHours=null,t}async function l(e){await t(n(`/api/config`),{method:`PATCH`,body:JSON.stringify({gateway:{heartbeat:c(e)}})}),r()}async function u(r){await t(n(`/api/workspace/heartbeat-md`),{method:`PUT`,body:JSON.stringify({content:r})}),e(i())}async function d(e){await t(n(`/api/heartbeat/trigger`),{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify(e?{reason:e}:{})})}export{a,d as i,l as n,i as o,u as r,s as t};
2
- //# sourceMappingURL=heartbeat-config-api-D4vLbsOG.js.map
1
+ import{o as e}from"./vendor-swr-B5fPo7KK.js";import{hn as t,un as n,xt as r}from"./index-8IFT6i7x.js";function i(){return n(`/api/workspace/heartbeat-md`)}async function a(){let e=await t(i());return typeof e.payload?.content==`string`?e.payload.content:``}function o(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function s(e){let t=o(e)?e:{},n=o(t.gateway)?t.gateway:{},r=o(n.heartbeat)?n.heartbeat:{},i=r.activeHours,a=o(i)?i:null,s=a&&typeof a.start==`string`&&typeof a.end==`string`&&a.start&&a.end?{start:a.start,end:a.end,timezone:typeof a.timezone==`string`?a.timezone:``}:null;return{enabled:!!(r.enabled??!0),intervalMs:typeof r.intervalMs==`number`&&Number.isFinite(r.intervalMs)?r.intervalMs:18e5,target:typeof r.target==`string`?r.target:``,targetChatId:typeof r.targetChatId==`string`?r.targetChatId:``,prompt:typeof r.prompt==`string`?r.prompt:``,ackMaxChars:typeof r.ackMaxChars==`number`&&Number.isFinite(r.ackMaxChars)?r.ackMaxChars:``,isolatedSession:!!r.isolatedSession,activeHours:s}}function c(e){let t={enabled:e.enabled,intervalMs:e.intervalMs};return e.target.trim()?t.target=e.target.trim():t.target=null,e.targetChatId.trim()?t.targetChatId=e.targetChatId.trim():t.targetChatId=null,e.prompt.trim()?t.prompt=e.prompt.trim():t.prompt=null,e.ackMaxChars===``||e.ackMaxChars===void 0?t.ackMaxChars=null:t.ackMaxChars=e.ackMaxChars,e.isolatedSession?t.isolatedSession=!0:t.isolatedSession=null,e.activeHours?.start?.trim()&&e.activeHours?.end?.trim()?t.activeHours={start:e.activeHours.start.trim(),end:e.activeHours.end.trim(),...e.activeHours.timezone.trim()?{timezone:e.activeHours.timezone.trim()}:{}}:t.activeHours=null,t}async function l(e){await t(n(`/api/config`),{method:`PATCH`,body:JSON.stringify({gateway:{heartbeat:c(e)}})}),r()}async function u(r){await t(n(`/api/workspace/heartbeat-md`),{method:`PUT`,body:JSON.stringify({content:r})}),e(i())}async function d(e){await t(n(`/api/heartbeat/trigger`),{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify(e?{reason:e}:{})})}export{a,d as i,l as n,i as o,u as r,s as t};
2
+ //# sourceMappingURL=heartbeat-config-api-B9hxMalj.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"heartbeat-config-api-D4vLbsOG.js","names":[],"sources":["../../../../../web/src/features/settings/heartbeat-md-swr.ts","../../../../../web/src/features/settings/heartbeat-config-api.ts"],"sourcesContent":["import { fetchJson } from '@/lib/fetch';\nimport { apiUrl } from '@/lib/url';\n\nexport function heartbeatMdSwrKey(): string {\n return apiUrl('/api/workspace/heartbeat-md');\n}\n\nexport async function fetchHeartbeatMdSwr(): Promise<string> {\n const res = await fetchJson<{ ok?: boolean; payload?: { content?: string } }>(heartbeatMdSwrKey());\n return typeof res.payload?.content === 'string' ? res.payload.content : '';\n}\n","import { revalidateGatewayConfig } from '@/features/gateway/gateway-config-swr';\nimport { fetchJson } from '@/lib/fetch';\nimport { apiUrl } from '@/lib/url';\nimport { heartbeatMdSwrKey } from '@/features/settings/heartbeat-md-swr';\nimport { mutate } from 'swr';\n\nimport type { HeartbeatSettingsState } from './heartbeat-settings.types';\n\nexport type { HeartbeatSettingsState } from './heartbeat-settings.types';\n\nfunction isRecord(v: unknown): v is Record<string, unknown> {\n return v !== null && typeof v === 'object' && !Array.isArray(v);\n}\n\nexport function normalizeHeartbeatFromConfig(config: unknown): HeartbeatSettingsState {\n const c = isRecord(config) ? config : {};\n const gw = isRecord(c.gateway) ? c.gateway : {};\n const hb = isRecord(gw.heartbeat) ? gw.heartbeat : {};\n const ahRaw = hb.activeHours;\n const ah = isRecord(ahRaw) ? ahRaw : null;\n const activeHours =\n ah && typeof ah.start === 'string' && typeof ah.end === 'string' && ah.start && ah.end\n ? {\n start: ah.start,\n end: ah.end,\n timezone: typeof ah.timezone === 'string' ? ah.timezone : '',\n }\n : null;\n return {\n enabled: Boolean(hb.enabled ?? true),\n intervalMs: typeof hb.intervalMs === 'number' && Number.isFinite(hb.intervalMs) ? hb.intervalMs : 1_800_000,\n target: typeof hb.target === 'string' ? hb.target : '',\n targetChatId: typeof hb.targetChatId === 'string' ? hb.targetChatId : '',\n prompt: typeof hb.prompt === 'string' ? hb.prompt : '',\n ackMaxChars:\n typeof hb.ackMaxChars === 'number' && Number.isFinite(hb.ackMaxChars) ? hb.ackMaxChars : '',\n isolatedSession: Boolean(hb.isolatedSession),\n activeHours,\n };\n}\n\nfunction buildHeartbeatPayload(state: HeartbeatSettingsState): Record<string, unknown> {\n const p: Record<string, unknown> = {\n enabled: state.enabled,\n intervalMs: state.intervalMs,\n };\n if (state.target.trim()) p.target = state.target.trim();\n else p.target = null;\n if (state.targetChatId.trim()) p.targetChatId = state.targetChatId.trim();\n else p.targetChatId = null;\n if (state.prompt.trim()) p.prompt = state.prompt.trim();\n else p.prompt = null;\n if (state.ackMaxChars === '' || state.ackMaxChars === undefined) {\n p.ackMaxChars = null;\n } else {\n p.ackMaxChars = state.ackMaxChars;\n }\n if (state.isolatedSession) p.isolatedSession = true;\n else p.isolatedSession = null;\n if (state.activeHours?.start?.trim() && state.activeHours?.end?.trim()) {\n p.activeHours = {\n start: state.activeHours.start.trim(),\n end: state.activeHours.end.trim(),\n ...(state.activeHours.timezone.trim()\n ? { timezone: state.activeHours.timezone.trim() }\n : {}),\n };\n } else {\n p.activeHours = null;\n }\n return p;\n}\n\nexport async function patchHeartbeatSettings(state: HeartbeatSettingsState): Promise<void> {\n await fetchJson(apiUrl('/api/config'), {\n method: 'PATCH',\n body: JSON.stringify({\n gateway: {\n heartbeat: buildHeartbeatPayload(state),\n },\n }),\n });\n void revalidateGatewayConfig();\n}\n\nexport async function fetchHeartbeatMd(): Promise<string> {\n const res = await fetchJson<{ ok?: boolean; payload?: { content?: string } }>(\n apiUrl('/api/workspace/heartbeat-md'),\n );\n return typeof res.payload?.content === 'string' ? res.payload.content : '';\n}\n\nexport async function putHeartbeatMd(content: string): Promise<void> {\n await fetchJson(apiUrl('/api/workspace/heartbeat-md'), {\n method: 'PUT',\n body: JSON.stringify({ content }),\n });\n void mutate(heartbeatMdSwrKey());\n}\n\n/** Queue one heartbeat run (same path as the interval timer). */\nexport async function triggerHeartbeat(reason?: string): Promise<void> {\n await fetchJson(apiUrl('/api/heartbeat/trigger'), {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(reason ? { reason } : {}),\n });\n}\n"],"mappings":"sGAGA,SAAgB,GAA4B,CAC1C,OAAO,EAAO,8BAA8B,CAG9C,eAAsB,GAAuC,CAC3D,IAAM,EAAM,MAAM,EAA4D,GAAmB,CAAC,CAClG,OAAO,OAAO,EAAI,SAAS,SAAY,SAAW,EAAI,QAAQ,QAAU,GCC1E,SAAS,EAAS,EAA0C,CAC1D,OAAqB,OAAO,GAAM,YAA3B,GAAuC,CAAC,MAAM,QAAQ,EAAE,CAGjE,SAAgB,EAA6B,EAAyC,CACpF,IAAM,EAAI,EAAS,EAAO,CAAG,EAAS,EAAE,CAClC,EAAK,EAAS,EAAE,QAAQ,CAAG,EAAE,QAAU,EAAE,CACzC,EAAK,EAAS,EAAG,UAAU,CAAG,EAAG,UAAY,EAAE,CAC/C,EAAQ,EAAG,YACX,EAAK,EAAS,EAAM,CAAG,EAAQ,KAC/B,EACJ,GAAM,OAAO,EAAG,OAAU,UAAY,OAAO,EAAG,KAAQ,UAAY,EAAG,OAAS,EAAG,IAC/E,CACE,MAAO,EAAG,MACV,IAAK,EAAG,IACR,SAAU,OAAO,EAAG,UAAa,SAAW,EAAG,SAAW,GAC3D,CACD,KACN,MAAO,CACL,QAAS,GAAQ,EAAG,SAAW,IAC/B,WAAY,OAAO,EAAG,YAAe,UAAY,OAAO,SAAS,EAAG,WAAW,CAAG,EAAG,WAAa,KAClG,OAAQ,OAAO,EAAG,QAAW,SAAW,EAAG,OAAS,GACpD,aAAc,OAAO,EAAG,cAAiB,SAAW,EAAG,aAAe,GACtE,OAAQ,OAAO,EAAG,QAAW,SAAW,EAAG,OAAS,GACpD,YACE,OAAO,EAAG,aAAgB,UAAY,OAAO,SAAS,EAAG,YAAY,CAAG,EAAG,YAAc,GAC3F,gBAAiB,EAAQ,EAAG,gBAC5B,cACD,CAGH,SAAS,EAAsB,EAAwD,CACrF,IAAM,EAA6B,CACjC,QAAS,EAAM,QACf,WAAY,EAAM,WACnB,CAyBD,OAxBI,EAAM,OAAO,MAAM,CAAE,EAAE,OAAS,EAAM,OAAO,MAAM,CAClD,EAAE,OAAS,KACZ,EAAM,aAAa,MAAM,CAAE,EAAE,aAAe,EAAM,aAAa,MAAM,CACpE,EAAE,aAAe,KAClB,EAAM,OAAO,MAAM,CAAE,EAAE,OAAS,EAAM,OAAO,MAAM,CAClD,EAAE,OAAS,KACZ,EAAM,cAAgB,IAAM,EAAM,cAAgB,IAAA,GACpD,EAAE,YAAc,KAEhB,EAAE,YAAc,EAAM,YAEpB,EAAM,gBAAiB,EAAE,gBAAkB,GAC1C,EAAE,gBAAkB,KACrB,EAAM,aAAa,OAAO,MAAM,EAAI,EAAM,aAAa,KAAK,MAAM,CACpE,EAAE,YAAc,CACd,MAAO,EAAM,YAAY,MAAM,MAAM,CACrC,IAAK,EAAM,YAAY,IAAI,MAAM,CACjC,GAAI,EAAM,YAAY,SAAS,MAAM,CACjC,CAAE,SAAU,EAAM,YAAY,SAAS,MAAM,CAAE,CAC/C,EAAE,CACP,CAED,EAAE,YAAc,KAEX,EAGT,eAAsB,EAAuB,EAA8C,CACzF,MAAM,EAAU,EAAO,cAAc,CAAE,CACrC,OAAQ,QACR,KAAM,KAAK,UAAU,CACnB,QAAS,CACP,UAAW,EAAsB,EAAM,CACxC,CACF,CAAC,CACH,CAAC,CACG,GAAyB,CAUhC,eAAsB,EAAe,EAAgC,CACnE,MAAM,EAAU,EAAO,8BAA8B,CAAE,CACrD,OAAQ,MACR,KAAM,KAAK,UAAU,CAAE,UAAS,CAAC,CAClC,CAAC,CACG,EAAO,GAAmB,CAAC,CAIlC,eAAsB,EAAiB,EAAgC,CACrE,MAAM,EAAU,EAAO,yBAAyB,CAAE,CAChD,OAAQ,OACR,QAAS,CAAE,eAAgB,mBAAoB,CAC/C,KAAM,KAAK,UAAU,EAAS,CAAE,SAAQ,CAAG,EAAE,CAAC,CAC/C,CAAC"}
1
+ {"version":3,"file":"heartbeat-config-api-B9hxMalj.js","names":[],"sources":["../../../../../web/src/features/settings/heartbeat-md-swr.ts","../../../../../web/src/features/settings/heartbeat-config-api.ts"],"sourcesContent":["import { fetchJson } from '@/lib/fetch';\nimport { apiUrl } from '@/lib/url';\n\nexport function heartbeatMdSwrKey(): string {\n return apiUrl('/api/workspace/heartbeat-md');\n}\n\nexport async function fetchHeartbeatMdSwr(): Promise<string> {\n const res = await fetchJson<{ ok?: boolean; payload?: { content?: string } }>(heartbeatMdSwrKey());\n return typeof res.payload?.content === 'string' ? res.payload.content : '';\n}\n","import { revalidateGatewayConfig } from '@/features/gateway/gateway-config-swr';\nimport { fetchJson } from '@/lib/fetch';\nimport { apiUrl } from '@/lib/url';\nimport { heartbeatMdSwrKey } from '@/features/settings/heartbeat-md-swr';\nimport { mutate } from 'swr';\n\nimport type { HeartbeatSettingsState } from './heartbeat-settings.types';\n\nexport type { HeartbeatSettingsState } from './heartbeat-settings.types';\n\nfunction isRecord(v: unknown): v is Record<string, unknown> {\n return v !== null && typeof v === 'object' && !Array.isArray(v);\n}\n\nexport function normalizeHeartbeatFromConfig(config: unknown): HeartbeatSettingsState {\n const c = isRecord(config) ? config : {};\n const gw = isRecord(c.gateway) ? c.gateway : {};\n const hb = isRecord(gw.heartbeat) ? gw.heartbeat : {};\n const ahRaw = hb.activeHours;\n const ah = isRecord(ahRaw) ? ahRaw : null;\n const activeHours =\n ah && typeof ah.start === 'string' && typeof ah.end === 'string' && ah.start && ah.end\n ? {\n start: ah.start,\n end: ah.end,\n timezone: typeof ah.timezone === 'string' ? ah.timezone : '',\n }\n : null;\n return {\n enabled: Boolean(hb.enabled ?? true),\n intervalMs: typeof hb.intervalMs === 'number' && Number.isFinite(hb.intervalMs) ? hb.intervalMs : 1_800_000,\n target: typeof hb.target === 'string' ? hb.target : '',\n targetChatId: typeof hb.targetChatId === 'string' ? hb.targetChatId : '',\n prompt: typeof hb.prompt === 'string' ? hb.prompt : '',\n ackMaxChars:\n typeof hb.ackMaxChars === 'number' && Number.isFinite(hb.ackMaxChars) ? hb.ackMaxChars : '',\n isolatedSession: Boolean(hb.isolatedSession),\n activeHours,\n };\n}\n\nfunction buildHeartbeatPayload(state: HeartbeatSettingsState): Record<string, unknown> {\n const p: Record<string, unknown> = {\n enabled: state.enabled,\n intervalMs: state.intervalMs,\n };\n if (state.target.trim()) p.target = state.target.trim();\n else p.target = null;\n if (state.targetChatId.trim()) p.targetChatId = state.targetChatId.trim();\n else p.targetChatId = null;\n if (state.prompt.trim()) p.prompt = state.prompt.trim();\n else p.prompt = null;\n if (state.ackMaxChars === '' || state.ackMaxChars === undefined) {\n p.ackMaxChars = null;\n } else {\n p.ackMaxChars = state.ackMaxChars;\n }\n if (state.isolatedSession) p.isolatedSession = true;\n else p.isolatedSession = null;\n if (state.activeHours?.start?.trim() && state.activeHours?.end?.trim()) {\n p.activeHours = {\n start: state.activeHours.start.trim(),\n end: state.activeHours.end.trim(),\n ...(state.activeHours.timezone.trim()\n ? { timezone: state.activeHours.timezone.trim() }\n : {}),\n };\n } else {\n p.activeHours = null;\n }\n return p;\n}\n\nexport async function patchHeartbeatSettings(state: HeartbeatSettingsState): Promise<void> {\n await fetchJson(apiUrl('/api/config'), {\n method: 'PATCH',\n body: JSON.stringify({\n gateway: {\n heartbeat: buildHeartbeatPayload(state),\n },\n }),\n });\n void revalidateGatewayConfig();\n}\n\nexport async function fetchHeartbeatMd(): Promise<string> {\n const res = await fetchJson<{ ok?: boolean; payload?: { content?: string } }>(\n apiUrl('/api/workspace/heartbeat-md'),\n );\n return typeof res.payload?.content === 'string' ? res.payload.content : '';\n}\n\nexport async function putHeartbeatMd(content: string): Promise<void> {\n await fetchJson(apiUrl('/api/workspace/heartbeat-md'), {\n method: 'PUT',\n body: JSON.stringify({ content }),\n });\n void mutate(heartbeatMdSwrKey());\n}\n\n/** Queue one heartbeat run (same path as the interval timer). */\nexport async function triggerHeartbeat(reason?: string): Promise<void> {\n await fetchJson(apiUrl('/api/heartbeat/trigger'), {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(reason ? { reason } : {}),\n });\n}\n"],"mappings":"sGAGA,SAAgB,GAA4B,CAC1C,OAAO,EAAO,8BAA8B,CAG9C,eAAsB,GAAuC,CAC3D,IAAM,EAAM,MAAM,EAA4D,GAAmB,CAAC,CAClG,OAAO,OAAO,EAAI,SAAS,SAAY,SAAW,EAAI,QAAQ,QAAU,GCC1E,SAAS,EAAS,EAA0C,CAC1D,OAAqB,OAAO,GAAM,YAA3B,GAAuC,CAAC,MAAM,QAAQ,EAAE,CAGjE,SAAgB,EAA6B,EAAyC,CACpF,IAAM,EAAI,EAAS,EAAO,CAAG,EAAS,EAAE,CAClC,EAAK,EAAS,EAAE,QAAQ,CAAG,EAAE,QAAU,EAAE,CACzC,EAAK,EAAS,EAAG,UAAU,CAAG,EAAG,UAAY,EAAE,CAC/C,EAAQ,EAAG,YACX,EAAK,EAAS,EAAM,CAAG,EAAQ,KAC/B,EACJ,GAAM,OAAO,EAAG,OAAU,UAAY,OAAO,EAAG,KAAQ,UAAY,EAAG,OAAS,EAAG,IAC/E,CACE,MAAO,EAAG,MACV,IAAK,EAAG,IACR,SAAU,OAAO,EAAG,UAAa,SAAW,EAAG,SAAW,GAC3D,CACD,KACN,MAAO,CACL,QAAS,GAAQ,EAAG,SAAW,IAC/B,WAAY,OAAO,EAAG,YAAe,UAAY,OAAO,SAAS,EAAG,WAAW,CAAG,EAAG,WAAa,KAClG,OAAQ,OAAO,EAAG,QAAW,SAAW,EAAG,OAAS,GACpD,aAAc,OAAO,EAAG,cAAiB,SAAW,EAAG,aAAe,GACtE,OAAQ,OAAO,EAAG,QAAW,SAAW,EAAG,OAAS,GACpD,YACE,OAAO,EAAG,aAAgB,UAAY,OAAO,SAAS,EAAG,YAAY,CAAG,EAAG,YAAc,GAC3F,gBAAiB,EAAQ,EAAG,gBAC5B,cACD,CAGH,SAAS,EAAsB,EAAwD,CACrF,IAAM,EAA6B,CACjC,QAAS,EAAM,QACf,WAAY,EAAM,WACnB,CAyBD,OAxBI,EAAM,OAAO,MAAM,CAAE,EAAE,OAAS,EAAM,OAAO,MAAM,CAClD,EAAE,OAAS,KACZ,EAAM,aAAa,MAAM,CAAE,EAAE,aAAe,EAAM,aAAa,MAAM,CACpE,EAAE,aAAe,KAClB,EAAM,OAAO,MAAM,CAAE,EAAE,OAAS,EAAM,OAAO,MAAM,CAClD,EAAE,OAAS,KACZ,EAAM,cAAgB,IAAM,EAAM,cAAgB,IAAA,GACpD,EAAE,YAAc,KAEhB,EAAE,YAAc,EAAM,YAEpB,EAAM,gBAAiB,EAAE,gBAAkB,GAC1C,EAAE,gBAAkB,KACrB,EAAM,aAAa,OAAO,MAAM,EAAI,EAAM,aAAa,KAAK,MAAM,CACpE,EAAE,YAAc,CACd,MAAO,EAAM,YAAY,MAAM,MAAM,CACrC,IAAK,EAAM,YAAY,IAAI,MAAM,CACjC,GAAI,EAAM,YAAY,SAAS,MAAM,CACjC,CAAE,SAAU,EAAM,YAAY,SAAS,MAAM,CAAE,CAC/C,EAAE,CACP,CAED,EAAE,YAAc,KAEX,EAGT,eAAsB,EAAuB,EAA8C,CACzF,MAAM,EAAU,EAAO,cAAc,CAAE,CACrC,OAAQ,QACR,KAAM,KAAK,UAAU,CACnB,QAAS,CACP,UAAW,EAAsB,EAAM,CACxC,CACF,CAAC,CACH,CAAC,CACG,GAAyB,CAUhC,eAAsB,EAAe,EAAgC,CACnE,MAAM,EAAU,EAAO,8BAA8B,CAAE,CACrD,OAAQ,MACR,KAAM,KAAK,UAAU,CAAE,UAAS,CAAC,CAClC,CAAC,CACG,EAAO,GAAmB,CAAC,CAIlC,eAAsB,EAAiB,EAAgC,CACrE,MAAM,EAAU,EAAO,yBAAyB,CAAE,CAChD,OAAQ,OACR,QAAS,CAAE,eAAgB,mBAAoB,CAC/C,KAAM,KAAK,UAAU,EAAS,CAAE,SAAQ,CAAG,EAAE,CAAC,CAC/C,CAAC"}