imcp 0.1.13 → 0.1.14
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.
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{showToast}from"../notifications.js";import{state,setServerCounter,getServerCounter,clearEnvCountersForTab,clearServerRequirementCountersForTab}from"./state.js";function setupRealTimeValidation(e){const t=document.getElementById(e);if(!t)return;if(!t)return;const r=t.querySelector('input[name="name"]');r&&r.addEventListener("input",(e=>{const t=e.target.value.trim();t?/^[a-zA-Z0-9-_]+$/.test(t)?t.length>50?showValidationMessage(e.target,"Must not exceed 50 characters"):showValidationMessage(e.target,"Valid name",!1):showValidationMessage(e.target,"Only alphanumeric characters, hyphens, and underscores allowed"):showValidationMessage(e.target,"Name is required")}));const s=t.querySelector('input[name="displayName"]');s&&s.addEventListener("input",(e=>{const t=e.target.value.trim();t?t.length>100?showValidationMessage(e.target,"Must not exceed 100 characters"):showValidationMessage(e.target,"Valid display name",!1):showValidationMessage(e.target,"Display name is required")}));const a=t.querySelector('textarea[name="description"]');a&&a.addEventListener("input",(e=>{const t=e.target.value.trim();t.length>500?showValidationMessage(e.target,"Must not exceed 500 characters"):0===t.length?showValidationMessage(e.target,"Description is required"):showValidationMessage(e.target,"Valid description",!1)}));const n=t.querySelector('input[name="repository"]');n&&n.addEventListener("input",(e=>{const t=e.target.value.trim();if(t)try{new URL(t),showValidationMessage(e.target,"Valid URL",!1)}catch(t){showValidationMessage(e.target,"Invalid URL format")}else e.target.nextElementSibling?.remove()})),t.addEventListener("change",(e=>{if(e.target.name?.match(/servers\[\d+\]\.mode/)){const r=e.target.name.match(/servers\[(\d+)\]/)[1],s=t.querySelector(`[name="servers[${r}].installation.command"]`),a=t.querySelector(`[name="servers[${r}].installation.url"]`),n=t.querySelector(`[name="servers[${r}].installation.args"]`);"stdio"===e.target.value?(s&&(s.required=!0,showValidationMessage(s,"Command is required for stdio mode")),a&&(a.required=!1,a.value="",a.nextElementSibling?.remove())):"sse"===e.target.value&&(a&&(a.required=!0,showValidationMessage(a,"URL is required for sse mode")),s&&(s.required=!1,s.value="",s.nextElementSibling?.remove()),n&&(n.value="",n.nextElementSibling?.remove()))}})),t.addEventListener("input",(e=>{if(e.target.name?.includes(".installation.env[")){const t=e.target.name.match(/servers\[(\d+)\]\.installation\.env\[(\d+)\]\.(name|default)/);if(t){const[,r,s,a]=t;if("name"===a){const t=e.target.value.trim();t?/^[A-Z_][A-Z0-9_]*$/.test(t)?t.length>50?showValidationMessage(e.target,"Must not exceed 50 characters"):showValidationMessage(e.target,"Valid name",!1):showValidationMessage(e.target,"Must be uppercase with only letters, numbers, and underscores"):showValidationMessage(e.target,"Environment variable name is required")}}}}))}export async function submitForm(e,t,r=null){e.preventDefault();const s=e.target;let a,n=!1;if("create-category"===t)try{a=formDataToFeedConfiguration(s);const e=new URLSearchParams(window.location.search);n="edit"===e.get("action")&&e.get("category")===a.name}catch(e){return void console.error("Validation error:",e)}else{if("create-server"!==t)return void showToast("Invalid tab context for submission.","error");{if(!r||!r.name)return void showToast("No existing category selected or category data is missing.","error");const e=formDataToFeedConfiguration(s,!0,r);a=JSON.parse(JSON.stringify(r)),a.mcpServers=e.mcpServers||[];const t=new Set((a.requirements||[]).map((e=>`${e.type}|${e.name}|${e.version}`)));(e.requirements||[]).forEach((e=>{const r=`${e.type}|${e.name}|${e.version}`;t.has(r)||(a.requirements.push(e),t.add(r))})),n=!0}}try{const e=await fetch("/api/categories/onboard",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({categoryData:a,isUpdate:n})});if(!e.ok){const t=await e.json().catch((()=>({error:"Failed to parse error response"})));throw new Error(`HTTP error! status: ${e.status}, message: ${t.error||e.statusText}`)}await e.json();showToast("Form submitted successfully! See console for operation details.","success")}catch(e){console.error("Error submitting form:",e),showToast(`Error submitting form: ${e.message}. Please try again.`,"error")}}export function getFormData(e,t=!1,r=null){return formDataToFeedConfiguration(e,t,r)}function validateServerConfig(e){const t=[];if(e.name?/^[a-zA-Z0-9-_]+$/.test(e.name)?e.name.length>50&&t.push("Server name must not exceed 50 characters"):t.push("Server name must only contain alphanumeric characters, hyphens, and underscores"):t.push("Server name is required"),e.description&&""!==e.description.trim()?e.description.length>200&&t.push("Server description must not exceed 200 characters"):t.push("Server description is required"),e.mode?["stdio","sse"].includes(e.mode)||t.push('Server mode must be either "stdio" or "sse"'):t.push("Server mode is required"),"stdio"===e.mode)e.installation?.command?/^[a-zA-Z0-9-_.\\/]+$/.test(e.installation.command)||t.push("Command must only contain alphanumeric characters, hyphens, underscores, dots, and slashes"):t.push("Command is required for stdio server"),e.installation?.args?.length>0&&e.installation.args.forEach(((e,r)=>{/^[a-zA-Z0-9-_./\\]+$/.test(e)||t.push(`Argument ${r+1} must only contain alphanumeric characters, hyphens, underscores, dots, and slashes`)}));else if("sse"===e.mode)if(e.installation?.url)try{new URL(e.installation.url)}catch(e){t.push("Invalid URL format")}else t.push("URL is required for sse server");if(e.installation?.env&&Object.entries(e.installation.env).forEach((([e,r])=>{e?/^[A-Z_][A-Z0-9_]*$/.test(e)?e.length>50&&t.push(`Environment variable name "${e}" must not exceed 50 characters`):t.push(`Environment variable name "${e}" must be uppercase with only letters, numbers, and underscores`):t.push("Environment variable name is required"),r.Required&&!r.Default&&t.push(`Required environment variable "${e}" should have a default value`),r.Description&&r.Description.length>200&&t.push(`Description for environment variable "${e}" must not exceed 200 characters`)})),e.schemas)try{JSON.parse(e.schemas)}catch(e){t.push("Invalid JSON format in schemas")}return t}export function formDataToFeedConfiguration(e,t=!1,r=null){const s=new FormData(e),a={requirements:[],mcpServers:[]};let n;"onboardForm"===e.id?n="serversList":"onboardServerForm"===e.id?n="existingCategoryServersList":console.warn("[formDataToFeedConfiguration] Could not determine serversListId from formElement.id:",e.id),t?r&&(a.name=r.name):(a.name=s.get("name")||"",a.displayName=s.get("displayName")||"",a.description=s.get("description")||"",a.repository=s.get("repository")||void 0);const i=new Map,o=new Map;for(const[e,r]of s.entries()){if(t&&!e.startsWith("servers["))continue;const a=e.match(/^servers\[(\d+)\]\.(.+)$/);if(a){let t=parseInt(a[1],10);const n=a[2];let o=t;i.has(o)||i.set(o,{installation:{env:new Map},dependencies:{requirements:new Map},isNew:!0});const l=i.get(o);if("name"===n)l.name=r;else if("description"===n)l.description=r;else if("mode"===n)l.mode=r;else if("repository"===n)l.repository=r||void 0;else if("schemas"===n)l.schemas=r||void 0;else if("installation.command"===n)l.installation.command=r;else if("installation.args"===n)l.installation.args=r?r.split(",").map((e=>e.trim())).filter((e=>e)):[];else if("installation.url"===n)l.installation.url=r;else if("installation.isLocal"===n)l.installation.isLocal="on"===r;else if("installation.startingCommand"===n)l.installation.startingCommand=r.trim()||void 0;else if(n.startsWith("installation.env[")){const t=n.match(/^installation\.env\[(\d+)\]\.(name|default|required|description)$/);if(t){const a=parseInt(t[1],10),n=t[2];l.installation.env.has(a)||l.installation.env.set(a,{});const i=l.installation.env.get(a);i[n]="required"===n?"on"===s.get(e):r||void 0}}else if(n.startsWith("requirements[")){const e=n.match(/^requirements\[(\d+)\]\.(.+)$/);if(e){const t=parseInt(e[1],10),s=e[2];l.dependencies.requirements.has(t)||l.dependencies.requirements.set(t,{registry:{}});const a=l.dependencies.requirements.get(t);"name"===s?a.name=r:"type"===s?a.type=r:"version"===s?a.version=r:"order"===s?a.order=r?parseInt(r,10):void 0:"alias"===s?a.alias=r||void 0:"registryType"===s?a.registryType=r:s.startsWith("registry.githubRelease.")?(a.registry.githubRelease=a.registry.githubRelease||{},a.registry.githubRelease[s.substring(23)]=r||void 0):s.startsWith("registry.artifacts.")?(a.registry.artifacts=a.registry.artifacts||{},a.registry.artifacts[s.substring(19)]=r||void 0):s.startsWith("registry.local.")&&(a.registry.local=a.registry.local||{},a.registry.local[s.substring(15)]=r||void 0)}}}}i.forEach(((t,r)=>{let s;if("sse"===t.mode)s={name:t.name,description:t.description,mode:t.mode,schemas:t.schemas,repository:t.repository,installation:{url:t.installation.url||""},dependencies:{requirements:[]}},t.installation.isLocal&&t.installation.startingCommand&&(s.installation.startingCommand=t.installation.startingCommand);else{s={name:t.name,description:t.description,mode:t.mode,schemas:t.schemas,repository:t.repository,installation:{command:t.installation.command,args:t.installation.args||[],env:{}},dependencies:{requirements:[]}};const e={};t.installation.env.forEach((t=>{t.name&&(e[t.name]={Required:t.required||!1,Description:t.description||"",Default:t.default||void 0})})),Object.keys(e).length>0?s.installation.env=e:delete s.installation.env}if(t.dependencies.requirements.forEach((e=>{if(!e.name||!e.type||!e.version)return;const t={name:e.name,type:e.type,version:e.version,alias:e.alias,order:e.order};e.registryType&&"public"!==e.registryType&&(t.registry={},"github"===e.registryType&&e.registry.githubRelease?t.registry.githubRelease={repository:e.registry.githubRelease.repository,assetsName:e.registry.githubRelease.assetsName,assetName:e.registry.githubRelease.assetName}:"artifacts"===e.registryType&&e.registry.artifacts?t.registry.artifacts={registryUrl:e.registry.artifacts.registryUrl,registryName:e.registry.artifacts.registryName}:"local"===e.registryType&&e.registry.local&&(t.registry.local={localPath:e.registry.local.localPath,assetName:e.registry.local.assetName}),t.registry.githubRelease&&!t.registry.githubRelease.repository&&delete t.registry.githubRelease,t.registry.artifacts&&!t.registry.artifacts.registryUrl&&delete t.registry.artifacts,t.registry.local&&!t.registry.local.localPath&&delete t.registry.local,0===Object.keys(t.registry).length&&delete t.registry),s.dependencies.requirements.push({name:e.name,version:e.version,order:e.order});const r=`${e.type}|${e.name}|${e.version}`;if(!o.has(r)){const{order:e,...s}=t;o.set(r,s)}})),0===s.dependencies.requirements.length&&delete s.dependencies,"onboardServerForm"===e.id&&n){const t=`#${n} .server-item[data-index="${serverIndex}"]`,r=document.querySelector(t);if(r&&r.dataset.systemTags)try{s.systemTags=JSON.parse(r.dataset.systemTags)}catch(t){console.error(`[formDataToFeedConfiguration] Error parsing systemTags for server index ${serverIndex} ('${s.name}') on ${e.id}:`,t,r.dataset.systemTags),s.systemTags={parseError:!0}}}else delete s.systemTags;a.mcpServers.push(s)})),t&&r&&Array.isArray(r.mcpServers)&&r.mcpServers.forEach((e=>{a.mcpServers.some((t=>t.name===e.name))||e.systemTags&&"true"===e.systemTags.adhoc||(a.mcpServers.push(JSON.parse(JSON.stringify(e))),e.dependencies&&Array.isArray(e.dependencies.requirements)&&e.dependencies.requirements.forEach((t=>{const s=r.requirements?.find((e=>e.name===t.name&&e.type&&e.version===t.version));if(s){const e=`${s.type}|${s.name}|${s.version}`;o.has(e)||o.set(e,JSON.parse(JSON.stringify(s)))}else{const s=r.requirements?.find((e=>e.name===t.name&&e.version===t.version));if(s&&s.type){const e=`${s.type}|${t.name}|${t.version}`;o.has(e)||o.set(e,{name:t.name,version:t.version,type:s.type})}else console.warn(`Could not find full global requirement definition (or type) for ${t.name} v${t.version} from original server ${e.name}`)}})))})),a.requirements=Array.from(o.values());const l=[];if(t||(a.name?/^[a-zA-Z0-9-_]+$/.test(a.name)||l.push("Category name must only contain alphanumeric characters, hyphens, and underscores"):l.push("Category name is required"),a.displayName||l.push("Display name is required")),a.mcpServers.forEach(((e,t)=>{const r=validateServerConfig(e);r.length>0&&l.push(`Server ${t+1} (${e.name||"unnamed"}): ${r.join(", ")}`)})),a.requirements.forEach(((e,t)=>{if(e.name&&e.type&&e.version||l.push(`Requirement ${t+1}: name, type, and version are required`),e.registry){const r=Object.keys(e.registry)[0];["githubRelease","artifacts","local"].includes(r)||l.push(`Requirement ${t+1}: Invalid registry type ${r}`)}})),l.length>0){e.querySelectorAll(".validation-error-message").forEach((e=>e.remove()));l.forEach((t=>{let r=null;if(t.includes("Category name")?r='input[name="name"]':t.includes("Display name")&&(r='input[name="displayName"]'),r){const s=e.querySelector(r);if(s){const e=document.createElement("div");e.className="validation-error-message text-red-500 text-xs mt-1",e.textContent=t,s.insertAdjacentElement("afterend",e)}}}))}return a}export function populateForm(e,t="onboardForm",r=!1,s=null){const a=document.getElementById(t);if(!a)return void console.error(`populateForm: Form with ID "${t}" not found.`);const n=s||("onboardForm"===t?"serversList":"existingCategoryServersList");if(resetOnboardFormDynamicContent(t,n),setupRealTimeValidation(t),e){if("onboardForm"===t){a.querySelector('[name="name"]').value=e.name||"",a.querySelector('[name="displayName"]').value=e.displayName||"",a.querySelector('[name="description"]').value=e.description||"",e.repository&&(a.querySelector('[name="repository"]').value=e.repository);const t=new URLSearchParams(window.location.search);if("edit"===t.get("action")&&t.get("category")===e.name){const e=a.querySelector('[name="name"]');e&&(e.readOnly=!0,e.classList.add("bg-gray-100","cursor-not-allowed"))}}else if("onboardServerForm"===t&&e){a.querySelector('input[name="name"]').value=e.name||"",a.querySelector('input[name="displayName"]').value=e.displayName||"",a.querySelector('textarea[name="description"]').value=e.description||"",a.querySelector('input[name="repository"]').value=e.repository||"";const t=document.getElementById("existingCategoryBasicInfoContainer");t&&t.classList.remove("hidden");const r=document.getElementById("existingCategoryMcpServersContainer");r&&r.classList.remove("hidden")}setServerCounter(n,0),clearEnvCountersForTab(n),clearServerRequirementCountersForTab(n),(e.mcpServers||[]).forEach((s=>{const i=getServerCounter(n);window.addServer(n,r,s);const o=a.querySelector(`#${n} .server-item[data-index="${i}"]`);if(o)if("onboardServerForm"===t)if("true"===s.systemTags?.adhoc)o.dataset.systemTags=JSON.stringify(s.systemTags);else if(state.originalServerNamesForFormPopulation&&s.name&&state.originalServerNamesForFormPopulation.has(s.name))o.dataset.systemTags=JSON.stringify({adhoc:"true"});else if(s.systemTags&&Object.keys(s.systemTags).length>0){const e={...s.systemTags};delete e.adhoc,Object.keys(e).length>0?o.dataset.systemTags=JSON.stringify(e):delete o.dataset.systemTags}else delete o.dataset.systemTags;else s.systemTags?o.dataset.systemTags=JSON.stringify(s.systemTags):delete o.dataset.systemTags;const l=a.querySelector(`[name="servers[${i}].name"]`);l&&(l.value=s.name||"");const m=a.querySelector(`[name="servers[${i}].mode"]`);m&&(m.value=s.mode||"stdio","function"==typeof window.renderInstallationConfig&&window.renderInstallationConfig(i,n,s.mode||"stdio",r,s.installation));const c=a.querySelector(`[name="servers[${i}].description"]`);if(c&&(c.value=s.description||""),s.schemas){const e=document.getElementById(`schema-path-${i}`);e&&(e.value=s.schemas)}if(s.repository){const e=a.querySelector(`[name="servers[${i}].repository"]`);e&&(e.value=s.repository)}if(s.installation)if("sse"===s.mode){const e=a.querySelector(`[name="servers[${i}].installation.url"]`);e&&(e.value=s.installation.url||"")}else{const e=a.querySelector(`[name="servers[${i}].installation.command"]`);if(e&&(e.value=s.installation.command||""),s.installation.args&&Array.isArray(s.installation.args)){const e=a.querySelector(`[name="servers[${i}].installation.args"]`);e&&(e.value=s.installation.args.join(", "))}s.installation.env&&Object.entries(s.installation.env).forEach((([e,t])=>{const s=window.addEnvVariable(i,n,r),o=a.querySelector(`[name="servers[${i}].installation.env[${s}].name"]`);if(o&&(o.value=e),t.Default){const e=a.querySelector(`[name="servers[${i}].installation.env[${s}].default"]`);e&&(e.value=t.Default)}if(t.Required){const e=a.querySelector(`[name="servers[${i}].installation.env[${s}].required"]`);e&&(e.checked=!0)}if(t.Description){const e=a.querySelector(`[name="servers[${i}].installation.env[${s}].description"]`);e&&(e.value=t.Description)}}))}if(s.dependencies&&s.dependencies.requirements){const t=r&&!("true"===s.systemTags?.adhoc);s.dependencies.requirements.forEach((r=>{const s=(e.requirements||[]).find((e=>e.name===r.name));if(!s)return void console.warn(`Could not find full requirement config for dependency name: ${r.name} (version ${r.version} specified by server, but lookup is by name only). Skipping.`);const o=window.addServerRequirement(i,n,t);a.querySelector(`[name="servers[${i}].requirements[${o}].name"]`).value=s.name||"",a.querySelector(`[name="servers[${i}].requirements[${o}].type"]`).value=s.type||"",a.querySelector(`[name="servers[${i}].requirements[${o}].version"]`).value=s.version||"",void 0!==r.order&&(a.querySelector(`[name="servers[${i}].requirements[${o}].order"]`).value=r.order),"command"===s.type&&s.alias&&(a.querySelector(`[name="servers[${i}].requirements[${o}].alias"]`).value=s.alias,window.toggleServerAliasField(i,o,n));let l="public";s.registry&&(s.registry.githubRelease?l="github":s.registry.artifacts?l="artifacts":s.registry.local&&(l="local"));const m=a.querySelector(`[name="servers[${i}].requirements[${o}].registryType"]`);if(m&&(m.value=l,window.toggleServerRegistryConfig(i,o,n)),"github"===l&&s.registry.githubRelease){const e=s.registry.githubRelease;e.repository&&(a.querySelector(`[name="servers[${i}].requirements[${o}].registry.githubRelease.repository"]`).value=e.repository),e.assetsName&&(a.querySelector(`[name="servers[${i}].requirements[${o}].registry.githubRelease.assetsName"]`).value=e.assetsName),e.assetName&&(a.querySelector(`[name="servers[${i}].requirements[${o}].registry.githubRelease.assetName"]`).value=e.assetName)}else if("artifacts"===l&&s.registry.artifacts){const e=s.registry.artifacts;e.registryUrl&&(a.querySelector(`[name="servers[${i}].requirements[${o}].registry.artifacts.registryUrl"]`).value=e.registryUrl),e.registryName&&(a.querySelector(`[name="servers[${i}].requirements[${o}].registry.artifacts.registryName"]`).value=e.registryName)}else if("local"===l&&s.registry.local){const e=s.registry.local;e.localPath&&(a.querySelector(`[name="servers[${i}].requirements[${o}].registry.local.localPath"]`).value=e.localPath),e.assetName&&(a.querySelector(`[name="servers[${i}].requirements[${o}].registry.local.assetName"]`).value=e.assetName)}}))}}))}}export function resetOnboardFormDynamicContent(e="onboardForm",t="serversList"){const r=document.getElementById(e);r&&"onboardServerForm"!==e&&r.reset();const s=document.getElementById(t);let a,n;if(s&&(s.innerHTML=""),setServerCounter(0),state&&state.envCounters&&"function"==typeof state.envCounters.clear&&state.envCounters.clear(),state&&state.serverRequirementCounters&&"function"==typeof state.serverRequirementCounters.clear&&state.serverRequirementCounters.clear(),"onboardForm"===e?(a="validationStatusPanelNewCategory",n="validationStatusContentNewCategory"):"onboardServerForm"===e&&(a="validationStatusPanelExistingCategory",n="validationStatusContentExistingCategoryTab"),a){const e=document.getElementById(a);e&&e.classList.add("hidden")}if(n){const e=document.getElementById(n);e&&(e.innerHTML="")}if("onboardServerForm"===e){const e=document.getElementById("existingCategoryBasicInfoContainer");e&&e.classList.add("hidden");const t=document.getElementById("existingCategoryMcpServersContainer");t&&t.classList.add("hidden")}setupRealTimeValidation(e)}export function showValidationMessage(e,t,r=!0){let s=e.nextElementSibling;s&&s.classList.contains("validation-message")||(s=document.createElement("div"),s.className="validation-message text-xs mt-1 "+(r?"text-red-500":"text-green-500"),e.insertAdjacentElement("afterend",s)),s.textContent=t,s.className="validation-message text-xs mt-1 "+(r?"text-red-500":"text-green-500")}export{setupRealTimeValidation};
|
|
1
|
+
import{showToast}from"../notifications.js";import{state,setServerCounter,getServerCounter,clearEnvCountersForTab,clearServerRequirementCountersForTab}from"./state.js";function setupRealTimeValidation(e){const t=document.getElementById(e);if(!t)return;if(!t)return;const r=t.querySelector('input[name="name"]');r&&r.addEventListener("input",(e=>{const t=e.target.value.trim();t?/^[a-zA-Z0-9-_]+$/.test(t)?t.length>50?showValidationMessage(e.target,"Must not exceed 50 characters"):showValidationMessage(e.target,"Valid name",!1):showValidationMessage(e.target,"Only alphanumeric characters, hyphens, and underscores allowed"):showValidationMessage(e.target,"Name is required")}));const s=t.querySelector('input[name="displayName"]');s&&s.addEventListener("input",(e=>{const t=e.target.value.trim();t?t.length>100?showValidationMessage(e.target,"Must not exceed 100 characters"):showValidationMessage(e.target,"Valid display name",!1):showValidationMessage(e.target,"Display name is required")}));const a=t.querySelector('textarea[name="description"]');a&&a.addEventListener("input",(e=>{const t=e.target.value.trim();t.length>500?showValidationMessage(e.target,"Must not exceed 500 characters"):0===t.length?showValidationMessage(e.target,"Description is required"):showValidationMessage(e.target,"Valid description",!1)}));const n=t.querySelector('input[name="repository"]');n&&n.addEventListener("input",(e=>{const t=e.target.value.trim();if(t)try{new URL(t),showValidationMessage(e.target,"Valid URL",!1)}catch(t){showValidationMessage(e.target,"Invalid URL format")}else e.target.nextElementSibling?.remove()})),t.addEventListener("change",(e=>{if(e.target.name?.match(/servers\[\d+\]\.mode/)){const r=e.target.name.match(/servers\[(\d+)\]/)[1],s=t.querySelector(`[name="servers[${r}].installation.command"]`),a=t.querySelector(`[name="servers[${r}].installation.url"]`),n=t.querySelector(`[name="servers[${r}].installation.args"]`);"stdio"===e.target.value?(s&&(s.required=!0,showValidationMessage(s,"Command is required for stdio mode")),a&&(a.required=!1,a.value="",a.nextElementSibling?.remove())):"sse"===e.target.value&&(a&&(a.required=!0,showValidationMessage(a,"URL is required for sse mode")),s&&(s.required=!1,s.value="",s.nextElementSibling?.remove()),n&&(n.value="",n.nextElementSibling?.remove()))}})),t.addEventListener("input",(e=>{if(e.target.name?.includes(".installation.env[")){const t=e.target.name.match(/servers\[(\d+)\]\.installation\.env\[(\d+)\]\.(name|default)/);if(t){const[,r,s,a]=t;if("name"===a){const t=e.target.value.trim();t?/^[A-Z_][A-Z0-9_]*$/.test(t)?t.length>50?showValidationMessage(e.target,"Must not exceed 50 characters"):showValidationMessage(e.target,"Valid name",!1):showValidationMessage(e.target,"Must be uppercase with only letters, numbers, and underscores"):showValidationMessage(e.target,"Environment variable name is required")}}}}))}export async function submitForm(e,t,r=null){e.preventDefault();const s=e.target;let a,n=!1;if("create-category"===t)try{a=formDataToFeedConfiguration(s);const e=new URLSearchParams(window.location.search);n="edit"===e.get("action")&&e.get("category")===a.name}catch(e){return void console.error("Validation error:",e)}else{if("create-server"!==t)return void showToast("Invalid tab context for submission.","error");{if(!r||!r.name)return void showToast("No existing category selected or category data is missing.","error");const e=formDataToFeedConfiguration(s,!0,r);a=JSON.parse(JSON.stringify(r)),a.mcpServers=e.mcpServers||[];const t=new Set((a.requirements||[]).map((e=>`${e.type}|${e.name}|${e.version}`)));(e.requirements||[]).forEach((e=>{const r=`${e.type}|${e.name}|${e.version}`;t.has(r)||(a.requirements.push(e),t.add(r))})),n=!0}}try{const e=await fetch("/api/categories/onboard",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({categoryData:a,isUpdate:n})});if(!e.ok){const t=await e.json().catch((()=>({error:"Failed to parse error response"})));throw new Error(`HTTP error! status: ${e.status}, message: ${t.error||e.statusText}`)}await e.json();showToast("Form submitted successfully! See console for operation details.","success")}catch(e){console.error("Error submitting form:",e),showToast(`Error submitting form: ${e.message}. Please try again.`,"error")}}export function getFormData(e,t=!1,r=null){return formDataToFeedConfiguration(e,t,r)}function validateServerConfig(e){const t=[];if(e.name?/^[a-zA-Z0-9-_]+$/.test(e.name)?e.name.length>50&&t.push("Server name must not exceed 50 characters"):t.push("Server name must only contain alphanumeric characters, hyphens, and underscores"):t.push("Server name is required"),e.description&&""!==e.description.trim()?e.description.length>200&&t.push("Server description must not exceed 200 characters"):t.push("Server description is required"),e.mode?["stdio","sse"].includes(e.mode)||t.push('Server mode must be either "stdio" or "sse"'):t.push("Server mode is required"),"stdio"===e.mode)e.installation?.command?/^[a-zA-Z0-9-_.\\/]+$/.test(e.installation.command)||t.push("Command must only contain alphanumeric characters, hyphens, underscores, dots, and slashes"):t.push("Command is required for stdio server"),e.installation?.args?.length>0&&e.installation.args.forEach(((e,r)=>{/^[a-zA-Z0-9-_./\\]+$/.test(e)||t.push(`Argument ${r+1} must only contain alphanumeric characters, hyphens, underscores, dots, and slashes`)}));else if("sse"===e.mode)if(e.installation?.url)try{new URL(e.installation.url)}catch(e){t.push("Invalid URL format")}else t.push("URL is required for sse server");if(e.installation?.env&&Object.entries(e.installation.env).forEach((([e,r])=>{e?/^[A-Z_][A-Z0-9_]*$/.test(e)?e.length>50&&t.push(`Environment variable name "${e}" must not exceed 50 characters`):t.push(`Environment variable name "${e}" must be uppercase with only letters, numbers, and underscores`):t.push("Environment variable name is required"),r.Required&&!r.Default&&t.push(`Required environment variable "${e}" should have a default value`),r.Description&&r.Description.length>200&&t.push(`Description for environment variable "${e}" must not exceed 200 characters`)})),e.schemas)try{JSON.parse(e.schemas)}catch(e){t.push("Invalid JSON format in schemas")}return t}export function formDataToFeedConfiguration(e,t=!1,r=null){const s=new FormData(e),a={requirements:[],mcpServers:[]};let n;"onboardForm"===e.id?n="serversList":"onboardServerForm"===e.id?n="existingCategoryServersList":console.warn("[formDataToFeedConfiguration] Could not determine serversListId from formElement.id:",e.id),t?r&&(a.name=r.name):(a.name=s.get("name")||"",a.displayName=s.get("displayName")||"",a.description=s.get("description")||"",a.repository=s.get("repository")||void 0);const i=new Map,o=new Map;for(const[e,r]of s.entries()){if(t&&!e.startsWith("servers["))continue;const a=e.match(/^servers\[(\d+)\]\.(.+)$/);if(a){let t=parseInt(a[1],10);const n=a[2];let o=t;i.has(o)||i.set(o,{installation:{env:new Map},dependencies:{requirements:new Map},isNew:!0});const l=i.get(o);if("name"===n)l.name=r;else if("description"===n)l.description=r;else if("mode"===n)l.mode=r;else if("repository"===n)l.repository=r||void 0;else if("schemas"===n)l.schemas=r||void 0;else if("installation.command"===n)l.installation.command=r;else if("installation.args"===n)l.installation.args=r?r.split(",").map((e=>e.trim())).filter((e=>e)):[];else if("installation.url"===n)l.installation.url=r;else if("installation.isLocal"===n)l.installation.isLocal="on"===r;else if("installation.startingCommand"===n)l.installation.startingCommand=r.trim()||void 0;else if(n.startsWith("installation.env[")){const t=n.match(/^installation\.env\[(\d+)\]\.(name|default|required|description)$/);if(t){const a=parseInt(t[1],10),n=t[2];l.installation.env.has(a)||l.installation.env.set(a,{});const i=l.installation.env.get(a);i[n]="required"===n?"on"===s.get(e):r||void 0}}else if(n.startsWith("requirements[")){const e=n.match(/^requirements\[(\d+)\]\.(.+)$/);if(e){const t=parseInt(e[1],10),s=e[2];l.dependencies.requirements.has(t)||l.dependencies.requirements.set(t,{registry:{}});const a=l.dependencies.requirements.get(t);"name"===s?a.name=r:"type"===s?a.type=r:"version"===s?a.version=r:"order"===s?a.order=r?parseInt(r,10):void 0:"alias"===s?a.alias=r||void 0:"registryType"===s?a.registryType=r:s.startsWith("registry.githubRelease.")?(a.registry.githubRelease=a.registry.githubRelease||{},a.registry.githubRelease[s.substring(23)]=r||void 0):s.startsWith("registry.artifacts.")?(a.registry.artifacts=a.registry.artifacts||{},a.registry.artifacts[s.substring(19)]=r||void 0):s.startsWith("registry.local.")&&(a.registry.local=a.registry.local||{},a.registry.local[s.substring(15)]=r||void 0)}}}}i.forEach(((t,r)=>{let s;if("sse"===t.mode)s={name:t.name,description:t.description,mode:t.mode,schemas:t.schemas,repository:t.repository,installation:{url:t.installation.url||""},dependencies:{requirements:[]}},t.installation.isLocal&&t.installation.startingCommand&&(s.installation.startingCommand=t.installation.startingCommand);else{s={name:t.name,description:t.description,mode:t.mode,schemas:t.schemas,repository:t.repository,installation:{command:t.installation.command,args:t.installation.args||[],env:{}},dependencies:{requirements:[]}};const e={};t.installation.env.forEach((t=>{t.name&&(e[t.name]={Required:t.required||!1,Description:t.description||"",Default:t.default||void 0})})),Object.keys(e).length>0?s.installation.env=e:delete s.installation.env}if(t.dependencies.requirements.forEach((e=>{if(!e.name||!e.type||!e.version)return;const t={name:e.name,type:e.type,version:e.version,alias:e.alias,order:e.order};e.registryType&&"public"!==e.registryType&&(t.registry={},"github"===e.registryType&&e.registry.githubRelease?t.registry.githubRelease={repository:e.registry.githubRelease.repository,assetsName:e.registry.githubRelease.assetsName,assetName:e.registry.githubRelease.assetName}:"artifacts"===e.registryType&&e.registry.artifacts?t.registry.artifacts={registryUrl:e.registry.artifacts.registryUrl,registryName:e.registry.artifacts.registryName}:"local"===e.registryType&&e.registry.local&&(t.registry.local={localPath:e.registry.local.localPath,assetName:e.registry.local.assetName}),t.registry.githubRelease&&!t.registry.githubRelease.repository&&delete t.registry.githubRelease,t.registry.artifacts&&!t.registry.artifacts.registryUrl&&delete t.registry.artifacts,t.registry.local&&!t.registry.local.localPath&&delete t.registry.local,0===Object.keys(t.registry).length&&delete t.registry),s.dependencies.requirements.push({name:e.name,version:e.version,order:e.order});const r=`${e.type}|${e.name}|${e.version}`;if(!o.has(r)){const{order:e,...s}=t;o.set(r,s)}})),0===s.dependencies.requirements.length&&delete s.dependencies,"onboardServerForm"===e.id&&n){const t=`#${n} .server-item[data-index="${r}"]`,a=document.querySelector(t);if(a&&a.dataset.systemTags)try{s.systemTags=JSON.parse(a.dataset.systemTags)}catch(t){console.error(`[formDataToFeedConfiguration] Error parsing systemTags for server index ${r} ('${s.name}') on ${e.id}:`,t,a.dataset.systemTags),s.systemTags={parseError:!0}}}else delete s.systemTags;a.mcpServers.push(s)})),t&&r&&Array.isArray(r.mcpServers)&&r.mcpServers.forEach((e=>{a.mcpServers.some((t=>t.name===e.name))||e.systemTags&&"true"===e.systemTags.adhoc||(a.mcpServers.push(JSON.parse(JSON.stringify(e))),e.dependencies&&Array.isArray(e.dependencies.requirements)&&e.dependencies.requirements.forEach((t=>{const s=r.requirements?.find((e=>e.name===t.name&&e.type&&e.version===t.version));if(s){const e=`${s.type}|${s.name}|${s.version}`;o.has(e)||o.set(e,JSON.parse(JSON.stringify(s)))}else{const s=r.requirements?.find((e=>e.name===t.name&&e.version===t.version));if(s&&s.type){const e=`${s.type}|${t.name}|${t.version}`;o.has(e)||o.set(e,{name:t.name,version:t.version,type:s.type})}else console.warn(`Could not find full global requirement definition (or type) for ${t.name} v${t.version} from original server ${e.name}`)}})))})),a.requirements=Array.from(o.values());const l=[];if(t||(a.name?/^[a-zA-Z0-9-_]+$/.test(a.name)||l.push("Category name must only contain alphanumeric characters, hyphens, and underscores"):l.push("Category name is required"),a.displayName||l.push("Display name is required")),a.mcpServers.forEach(((e,t)=>{const r=validateServerConfig(e);r.length>0&&l.push(`Server ${t+1} (${e.name||"unnamed"}): ${r.join(", ")}`)})),a.requirements.forEach(((e,t)=>{if(e.name&&e.type&&e.version||l.push(`Requirement ${t+1}: name, type, and version are required`),e.registry){const r=Object.keys(e.registry)[0];["githubRelease","artifacts","local"].includes(r)||l.push(`Requirement ${t+1}: Invalid registry type ${r}`)}})),l.length>0){e.querySelectorAll(".validation-error-message").forEach((e=>e.remove()));l.forEach((t=>{let r=null;if(t.includes("Category name")?r='input[name="name"]':t.includes("Display name")&&(r='input[name="displayName"]'),r){const s=e.querySelector(r);if(s){const e=document.createElement("div");e.className="validation-error-message text-red-500 text-xs mt-1",e.textContent=t,s.insertAdjacentElement("afterend",e)}}}))}return a}export function populateForm(e,t="onboardForm",r=!1,s=null){const a=document.getElementById(t);if(!a)return void console.error(`populateForm: Form with ID "${t}" not found.`);const n=s||("onboardForm"===t?"serversList":"existingCategoryServersList");if(resetOnboardFormDynamicContent(t,n),setupRealTimeValidation(t),e){if("onboardForm"===t){a.querySelector('[name="name"]').value=e.name||"",a.querySelector('[name="displayName"]').value=e.displayName||"",a.querySelector('[name="description"]').value=e.description||"",e.repository&&(a.querySelector('[name="repository"]').value=e.repository);const t=new URLSearchParams(window.location.search);if("edit"===t.get("action")&&t.get("category")===e.name){const e=a.querySelector('[name="name"]');e&&(e.readOnly=!0,e.classList.add("bg-gray-100","cursor-not-allowed"))}}else if("onboardServerForm"===t&&e){a.querySelector('input[name="name"]').value=e.name||"",a.querySelector('input[name="displayName"]').value=e.displayName||"",a.querySelector('textarea[name="description"]').value=e.description||"",a.querySelector('input[name="repository"]').value=e.repository||"";const t=document.getElementById("existingCategoryBasicInfoContainer");t&&t.classList.remove("hidden");const r=document.getElementById("existingCategoryMcpServersContainer");r&&r.classList.remove("hidden")}setServerCounter(n,0),clearEnvCountersForTab(n),clearServerRequirementCountersForTab(n),(e.mcpServers||[]).forEach((s=>{const i=getServerCounter(n);window.addServer(n,r,s);const o=a.querySelector(`#${n} .server-item[data-index="${i}"]`);if(o)if("onboardServerForm"===t)if("true"===s.systemTags?.adhoc)o.dataset.systemTags=JSON.stringify(s.systemTags);else if(state.originalServerNamesForFormPopulation&&s.name&&state.originalServerNamesForFormPopulation.has(s.name))o.dataset.systemTags=JSON.stringify({adhoc:"true"});else if(s.systemTags&&Object.keys(s.systemTags).length>0){const e={...s.systemTags};delete e.adhoc,Object.keys(e).length>0?o.dataset.systemTags=JSON.stringify(e):delete o.dataset.systemTags}else delete o.dataset.systemTags;else s.systemTags?o.dataset.systemTags=JSON.stringify(s.systemTags):delete o.dataset.systemTags;const l=a.querySelector(`[name="servers[${i}].name"]`);l&&(l.value=s.name||"");const m=a.querySelector(`[name="servers[${i}].mode"]`);m&&(m.value=s.mode||"stdio","function"==typeof window.renderInstallationConfig&&window.renderInstallationConfig(i,n,s.mode||"stdio",r,s.installation));const c=a.querySelector(`[name="servers[${i}].description"]`);if(c&&(c.value=s.description||""),s.schemas){const e=document.getElementById(`schema-path-${i}`);e&&(e.value=s.schemas)}if(s.repository){const e=a.querySelector(`[name="servers[${i}].repository"]`);e&&(e.value=s.repository)}if(s.installation)if("sse"===s.mode){const e=a.querySelector(`[name="servers[${i}].installation.url"]`);e&&(e.value=s.installation.url||"")}else{const e=a.querySelector(`[name="servers[${i}].installation.command"]`);if(e&&(e.value=s.installation.command||""),s.installation.args&&Array.isArray(s.installation.args)){const e=a.querySelector(`[name="servers[${i}].installation.args"]`);e&&(e.value=s.installation.args.join(", "))}s.installation.env&&Object.entries(s.installation.env).forEach((([e,t])=>{const s=window.addEnvVariable(i,n,r),o=a.querySelector(`[name="servers[${i}].installation.env[${s}].name"]`);if(o&&(o.value=e),t.Default){const e=a.querySelector(`[name="servers[${i}].installation.env[${s}].default"]`);e&&(e.value=t.Default)}if(t.Required){const e=a.querySelector(`[name="servers[${i}].installation.env[${s}].required"]`);e&&(e.checked=!0)}if(t.Description){const e=a.querySelector(`[name="servers[${i}].installation.env[${s}].description"]`);e&&(e.value=t.Description)}}))}if(s.dependencies&&s.dependencies.requirements){const t=r&&!("true"===s.systemTags?.adhoc);s.dependencies.requirements.forEach((r=>{const s=(e.requirements||[]).find((e=>e.name===r.name));if(!s)return void console.warn(`Could not find full requirement config for dependency name: ${r.name} (version ${r.version} specified by server, but lookup is by name only). Skipping.`);const o=window.addServerRequirement(i,n,t);a.querySelector(`[name="servers[${i}].requirements[${o}].name"]`).value=s.name||"",a.querySelector(`[name="servers[${i}].requirements[${o}].type"]`).value=s.type||"",a.querySelector(`[name="servers[${i}].requirements[${o}].version"]`).value=s.version||"",void 0!==r.order&&(a.querySelector(`[name="servers[${i}].requirements[${o}].order"]`).value=r.order),"command"===s.type&&s.alias&&(a.querySelector(`[name="servers[${i}].requirements[${o}].alias"]`).value=s.alias,window.toggleServerAliasField(i,o,n));let l="public";s.registry&&(s.registry.githubRelease?l="github":s.registry.artifacts?l="artifacts":s.registry.local&&(l="local"));const m=a.querySelector(`[name="servers[${i}].requirements[${o}].registryType"]`);if(m&&(m.value=l,window.toggleServerRegistryConfig(i,o,n)),"github"===l&&s.registry.githubRelease){const e=s.registry.githubRelease;e.repository&&(a.querySelector(`[name="servers[${i}].requirements[${o}].registry.githubRelease.repository"]`).value=e.repository),e.assetsName&&(a.querySelector(`[name="servers[${i}].requirements[${o}].registry.githubRelease.assetsName"]`).value=e.assetsName),e.assetName&&(a.querySelector(`[name="servers[${i}].requirements[${o}].registry.githubRelease.assetName"]`).value=e.assetName)}else if("artifacts"===l&&s.registry.artifacts){const e=s.registry.artifacts;e.registryUrl&&(a.querySelector(`[name="servers[${i}].requirements[${o}].registry.artifacts.registryUrl"]`).value=e.registryUrl),e.registryName&&(a.querySelector(`[name="servers[${i}].requirements[${o}].registry.artifacts.registryName"]`).value=e.registryName)}else if("local"===l&&s.registry.local){const e=s.registry.local;e.localPath&&(a.querySelector(`[name="servers[${i}].requirements[${o}].registry.local.localPath"]`).value=e.localPath),e.assetName&&(a.querySelector(`[name="servers[${i}].requirements[${o}].registry.local.assetName"]`).value=e.assetName)}}))}}))}}export function resetOnboardFormDynamicContent(e="onboardForm",t="serversList"){const r=document.getElementById(e);r&&"onboardServerForm"!==e&&r.reset();const s=document.getElementById(t);let a,n;if(s&&(s.innerHTML=""),setServerCounter(0),state&&state.envCounters&&"function"==typeof state.envCounters.clear&&state.envCounters.clear(),state&&state.serverRequirementCounters&&"function"==typeof state.serverRequirementCounters.clear&&state.serverRequirementCounters.clear(),"onboardForm"===e?(a="validationStatusPanelNewCategory",n="validationStatusContentNewCategory"):"onboardServerForm"===e&&(a="validationStatusPanelExistingCategory",n="validationStatusContentExistingCategoryTab"),a){const e=document.getElementById(a);e&&e.classList.add("hidden")}if(n){const e=document.getElementById(n);e&&(e.innerHTML="")}if("onboardServerForm"===e){const e=document.getElementById("existingCategoryBasicInfoContainer");e&&e.classList.add("hidden");const t=document.getElementById("existingCategoryMcpServersContainer");t&&t.classList.add("hidden")}setupRealTimeValidation(e)}export function showValidationMessage(e,t,r=!0){let s=e.nextElementSibling;s&&s.classList.contains("validation-message")||(s=document.createElement("div"),s.className="validation-message text-xs mt-1 "+(r?"text-red-500":"text-green-500"),e.insertAdjacentElement("afterend",s)),s.textContent=t,s.className="validation-message text-xs mt-1 "+(r?"text-red-500":"text-green-500")}export{setupRealTimeValidation};
|
|
2
2
|
//# sourceMappingURL=formProcessor.js.map
|