UNPKG

aem-mcp-server

Version:
2 lines (1 loc) 28.5 kB
"use strict";import{getAEMConfig as M,isValidContentPath as y,isValidLocale as $}from"./aem.config.js";import{AEM_ERROR_CODES as d,createAEMError as m,createSuccessResponse as p,handleAEMHttpError as j,safeExecute as l,validateComponentOperation as I}from"./aem.errors.js";import{AEMFetch as R}from"./aem.fetch.js";import{LOGGER as u}from"../utils/logger.js";export class AEMConnector{isInitialized;isAEMaaCS;config;aemConfig;fetch;constructor(e){this.isInitialized=!1,this.config=this.loadConfig(e),this.aemConfig=M({}),this.isAEMaaCS=this.isConfigAEMaaCS(),this.fetch=new R({host:this.config.aem.host,auth:this.config.aem.auth,timeout:this.aemConfig.queries.timeoutMs})}async init(){try{await this.fetch.init(),this.isInitialized=!0}catch{this.isInitialized=!1}}isConfigAEMaaCS(){return!!(this.config.aem.auth.clientId&&this.config.aem.auth.clientSecret)}loadConfig(e={}){let t;return e.id&&e.secret?t={clientId:e.id,clientSecret:e.secret}:t={username:e.user||"admin",password:e.pass||"admin"},{aem:{host:e.host||"http://localhost:4502",author:e.host||"http://localhost:4502",publish:"http://localhost:4503",auth:t,endpoints:{content:"/content",dam:"/content/dam",query:"/bin/querybuilder.json",crxde:"/crx/de",jcr:""}},mcp:{name:"NAEM MCP Server",version:"1.0.0"}}}async testConnection(){const e=await this.testAEMConnection(),t=e?await this.testAuthConnection():!1;return{aem:e,auth:t}}async testAEMConnection(){try{this.isInitialized||await this.init();const e="/libs/granite/core/content/login.html";u.log("Testing AEM connection to:",e);const t=await this.fetch.get(e,void 0,void 0,5e3,!0);return u.log("\u2705 AEM connection successful!"),!0}catch(e){return u.error("\u274C AEM connection failed:",e.message),!1}}async testAuthConnection(){try{this.isInitialized||await this.init();const e="/libs/granite/security/currentuser.json";u.log("Testing AEM authentication connection to:",e);const t=await this.fetch.get(e,void 0,void 0,5e3);return u.log("\u2705 AEM authentication connection successful!"),!0}catch(e){return u.error("\u274C AEM authentication connection failed:",e.message),!1}}async validateComponent(e){return l(async()=>{const t=e.pagePath||e.page_path,{locale:n,component:a,props:s}=e;if(I(n,t,a,s),!$(n,this.aemConfig))throw m(d.INVALID_LOCALE,`Locale '${n}' is not supported`,{locale:n,allowedLocales:this.aemConfig.validation.allowedLocales});if(!y(t,this.aemConfig))throw m(d.INVALID_PATH,`Path '${t}' is not within allowed content roots`,{path:t,allowedRoots:Object.values(this.aemConfig.contentPaths)});const r=`${t}.json`,o=await this.fetch.get(r,{params:{":depth":"2"},timeout:this.aemConfig.queries.timeoutMs}),c=this.validateComponentProps(o.data,a,s);return p({message:"Component validation completed successfully",pageData:o.data,component:a,locale:n,validation:c,configUsed:{allowedLocales:this.aemConfig.validation.allowedLocales}},"validateComponent")},"validateComponent")}validateComponentProps(e,t,n){const a=[],s=[];return t==="text"&&!n.text&&!n.richText&&a.push("Text component should have text or richText property"),t==="image"&&!n.fileReference&&!n.src&&s.push("Image component requires fileReference or src property"),{valid:s.length===0,errors:s,warnings:a,componentType:t,propsValidated:Object.keys(n).length}}async updateComponent(e){return l(async()=>{if(!e.componentPath||typeof e.componentPath!="string")throw m(d.INVALID_PARAMETERS,"Component path is required and must be a string");if(!e.properties||typeof e.properties!="object")throw m(d.INVALID_PARAMETERS,"Properties are required and must be an object");if(!y(e.componentPath,this.aemConfig))throw m(d.INVALID_PATH,`Component path '${e.componentPath}' is not within allowed content roots`,{path:e.componentPath,allowedRoots:Object.values(this.aemConfig.contentPaths)});const t=`${e.componentPath}.json`,n=await this.fetch.get(t);try{await n.json()}catch(o){throw o.response?.status===404?m(d.COMPONENT_NOT_FOUND,`Component not found at path: ${e.componentPath}`,{componentPath:e.componentPath}):j(o,"updateComponent")}const a=new URLSearchParams;Object.entries(e.properties).forEach(([o,c])=>{c==null?a.append(`${o}@Delete`,""):Array.isArray(c)?c.forEach(i=>{a.append(`${o}`,i.toString())}):typeof c=="object"?a.append(o,JSON.stringify(c)):a.append(o,c.toString())});const s=await this.fetch.post(e.componentPath,a),r=await this.fetch.get(`${e.componentPath}.json`);return p({message:"Component updated successfully",path:e.componentPath,properties:e.properties,updatedProperties:r.data,response:s.data,verification:{success:!0,propertiesChanged:Object.keys(e.properties).length,timestamp:new Date().toISOString()}},"updateComponent")},"updateComponent")}async undoChanges(e){return p({message:"undoChanges is not implemented. Please use AEM version history for undo/rollback.",request:e,timestamp:new Date().toISOString()},"undoChanges")}async scanPageComponents(e){return l(async()=>{const t=`${e}.infinity.json`,n=await this.fetch.get(t),a=[],s=(r,o)=>{!r||typeof r!="object"||(r["sling:resourceType"]&&a.push({path:o,resourceType:r["sling:resourceType"],properties:{...r}}),Object.entries(r).forEach(([c,i])=>{if(typeof i=="object"&&i!==null&&!c.startsWith("rep:")&&!c.startsWith("oak:")){const h=o?`${o}/${c}`:c;s(i,h)}}))};return n.data["jcr:content"]?s(n.data["jcr:content"],"jcr:content"):s(n.data,e),p({pagePath:e,components:a,totalComponents:a.length},"scanPageComponents")},"scanPageComponents")}async fetchSites(){return l(async()=>{const t=await this.fetch.get("/content.json",{":depth":"2"}),n=[];return Object.entries(t).forEach(([a,s])=>{a.startsWith("jcr:")||a.startsWith("sling:")||s&&typeof s=="object"&&s["jcr:content"]&&n.push({name:a,path:`/content/${a}`,title:s["jcr:content"]["jcr:title"]||a,template:s["jcr:content"]["cq:template"],lastModified:s["jcr:content"]["cq:lastModified"]})}),p({sites:n,totalCount:n.length},"fetchSites")},"fetchSites")}async fetchLanguageMasters(e){return l(async()=>{const t=`/content/${e}.json`,n=await this.fetch.get(t,{":depth":"3"}),a=[];return Object.entries(n).forEach(([s,r])=>{s.startsWith("jcr:")||s.startsWith("sling:")||r&&typeof r=="object"&&r["jcr:content"]&&a.push({name:s,path:`/content/${s}`,title:r["jcr:content"]["jcr:title"]||s,language:r["jcr:content"]["jcr:language"]||"en"})}),p({site:e,languageMasters:a},"fetchLanguageMasters")},"fetchLanguageMasters")}async fetchAvailableLocales(e,t){return l(async()=>{const n=`${t}.json`,a=await this.fetch.get(n,{":depth":"2"}),s=[];return Object.entries(a).forEach(([r,o])=>{r.startsWith("jcr:")||r.startsWith("sling:")||o&&typeof o=="object"&&s.push({name:r,title:o["jcr:content"]?.["jcr:title"]||r,language:o["jcr:content"]?.["jcr:language"]||r})}),p({site:e,languageMasterPath:t,availableLocales:s},"fetchAvailableLocales")},"fetchAvailableLocales")}async replicateAndPublish(e,t,n){return l(async()=>p({message:"Replication simulated",selectedLocales:e,componentData:t,localizedOverrides:n},"replicateAndPublish"),"replicateAndPublish")}async getAllTextContent(e){return l(async()=>{const t=`${e}.infinity.json`,n=await this.fetch.get(t),a=[],s=(r,o)=>{!r||typeof r!="object"||((r.text||r["jcr:title"]||r["jcr:description"])&&a.push({path:o,title:r["jcr:title"],text:r.text,description:r["jcr:description"]}),Object.entries(r).forEach(([c,i])=>{if(typeof i=="object"&&i!==null&&!c.startsWith("rep:")&&!c.startsWith("oak:")){const h=o?`${o}/${c}`:c;s(i,h)}}))};return n["jcr:content"]?s(n["jcr:content"],"jcr:content"):s(n,e),p({pagePath:e,textContent:a},"getAllTextContent")},"getAllTextContent")}async getPageTextContent(e){return l(async()=>this.getAllTextContent(e),"getPageTextContent")}async getPageImages(e){return l(async()=>{const t=`${e}.infinity.json`,n=await this.fetch.get(t),a=[],s=(r,o)=>{!r||typeof r!="object"||((r.fileReference||r.src)&&a.push({path:o,fileReference:r.fileReference,src:r.src,alt:r.alt||r.altText,title:r["jcr:title"]||r.title}),Object.entries(r).forEach(([c,i])=>{if(typeof i=="object"&&i!==null&&!c.startsWith("rep:")&&!c.startsWith("oak:")){const h=o?`${o}/${c}`:c;s(i,h)}}))};return n["jcr:content"]?s(n["jcr:content"],"jcr:content"):s(n,e),p({pagePath:e,images:a},"getPageImages")},"getPageImages")}async updateImagePath(e,t){return l(async()=>this.updateComponent({componentPath:e,properties:{fileReference:t}}),"updateImagePath")}async getPageContent(e){return l(async()=>{const t=`${e}.infinity.json`,n=await this.fetch.get(t);return p({pagePath:e,content:n},"getPageContent")},"getPageContent")}async listChildren(e,t=1){return l(async()=>{try{const n=await this.fetch.get(`${e}.${t}.json`),a=[];return n&&typeof n=="object"&&Object.entries(n).forEach(([s,r])=>{if(!(s.startsWith("jcr:")||s.startsWith("sling:")||s.startsWith("cq:")||s.startsWith("rep:")||s.startsWith("oak:")||s==="jcr:content")&&r&&typeof r=="object"){const o=`${e}/${s}`;a.push({name:s,path:o,primaryType:r["jcr:primaryType"]||"nt:unstructured",title:r["jcr:content"]?.["jcr:title"]||r["jcr:title"]||s,lastModified:r["jcr:content"]?.["cq:lastModified"]||r["cq:lastModified"],resourceType:r["jcr:content"]?.["sling:resourceType"]||r["sling:resourceType"]})}}),a}catch(n){if(n.response?.status===404||n.response?.status===403)return((await this.fetch.get("/bin/querybuilder.json",{path:e,type:"cq:Page","p.nodedepth":"1","p.limit":"1000","p.hits":"full"})).hits||[]).map(s=>({name:s.name||s.path?.split("/").pop(),path:s.path,primaryType:s["jcr:primaryType"]||"cq:Page",title:s["jcr:content/jcr:title"]||s.title||s.name,lastModified:s["jcr:content/cq:lastModified"],resourceType:s["jcr:content/sling:resourceType"]}));throw n}},"listChildren")}async listPages(e,t=1,n=20){return l(async()=>{try{const a=await this.fetch.get(`${e}.${t}.json`),s=[],r=(o,c,i)=>{i>t||s.length>=n||Object.entries(o).forEach(([h,f])=>{if(!(s.length>=n)&&!(h.startsWith("jcr:")||h.startsWith("sling:")||h.startsWith("cq:")||h.startsWith("rep:")||h.startsWith("oak:"))&&f&&typeof f=="object"){const P=`${c}/${h}`;f["jcr:primaryType"]==="cq:Page"&&s.push({name:h,path:P,primaryType:"cq:Page",title:f["jcr:content"]?.["jcr:title"]||h,template:f["jcr:content"]?.["cq:template"],lastModified:f["jcr:content"]?.["cq:lastModified"],lastModifiedBy:f["jcr:content"]?.["cq:lastModifiedBy"],resourceType:f["jcr:content"]?.["sling:resourceType"],type:"page"}),i<t&&r(f,P,i+1)}})};return a&&typeof a=="object"&&r(a,e,0),p({siteRoot:e,pages:s,pageCount:s.length,depth:t,limit:n,totalChildrenScanned:s.length},"listPages")}catch(a){if(u.warn("JSON API failed, falling back to QueryBuilder:",a.message),a.response?.status===404||a.response?.status===403){const s=await this.fetch.get("/bin/querybuilder.json",{path:e,type:"cq:Page","p.nodedepth":t.toString(),"p.limit":n.toString(),"p.hits":"full"}),r=(s.hits||[]).map(o=>({name:o.name||o.path?.split("/").pop(),path:o.path,primaryType:"cq:Page",title:o["jcr:content/jcr:title"]||o.title||o.name,template:o["jcr:content/cq:template"],lastModified:o["jcr:content/cq:lastModified"],lastModifiedBy:o["jcr:content/cq:lastModifiedBy"],resourceType:o["jcr:content/sling:resourceType"],type:"page"}));return p({siteRoot:e,pages:r,pageCount:r.length,depth:t,limit:n,totalChildrenScanned:s.total||r.length,fallbackUsed:"QueryBuilder"},"listPages")}throw a}},"listPages")}async executeJCRQuery(e,t=20){return l(async()=>{if(!e||e.trim().length===0)throw new Error("Query is required and must be a non-empty string. Note: Only QueryBuilder fulltext is supported, not JCR SQL2.");const n=e.toLowerCase();if(/drop|delete|update|insert|exec|script|\.|<script/i.test(n)||e.length>1e3)throw new Error("Query contains potentially unsafe patterns or is too long");const a=await this.fetch.get("/bin/querybuilder.json",{path:"/content",type:"cq:Page",fulltext:e,"p.limit":t});return{query:e,results:a.hits||[],total:a.total||0,limit:t}},"executeJCRQuery")}async getPageProperties(e){return l(async()=>{const t=`${e}/jcr:content.json`,n=await this.fetch.get(t),a={title:n["jcr:title"],description:n["jcr:description"],template:n["cq:template"],lastModified:n["cq:lastModified"],lastModifiedBy:n["jcr:createdBy"],created:n["jcr:created"],createdBy:n["jcr:createdBy"],primaryType:n["jcr:primaryType"],resourceType:n["sling:resourceType"],tags:n["cq:tags"]||[],properties:n};return p({pagePath:e,properties:a},"getPageProperties")},"getPageProperties")}async searchContent(e){return l(async()=>{const t=await this.fetch.get(this.config.aem.endpoints.query,e);return p({params:e,results:t.hits||[],total:t.total||0,rawResponse:t},"searchContent")},"searchContent")}async getAssetMetadata(e){return l(async()=>{const t=`${e}.json`,n=await this.fetch.get(t),a=n["jcr:content"]?.metadata||{};return p({assetPath:e,metadata:a,fullData:n},"getAssetMetadata")},"getAssetMetadata")}async createPage(e){return this.createPageWithTemplate(e)}async deletePage(e){return l(async()=>{const{pagePath:t}=e;if(!y(t,this.aemConfig))throw m(d.INVALID_PARAMETERS,`Invalid page path: ${String(t)}`,{pagePath:t});let n=!1;try{await this.fetch.delete(t),n=!0}catch(a){if(a?.status===405||a?.response?.status===405)try{await this.fetch.post("/bin/wcmcommand",{cmd:"deletePage",path:t,force:e.force?"true":"false"}),n=!0}catch{try{await this.fetch.post(t,{":operation":"delete"}),n=!0}catch(r){throw r}}else throw u.error("DELETE failed:",a.response?.status,a.response?.data),a}return p({success:n,deletedPath:t,timestamp:new Date().toISOString()},"deletePage")},"deletePage")}async createComponent(e){return l(async()=>{const{pagePath:t,componentPath:n,componentType:a,resourceType:s,properties:r={},name:o}=e;if(!y(t,this.aemConfig))throw m(d.INVALID_PARAMETERS,`Invalid page path: ${String(t)}`,{pagePath:t});const c=o||`${a}_${Date.now()}`,i=n||`${t}/jcr:content/${c}`;return await this.fetch.post(i,{"jcr:primaryType":"nt:unstructured","sling:resourceType":s,...r,":operation":"import",":contentType":"json",":replace":"true"}),p({success:!0,componentPath:i,componentType:a,resourceType:s,properties:r,timestamp:new Date().toISOString()},"createComponent")},"createComponent")}async deleteComponent(e){return l(async()=>{const{componentPath:t}=e;if(!y(t,this.aemConfig))throw m(d.INVALID_PARAMETERS,`Invalid component path: ${String(t)}`,{componentPath:t});let n=!1;try{await this.fetch.delete(t),n=!0}catch(a){if(a?.status===405||a?.response?.status===405)try{await this.fetch.post(t,{":operation":"delete"}),n=!0}catch(s){throw s}else throw u.error("DELETE failed:",a.response?.status,a.response?.data),a}return p({success:n,deletedPath:t,timestamp:new Date().toISOString()},"deleteComponent")},"deleteComponent")}async unpublishContent(e){return l(async()=>{const{contentPaths:t,unpublishTree:n=!1}=e;if(!t||Array.isArray(t)&&t.length===0)throw m(d.INVALID_PARAMETERS,"Content paths array is required and cannot be empty",{contentPaths:t});const a=[];for(const s of Array.isArray(t)?t:[t])try{const r=new URLSearchParams;r.append("cmd","Deactivate"),r.append("path",s),r.append("ignoredeactivated","false"),r.append("onlymodified","false"),n&&r.append("deep","true");const o=await this.fetch.post("/bin/replicate.json",r);a.push({path:s,success:!0,response:o})}catch(r){a.push({path:s,success:!1,error:r.message})}return p({success:a.every(s=>s.success),results:a,unpublishedPaths:t,unpublishTree:n,timestamp:new Date().toISOString()},"unpublishContent")},"unpublishContent")}async activatePage(e){return l(async()=>{const{pagePath:t,activateTree:n=!1}=e;if(!y(t,this.aemConfig))throw m(d.INVALID_PARAMETERS,`Invalid page path: ${String(t)}`,{pagePath:t});try{const a=new URLSearchParams;a.append("cmd","Activate"),a.append("path",t),a.append("ignoredeactivated","false"),a.append("onlymodified","false"),n&&a.append("deep","true");const s=await this.fetch.post("/bin/replicate.json",a);return p({success:!0,activatedPath:t,activateTree:n,response:s,timestamp:new Date().toISOString()},"activatePage")}catch(a){try{const s=await this.fetch.post("/bin/wcmcommand",{cmd:"activate",path:t,ignoredeactivated:!1,onlymodified:!1});return p({success:!0,activatedPath:t,activateTree:n,response:s,fallbackUsed:"WCM Command",timestamp:new Date().toISOString()},"activatePage")}catch{throw j(a,"activatePage")}}},"activatePage")}async deactivatePage(e){return l(async()=>{const{pagePath:t,deactivateTree:n=!1}=e;if(!y(t,this.aemConfig))throw m(d.INVALID_PARAMETERS,`Invalid page path: ${String(t)}`,{pagePath:t});try{const a=new URLSearchParams;a.append("cmd","Deactivate"),a.append("path",t),a.append("ignoredeactivated","false"),a.append("onlymodified","false"),n&&a.append("deep","true");const s=await this.fetch.post("/bin/replicate.json",a);return p({success:!0,deactivatedPath:t,deactivateTree:n,response:s,timestamp:new Date().toISOString()},"deactivatePage")}catch(a){try{const s=await this.fetch.post("/bin/wcmcommand",{cmd:"deactivate",path:t,ignoredeactivated:!1,onlymodified:!1});return p({success:!0,deactivatedPath:t,deactivateTree:n,response:s,fallbackUsed:"WCM Command",timestamp:new Date().toISOString()},"deactivatePage")}catch{throw j(a,"deactivatePage")}}},"deactivatePage")}async uploadAsset(e){return l(async()=>{const{parentPath:t,fileName:n,fileContent:a,mimeType:s,metadata:r={}}=e;if(!y(t,this.aemConfig))throw m(d.INVALID_PARAMETERS,`Invalid parent path: ${String(t)}`,{parentPath:t});const o=`${t}/${n}`;try{const c=new URLSearchParams;typeof a=="string"?c.append("file",a):c.append("file",a.toString()),c.append("fileName",n),c.append(":operation","import"),c.append(":contentType","json"),c.append(":replace","true"),c.append("jcr:primaryType","dam:Asset"),s&&c.append("jcr:content/jcr:mimeType",s),Object.entries(r).forEach(([f,P])=>{c.append(`jcr:content/metadata/${f}`,String(P))});const i=await this.fetch.post(o,c),h=await this.fetch.get(`${o}.json`);return p({success:!0,assetPath:o,fileName:n,mimeType:s,metadata:r,uploadResponse:i,assetData:h,timestamp:new Date().toISOString()},"uploadAsset")}catch(c){try{const i=await this.fetch.post("/api/assets"+t,{fileName:n,fileContent:a,mimeType:s,metadata:r});return p({success:!0,assetPath:o,fileName:n,mimeType:s,metadata:r,uploadResponse:i,fallbackUsed:"DAM API",timestamp:new Date().toISOString()},"uploadAsset")}catch{throw j(c,"uploadAsset")}}},"uploadAsset")}async updateAsset(e){return l(async()=>{const{assetPath:t,metadata:n,fileContent:a,mimeType:s}=e;if(!y(t,this.aemConfig))throw m(d.INVALID_PARAMETERS,`Invalid asset path: ${String(t)}`,{assetPath:t});const r=new URLSearchParams;a&&(r.append("file",a),s&&r.append("jcr:content/jcr:mimeType",s)),n&&typeof n=="object"&&Object.entries(n).forEach(([o,c])=>{r.append(`jcr:content/metadata/${o}`,String(c))});try{const o=await this.fetch.post(t,r),c=await this.fetch.get(`${t}.json`);return p({success:!0,assetPath:t,updatedMetadata:n,updateResponse:o,assetData:c,timestamp:new Date().toISOString()},"updateAsset")}catch(o){throw j(o,"updateAsset")}},"updateAsset")}async deleteAsset(e){return l(async()=>{const{assetPath:t,force:n=!1}=e;if(!y(t,this.aemConfig))throw m(d.INVALID_PARAMETERS,`Invalid asset path: ${String(t)}`,{assetPath:t});return await this.fetch.delete(t),p({success:!0,deletedPath:t,force:n,timestamp:new Date().toISOString()},"deleteAsset")},"deleteAsset")}getTemplatesPath(e){if(!e||e.trim().length===0)return"";let t=e.trim(),n="/conf",a="/settings/wcm/templates";return t=t.replace(/\/+$/,""),t.startsWith("/content/")&&(t=t.replace("/content","")),t.startsWith(n)||(t=`${n}/${t.replace(/^\//,"")}`),t.endsWith(a)||(t+=a),t}async getTemplates(e){return l(async()=>{if(e)try{const t=this.getTemplatesPath(e);if(!t)throw m(d.INVALID_PARAMETERS,`Cannot determine configuration path for site: ${e}`,{sitePath:e});u.log("Looking for site-specific templates at:",t);const n=await this.fetch.get(`${t}.2.json`),a=[];return n&&typeof n=="object"&&Object.entries(n).forEach(([s,r])=>{s.startsWith("jcr:")||s.startsWith("sling:")||r&&typeof r=="object"&&r["jcr:content"]&&a.push({name:s,path:`${t}/${s}`,title:r["jcr:content"]["jcr:title"]||s,description:r["jcr:content"]["jcr:description"],allowedPaths:r["jcr:content"].allowedPaths,ranking:r["jcr:content"].ranking||0})}),p({sitePath:e,templates:a,totalCount:a.length,source:"site-specific"},"getTemplates")}catch{}try{const t=["/apps/wcm/core/content/sites/templates","/libs/wcm/core/content/sites/templates"],n=[];for(const a of t)try{const s=await this.fetch.get(`${a}.json`,{":depth":"2"});s&&typeof s=="object"&&Object.entries(s).forEach(([r,o])=>{r.startsWith("jcr:")||r.startsWith("sling:")||o&&typeof o=="object"&&n.push({name:r,path:`${a}/${r}`,title:o["jcr:content"]?.["jcr:title"]||r,description:o["jcr:content"]?.["jcr:description"],allowedPaths:o["jcr:content"]?.allowedPaths,ranking:o["jcr:content"]?.ranking||0,source:a.includes("/apps/")?"apps":"libs"})})}catch{}return p({sitePath:e||"global",templates:n,totalCount:n.length,source:"global"},"getTemplates")}catch(t){throw j(t,"getTemplates")}},"getTemplates")}async getTemplateStructure(e){return l(async()=>{try{const t=await this.fetch.get(`${e}.infinity.json`),n={path:e,properties:t["jcr:content"]||{},policies:t["jcr:content"]?.policies||{},structure:t["jcr:content"]?.structure||{},initialContent:t["jcr:content"]?.initial||{},allowedComponents:[],allowedPaths:t["jcr:content"]?.allowedPaths||[]},a=(s,r="")=>{if(!(!s||typeof s!="object")){if(s.components){const o=Object.keys(s.components);n.allowedComponents.push(...o)}Object.entries(s).forEach(([o,c])=>{typeof c=="object"&&c!==null&&!o.startsWith("jcr:")&&a(c,r?`${r}/${o}`:o)})}};return a(n.policies),n.allowedComponents=[...new Set(n.allowedComponents)],p({templatePath:e,structure:n,fullData:t},"getTemplateStructure")}catch(t){throw j(t,"getTemplateStructure")}},"getTemplateStructure")}async bulkUpdateComponents(e){return l(async()=>{const{updates:t,validateFirst:n=!0,continueOnError:a=!1}=e;if(!Array.isArray(t)||t.length===0)throw m(d.INVALID_PARAMETERS,"Updates array is required and cannot be empty");const s=[];if(n)for(const o of t)try{await this.fetch.get(`${o.componentPath}.json`)}catch(c){if(c.response?.status===404&&(s.push({componentPath:o.componentPath,success:!1,error:`Component not found: ${o.componentPath}`,phase:"validation"}),!a))return p({success:!1,message:"Bulk update failed during validation phase",results:s,totalUpdates:t.length,successfulUpdates:0},"bulkUpdateComponents")}let r=0;for(const o of t)try{const c=await this.updateComponent({componentPath:o.componentPath,properties:o.properties});s.push({componentPath:o.componentPath,success:!0,result:c,phase:"update"}),r++}catch(c){if(s.push({componentPath:o.componentPath,success:!1,error:c.message,phase:"update"}),!a)break}return p({success:r===t.length,message:`Bulk update completed: ${r}/${t.length} successful`,results:s,totalUpdates:t.length,successfulUpdates:r,failedUpdates:t.length-r},"bulkUpdateComponents")},"bulkUpdateComponents")}async getNodeContent(e,t=1){return l(async()=>{const n=`${e}.json`,a=await this.fetch.get(n,{":depth":t.toString()});return{path:e,depth:t,content:a,timestamp:new Date().toISOString()}},"getNodeContent")}async getAvailableTemplates(e){return l(async()=>{console.log("getAvailableTemplates for parentPath:",e);let t="/conf";const n=e.split("/");n.length>=3&&n[1]==="content"&&(t=`/conf/${n[2]}`);const a=`${t}/settings/wcm/templates`;try{const s=await this.fetch.get(`${a}.3.json`),r=[];return s&&typeof s=="object"&&Object.entries(s).forEach(([o,c])=>{if(!(o.startsWith("jcr:")||o.startsWith("sling:"))&&c&&typeof c=="object"&&c["jcr:content"]){const i=`${a}/${o}`,h=c["jcr:content"],f=c?.structure?.["jcr:content"]||{};r.push({name:o,path:i,title:h["jcr:title"]||o,description:h["jcr:description"]||"",thumbnail:h.thumbnail||"",allowedPaths:h.allowedPaths||[],status:h.status||"enabled",ranking:h.ranking||0,templateType:h.templateType||"page",resourceType:f["sling:resourceType"]||"",lastModified:h["cq:lastModified"],createdBy:h["jcr:createdBy"]})}}),r.sort((o,c)=>o.ranking!==c.ranking?c.ranking-o.ranking:o.name.localeCompare(c.name)),p({parentPath:e,templatesPath:a,templates:r,totalCount:r.length,availableTemplates:r.filter(o=>o.status==="enabled")},"getAvailableTemplates")}catch(s){if(s.response?.status===404){const r="/libs/wcm/foundation/templates",o=await this.fetch.get(`${r}.json`,{":depth":"2"}),c=[];return o&&typeof o=="object"&&Object.entries(o).forEach(([i,h])=>{i.startsWith("jcr:")||i.startsWith("sling:")||h&&typeof h=="object"&&c.push({name:i,path:`${r}/${i}`,title:h["jcr:title"]||i,description:h["jcr:description"]||"Global template",status:"enabled",ranking:0,templateType:"page",isGlobal:!0})}),p({parentPath:e,templatesPath:r,templates:c,totalCount:c.length,availableTemplates:c,fallbackUsed:!0},"getAvailableTemplates")}throw s}},"getAvailableTemplates")}async createPageWithTemplate(e){return l(async()=>{const{parentPath:t,title:n,template:a,name:s,properties:r={},resourceType:o=""}=e;if(!y(t,this.aemConfig))throw m(d.INVALID_PARAMETERS,`Invalid parent path: ${String(t)}`,{parentPath:t});let c=a,i=o;if(!c||!i){const b=(await this.getAvailableTemplates(t)).data.availableTemplates;if(b.length===0)throw m(d.INVALID_PARAMETERS,"No templates available for this path",{parentPath:t});const T=b[0];c&&(c=T.path),!i&&T.resourceType&&(i=T.resourceType),u.log(`\u{1F3AF} Auto-selected template: ${c} (${b[0].title})`,i)}try{const g=await this.fetch.get(`${c}.json`);u.log(`\u2705 Template verified: ${c}`,g)}catch(g){throw u.error("Template verification failed:",g.message,g),g?.response?.status===404?m(d.INVALID_PARAMETERS,`Template not found: ${c}`,{template:c}):j(g,"createPageWithTemplate")}const h=s||n.replace(/\s+/g,"-").toLowerCase(),f=`${t}/${h}`,P={"jcr:primaryType":"cq:Page","jcr:content":{"jcr:primaryType":"cq:PageContent","jcr:title":n,"cq:template":c,"sling:resourceType":i||"foundation/components/page","cq:lastModified":new Date().toISOString(),"cq:lastModifiedBy":"admin",...r}},w=new URLSearchParams;w.append("jcr:primaryType","cq:Page"),await this.fetch.post(f,w);const C=new URLSearchParams;Object.entries(P["jcr:content"]).forEach(([g,b])=>{g==="jcr:created"||g==="jcr:createdBy"||(typeof b=="object"?C.append(g,JSON.stringify(b)):C.append(g,String(b)))}),await this.fetch.post(`${f}/jcr:content`,C);const E=await this.fetch.get(`${f}.json`),S=E["jcr:content"]!==void 0;let A=!1;try{A=(await this.fetch.get(`${f}.html`)).status===200}catch{A=!1}return p({success:!0,pagePath:f,title:n,templateUsed:c,jcrContentCreated:S,pageAccessible:A,errorLogCheck:{hasErrors:!1,errors:[]},creationDetails:{timestamp:new Date().toISOString(),steps:["Template validation completed","Page node created","jcr:content node created","Page structure verified","Accessibility check completed"]},pageStructure:E.data},"createPageWithTemplate")},"createPageWithTemplate")}async validateTemplate(e,t){return l(async()=>{try{const n=await this.fetch.get(`${e}.json`);if(!n||!n["jcr:content"])throw m(d.INVALID_PARAMETERS,"Invalid template structure",{templatePath:e});const a=n["jcr:content"],s=a.allowedPaths||[];let r=s.length===0;return s.length>0&&(r=s.some(o=>t.startsWith(o))),p({templatePath:e,targetPath:t,isValid:r,templateTitle:a["jcr:title"]||"Untitled Template",templateDescription:a["jcr:description"]||"",allowedPaths:s,restrictions:{hasPathRestrictions:s.length>0,allowedPaths:s}},"validateTemplate")}catch(n){throw n.response?.status===404?m(d.INVALID_PARAMETERS,`Template not found: ${e}`,{templatePath:e}):j(n,"validateTemplate")}},"validateTemplate")}templateCache=new Map;templateCacheExpiry=new Map;TEMPLATE_CACHE_TTL=300*1e3;async getTemplateMetadata(e,t=!0){return l(async()=>{if(t&&this.templateCache.has(e)){const r=this.templateCacheExpiry.get(e)||0;if(Date.now()<r)return p({...this.templateCache.get(e),fromCache:!0},"getTemplateMetadata")}const n=await this.fetch.get(`${e}.json`);if(!n||!n["jcr:content"])throw m(d.INVALID_PARAMETERS,"Invalid template structure",{templatePath:e});const a=n["jcr:content"],s={templatePath:e,title:a["jcr:title"]||"Untitled Template",description:a["jcr:description"]||"",thumbnail:a.thumbnail||"",allowedPaths:a.allowedPaths||[],status:a.status||"enabled",ranking:a.ranking||0,templateType:a.templateType||"page",lastModified:a["cq:lastModified"],createdBy:a["jcr:createdBy"],policies:a.policies||{},structure:a.structure||{},initialContent:a.initial||{}};return t&&(this.templateCache.set(e,s),this.templateCacheExpiry.set(e,Date.now()+this.TEMPLATE_CACHE_TTL)),p(s,"getTemplateMetadata")},"getTemplateMetadata")}clearTemplateCache(){this.templateCache.clear(),this.templateCacheExpiry.clear(),console.log("\u{1F5D1}\uFE0F Template cache cleared")}}