aem-mcp-server 1.4.0 → 1.5.1
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.
- package/README.md +11 -20
- package/dist/aem/aem.connector.js +1 -1
- package/dist/aem/aem.content-fragments.js +1 -0
- package/dist/aem/aem.experience-fragments.js +1 -0
- package/dist/aem/aem.fetch.js +1 -1
- package/dist/mcp/mcp.aem-handler.js +1 -1
- package/dist/mcp/mcp.tools.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -22,7 +22,7 @@ This project is designed for non-technical persons who want to manage AEM via na
|
|
|
22
22
|
- **CLI agents** — Claude Code, GitHub Copilot CLI, Gemini CLI, Amazon Q CLI
|
|
23
23
|
- **Chat & desktop apps** — Claude Desktop, ChatGPT Desktop, Goose
|
|
24
24
|
- **Supports both AEMaaCS and self-hosted AEM instances**
|
|
25
|
-
- **Two transport modes** — stdio (
|
|
25
|
+
- **Two transport modes** — stdio via `npx` (recommended, zero install) and streamable HTTP
|
|
26
26
|
|
|
27
27
|
---
|
|
28
28
|
|
|
@@ -32,19 +32,9 @@ This project is designed for non-technical persons who want to manage AEM via na
|
|
|
32
32
|
- Node.js 20.19.0+ || 22.12.0+ || 23+
|
|
33
33
|
- Access to an AEM instance (local or remote)
|
|
34
34
|
|
|
35
|
-
###
|
|
35
|
+
### Stdio Transport (recommended)
|
|
36
36
|
|
|
37
|
-
|
|
38
|
-
npm install aem-mcp-server -g
|
|
39
|
-
```
|
|
40
|
-
|
|
41
|
-
### Two Transport Modes
|
|
42
|
-
|
|
43
|
-
AEM MCP Server supports two transport modes. In both cases, the AI agent is configured via the `mcp.json` (or equivalent) settings file in your IDE.
|
|
44
|
-
|
|
45
|
-
#### 1. Stdio Transport (recommended)
|
|
46
|
-
|
|
47
|
-
No manual server start needed — the AI agent spawns the process automatically.
|
|
37
|
+
No installation needed — the AI agent downloads and spawns the process automatically via `npx`.
|
|
48
38
|
|
|
49
39
|
Add to your project's MCP config (`.mcp.json`, `.vscode/mcp.json`, `.cursor/mcp.json`, etc.):
|
|
50
40
|
|
|
@@ -52,8 +42,8 @@ Add to your project's MCP config (`.mcp.json`, `.vscode/mcp.json`, `.cursor/mcp.
|
|
|
52
42
|
{
|
|
53
43
|
"mcpServers": {
|
|
54
44
|
"AEM": {
|
|
55
|
-
"command": "
|
|
56
|
-
"args": ["-t", "stdio", "-H", "http://localhost:4502", "-u", "admin", "-p", "admin"]
|
|
45
|
+
"command": "npx",
|
|
46
|
+
"args": ["-y", "aem-mcp-server", "-t", "stdio", "-H", "http://localhost:4502", "-u", "admin", "-p", "admin"]
|
|
57
47
|
}
|
|
58
48
|
}
|
|
59
49
|
}
|
|
@@ -72,22 +62,23 @@ Add to your project's MCP config (`.mcp.json`, `.vscode/mcp.json`, `.cursor/mcp.
|
|
|
72
62
|
> {
|
|
73
63
|
> "mcpServers": {
|
|
74
64
|
> "AEM": {
|
|
75
|
-
> "command": "
|
|
76
|
-
> "args": ["-t", "stdio", "-H", "${AEM_HOST:-http://localhost:4502}", "-u", "${AEM_USER:-admin}", "-p", "${AEM_PASSWORD:-admin}"]
|
|
65
|
+
> "command": "npx",
|
|
66
|
+
> "args": ["-y", "aem-mcp-server", "-t", "stdio", "-H", "${AEM_HOST:-http://localhost:4502}", "-u", "${AEM_USER:-admin}", "-p", "${AEM_PASSWORD:-admin}"]
|
|
77
67
|
> }
|
|
78
68
|
> }
|
|
79
69
|
> }
|
|
80
70
|
> ```
|
|
81
71
|
|
|
82
|
-
|
|
72
|
+
### Streamable HTTP Transport (alternative)
|
|
83
73
|
|
|
84
|
-
|
|
74
|
+
For scenarios where you need a persistent server (shared team server, multiple clients connecting simultaneously, etc.), install globally and start the server manually:
|
|
85
75
|
|
|
86
76
|
```sh
|
|
77
|
+
npm install aem-mcp-server -g
|
|
87
78
|
aem-mcp -H=http://localhost:4502 -u=admin -p=admin
|
|
88
79
|
```
|
|
89
80
|
|
|
90
|
-
|
|
81
|
+
Then point your AI agent to the URL:
|
|
91
82
|
|
|
92
83
|
```json
|
|
93
84
|
{
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";import{getAEMConfig as k,isValidContentPath as v}from"./aem.config.js";import{AEM_ERROR_CODES as P,createAEMError as $,createSuccessResponse as y,handleAEMHttpError as M,safeExecute as C}from"./aem.errors.js";import{AEMFetch as B}from"./aem.fetch.js";import{LOGGER as p}from"../utils/logger.js";export class AEMConnector{isInitialized;isAEMaaCS;config;aemConfig;fetch;constructor(e){this.isInitialized=!1,this.config=this.loadConfig(e),this.aemConfig=k({}),this.isAEMaaCS=this.isConfigAEMaaCS(),this.fetch=new B({host:this.config.aem.host,auth:this.config.aem.auth,timeout:this.aemConfig.queries.timeoutMs})}async init(){await this.fetch.init(),this.isInitialized=!0}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"}}}getPreviewUrl(e){return`${this.config.aem.host}${e}.html?wcmmode=disabled`}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";p.log("Testing AEM connection to:",e);const t=await this.fetch.get(e,void 0,void 0,5e3,!0);return p.log("\u2705 AEM connection successful!"),!0}catch(e){return p.error("\u274C AEM connection failed:",e.message),!1}}async testAuthConnection(){try{this.isInitialized||await this.init();const e="/libs/granite/security/currentuser.json";p.log("Testing AEM authentication connection to:",e);const t=await this.fetch.get(e,void 0,void 0,5e3);return p.log("\u2705 AEM authentication connection successful!"),!0}catch(e){return p.error("\u274C AEM authentication connection failed:",e.message),!1}}validateComponentProps(e,t,n){const r=[],o=[];return t==="text"&&!n.text&&!n.richText&&r.push("Text component should have text or richText property"),t==="image"&&!n.fileReference&&!n.src&&o.push("Image component requires fileReference or src property"),{valid:o.length===0,errors:o,warnings:r,componentType:t,propsValidated:Object.keys(n).length}}async updateComponent(e){return C(async()=>{if(!e.componentPath||typeof e.componentPath!="string")throw $(P.INVALID_PARAMETERS,"Component path is required and must be a string");if(!e.properties||typeof e.properties!="object")throw $(P.INVALID_PARAMETERS,"Properties are required and must be an object");if(!v(e.componentPath,this.aemConfig))throw $(P.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`;let n;try{if(n=await this.fetch.get(t),!n||typeof n=="object"&&Object.keys(n).length===0)throw $(P.COMPONENT_NOT_FOUND,`Component not found at path: ${e.componentPath}`,{componentPath:e.componentPath})}catch(a){throw a.code===P.COMPONENT_NOT_FOUND?a:a.message?.includes("404")||a.response?.status===404?$(P.COMPONENT_NOT_FOUND,`Component not found at path: ${e.componentPath}`,{componentPath:e.componentPath}):M(a,"updateComponent")}const r=n["sling:resourceType"];if(r){p.log(`Validating properties against component definition for: ${r}`);const a=await this.getComponentDefinition(r);if(Object.keys(a.fieldDefinitions).length>0){const l=this.validateComponentProperties(e.properties,a.fieldDefinitions);if(!l.valid){const c=l.errors.join("; ");throw $(P.INVALID_PARAMETERS,`Invalid property values for component ${r}: ${c}`,{resourceType:r,componentPath:a.componentPath,validationErrors:l.errors,invalidFields:l.invalidFields,providedProperties:e.properties})}l.warnings.length>0&&p.warn(`Property validation warnings: ${l.warnings.join("; ")}`),p.log("Property values validated successfully against component dialog definitions")}}const o=new URLSearchParams;r&&o.append("sling:resourceType",r),Object.entries(e.properties).forEach(([a,l])=>{l==null?o.append(`${a}@Delete`,""):Array.isArray(l)?l.forEach(c=>{o.append(`${a}`,c.toString())}):typeof l=="object"?o.append(a,JSON.stringify(l)):o.append(a,l.toString())});const s=await this.fetch.post(e.componentPath,o,{headers:{Accept:"application/json"}}),i=await this.fetch.get(`${e.componentPath}.json`);return y({message:"Component updated successfully",path:e.componentPath,properties:e.properties,updatedProperties:i,response:s,verification:{success:!0,propertiesChanged:Object.keys(e.properties).length,timestamp:new Date().toISOString()}},"updateComponent")},"updateComponent")}async scanPageComponents(e){return C(async()=>{const t=`${e}.infinity.json`,n=await this.fetch.get(t),r=[],o=(s,i)=>{!s||typeof s!="object"||(s["sling:resourceType"]&&r.push({path:i,resourceType:s["sling:resourceType"],properties:{...s}}),Object.entries(s).forEach(([a,l])=>{if(typeof l=="object"&&l!==null&&!a.startsWith("rep:")&&!a.startsWith("oak:")){const c=i?`${i}/${a}`:a;o(l,c)}}))};return n["jcr:content"]?o(n["jcr:content"],"jcr:content"):o(n,e),y({pagePath:e,components:r,totalComponents:r.length},"scanPageComponents")},"scanPageComponents")}async fetchSites(){return C(async()=>{const t=await this.fetch.get("/content.2.json",{":depth":"2"}),n=[];return Object.entries(t).forEach(([r,o])=>{r.startsWith("jcr:")||r.startsWith("sling:")||o&&typeof o=="object"&&o["jcr:content"]&&n.push({name:r,path:`/content/${r}`,title:o["jcr:content"]["jcr:title"]||r,template:o["jcr:content"]["cq:template"],lastModified:o["jcr:content"]["cq:lastModified"]})}),y({sites:n,totalCount:n.length},"fetchSites")},"fetchSites")}async fetchLanguageMasters(e){return C(async()=>{const t=`/content/${e}.2.json`,n=await this.fetch.get(t),r=[];let o=null,s="";return Object.entries(n).forEach(([i,a])=>{(i==="master"||i==="language-masters")&&a&&typeof a=="object"&&(o=a,s=`/content/${e}/${i}`)}),o?(Object.entries(o).forEach(([i,a])=>{i.startsWith("jcr:")||i.startsWith("sling:")||a&&typeof a=="object"&&r.push({name:i,path:`${s}/${i}`,title:a["jcr:content"]?.["jcr:title"]||a["jcr:title"]||i,language:a["jcr:content"]?.["jcr:language"]||a["jcr:language"]||i})}),y({site:e,languageMasters:r},"fetchLanguageMasters")):y({site:e,languageMasters:[],message:"No master or language-masters node found"},"fetchLanguageMasters")},"fetchLanguageMasters")}async fetchAvailableLocales(e){return C(async()=>{const t=`/content/${e}.4.json`,n=await this.fetch.get(t),r={},o=(s,i,a=[])=>{!s||typeof s!="object"||Object.entries(s).forEach(([l,c])=>{if(!(l.startsWith("jcr:")||l.startsWith("sling:")||l.startsWith("cq:")||l.startsWith("rep:")||l.startsWith("oak:")||l==="jcr:content")&&c&&typeof c=="object"){const h=`${i}/${l}`,A=[...a,l],T=c["jcr:content"],m=T&&typeof T=="object",j=T?.["jcr:language"]||null,S=l.length===2||l.length===3,b=a.length>0&&(a[a.length-1].length===2||a[a.length-1].length===3);if(m&&S&&b){const d=a[a.length-1].toUpperCase(),u=l.toLowerCase(),g=`${u}_${d}`;r[g]={path:h,title:T?.["jcr:title"]||l,language:j||`${u}_${d}`,country:d}}o(c,h,A)}})};return o(n,`/content/${e}`,[]),y({site:e,locales:r,totalCount:Object.keys(r).length},"fetchAvailableLocales")},"fetchAvailableLocales")}async getAllTextContent(e){return C(async()=>{let t;try{const o=`${e}.infinity.json`;t=await this.fetch.get(o)}catch(o){if(o.message?.includes("300")||o.message?.includes("redirect")){p.warn(`infinity.json failed for ${e}, trying depth-based approach`);try{t=await this.fetch.get(`${e}.5.json`)}catch{try{t=await this.fetch.get(`${e}/jcr:content.5.json`)}catch{throw M(o,"getAllTextContent")}}}else throw M(o,"getAllTextContent")}const n=[],r=(o,s)=>{!o||typeof o!="object"||((o.text||o["jcr:title"]||o["jcr:description"])&&n.push({path:s,title:o["jcr:title"],text:o.text,description:o["jcr:description"]}),Object.entries(o).forEach(([i,a])=>{if(typeof a=="object"&&a!==null&&!i.startsWith("rep:")&&!i.startsWith("oak:")){const l=s?`${s}/${i}`:i;r(a,l)}}))};return t["jcr:content"]?r(t["jcr:content"],"jcr:content"):r(t,e),y({pagePath:e,textContent:n},"getAllTextContent")},"getAllTextContent")}async getPageTextContent(e){return C(async()=>this.getAllTextContent(e),"getPageTextContent")}async getPageImages(e){return C(async()=>{const t=`${e}.infinity.json`,n=await this.fetch.get(t),r=[],o=(s,i)=>{!s||typeof s!="object"||((s.fileReference||s.src)&&r.push({path:i,fileReference:s.fileReference,src:s.src,alt:s.alt||s.altText,title:s["jcr:title"]||s.title}),Object.entries(s).forEach(([a,l])=>{if(typeof l=="object"&&l!==null&&!a.startsWith("rep:")&&!a.startsWith("oak:")){const c=i?`${i}/${a}`:a;o(l,c)}}))};return n["jcr:content"]?o(n["jcr:content"],"jcr:content"):o(n,e),y({pagePath:e,images:r},"getPageImages")},"getPageImages")}async updateImagePath(e,t){return C(async()=>this.updateComponent({componentPath:e,properties:{fileReference:t}}),"updateImagePath")}async getPageContent(e){return C(async()=>{const t=`${e}.infinity.json`,n=await this.fetch.get(t);return y({pagePath:e,content:n},"getPageContent")},"getPageContent")}async listChildren(e,t=1){return C(async()=>{try{const n=await this.fetch.get(`${e}.${t}.json`),r=[];return n&&typeof n=="object"&&Object.entries(n).forEach(([o,s])=>{if(!(o.startsWith("jcr:")||o.startsWith("sling:")||o.startsWith("cq:")||o.startsWith("rep:")||o.startsWith("oak:")||o==="jcr:content")&&s&&typeof s=="object"){const i=`${e}/${o}`;r.push({name:o,path:i,primaryType:s["jcr:primaryType"]||"nt:unstructured",title:s["jcr:content"]?.["jcr:title"]||s["jcr:title"]||o,lastModified:s["jcr:content"]?.["cq:lastModified"]||s["cq:lastModified"],resourceType:s["jcr:content"]?.["sling:resourceType"]||s["sling:resourceType"]})}}),r}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(o=>({name:o.name||o.path?.split("/").pop(),path:o.path,primaryType:o["jcr:primaryType"]||"cq:Page",title:o["jcr:content/jcr:title"]||o.title||o.name,lastModified:o["jcr:content/cq:lastModified"],resourceType:o["jcr:content/sling:resourceType"]}));throw n}},"listChildren")}async listPages(e,t=1,n=20){return C(async()=>{try{const r=await this.fetch.get(`${e}.${t}.json`),o=[],s=(i,a,l)=>{l>t||o.length>=n||Object.entries(i).forEach(([c,h])=>{if(!(o.length>=n)&&!(c.startsWith("jcr:")||c.startsWith("sling:")||c.startsWith("cq:")||c.startsWith("rep:")||c.startsWith("oak:"))&&h&&typeof h=="object"){const A=`${a}/${c}`;h["jcr:primaryType"]==="cq:Page"&&o.push({name:c,path:A,primaryType:"cq:Page",title:h["jcr:content"]?.["jcr:title"]||c,template:h["jcr:content"]?.["cq:template"],lastModified:h["jcr:content"]?.["cq:lastModified"],lastModifiedBy:h["jcr:content"]?.["cq:lastModifiedBy"],resourceType:h["jcr:content"]?.["sling:resourceType"],type:"page"}),l<t&&s(h,A,l+1)}})};return r&&typeof r=="object"&&s(r,e,0),y({siteRoot:e,pages:o,pageCount:o.length,depth:t,limit:n,totalChildrenScanned:o.length},"listPages")}catch(r){if(p.warn("JSON API failed, falling back to QueryBuilder:",r.message),r.response?.status===404||r.response?.status===403){const o=await this.fetch.get("/bin/querybuilder.json",{path:e,type:"cq:Page","p.nodedepth":t.toString(),"p.limit":n.toString(),"p.hits":"full"}),s=(o.hits||[]).map(i=>({name:i.name||i.path?.split("/").pop(),path:i.path,primaryType:"cq:Page",title:i["jcr:content/jcr:title"]||i.title||i.name,template:i["jcr:content/cq:template"],lastModified:i["jcr:content/cq:lastModified"],lastModifiedBy:i["jcr:content/cq:lastModifiedBy"],resourceType:i["jcr:content/sling:resourceType"],type:"page"}));return y({siteRoot:e,pages:s,pageCount:s.length,depth:t,limit:n,totalChildrenScanned:o.total||s.length,fallbackUsed:"QueryBuilder"},"listPages")}throw r}},"listPages")}async executeJCRQuery(e,t=20){return C(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 r=await this.fetch.get("/bin/querybuilder.json",{path:"/content",type:"cq:Page",fulltext:e,"p.limit":t});return{query:e,results:r.hits||[],total:r.total||0,limit:t}},"executeJCRQuery")}async getPageProperties(e){return C(async()=>{const t=`${e}/jcr:content.json`,n=await this.fetch.get(t),r={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 y({pagePath:e,properties:r},"getPageProperties")},"getPageProperties")}async searchContent(e){return C(async()=>{const t=await this.fetch.get(this.config.aem.endpoints.query,e);return y({params:e,results:t.hits||[],total:t.total||0,rawResponse:t},"searchContent")},"searchContent")}async getAssetMetadata(e){return C(async()=>{const t=`${e}.json`,n=await this.fetch.get(t),r=n["jcr:content"]?.metadata||{};return y({assetPath:e,metadata:r,fullData:n},"getAssetMetadata")},"getAssetMetadata")}async createPage(e){return this.createPageWithTemplate(e)}async deletePage(e){return C(async()=>{const{pagePath:t}=e;if(!v(t,this.aemConfig))throw $(P.INVALID_PARAMETERS,`Invalid page path: ${String(t)}`,{pagePath:t});let n=!1;try{await this.fetch.delete(t),n=!0}catch(r){if(r?.status===405||r?.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(s){throw s}}else throw p.error("DELETE failed:",r.response?.status,r.response?.data),r}return y({success:n,deletedPath:t,timestamp:new Date().toISOString()},"deletePage")},"deletePage")}async createComponent(e){return C(async()=>{const{pagePath:t,componentPath:n,componentType:r,resourceType:o,properties:s={},name:i}=e;if(!v(t,this.aemConfig))throw $(P.INVALID_PARAMETERS,`Invalid page path: ${String(t)}`,{pagePath:t});const a=i||`${r}_${Date.now()}`,l=n||`${t}/jcr:content/${a}`;return await this.fetch.post(l,{"jcr:primaryType":"nt:unstructured","sling:resourceType":o,...s,":operation":"import",":contentType":"json",":replace":"true"}),y({success:!0,componentPath:l,componentType:r,resourceType:o,properties:s,timestamp:new Date().toISOString()},"createComponent")},"createComponent")}async getComponentDefinition(e,t=new Set){const n=[],r={};let o="";if(t.has(e))return p.warn(`Circular reference detected for resourceType: ${e}`),{componentPath:o,requiredProperties:n,fieldDefinitions:r};t.add(e);const s=e.replace(/:/g,"/"),i=[`/apps/${s}`,`/libs/${s}`];let a=!1,l=null;for(const c of i)try{const h=await this.fetch.get(`${c}.json`,{":depth":"2"});if(h){o=c,h["sling:resourceSuperType"]&&(l=h["sling:resourceSuperType"],p.log(`Found sling:resourceSuperType: ${l} for component at ${c}`));try{const A=`${c}/_cq_dialog`,T=await this.fetch.get(`${A}.infinity.json`),m=(j,S="")=>{if(!j||typeof j!="object")return;const b=j["sling:resourceType"]||"",d=j.name||j.fieldName,u=d?d.replace(/^\.\//,""):null;if(u&&(b.includes("form/select")||b.includes("form/checkbox")||b.includes("form/textfield")||b.includes("form/textarea")||b.includes("form/numberfield")||b.includes("form/pathfield")||b.includes("form/datepicker")||b.includes("form/colorfield"))){const g=j.required===!0||j.required==="true",f={name:u,type:this.getFieldType(b),required:g,description:j.fieldDescription||j.fieldLabel||"",defaultValue:j.value!==void 0?j.value:j.checked!==void 0?j.checked:void 0};if(b.includes("form/select")&&j.items){const w=[],I=j.items;typeof I=="object"&&Object.values(I).forEach(E=>{E&&typeof E=="object"&&E.value!==void 0&&w.push(String(E.value))}),w.length>0&&(f.options=w)}b.includes("form/checkbox"),r[u]=f,p.log(`Found field definition: ${u} (type: ${f.type}, options: ${f.options?f.options.join(", "):"N/A"})`),g&&!n.includes(u)&&n.push(u)}j.items&&(Array.isArray(j.items)?j.items.forEach((g,f)=>{m(g,S?`${S}/items[${f}]`:`items[${f}]`)}):typeof j.items=="object"&&Object.entries(j.items).forEach(([g,f])=>{m(f,S?`${S}/items/${g}`:`items/${g}`)})),Object.entries(j).forEach(([g,f])=>{typeof f=="object"&&f!==null&&!g.startsWith("jcr:")&&!g.startsWith("sling:")&&g!=="items"&&m(f,S?`${S}/${g}`:g)})};m(T),a=!0,p.log(`Found component definition at ${o}, required properties: ${n.join(", ")}, field definitions: ${Object.keys(r).join(", ")}`);break}catch(A){p.warn(`Could not fetch dialog for ${c}: ${A.message}`)}}}catch{continue}if(!a&&l){p.log(`No dialog found for ${e}, checking super type: ${l}`);const c=await this.getComponentDefinition(l,t);c.requiredProperties.forEach(h=>{n.includes(h)||n.push(h)}),Object.entries(c.fieldDefinitions).forEach(([h,A])=>{r[h]||(r[h]=A)}),!o&&c.componentPath&&(o=c.componentPath)}return{componentPath:o,requiredProperties:n,fieldDefinitions:r}}getFieldType(e){return e.includes("form/select")?"select":e.includes("form/checkbox")?"checkbox":e.includes("form/textfield")?"textfield":e.includes("form/textarea")?"textarea":e.includes("form/numberfield")?"numberfield":e.includes("form/pathfield")?"pathfield":e.includes("form/datepicker")?"datepicker":e.includes("form/colorfield")?"colorfield":"unknown"}validateComponentProperties(e,t){const n=[],r=[],o={};for(const[s,i]of Object.entries(t)){const a=e[s];if(a!=null){if(i.type==="select"&&i.options){const l=String(a);if(!i.options.includes(l)){const c=`Invalid value '${a}' for field '${s}'. Allowed values: ${i.options.join(", ")}`;n.push(c),o[s]={provided:a,expected:i.options,message:c}}}if(i.type==="checkbox"&&!(typeof a=="boolean"||a==="true"||a==="false"||a===!0||a===!1)){const c=`Invalid value '${a}' for checkbox field '${s}'. Must be boolean or 'true'/'false'`;n.push(c),o[s]={provided:a,expected:'boolean or "true"/"false"',message:c}}if(i.type==="numberfield"&&isNaN(Number(a))){const l=`Invalid value '${a}' for number field '${s}'. Must be a number`;n.push(l),o[s]={provided:a,expected:"number",message:l}}}}return{valid:n.length===0,errors:n,warnings:r,invalidFields:o}}async getComponentTemplate(e){if(!e)return null;try{const t=`${e}/cq:template.infinity.json`;p.log(`Checking for cq:template at: ${t}`);const n=await this.fetch.get(t);if(n&&typeof n=="object"&&Object.keys(n).length>0){p.log(`\u2705 Found cq:template with ${Object.keys(n).length} top-level keys`);const r=Object.keys(n).filter(o=>!o.startsWith("jcr:")&&!o.startsWith("sling:"));return r.length>0&&p.log(`Template child nodes: ${r.join(", ")}`),n}return null}catch(t){const n=t.response?.status||t.statusCode||"unknown";return n===404?p.log(`No cq:template found at ${e}/cq:template`):p.warn(`Error checking for cq:template: ${t.message} (status: ${n})`),null}}async applyTemplateChildNodes(e,t){if(!(!t||Object.keys(t).length===0)){p.log(`Applying ${Object.keys(t).length} child nodes from cq:template to: ${e}`);for(const[n,r]of Object.entries(t))try{const o=`${e}/${n}`,s=new URLSearchParams;r["jcr:primaryType"]?s.append("jcr:primaryType",r["jcr:primaryType"]):s.append("jcr:primaryType","nt:unstructured");for(const[i,a]of Object.entries(r))i!=="jcr:primaryType"&&a!=null&&(Array.isArray(a)?a.forEach(l=>{s.append(i,l.toString())}):typeof a=="object"?s.append(i,JSON.stringify(a)):s.append(i,a.toString()));await this.fetch.post(o,s),p.log(`Created template child node: ${o}`)}catch(o){p.warn(`Failed to create template child node ${n}: ${o.message}`)}}}async addComponent(e){return C(async()=>{const{pagePath:t,resourceType:n,containerPath:r,name:o,properties:s={}}=e;if(!t||typeof t!="string")throw $(P.INVALID_PARAMETERS,"Page path is required and must be a string",{pagePath:t});if(!n||typeof n!="string")throw $(P.INVALID_PARAMETERS,"Resource type is required and must be a string",{resourceType:n});if(!v(t,this.aemConfig))throw $(P.INVALID_PATH,`Invalid page path: ${String(t)}`,{pagePath:t});p.log(`Fetching component definition for resourceType: ${n}`);const i=await this.getComponentDefinition(n);if(i.componentPath?p.log(`Component definition found at: ${i.componentPath}`):p.warn(`Component definition not found for ${n}, skipping required property validation`),i.requiredProperties.length>0){const d=[];if(i.requiredProperties.forEach(u=>{(!(u in s)||s[u]===null||s[u]===void 0||s[u]==="")&&d.push(u)}),d.length>0)throw $(P.INVALID_PARAMETERS,`Missing required properties for component ${n}: ${d.join(", ")}`,{resourceType:n,componentPath:i.componentPath,requiredProperties:i.requiredProperties,missingProperties:d,providedProperties:Object.keys(s)});p.log(`All required properties validated: ${i.requiredProperties.join(", ")}`)}if(p.log(`Checking field definitions: ${Object.keys(i.fieldDefinitions).length} fields found`),Object.keys(i.fieldDefinitions).length>0){p.log(`Field definitions: ${JSON.stringify(Object.keys(i.fieldDefinitions))}`),p.log(`Validating properties: ${JSON.stringify(Object.keys(s))}`);const d=this.validateComponentProperties(s,i.fieldDefinitions);if(p.log(`Validation result: valid=${d.valid}, errors=${d.errors.length}`),!d.valid){const u=d.errors.join("; ");throw p.error(`Property validation failed: ${u}`),$(P.INVALID_PARAMETERS,`Invalid property values for component ${n}: ${u}`,{resourceType:n,componentPath:i.componentPath,validationErrors:d.errors,invalidFields:d.invalidFields,providedProperties:s})}d.warnings.length>0&&p.warn(`Property validation warnings: ${d.warnings.join("; ")}`),p.log("Property values validated successfully against component dialog definitions")}else p.log(`No field definitions found for component ${n}, skipping property value validation`);try{const d=await this.fetch.get(`${t}.json`);if(!d||typeof d=="object"&&Object.keys(d).length===0)throw $(P.INVALID_PATH,`Page not found or invalid at: ${t}`,{pagePath:t});p.log(`Page verified at: ${t}`)}catch(d){throw d.message?.includes("404")||d.message?.includes("Page not found")||d.response?.status===404?$(P.INVALID_PATH,`Page not found at: ${t}`,{pagePath:t}):M(d,"addComponent")}let a;if(r)r.startsWith("/")?a=r:r.includes("jcr:content")?a=`${t}/${r}`:a=`${t}/jcr:content/${r}`;else{const d=`${t}/jcr:content`;let u=!1;try{const g=await this.fetch.get(`${d}.5.json`);g&&g.root?g.root.container?(a=`${d}/root/container`,u=!0,p.log(`\u2705 Found root/container at: ${a}`)):(a=`${d}/root/container`,u=!1,p.log(`Found root but no container, will create container at: ${a}`)):(a=`${d}/root/container`,u=!1,p.log(`No root found, will create root/container at: ${a}`))}catch{a=`${d}/root/container`,u=!1,p.warn(`Could not fetch jcr:content structure, will create root/container at: ${a}`)}}try{await this.fetch.get(`${a}.json`),p.log(`\u2705 Container exists at: ${a}`)}catch(d){if(d.message?.includes("404")||d.response?.status===404){p.warn(`Container not found at ${a}, attempting to create root/container structure`);const g=`${`${t}/jcr:content`}/root`,f=`${g}/container`;try{try{await this.fetch.get(`${g}.json`),p.log(`\u2705 Root already exists at: ${g}`)}catch{p.log(`Creating root at: ${g}`),await this.fetch.post(g,{"jcr:primaryType":"nt:unstructured","sling:resourceType":"aemmcp/base/components/aemmcp-container/v1/aemmcp-container"}),p.log(`\u2705 Created root at: ${g}`)}a===f&&(p.log(`Creating container at: ${f}`),await this.fetch.post(f,{"jcr:primaryType":"nt:unstructured","sling:resourceType":"aemmcp/base/components/aemmcp-container/v1/aemmcp-container"}),p.log(`\u2705 Created container at: ${f}`))}catch(w){throw $(P.INVALID_PATH,`Could not create root/container structure at: ${a}`,{targetContainerPath:a,error:w.message})}}else throw M(d,"addComponent")}const l=o||`component_${Date.now()}`,c=`${a}/${l}`;let h=null,A={},T={};if(i.componentPath&&(h=await this.getComponentTemplate(i.componentPath),h)){p.log("Component has cq:template, processing structure...");const d=["jcr:created","jcr:createdBy","jcr:lastModified","jcr:lastModifiedBy","jcr:mixinTypes"],u=["jcr:primaryType","sling:resourceType","layout","showSeparator","columns","separator"];for(const[g,f]of Object.entries(h))d.includes(g)||(u.includes(g)?A[g]=f:typeof f=="object"&&f!==null&&!Array.isArray(f)&&(f["jcr:primaryType"]!==void 0||f["sling:resourceType"]!==void 0)?T[g]=f:(typeof f!="object"||Array.isArray(f))&&(A[g]=f));p.log(`Template: ${Object.keys(A).length} properties, ${Object.keys(T).length} child nodes`)}const m=new URLSearchParams;if(Object.entries(A).forEach(([d,u])=>{u!=null&&(Array.isArray(u)?u.forEach(g=>m.append(d,g.toString())):typeof u=="object"?m.append(d,JSON.stringify(u)):m.append(d,u.toString()))}),Object.entries(s).forEach(([d,u])=>{u!=null&&(Array.isArray(u)?u.forEach(g=>m.append(d,g.toString())):typeof u=="object"?m.append(d,JSON.stringify(u)):m.append(d,u.toString()))}),m.has("jcr:primaryType")||m.append("jcr:primaryType","nt:unstructured"),m.has("sling:resourceType")||m.append("sling:resourceType",n),await this.fetch.post(c,m),Object.keys(T).length>0)try{await this.applyTemplateChildNodes(c,T),p.log(`\u2705 Applied ${Object.keys(T).length} child nodes from cq:template`)}catch(d){p.warn(`Failed to apply cq:template child nodes: ${d.message}`)}let j=await this.fetch.get(`${c}.json`),S=!1,b=null;try{if(i.componentPath){const d=await this.fetch.get(`${i.componentPath}.json`,{":depth":"2"});if(d&&(d["cq:isContainer"]===!0||d["cq:isContainer"]==="true")){S=!0,p.log(`Component ${n} is a container component (cq:isContainer=true)`),await new Promise(f=>setTimeout(f,1e3)),j=await this.fetch.get(`${c}.json`,{":depth":"5"}),Object.keys(j).some(f=>!f.startsWith("jcr:")&&!f.startsWith("sling:")&&!f.startsWith("cq:")&&f!=="layout"&&f!=="showSeparator"&&f!=="columns"&&f!=="separator")||(p.log("No default structure detected immediately, waiting longer..."),await new Promise(f=>setTimeout(f,1500)),j=await this.fetch.get(`${c}.json`,{":depth":"5"})),b={};const g=(f,w,I=0)=>{I>3||Object.keys(f).forEach(E=>{if(!E.startsWith("jcr:")&&!E.startsWith("sling:")&&!E.startsWith("cq:")&&E!=="layout"&&E!=="showSeparator"&&E!=="columns"&&E!=="separator"){const R=f[E];if(R&&typeof R=="object"&&!Array.isArray(R)){const O=w?`${w}/${E}`:E;if(R["sling:resourceType"]){const D=R["sling:resourceType"];D.includes("aemmcp-cc-container")||D.includes("columncontrol")||E.startsWith("col_")||E.match(/^col_\d+$/)?b[E]={path:`${c}/${O}`,resourceType:D,type:"column",isContainer:R["cq:isContainer"]===!0||R["cq:isContainer"]==="true"}:b[E]={path:`${c}/${O}`,resourceType:D,isContainer:R["cq:isContainer"]===!0||R["cq:isContainer"]==="true"},g(R,O,I+1)}else(E.startsWith("col_")||E.match(/^col_\d+$/)||E.startsWith("column")||E.match(/^column\d+$/)||E.includes("container")||E.includes("parsys")||E.includes("Column")||E.includes("Container"))&&(b[E]={path:`${c}/${O}`,type:"container",children:Object.keys(R).filter(D=>!D.startsWith("jcr:")&&!D.startsWith("sling:")&&!D.startsWith("cq:"))},g(R,O,I+1))}}})};g(j,""),Object.keys(b).length>0?p.log(`Container structure detected: ${Object.keys(b).join(", ")}`):p.log("Container component created but no default structure detected yet")}}}catch(d){p.warn(`Could not check container status: ${d.message}`)}return y({success:!0,pagePath:t,previewUrl:this.getPreviewUrl(t),componentPath:c,resourceType:n,isContainer:S,containerStructure:b||void 0,componentDefinition:{path:i.componentPath||"Not found",requiredProperties:i.requiredProperties,validationPassed:i.requiredProperties.length===0||i.requiredProperties.every(d=>d in s&&s[d]!==null&&s[d]!==void 0&&s[d]!==""),hasTemplate:h!==null,templatePath:h?`${i.componentPath}/cq:template`:void 0,templateChildNodesCount:Object.keys(T).length,fieldDefinitions:Object.keys(i.fieldDefinitions).length>0?i.fieldDefinitions:void 0},containerPath:a,componentName:l,properties:s,verification:j,timestamp:new Date().toISOString()},"addComponent")},"addComponent")}async deleteComponent(e){return C(async()=>{const{componentPath:t}=e;if(!v(t,this.aemConfig))throw $(P.INVALID_PARAMETERS,`Invalid component path: ${String(t)}`,{componentPath:t});let n=!1;try{const r=new URLSearchParams;r.append(":operation","delete"),await this.fetch.post(t,r),n=!0}catch(r){if(r?.status===405||r?.response?.status===405||r?.status===403||r?.response?.status===403)try{await this.fetch.delete(t),n=!0}catch(o){throw p.error("Both POST and DELETE failed:",r.response?.status,o.response?.status),r}else throw p.error("DELETE failed:",r.response?.status,r.response?.data),r}return y({success:n,deletedPath:t,timestamp:new Date().toISOString()},"deleteComponent")},"deleteComponent")}async unpublishContent(e){return C(async()=>{const{contentPaths:t,unpublishTree:n=!1}=e;if(!t||Array.isArray(t)&&t.length===0)throw $(P.INVALID_PARAMETERS,"Content paths array is required and cannot be empty",{contentPaths:t});const r=[];for(const o of Array.isArray(t)?t:[t])try{const s=new URLSearchParams;s.append("cmd","Deactivate"),s.append("path",o),s.append("ignoredeactivated","false"),s.append("onlymodified","false"),n&&s.append("deep","true");const i=await this.fetch.post("/bin/replicate.json",s);r.push({path:o,success:!0,response:i})}catch(s){r.push({path:o,success:!1,error:s.message})}return y({success:r.every(o=>o.success),results:r,unpublishedPaths:t,unpublishTree:n,timestamp:new Date().toISOString()},"unpublishContent")},"unpublishContent")}async activatePage(e){return C(async()=>{const{pagePath:t,activateTree:n=!1}=e;if(!v(t,this.aemConfig))throw $(P.INVALID_PARAMETERS,`Invalid page path: ${String(t)}`,{pagePath:t});try{const r=new URLSearchParams;r.append("cmd","Activate"),r.append("path",t);let o;return n?(r.append("ignoredeactivated","false"),r.append("onlymodified","false"),r.append("deep","true"),o=await this.fetch.post("/libs/replication/treeactivation.html",r)):o=await this.fetch.post("/bin/replicate.json",r),y({success:!0,activatedPath:t,activateTree:n,response:o,timestamp:new Date().toISOString()},"activatePage")}catch(r){try{const o=await this.fetch.post("/bin/wcmcommand",{cmd:"activate",path:t,ignoredeactivated:!1,onlymodified:!1});return y({success:!0,activatedPath:t,activateTree:n,response:o,fallbackUsed:"WCM Command",timestamp:new Date().toISOString()},"activatePage")}catch{throw M(r,"activatePage")}}},"activatePage")}async deactivatePage(e){return C(async()=>{const{pagePath:t,deactivateTree:n=!1}=e;if(!v(t,this.aemConfig))throw $(P.INVALID_PARAMETERS,`Invalid page path: ${String(t)}`,{pagePath:t});try{const r=new URLSearchParams;r.append("cmd","Deactivate"),r.append("path",t),r.append("ignoredeactivated","false"),r.append("onlymodified","false"),n&&r.append("deep","true");const o=await this.fetch.post("/bin/replicate.json",r);return y({success:!0,deactivatedPath:t,deactivateTree:n,response:o,timestamp:new Date().toISOString()},"deactivatePage")}catch(r){try{const o=await this.fetch.post("/bin/wcmcommand",{cmd:"deactivate",path:t,ignoredeactivated:!1,onlymodified:!1});return y({success:!0,deactivatedPath:t,deactivateTree:n,response:o,fallbackUsed:"WCM Command",timestamp:new Date().toISOString()},"deactivatePage")}catch{throw M(r,"deactivatePage")}}},"deactivatePage")}async updateAsset(e){return C(async()=>{const{assetPath:t,metadata:n,fileContent:r,mimeType:o}=e;if(!v(t,this.aemConfig))throw $(P.INVALID_PARAMETERS,`Invalid asset path: ${String(t)}`,{assetPath:t});const s=new URLSearchParams;r&&(s.append("file",r),o&&s.append("jcr:content/jcr:mimeType",o)),n&&typeof n=="object"&&Object.entries(n).forEach(([i,a])=>{s.append(`jcr:content/metadata/${i}`,String(a))});try{const i=await this.fetch.post(t,s),a=await this.fetch.get(`${t}.json`);return y({success:!0,assetPath:t,updatedMetadata:n,updateResponse:i,assetData:a,timestamp:new Date().toISOString()},"updateAsset")}catch(i){throw M(i,"updateAsset")}},"updateAsset")}async deleteAsset(e){return C(async()=>{const{assetPath:t,force:n=!1}=e;if(!v(t,this.aemConfig))throw $(P.INVALID_PARAMETERS,`Invalid asset path: ${String(t)}`,{assetPath:t});return await this.fetch.delete(t),y({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",r="/settings/wcm/templates";return t=t.replace(/\/+$/,""),t.startsWith("/content/")&&(t=t.replace("/content","")),t.startsWith(n)||(t=`${n}/${t.replace(/^\//,"")}`),t.endsWith(r)||(t+=r),t}async getTemplates(e){return C(async()=>{if(e)try{const t=this.getTemplatesPath(e);if(!t)throw $(P.INVALID_PARAMETERS,`Cannot determine configuration path for site: ${e}`,{sitePath:e});p.log("Looking for site-specific templates at:",t);const n=await this.fetch.get(`${t}.2.json`),r=[];return n&&typeof n=="object"&&Object.entries(n).forEach(([o,s])=>{o.startsWith("jcr:")||o.startsWith("sling:")||s&&typeof s=="object"&&s["jcr:content"]&&r.push({name:o,path:`${t}/${o}`,title:s["jcr:content"]["jcr:title"]||o,description:s["jcr:content"]["jcr:description"],allowedPaths:s["jcr:content"].allowedPaths,ranking:s["jcr:content"].ranking||0})}),y({sitePath:e,templates:r,totalCount:r.length,source:"site-specific"},"getTemplates")}catch{}try{const t=["/apps/wcm/core/content/sites/templates","/libs/wcm/core/content/sites/templates"],n=[];for(const r of t)try{const o=await this.fetch.get(`${r}.json`,{":depth":"2"});o&&typeof o=="object"&&Object.entries(o).forEach(([s,i])=>{s.startsWith("jcr:")||s.startsWith("sling:")||i&&typeof i=="object"&&n.push({name:s,path:`${r}/${s}`,title:i["jcr:content"]?.["jcr:title"]||s,description:i["jcr:content"]?.["jcr:description"],allowedPaths:i["jcr:content"]?.allowedPaths,ranking:i["jcr:content"]?.ranking||0,source:r.includes("/apps/")?"apps":"libs"})})}catch{}return y({sitePath:e||"global",templates:n,totalCount:n.length,source:"global"},"getTemplates")}catch(t){throw M(t,"getTemplates")}},"getTemplates")}async getTemplateStructure(e){return C(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||[]},r=(o,s="")=>{if(!(!o||typeof o!="object")){if(o.components){const i=Object.keys(o.components);n.allowedComponents.push(...i)}Object.entries(o).forEach(([i,a])=>{typeof a=="object"&&a!==null&&!i.startsWith("jcr:")&&r(a,s?`${s}/${i}`:i)})}};return r(n.policies),n.allowedComponents=[...new Set(n.allowedComponents)],y({templatePath:e,structure:n,fullData:t},"getTemplateStructure")}catch(t){throw M(t,"getTemplateStructure")}},"getTemplateStructure")}async bulkUpdateComponents(e){return C(async()=>{const{updates:t,validateFirst:n=!0,continueOnError:r=!1}=e;if(!Array.isArray(t)||t.length===0)throw $(P.INVALID_PARAMETERS,"Updates array is required and cannot be empty");const o=[];if(n)for(const i of t)try{await this.fetch.get(`${i.componentPath}.json`)}catch(a){if(a.response?.status===404&&(o.push({componentPath:i.componentPath,success:!1,error:`Component not found: ${i.componentPath}`,phase:"validation"}),!r))return y({success:!1,message:"Bulk update failed during validation phase",results:o,totalUpdates:t.length,successfulUpdates:0},"bulkUpdateComponents")}let s=0;for(const i of t)try{const a=await this.updateComponent({componentPath:i.componentPath,properties:i.properties});o.push({componentPath:i.componentPath,success:!0,result:a,phase:"update"}),s++}catch(a){if(o.push({componentPath:i.componentPath,success:!1,error:a.message,phase:"update"}),!r)break}return y({success:s===t.length,message:`Bulk update completed: ${s}/${t.length} successful`,results:o,totalUpdates:t.length,successfulUpdates:s,failedUpdates:t.length-s},"bulkUpdateComponents")},"bulkUpdateComponents")}async convertComponents(e){return C(async()=>{const{pagePath:t,sourceResourceType:n,targetResourceType:r,requiredProperties:o={},continueOnError:s=!0}=e;if(!t||typeof t!="string")throw $(P.INVALID_PARAMETERS,"Page path is required and must be a string");if(!n||typeof n!="string")throw $(P.INVALID_PARAMETERS,"Source resource type is required and must be a string");if(!r||typeof r!="string")throw $(P.INVALID_PARAMETERS,"Target resource type is required and must be a string");if(!v(t,this.aemConfig))throw $(P.INVALID_PATH,`Page path '${t}' is not within allowed content roots`);p.log(`Scanning page ${t} for components with resourceType: ${n}`);const a=await this.scanPageComponents(t),c=(a.data?.components||a.components||[]).filter(b=>b.resourceType===n);if(c.length===0)return y({message:`No components found with resourceType: ${n} on page ${t}`,pagePath:t,sourceResourceType:n,targetResourceType:r,componentsFound:0,componentsConverted:0},"convertComponents");p.log(`Found ${c.length} components with resourceType: ${n}`);const A=(await this.getComponentDefinition(r)).requiredProperties||[],T=[];if(A.length>0&&(A.forEach(b=>{(!(b in o)||o[b]===null||o[b]===void 0||o[b]==="")&&T.push(b)}),T.length>0))return y({message:"Target component requires properties that are not provided",pagePath:t,sourceResourceType:n,targetResourceType:r,componentsFound:c.length,componentsConverted:0,targetComponentRequiredProperties:A,missingRequiredProperties:T,providedProperties:Object.keys(o),note:"Please provide the missing required properties in the requiredProperties parameter and retry"},"convertComponents");const m=[];let j=0,S=0;for(const b of c)try{let d;b.path.startsWith("/")?d=b.path:b.path.startsWith("jcr:content")?d=`${t}/${b.path}`:d=`${t}/${b.path}`,p.log(`Processing component at: ${d}`),p.log(`Deleting source component at: ${d}`),await this.deleteComponent({componentPath:d}),p.log(`Creating target component at: ${d}`);const u=new URLSearchParams;u.append("jcr:primaryType","nt:unstructured"),u.append("sling:resourceType",r),Object.entries(o).forEach(([f,w])=>{if(w!=null){const I=f.startsWith("./")?f.substring(2):f;Array.isArray(w)?w.forEach(E=>{u.append(I,E.toString())}):typeof w=="object"?u.append(I,JSON.stringify(w)):u.append(I,w.toString())}}),await this.fetch.post(d,u,{headers:{Accept:"application/json"}});const g=await this.fetch.get(`${d}.json`);if(!g||!g["sling:resourceType"]||g["sling:resourceType"]!==r)throw new Error("Component creation verification failed: resourceType mismatch");m.push({sourceComponentPath:d,targetComponentPath:d,success:!0,message:`Successfully converted component from ${n} to ${r}`}),j++,p.log(`\u2705 Successfully converted component at: ${d}`)}catch(d){const u=d.message||String(d);if(p.error(`Failed to convert component at ${b.path}: ${u}`),m.push({sourceComponentPath:b.path,success:!1,error:u}),S++,!s)return y({message:"Conversion stopped due to error (continueOnError=false)",pagePath:t,sourceResourceType:n,targetResourceType:r,componentsFound:c.length,componentsConverted:j,componentsFailed:S,results:m},"convertComponents")}return y({message:`Converted ${j} of ${c.length} components from ${n} to ${r}`,pagePath:t,sourceResourceType:n,targetResourceType:r,componentsFound:c.length,componentsConverted:j,componentsFailed:S,results:m},"convertComponents")},"convertComponents")}async bulkConvertComponents(e){return C(async()=>{const{pagePaths:t,searchPath:n,depth:r=2,limit:o=50,sourceResourceType:s,targetResourceType:i,requiredProperties:a={},continueOnError:l=!0}=e;if(!s||typeof s!="string")throw $(P.INVALID_PARAMETERS,"Source resource type is required and must be a string");if(!i||typeof i!="string")throw $(P.INVALID_PARAMETERS,"Target resource type is required and must be a string");let c=[];if(t&&Array.isArray(t)&&t.length>0)c=t,p.log(`Processing ${c.length} specified pages`);else if(n){if(!v(n,this.aemConfig))throw $(P.INVALID_PATH,`Search path '${n}' is not within allowed content roots`);p.log(`Searching for pages under ${n} with depth ${r}`);const d=await this.listPages(n,r,o),u=d.data?.pages||d.pages||[];if(u.length===0)return y({message:`No pages found under ${n}`,searchPath:n,sourceResourceType:s,targetResourceType:i,pagesProcessed:0,pagesSucceeded:0,pagesFailed:0,totalComponentsConverted:0},"bulkConvertComponents");c=u.map(g=>g.path||g["@path"]).filter(g=>g),p.log(`Found ${c.length} pages to process`)}else throw $(P.INVALID_PARAMETERS,"Either pagePaths array or searchPath must be provided");if(c.length===0)return y({message:"No pages to process",sourceResourceType:s,targetResourceType:i,pagesProcessed:0,pagesSucceeded:0,pagesFailed:0,totalComponentsConverted:0},"bulkConvertComponents");const h=[];let A=0,T=0,m=0,j=0,S=0;for(const b of c)try{p.log(`Processing page: ${b}`);const u=await this.convertComponents({pagePath:b,sourceResourceType:s,targetResourceType:i,requiredProperties:a,continueOnError:l}),g=u.data||u;if(u.success!==!1){const f=g.componentsFound||0,w=g.componentsConverted||0,I=g.componentsFailed||0;m+=f,j+=w,S+=I,f>0&&A++,h.push({pagePath:b,success:!0,componentsFound:f,componentsConverted:w,componentsFailed:I,message:g.message||"Processed successfully"})}else T++,h.push({pagePath:b,success:!1,error:g.message||"Conversion failed",componentsFound:0,componentsConverted:0,componentsFailed:0})}catch(d){const u=d.message||String(d);if(p.error(`Failed to process page ${b}: ${u}`),T++,h.push({pagePath:b,success:!1,error:u,componentsFound:0,componentsConverted:0,componentsFailed:0}),!l)return y({message:"Bulk conversion stopped due to error (continueOnError=false)",sourceResourceType:s,targetResourceType:i,pagesProcessed:c.length,pagesSucceeded:A,pagesFailed:T,totalComponentsFound:m,totalComponentsConverted:j,totalComponentsFailed:S,pageResults:h},"bulkConvertComponents")}return y({message:`Bulk conversion completed: ${A} pages succeeded, ${T} pages failed. Total components converted: ${j}`,sourceResourceType:s,targetResourceType:i,pagesProcessed:c.length,pagesSucceeded:A,pagesFailed:T,totalComponentsFound:m,totalComponentsConverted:j,totalComponentsFailed:S,pageResults:h},"bulkConvertComponents")},"bulkConvertComponents")}async getNodeContent(e,t=1){return C(async()=>{const n=`${e}.json`,r=await this.fetch.get(n,{":depth":t.toString()});return{path:e,depth:t,content:r,timestamp:new Date().toISOString()}},"getNodeContent")}async getAvailableTemplates(e){return C(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 r=`${t}/settings/wcm/templates`;try{const o=await this.fetch.get(`${r}.3.json`),s=[];return o&&typeof o=="object"&&Object.entries(o).forEach(([i,a])=>{if(!(i.startsWith("jcr:")||i.startsWith("sling:"))&&a&&typeof a=="object"&&a["jcr:content"]){const l=`${r}/${i}`,c=a["jcr:content"],h=a?.structure?.["jcr:content"]||{};s.push({name:i,path:l,title:c["jcr:title"]||i,description:c["jcr:description"]||"",thumbnail:c.thumbnail||"",allowedPaths:c.allowedPaths||[],status:c.status||"enabled",ranking:c.ranking||0,templateType:c.templateType||"page",resourceType:h["sling:resourceType"]||"",lastModified:c["cq:lastModified"],createdBy:c["jcr:createdBy"]})}}),s.sort((i,a)=>i.ranking!==a.ranking?a.ranking-i.ranking:i.name.localeCompare(a.name)),y({parentPath:e,templatesPath:r,templates:s,totalCount:s.length,availableTemplates:s.filter(i=>i.status==="enabled")},"getAvailableTemplates")}catch(o){if(o.response?.status===404){const s="/libs/wcm/foundation/templates",i=await this.fetch.get(`${s}.json`,{":depth":"2"}),a=[];return i&&typeof i=="object"&&Object.entries(i).forEach(([l,c])=>{l.startsWith("jcr:")||l.startsWith("sling:")||c&&typeof c=="object"&&a.push({name:l,path:`${s}/${l}`,title:c["jcr:title"]||l,description:c["jcr:description"]||"Global template",status:"enabled",ranking:0,templateType:"page",isGlobal:!0})}),y({parentPath:e,templatesPath:s,templates:a,totalCount:a.length,availableTemplates:a,fallbackUsed:!0},"getAvailableTemplates")}throw o}},"getAvailableTemplates")}async createPageWithTemplate(e){return C(async()=>{const{parentPath:t,title:n,template:r,name:o,properties:s={},resourceType:i=""}=e;if(!v(t,this.aemConfig))throw $(P.INVALID_PARAMETERS,`Invalid parent path: ${String(t)}`,{parentPath:t});if(!o&&!n)throw $(P.INVALID_PARAMETERS,'Either "name" or "title" must be provided to create a page. Please provide at least one of these parameters.',{parentPath:t,providedParams:{name:o,title:n}});const a=n||(o?o.replace(/-/g," ").replace(/\b\w/g,f=>f.toUpperCase()):"");let l=r,c=i;if(!l){const w=(await this.getAvailableTemplates(t)).data.availableTemplates;if(w.length===0)throw $(P.INVALID_PARAMETERS,"No templates available for this path",{parentPath:t});const I=w[0];l=I.path,!c&&I.resourceType&&(c=I.resourceType),p.log(`\u{1F3AF} Auto-selected template: ${l} (${w[0].title})`,c)}let h=null;try{const f=await this.fetch.get(`${l}.json`);p.log(`\u2705 Template verified: ${l}`,f);try{const w=await this.fetch.get(`${l}.infinity.json`);if(!c&&w){const I=w.structure?.["jcr:content"];if(I&&I["sling:resourceType"])c=I["sling:resourceType"],p.log(`\u{1F4CB} Extracted resourceType from template structure: ${c}`);else{const E=w["jcr:content"];E&&E["sling:resourceType"]&&(c=E["sling:resourceType"],p.log(`\u{1F4CB} Extracted resourceType from template jcr:content: ${c}`))}}w&&w["jcr:content"]&&w.initial?(h=w.initial,p.log(`\u{1F4CB} Found initial content node at template/initial: ${l}`)):p.warn(`\u26A0\uFE0F No initial content found in template at /initial: ${l}`)}catch(w){p.warn(`Could not fetch template structure: ${w.message}`)}}catch(f){throw p.error("Template verification failed:",f.message,f),f?.response?.status===404?$(P.INVALID_PARAMETERS,`Template not found: ${l}`,{template:l}):M(f,"createPageWithTemplate")}try{await this.validateTemplate(l,t),p.log(`\u2705 Template validation passed for ${l} at ${t}`)}catch(f){throw f}const A=o||(a?a.replace(/\s+/g,"-").toLowerCase():""),T=`${t}/${A}`;try{const f=await this.fetch.get(`${T}.json`);if(f&&(f["jcr:primaryType"]==="cq:Page"||f["jcr:content"]))throw $(P.INVALID_PARAMETERS,`Page already exists at path: ${T}. Cannot overwrite existing page. Please use a different name or delete the existing page first.`,{pagePath:T,parentPath:t,pageName:A,existingPage:!0})}catch(f){if(f.code===P.INVALID_PARAMETERS&&f.message?.includes("already exists"))throw f;f.response?.status!==404&&!f.message?.includes("404")&&p.warn(`Could not check if page exists at ${T}: ${f.message}`)}const m={"jcr:primaryType":"cq:Page","jcr:content":{"jcr:primaryType":"cq:PageContent","jcr:title":a,"cq:template":l,"sling:resourceType":c||"foundation/components/page","cq:lastModified":new Date().toISOString(),"jcr:createdBy":"admin","jcr:created":new Date().toISOString(),"cq:lastModifiedBy":"admin",...s}};if(h&&h["jcr:content"]){const f=h["jcr:content"];Object.entries(f).forEach(([w,I])=>{w==="jcr:created"||w==="jcr:createdBy"||w==="jcr:title"||w==="cq:template"||w.startsWith("jcr:")&&w!=="jcr:primaryType"||typeof I=="object"&&!Array.isArray(I)&&!w.startsWith("jcr:")&&!w.startsWith("sling:")&&!w.startsWith("cq:")||m["jcr:content"][w]||(m["jcr:content"][w]=I)}),p.log("\u{1F4E6} Merged initial content properties from template")}const j=new URLSearchParams;j.append("jcr:primaryType","cq:Page"),await this.fetch.post(T,j);const S=new URLSearchParams;if(Object.entries(m["jcr:content"]).forEach(([f,w])=>{if(!(f==="jcr:created"||f==="jcr:createdBy"))if(typeof w=="object"&&w!==null&&!Array.isArray(w)){if(!f.startsWith("jcr:")&&!f.startsWith("sling:")&&!f.startsWith("cq:"))return;S.append(f,JSON.stringify(w))}else S.append(f,String(w))}),await this.fetch.post(`${T}/jcr:content`,S),h&&h["jcr:content"]){const f=`${T}/jcr:content`,I=h["jcr:content"],E=async(R,O,D=10)=>{if(!(D<=0)){for(const[q,F]of Object.entries(O))if(!(q.startsWith("jcr:")||q.startsWith("sling:")||q.startsWith("cq:")||q.startsWith("rep:")||q.startsWith("oak:"))&&F&&typeof F=="object"&&!Array.isArray(F)){const _=`${R}/${q}`,W=F;try{try{await this.fetch.get(`${_}.json`),W&&typeof W=="object"&&await E(_,W,D-1)}catch{const L=new URLSearchParams;W["jcr:primaryType"]?L.append("jcr:primaryType",W["jcr:primaryType"]):L.append("jcr:primaryType","nt:unstructured"),Object.entries(W).forEach(([x,N])=>{x!=="jcr:primaryType"&&(x.startsWith("jcr:")&&x!=="jcr:primaryType"||typeof N=="object"&&!Array.isArray(N)||N!=null&&(Array.isArray(N)?N.forEach(U=>{L.append(x,String(U))}):L.append(x,String(N))))}),await this.fetch.post(_,L),p.log(`\u2705 Created initial node: ${_}`),await E(_,W,D-1)}}catch(V){p.warn(`Could not create initial node ${_}: ${V.message}`)}}}};await E(f,I),p.log("\u2705 Created initial content structure from template under jcr:content")}const b=await this.fetch.get(`${T}.json`),d=b["jcr:content"]!==void 0;let u=!1;try{u=(await this.fetch.get(`${T}.html`)).status===200}catch{u=!1}const g={hasErrors:!1,errors:[]};return y({success:!0,pagePath:T,previewUrl:this.getPreviewUrl(T),title:n,templateUsed:l,jcrContentCreated:d,pageAccessible:u,errorLogCheck:g,creationDetails:{timestamp:new Date().toISOString(),steps:["Template validation completed","Template initial content fetched","Page node created","jcr:content node created",h?"Initial content structure created from template":"No initial content in template","Page structure verified","Accessibility check completed"],initialContentCreated:h!==null},pageStructure:b.data},"createPageWithTemplate")},"createPageWithTemplate")}async validateTemplate(e,t){return C(async()=>{try{let n;try{n=await this.fetch.get(`${e}.2.json`)}catch(m){try{n=await this.fetch.get(`${e}.infinity.json`)}catch(j){throw $(P.INVALID_PARAMETERS,`Template not found or inaccessible: ${e}`,{templatePath:e,fetchError:m.message,infinityError:j.message})}}if(!n||typeof n!="object")throw $(P.INVALID_PARAMETERS,"Invalid template structure: template data is not an object",{templatePath:e});const r=n["jcr:content"];if(!r||typeof r!="object")throw $(P.INVALID_PARAMETERS,"Invalid template structure: jcr:content not found",{templatePath:e,templateDataKeys:Object.keys(n)});const o=r.allowedPaths,s=Array.isArray(o)?o:o?[o]:[],i=r.allowedParents,a=Array.isArray(i)?i:i?[i]:[];let l=s.length===0;s.length>0&&(l=s.some(m=>{if(m.includes("(")||m.includes("*")||m.includes("?"))try{return new RegExp(m).test(t)}catch{return t.startsWith(m.replace(/[()*?]/g,""))}return t.startsWith(m)}));let c=!0,h=null,A=null;if(a.length>0)try{const m=await this.fetch.get(`${t}.2.json`);m&&m["jcr:content"]?(h=m["jcr:content"]["cq:template"]||null,h?(c=a.includes(h),c||(A=`Template '${e}' cannot be used under parent page with template '${h}'. Allowed parent templates: ${a.join(", ")}`)):(c=!1,A=`Template '${e}' requires a parent page with one of the allowed templates, but parent page at '${t}' has no template. Allowed parent templates: ${a.join(", ")}`)):(c=!1,A=`Template '${e}' requires a parent page with one of the allowed templates, but '${t}' is not a page. Allowed parent templates: ${a.join(", ")}`)}catch(m){m.response?.status===404?(c=!1,A=`Template '${e}' requires a parent page with one of the allowed templates, but parent path '${t}' does not exist. Allowed parent templates: ${a.join(", ")}`):(p.warn(`Could not validate parent path ${t}: ${m.message}`),c=!1,A=`Could not validate parent path '${t}': ${m.message}. Template '${e}' requires a parent page with one of the allowed templates: ${a.join(", ")}`)}if(!(l&&c)){const m=[];throw l||m.push(`Path '${t}' is not allowed. Allowed paths: ${s.join(", ")}`),!c&&A&&m.push(A),$(P.INVALID_PARAMETERS,`Template '${e}' cannot be used at '${t}'. ${m.join(" ")}`,{templatePath:e,targetPath:t,allowedPaths:s,allowedParents:a,parentTemplate:h,pathAllowed:l,parentAllowed:c})}return y({templatePath:e,targetPath:t,isValid:!0,templateTitle:r["jcr:title"]||"Untitled Template",templateDescription:r["jcr:description"]||"",allowedPaths:s,allowedParents:a,parentTemplate:h,restrictions:{hasPathRestrictions:s.length>0,hasParentRestrictions:a.length>0,allowedPaths:s,allowedParents:a,pathAllowed:l,parentAllowed:c}},"validateTemplate")}catch(n){throw n.code===P.INVALID_PARAMETERS?n:n.response?.status===404?$(P.INVALID_PARAMETERS,`Template not found: ${e}`,{templatePath:e}):M(n,"validateTemplate")}},"validateTemplate")}templateCache=new Map;templateCacheExpiry=new Map;TEMPLATE_CACHE_TTL=300*1e3;async getTemplateMetadata(e,t=!0){return C(async()=>{if(t&&this.templateCache.has(e)){const s=this.templateCacheExpiry.get(e)||0;if(Date.now()<s)return y({...this.templateCache.get(e),fromCache:!0},"getTemplateMetadata")}const n=await this.fetch.get(`${e}.json`);if(!n||!n["jcr:content"])throw $(P.INVALID_PARAMETERS,"Invalid template structure",{templatePath:e});const r=n["jcr:content"],o={templatePath:e,title:r["jcr:title"]||"Untitled Template",description:r["jcr:description"]||"",thumbnail:r.thumbnail||"",allowedPaths:r.allowedPaths||[],status:r.status||"enabled",ranking:r.ranking||0,templateType:r.templateType||"page",lastModified:r["cq:lastModified"],createdBy:r["jcr:createdBy"],policies:r.policies||{},structure:r.structure||{},initialContent:r.initial||{}};return t&&(this.templateCache.set(e,o),this.templateCacheExpiry.set(e,Date.now()+this.TEMPLATE_CACHE_TTL)),y(o,"getTemplateMetadata")},"getTemplateMetadata")}clearTemplateCache(){this.templateCache.clear(),this.templateCacheExpiry.clear(),console.log("\u{1F5D1}\uFE0F Template cache cleared")}async getComponents(e){return C(async()=>{const t=e||this.aemConfig.components.componentPaths?.projectRoot1||"/apps/aemmcp/base/components";p.log(`Fetching components from root path: ${t}`);const n=[],r=async(o,s=5)=>{if(!(s<=0))try{const i=await this.fetch.get(`${o}.${Math.min(s,3)}.json`);if(i&&typeof i=="object")for(const[a,l]of Object.entries(i)){const c=l;if(!(a.startsWith("jcr:")||a.startsWith("sling:")||a.startsWith("rep:")||a.startsWith("oak:"))&&c&&typeof c=="object"){const h=`${o}/${a}`,A=c["jcr:primaryType"],T=c._cq_dialog!==void 0,m=c[".content.xml"]!==void 0||c["component.html"]!==void 0||c["component.js"]!==void 0||c["component.css"]!==void 0;if(T||m||A==="cq:Component"){let j=a,S="",b="",d="";if(c["jcr:title"]?j=c["jcr:title"]:c["jcr:content"]?.["jcr:title"]&&(j=c["jcr:content"]["jcr:title"]),c["jcr:description"]?S=c["jcr:description"]:c["jcr:content"]?.["jcr:description"]&&(S=c["jcr:content"]["jcr:description"]),c.componentGroup&&(b=c.componentGroup),d=h.replace("/apps/","").replace("/libs/",""),c._cq_dialog)try{const u=await this.fetch.get(`${h}/_cq_dialog.json`,{":depth":"2"});u&&u["jcr:title"]&&(j=u["jcr:title"]||j),u&&u["jcr:description"]&&(S=u["jcr:description"]||S)}catch{}n.push({name:a,title:j,description:S,path:h,resourceType:d,componentGroup:b||"General",primaryType:A,hasDialog:T})}else await r(h,s-1)}}}catch(i){i.message?.includes("404")?p.warn(`Path not found: ${o}`):p.warn(`Error fetching components from ${o}: ${i.message}`)}};return await r(t,5),n.sort((o,s)=>o.name.localeCompare(s.name)),p.log(`Found ${n.length} components from ${t}`),y({rootPath:t,components:n,totalCount:n.length},"getComponents")},"getComponents")}async listWorkflowModels(){return C(async()=>{const e=await this.fetch.get("/etc/workflow/models.json"),t=Array.isArray(e)?e:[],n={request_for_activation:"Publish/activate pages",request_for_deactivation:"Unpublish/deactivate pages",request_for_deletion:"Delete pages",request_for_deletion_without_deactivation:"Delete pages without unpublishing first","dam/update_asset":"Update DAM assets","dam/dam-update-language-copy":"Update language copies of assets","dam/dam-create-language-copy":"Create language copies of assets","wcm-translation/translate-language-copy":"Translate language copies","wcm-translation/create_language_copy":"Create language copies","wcm-translation/prepare_translation_project":"Prepare translation project","wcm-translation/sync_translation_job":"Sync translation job","wcm-translation/update_language_copy":"Update language copy",activationmodel:"Activation workflow model",scheduled_activation:"Scheduled activation",scheduled_deactivation:"Scheduled deactivation"},r=t.map(o=>{const s=o.uri||"",i=s.replace("/var/workflow/models/",""),a=n[i]||"Custom workflow model";return{uri:s,modelId:i,description:a,...o}});return y({models:r,totalCount:r.length,commonWorkflows:Object.entries(n).map(([o,s])=>({modelId:o,uri:`/var/workflow/models/${o}`,description:s}))},"listWorkflowModels")},"listWorkflowModels")}async startWorkflow(e,t,n="JCR_PATH"){return C(async()=>{const r=e.startsWith("/var/workflow/models/")?e:`/var/workflow/models/${e}`,o=new URLSearchParams;o.append("model",r),o.append("payloadType",n),o.append("payload",t);const s=await this.fetch.postWithHeaders("/etc/workflow/instances",o,{headers:{Accept:"application/json"}});if(!s.ok&&s.status!==201){const c=await s.text();throw $(P.INVALID_PARAMETERS,`Failed to start workflow: ${s.status} - ${c}`)}let i=null,a=null;const l=s.headers.get("Location");if(l){i=l.startsWith("http")?new URL(l).pathname:l;const c=i.split("/").filter(h=>h);c.length>0&&(a=c[c.length-1])}else try{const c=await s.text();if(c){const h=JSON.parse(c);if(h&&h.uri){i=h.uri;const A=i.split("/").filter(T=>T);A.length>0&&(a=A[A.length-1])}}}catch{p.log("Workflow created (201), but response is not JSON. Location header:",l||"not found")}return y({modelId:e,modelUri:r,payload:t,payloadType:n,instanceId:a,instancePath:i,locationHeader:l,status:s.status,message:"Workflow instance started successfully"},"startWorkflow")},"startWorkflow")}async listWorkflowInstances(e){return C(async()=>{const t=e?`/etc/workflow/instances.${e}.json`:"/etc/workflow/instances.json",n=await this.fetch.get(t),r=Array.isArray(n)?n:n?.instances||[];return y({instances:r,totalCount:r.length,state:e||"all",timestamp:new Date().toISOString()},"listWorkflowInstances")},"listWorkflowInstances")}async getWorkflowInstance(e){return C(async()=>{const t=e.startsWith("/var/workflow/instances/")?e:`/var/workflow/instances/${e}`,n=await this.fetch.get(`${t}.json`);return y({instanceId:e,instancePath:t,instance:n,timestamp:new Date().toISOString()},"getWorkflowInstance")},"getWorkflowInstance")}async updateWorkflowInstanceState(e,t){return C(async()=>{if(!["RUNNING","SUSPENDED","ABORTED"].includes(t))throw $(P.INVALID_PARAMETERS,`Invalid state: ${t}. Must be RUNNING, SUSPENDED, or ABORTED`);const n=e.startsWith("/var/workflow/instances/")?e:`/var/workflow/instances/${e}`,r=new URLSearchParams;r.append("state",t);const o=await this.fetch.post(n,r,{headers:{Accept:"application/json"}});return y({instanceId:e,instancePath:n,newState:t,response:o,message:`Workflow instance state updated to ${t}`},"updateWorkflowInstanceState")},"updateWorkflowInstanceState")}async getInboxItems(){return C(async()=>{const e=await this.fetch.get("/bin/workflow/inbox.json"),t=e?.items||e||[];return y({items:t,totalCount:Array.isArray(t)?t.length:0,timestamp:new Date().toISOString()},"getInboxItems")},"getInboxItems")}async completeWorkItem(e,t,n){return C(async()=>{let r=t||"";if(!r){const a=(await this.fetch.get(`${e}.routes.json`))?.routes||[];if(a.length===0)throw $(P.INVALID_PARAMETERS,"No routes available for this work item");const l=a[0];if(!l?.rid)throw $(P.INVALID_PARAMETERS,"No valid route ID found in available routes");r=l.rid,p.log(`No route specified, using first available route: ${l.label||"Unknown"} (${r})`)}const o=new URLSearchParams;o.append("item",e),o.append("route",r),n&&o.append("comment",n);const s=await this.fetch.post("/bin/workflow/inbox",o,{headers:{Accept:"application/json"}});return y({workItemPath:e,routeId:r,comment:n,response:s,message:"Work item completed successfully"},"completeWorkItem")},"completeWorkItem")}async delegateWorkItem(e,t){return C(async()=>{const n=new URLSearchParams;n.append("item",e),n.append("delegatee",t);const r=await this.fetch.post("/bin/workflow/inbox",n,{headers:{Accept:"application/json"}});return y({workItemPath:e,delegatee:t,response:r,message:`Work item delegated to ${t}`},"delegateWorkItem")},"delegateWorkItem")}async getWorkItemRoutes(e){return C(async()=>{const n=(await this.fetch.get(`${e}.routes.json`))?.routes||[];return y({workItemPath:e,routes:n,totalCount:n.length,timestamp:new Date().toISOString()},"getWorkItemRoutes")},"getWorkItemRoutes")}}
|
|
1
|
+
"use strict";import{getAEMConfig as B,isValidContentPath as v}from"./aem.config.js";import{AEM_ERROR_CODES as P,createAEMError as $,createSuccessResponse as y,handleAEMHttpError as M,safeExecute as C}from"./aem.errors.js";import{AEMFetch as k}from"./aem.fetch.js";import{ContentFragmentManager as J}from"./aem.content-fragments.js";import{ExperienceFragmentManager as H}from"./aem.experience-fragments.js";import{LOGGER as p}from"../utils/logger.js";export class AEMConnector{isInitialized;isAEMaaCS;config;aemConfig;fetch;contentFragments;experienceFragments;constructor(e){this.isInitialized=!1,this.config=this.loadConfig(e),this.aemConfig=B({}),this.isAEMaaCS=this.isConfigAEMaaCS(),this.fetch=new k({host:this.config.aem.host,auth:this.config.aem.auth,timeout:this.aemConfig.queries.timeoutMs}),this.contentFragments=new J(this.fetch,this.isAEMaaCS),this.experienceFragments=new H(this.fetch,this.config.aem.host)}async init(){await this.fetch.init(),this.isInitialized=!0}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"}}}getPreviewUrl(e){return`${this.config.aem.host}${e}.html?wcmmode=disabled`}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";p.log("Testing AEM connection to:",e);const t=await this.fetch.get(e,void 0,void 0,5e3,!0);return p.log("\u2705 AEM connection successful!"),!0}catch(e){return p.error("\u274C AEM connection failed:",e.message),!1}}async testAuthConnection(){try{this.isInitialized||await this.init();const e="/libs/granite/security/currentuser.json";p.log("Testing AEM authentication connection to:",e);const t=await this.fetch.get(e,void 0,void 0,5e3);return p.log("\u2705 AEM authentication connection successful!"),!0}catch(e){return p.error("\u274C AEM authentication connection failed:",e.message),!1}}validateComponentProps(e,t,n){const r=[],o=[];return t==="text"&&!n.text&&!n.richText&&r.push("Text component should have text or richText property"),t==="image"&&!n.fileReference&&!n.src&&o.push("Image component requires fileReference or src property"),{valid:o.length===0,errors:o,warnings:r,componentType:t,propsValidated:Object.keys(n).length}}async updateComponent(e){return C(async()=>{if(!e.componentPath||typeof e.componentPath!="string")throw $(P.INVALID_PARAMETERS,"Component path is required and must be a string");if(!e.properties||typeof e.properties!="object")throw $(P.INVALID_PARAMETERS,"Properties are required and must be an object");if(!v(e.componentPath,this.aemConfig))throw $(P.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`;let n;try{if(n=await this.fetch.get(t),!n||typeof n=="object"&&Object.keys(n).length===0)throw $(P.COMPONENT_NOT_FOUND,`Component not found at path: ${e.componentPath}`,{componentPath:e.componentPath})}catch(i){throw i.code===P.COMPONENT_NOT_FOUND?i:i.message?.includes("404")||i.response?.status===404?$(P.COMPONENT_NOT_FOUND,`Component not found at path: ${e.componentPath}`,{componentPath:e.componentPath}):M(i,"updateComponent")}const r=n["sling:resourceType"];if(r){p.log(`Validating properties against component definition for: ${r}`);const i=await this.getComponentDefinition(r);if(Object.keys(i.fieldDefinitions).length>0){const l=this.validateComponentProperties(e.properties,i.fieldDefinitions);if(!l.valid){const c=l.errors.join("; ");throw $(P.INVALID_PARAMETERS,`Invalid property values for component ${r}: ${c}`,{resourceType:r,componentPath:i.componentPath,validationErrors:l.errors,invalidFields:l.invalidFields,providedProperties:e.properties})}l.warnings.length>0&&p.warn(`Property validation warnings: ${l.warnings.join("; ")}`),p.log("Property values validated successfully against component dialog definitions")}}const o=new URLSearchParams;r&&o.append("sling:resourceType",r),Object.entries(e.properties).forEach(([i,l])=>{l==null?o.append(`${i}@Delete`,""):Array.isArray(l)?l.forEach(c=>{o.append(`${i}`,c.toString())}):typeof l=="object"?o.append(i,JSON.stringify(l)):o.append(i,l.toString())});const s=await this.fetch.post(e.componentPath,o,{headers:{Accept:"application/json"}}),a=await this.fetch.get(`${e.componentPath}.json`);return y({message:"Component updated successfully",path:e.componentPath,properties:e.properties,updatedProperties:a,response:s,verification:{success:!0,propertiesChanged:Object.keys(e.properties).length,timestamp:new Date().toISOString()}},"updateComponent")},"updateComponent")}async scanPageComponents(e){return C(async()=>{const t=`${e}.infinity.json`,n=await this.fetch.get(t),r=[],o=(s,a)=>{!s||typeof s!="object"||(s["sling:resourceType"]&&r.push({path:a,resourceType:s["sling:resourceType"],properties:{...s}}),Object.entries(s).forEach(([i,l])=>{if(typeof l=="object"&&l!==null&&!i.startsWith("rep:")&&!i.startsWith("oak:")){const c=a?`${a}/${i}`:i;o(l,c)}}))};return n["jcr:content"]?o(n["jcr:content"],"jcr:content"):o(n,e),y({pagePath:e,components:r,totalComponents:r.length},"scanPageComponents")},"scanPageComponents")}async fetchSites(){return C(async()=>{const t=await this.fetch.get("/content.2.json",{":depth":"2"}),n=[];return Object.entries(t).forEach(([r,o])=>{r.startsWith("jcr:")||r.startsWith("sling:")||o&&typeof o=="object"&&o["jcr:content"]&&n.push({name:r,path:`/content/${r}`,title:o["jcr:content"]["jcr:title"]||r,template:o["jcr:content"]["cq:template"],lastModified:o["jcr:content"]["cq:lastModified"]})}),y({sites:n,totalCount:n.length},"fetchSites")},"fetchSites")}async fetchLanguageMasters(e){return C(async()=>{const t=`/content/${e}.2.json`,n=await this.fetch.get(t),r=[];let o=null,s="";return Object.entries(n).forEach(([a,i])=>{(a==="master"||a==="language-masters")&&i&&typeof i=="object"&&(o=i,s=`/content/${e}/${a}`)}),o?(Object.entries(o).forEach(([a,i])=>{a.startsWith("jcr:")||a.startsWith("sling:")||i&&typeof i=="object"&&r.push({name:a,path:`${s}/${a}`,title:i["jcr:content"]?.["jcr:title"]||i["jcr:title"]||a,language:i["jcr:content"]?.["jcr:language"]||i["jcr:language"]||a})}),y({site:e,languageMasters:r},"fetchLanguageMasters")):y({site:e,languageMasters:[],message:"No master or language-masters node found"},"fetchLanguageMasters")},"fetchLanguageMasters")}async fetchAvailableLocales(e){return C(async()=>{const t=`/content/${e}.4.json`,n=await this.fetch.get(t),r={},o=(s,a,i=[])=>{!s||typeof s!="object"||Object.entries(s).forEach(([l,c])=>{if(!(l.startsWith("jcr:")||l.startsWith("sling:")||l.startsWith("cq:")||l.startsWith("rep:")||l.startsWith("oak:")||l==="jcr:content")&&c&&typeof c=="object"){const h=`${a}/${l}`,A=[...i,l],T=c["jcr:content"],m=T&&typeof T=="object",j=T?.["jcr:language"]||null,S=l.length===2||l.length===3,b=i.length>0&&(i[i.length-1].length===2||i[i.length-1].length===3);if(m&&S&&b){const d=i[i.length-1].toUpperCase(),g=l.toLowerCase(),u=`${g}_${d}`;r[u]={path:h,title:T?.["jcr:title"]||l,language:j||`${g}_${d}`,country:d}}o(c,h,A)}})};return o(n,`/content/${e}`,[]),y({site:e,locales:r,totalCount:Object.keys(r).length},"fetchAvailableLocales")},"fetchAvailableLocales")}async getAllTextContent(e){return C(async()=>{let t;try{const o=`${e}.infinity.json`;t=await this.fetch.get(o)}catch(o){if(o.message?.includes("300")||o.message?.includes("redirect")){p.warn(`infinity.json failed for ${e}, trying depth-based approach`);try{t=await this.fetch.get(`${e}.5.json`)}catch{try{t=await this.fetch.get(`${e}/jcr:content.5.json`)}catch{throw M(o,"getAllTextContent")}}}else throw M(o,"getAllTextContent")}const n=[],r=(o,s)=>{!o||typeof o!="object"||((o.text||o["jcr:title"]||o["jcr:description"])&&n.push({path:s,title:o["jcr:title"],text:o.text,description:o["jcr:description"]}),Object.entries(o).forEach(([a,i])=>{if(typeof i=="object"&&i!==null&&!a.startsWith("rep:")&&!a.startsWith("oak:")){const l=s?`${s}/${a}`:a;r(i,l)}}))};return t["jcr:content"]?r(t["jcr:content"],"jcr:content"):r(t,e),y({pagePath:e,textContent:n},"getAllTextContent")},"getAllTextContent")}async getPageTextContent(e){return C(async()=>this.getAllTextContent(e),"getPageTextContent")}async getPageImages(e){return C(async()=>{const t=`${e}.infinity.json`,n=await this.fetch.get(t),r=[],o=(s,a)=>{!s||typeof s!="object"||((s.fileReference||s.src)&&r.push({path:a,fileReference:s.fileReference,src:s.src,alt:s.alt||s.altText,title:s["jcr:title"]||s.title}),Object.entries(s).forEach(([i,l])=>{if(typeof l=="object"&&l!==null&&!i.startsWith("rep:")&&!i.startsWith("oak:")){const c=a?`${a}/${i}`:i;o(l,c)}}))};return n["jcr:content"]?o(n["jcr:content"],"jcr:content"):o(n,e),y({pagePath:e,images:r},"getPageImages")},"getPageImages")}async updateImagePath(e,t){return C(async()=>this.updateComponent({componentPath:e,properties:{fileReference:t}}),"updateImagePath")}async getPageContent(e){return C(async()=>{const t=`${e}.infinity.json`,n=await this.fetch.get(t);return y({pagePath:e,content:n},"getPageContent")},"getPageContent")}async listChildren(e,t=1){return C(async()=>{try{const n=await this.fetch.get(`${e}.${t}.json`),r=[];return n&&typeof n=="object"&&Object.entries(n).forEach(([o,s])=>{if(!(o.startsWith("jcr:")||o.startsWith("sling:")||o.startsWith("cq:")||o.startsWith("rep:")||o.startsWith("oak:")||o==="jcr:content")&&s&&typeof s=="object"){const a=`${e}/${o}`;r.push({name:o,path:a,primaryType:s["jcr:primaryType"]||"nt:unstructured",title:s["jcr:content"]?.["jcr:title"]||s["jcr:title"]||o,lastModified:s["jcr:content"]?.["cq:lastModified"]||s["cq:lastModified"],resourceType:s["jcr:content"]?.["sling:resourceType"]||s["sling:resourceType"]})}}),r}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(o=>({name:o.name||o.path?.split("/").pop(),path:o.path,primaryType:o["jcr:primaryType"]||"cq:Page",title:o["jcr:content/jcr:title"]||o.title||o.name,lastModified:o["jcr:content/cq:lastModified"],resourceType:o["jcr:content/sling:resourceType"]}));throw n}},"listChildren")}async listPages(e,t=1,n=20){return C(async()=>{try{const r=await this.fetch.get(`${e}.${t}.json`),o=[],s=(a,i,l)=>{l>t||o.length>=n||Object.entries(a).forEach(([c,h])=>{if(!(o.length>=n)&&!(c.startsWith("jcr:")||c.startsWith("sling:")||c.startsWith("cq:")||c.startsWith("rep:")||c.startsWith("oak:"))&&h&&typeof h=="object"){const A=`${i}/${c}`;h["jcr:primaryType"]==="cq:Page"&&o.push({name:c,path:A,primaryType:"cq:Page",title:h["jcr:content"]?.["jcr:title"]||c,template:h["jcr:content"]?.["cq:template"],lastModified:h["jcr:content"]?.["cq:lastModified"],lastModifiedBy:h["jcr:content"]?.["cq:lastModifiedBy"],resourceType:h["jcr:content"]?.["sling:resourceType"],type:"page"}),l<t&&s(h,A,l+1)}})};return r&&typeof r=="object"&&s(r,e,0),y({siteRoot:e,pages:o,pageCount:o.length,depth:t,limit:n,totalChildrenScanned:o.length},"listPages")}catch(r){if(p.warn("JSON API failed, falling back to QueryBuilder:",r.message),r.response?.status===404||r.response?.status===403){const o=await this.fetch.get("/bin/querybuilder.json",{path:e,type:"cq:Page","p.nodedepth":t.toString(),"p.limit":n.toString(),"p.hits":"full"}),s=(o.hits||[]).map(a=>({name:a.name||a.path?.split("/").pop(),path:a.path,primaryType:"cq:Page",title:a["jcr:content/jcr:title"]||a.title||a.name,template:a["jcr:content/cq:template"],lastModified:a["jcr:content/cq:lastModified"],lastModifiedBy:a["jcr:content/cq:lastModifiedBy"],resourceType:a["jcr:content/sling:resourceType"],type:"page"}));return y({siteRoot:e,pages:s,pageCount:s.length,depth:t,limit:n,totalChildrenScanned:o.total||s.length,fallbackUsed:"QueryBuilder"},"listPages")}throw r}},"listPages")}async executeJCRQuery(e,t=20){return C(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 r=await this.fetch.get("/bin/querybuilder.json",{path:"/content",type:"cq:Page",fulltext:e,"p.limit":t});return{query:e,results:r.hits||[],total:r.total||0,limit:t}},"executeJCRQuery")}async getPageProperties(e){return C(async()=>{const t=`${e}/jcr:content.json`,n=await this.fetch.get(t),r={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 y({pagePath:e,properties:r},"getPageProperties")},"getPageProperties")}async searchContent(e){return C(async()=>{const t=await this.fetch.get(this.config.aem.endpoints.query,e);return y({params:e,results:t.hits||[],total:t.total||0,rawResponse:t},"searchContent")},"searchContent")}async getAssetMetadata(e){return C(async()=>{const t=`${e}.json`,n=await this.fetch.get(t),r=n["jcr:content"]?.metadata||{};return y({assetPath:e,metadata:r,fullData:n},"getAssetMetadata")},"getAssetMetadata")}async createPage(e){return this.createPageWithTemplate(e)}async deletePage(e){return C(async()=>{const{pagePath:t}=e;if(!v(t,this.aemConfig))throw $(P.INVALID_PARAMETERS,`Invalid page path: ${String(t)}`,{pagePath:t});let n=!1;try{await this.fetch.delete(t),n=!0}catch(r){if(r?.status===405||r?.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(s){throw s}}else throw p.error("DELETE failed:",r.response?.status,r.response?.data),r}return y({success:n,deletedPath:t,timestamp:new Date().toISOString()},"deletePage")},"deletePage")}async createComponent(e){return C(async()=>{const{pagePath:t,componentPath:n,componentType:r,resourceType:o,properties:s={},name:a}=e;if(!v(t,this.aemConfig))throw $(P.INVALID_PARAMETERS,`Invalid page path: ${String(t)}`,{pagePath:t});const i=a||`${r}_${Date.now()}`,l=n||`${t}/jcr:content/${i}`;return await this.fetch.post(l,{"jcr:primaryType":"nt:unstructured","sling:resourceType":o,...s,":operation":"import",":contentType":"json",":replace":"true"}),y({success:!0,componentPath:l,componentType:r,resourceType:o,properties:s,timestamp:new Date().toISOString()},"createComponent")},"createComponent")}async getComponentDefinition(e,t=new Set){const n=[],r={};let o="";if(t.has(e))return p.warn(`Circular reference detected for resourceType: ${e}`),{componentPath:o,requiredProperties:n,fieldDefinitions:r};t.add(e);const s=e.replace(/:/g,"/"),a=[`/apps/${s}`,`/libs/${s}`];let i=!1,l=null;for(const c of a)try{const h=await this.fetch.get(`${c}.json`,{":depth":"2"});if(h){o=c,h["sling:resourceSuperType"]&&(l=h["sling:resourceSuperType"],p.log(`Found sling:resourceSuperType: ${l} for component at ${c}`));try{const A=`${c}/_cq_dialog`,T=await this.fetch.get(`${A}.infinity.json`),m=(j,S="")=>{if(!j||typeof j!="object")return;const b=j["sling:resourceType"]||"",d=j.name||j.fieldName,g=d?d.replace(/^\.\//,""):null;if(g&&(b.includes("form/select")||b.includes("form/checkbox")||b.includes("form/textfield")||b.includes("form/textarea")||b.includes("form/numberfield")||b.includes("form/pathfield")||b.includes("form/datepicker")||b.includes("form/colorfield"))){const u=j.required===!0||j.required==="true",f={name:g,type:this.getFieldType(b),required:u,description:j.fieldDescription||j.fieldLabel||"",defaultValue:j.value!==void 0?j.value:j.checked!==void 0?j.checked:void 0};if(b.includes("form/select")&&j.items){const w=[],I=j.items;typeof I=="object"&&Object.values(I).forEach(E=>{E&&typeof E=="object"&&E.value!==void 0&&w.push(String(E.value))}),w.length>0&&(f.options=w)}b.includes("form/checkbox"),r[g]=f,p.log(`Found field definition: ${g} (type: ${f.type}, options: ${f.options?f.options.join(", "):"N/A"})`),u&&!n.includes(g)&&n.push(g)}j.items&&(Array.isArray(j.items)?j.items.forEach((u,f)=>{m(u,S?`${S}/items[${f}]`:`items[${f}]`)}):typeof j.items=="object"&&Object.entries(j.items).forEach(([u,f])=>{m(f,S?`${S}/items/${u}`:`items/${u}`)})),Object.entries(j).forEach(([u,f])=>{typeof f=="object"&&f!==null&&!u.startsWith("jcr:")&&!u.startsWith("sling:")&&u!=="items"&&m(f,S?`${S}/${u}`:u)})};m(T),i=!0,p.log(`Found component definition at ${o}, required properties: ${n.join(", ")}, field definitions: ${Object.keys(r).join(", ")}`);break}catch(A){p.warn(`Could not fetch dialog for ${c}: ${A.message}`)}}}catch{continue}if(!i&&l){p.log(`No dialog found for ${e}, checking super type: ${l}`);const c=await this.getComponentDefinition(l,t);c.requiredProperties.forEach(h=>{n.includes(h)||n.push(h)}),Object.entries(c.fieldDefinitions).forEach(([h,A])=>{r[h]||(r[h]=A)}),!o&&c.componentPath&&(o=c.componentPath)}return{componentPath:o,requiredProperties:n,fieldDefinitions:r}}getFieldType(e){return e.includes("form/select")?"select":e.includes("form/checkbox")?"checkbox":e.includes("form/textfield")?"textfield":e.includes("form/textarea")?"textarea":e.includes("form/numberfield")?"numberfield":e.includes("form/pathfield")?"pathfield":e.includes("form/datepicker")?"datepicker":e.includes("form/colorfield")?"colorfield":"unknown"}validateComponentProperties(e,t){const n=[],r=[],o={};for(const[s,a]of Object.entries(t)){const i=e[s];if(i!=null){if(a.type==="select"&&a.options){const l=String(i);if(!a.options.includes(l)){const c=`Invalid value '${i}' for field '${s}'. Allowed values: ${a.options.join(", ")}`;n.push(c),o[s]={provided:i,expected:a.options,message:c}}}if(a.type==="checkbox"&&!(typeof i=="boolean"||i==="true"||i==="false"||i===!0||i===!1)){const c=`Invalid value '${i}' for checkbox field '${s}'. Must be boolean or 'true'/'false'`;n.push(c),o[s]={provided:i,expected:'boolean or "true"/"false"',message:c}}if(a.type==="numberfield"&&isNaN(Number(i))){const l=`Invalid value '${i}' for number field '${s}'. Must be a number`;n.push(l),o[s]={provided:i,expected:"number",message:l}}}}return{valid:n.length===0,errors:n,warnings:r,invalidFields:o}}async getComponentTemplate(e){if(!e)return null;try{const t=`${e}/cq:template.infinity.json`;p.log(`Checking for cq:template at: ${t}`);const n=await this.fetch.get(t);if(n&&typeof n=="object"&&Object.keys(n).length>0){p.log(`\u2705 Found cq:template with ${Object.keys(n).length} top-level keys`);const r=Object.keys(n).filter(o=>!o.startsWith("jcr:")&&!o.startsWith("sling:"));return r.length>0&&p.log(`Template child nodes: ${r.join(", ")}`),n}return null}catch(t){const n=t.response?.status||t.statusCode||"unknown";return n===404?p.log(`No cq:template found at ${e}/cq:template`):p.warn(`Error checking for cq:template: ${t.message} (status: ${n})`),null}}async applyTemplateChildNodes(e,t){if(!(!t||Object.keys(t).length===0)){p.log(`Applying ${Object.keys(t).length} child nodes from cq:template to: ${e}`);for(const[n,r]of Object.entries(t))try{const o=`${e}/${n}`,s={...r};s["jcr:primaryType"]||(s["jcr:primaryType"]="nt:unstructured"),await this.fetch.post(o,{...s,":operation":"import",":contentType":"json",":replace":"true"}),p.log(`Created template child node: ${o}`)}catch(o){p.warn(`Failed to create template child node ${n}: ${o.message}`)}}}async addComponent(e){return C(async()=>{const{pagePath:t,resourceType:n,containerPath:r,name:o,properties:s={}}=e;if(!t||typeof t!="string")throw $(P.INVALID_PARAMETERS,"Page path is required and must be a string",{pagePath:t});if(!n||typeof n!="string")throw $(P.INVALID_PARAMETERS,"Resource type is required and must be a string",{resourceType:n});if(!v(t,this.aemConfig))throw $(P.INVALID_PATH,`Invalid page path: ${String(t)}`,{pagePath:t});p.log(`Fetching component definition for resourceType: ${n}`);const a=await this.getComponentDefinition(n);if(a.componentPath?p.log(`Component definition found at: ${a.componentPath}`):p.warn(`Component definition not found for ${n}, skipping required property validation`),a.requiredProperties.length>0){const d=[];if(a.requiredProperties.forEach(g=>{(!(g in s)||s[g]===null||s[g]===void 0||s[g]==="")&&d.push(g)}),d.length>0)throw $(P.INVALID_PARAMETERS,`Missing required properties for component ${n}: ${d.join(", ")}`,{resourceType:n,componentPath:a.componentPath,requiredProperties:a.requiredProperties,missingProperties:d,providedProperties:Object.keys(s)});p.log(`All required properties validated: ${a.requiredProperties.join(", ")}`)}if(p.log(`Checking field definitions: ${Object.keys(a.fieldDefinitions).length} fields found`),Object.keys(a.fieldDefinitions).length>0){p.log(`Field definitions: ${JSON.stringify(Object.keys(a.fieldDefinitions))}`),p.log(`Validating properties: ${JSON.stringify(Object.keys(s))}`);const d=this.validateComponentProperties(s,a.fieldDefinitions);if(p.log(`Validation result: valid=${d.valid}, errors=${d.errors.length}`),!d.valid){const g=d.errors.join("; ");throw p.error(`Property validation failed: ${g}`),$(P.INVALID_PARAMETERS,`Invalid property values for component ${n}: ${g}`,{resourceType:n,componentPath:a.componentPath,validationErrors:d.errors,invalidFields:d.invalidFields,providedProperties:s})}d.warnings.length>0&&p.warn(`Property validation warnings: ${d.warnings.join("; ")}`),p.log("Property values validated successfully against component dialog definitions")}else p.log(`No field definitions found for component ${n}, skipping property value validation`);try{const d=await this.fetch.get(`${t}.json`);if(!d||typeof d=="object"&&Object.keys(d).length===0)throw $(P.INVALID_PATH,`Page not found or invalid at: ${t}`,{pagePath:t});p.log(`Page verified at: ${t}`)}catch(d){throw d.message?.includes("404")||d.message?.includes("Page not found")||d.response?.status===404?$(P.INVALID_PATH,`Page not found at: ${t}`,{pagePath:t}):M(d,"addComponent")}let i;if(r)r.startsWith("/")?i=r:r.includes("jcr:content")?i=`${t}/${r}`:i=`${t}/jcr:content/${r}`;else{const d=`${t}/jcr:content`;let g=!1;try{const u=await this.fetch.get(`${d}.5.json`);u&&u.root?u.root.container?(i=`${d}/root/container`,g=!0,p.log(`\u2705 Found root/container at: ${i}`)):(i=`${d}/root/container`,g=!1,p.log(`Found root but no container, will create container at: ${i}`)):(i=`${d}/root/container`,g=!1,p.log(`No root found, will create root/container at: ${i}`))}catch{i=`${d}/root/container`,g=!1,p.warn(`Could not fetch jcr:content structure, will create root/container at: ${i}`)}}try{await this.fetch.get(`${i}.json`),p.log(`\u2705 Container exists at: ${i}`)}catch(d){if(d.message?.includes("404")||d.response?.status===404){p.warn(`Container not found at ${i}, attempting to create root/container structure`);const u=`${`${t}/jcr:content`}/root`,f=`${u}/container`;try{try{await this.fetch.get(`${u}.json`),p.log(`\u2705 Root already exists at: ${u}`)}catch{p.log(`Creating root at: ${u}`),await this.fetch.post(u,{"jcr:primaryType":"nt:unstructured","sling:resourceType":"aemmcp/base/components/aemmcp-container/v1/aemmcp-container"}),p.log(`\u2705 Created root at: ${u}`)}i===f&&(p.log(`Creating container at: ${f}`),await this.fetch.post(f,{"jcr:primaryType":"nt:unstructured","sling:resourceType":"aemmcp/base/components/aemmcp-container/v1/aemmcp-container"}),p.log(`\u2705 Created container at: ${f}`))}catch(w){throw $(P.INVALID_PATH,`Could not create root/container structure at: ${i}`,{targetContainerPath:i,error:w.message})}}else throw M(d,"addComponent")}const l=o||`component_${Date.now()}`,c=`${i}/${l}`;let h=null,A={},T={};if(a.componentPath&&(h=await this.getComponentTemplate(a.componentPath),h)){p.log("Component has cq:template, processing structure...");const d=["jcr:created","jcr:createdBy","jcr:lastModified","jcr:lastModifiedBy","jcr:mixinTypes"],g=["jcr:primaryType","sling:resourceType","layout","showSeparator","columns","separator"];for(const[u,f]of Object.entries(h))d.includes(u)||(g.includes(u)?A[u]=f:typeof f=="object"&&f!==null&&!Array.isArray(f)&&(f["jcr:primaryType"]!==void 0||f["sling:resourceType"]!==void 0)?T[u]=f:(typeof f!="object"||Array.isArray(f))&&(A[u]=f));p.log(`Template: ${Object.keys(A).length} properties, ${Object.keys(T).length} child nodes`)}const m=new URLSearchParams;if(Object.entries(A).forEach(([d,g])=>{g!=null&&(Array.isArray(g)?g.forEach(u=>m.append(d,u.toString())):typeof g=="object"?m.append(d,JSON.stringify(g)):m.append(d,g.toString()))}),Object.entries(s).forEach(([d,g])=>{g!=null&&(Array.isArray(g)?g.forEach(u=>m.append(d,u.toString())):typeof g=="object"?m.append(d,JSON.stringify(g)):m.append(d,g.toString()))}),m.has("jcr:primaryType")||m.append("jcr:primaryType","nt:unstructured"),m.has("sling:resourceType")||m.append("sling:resourceType",n),await this.fetch.post(c,m),Object.keys(T).length>0)try{await this.applyTemplateChildNodes(c,T),p.log(`\u2705 Applied ${Object.keys(T).length} child nodes from cq:template`)}catch(d){p.warn(`Failed to apply cq:template child nodes: ${d.message}`)}let j=await this.fetch.get(`${c}.json`),S=!1,b=null;try{if(a.componentPath){const d=await this.fetch.get(`${a.componentPath}.json`,{":depth":"2"});if(d&&(d["cq:isContainer"]===!0||d["cq:isContainer"]==="true")){S=!0,p.log(`Component ${n} is a container component (cq:isContainer=true)`),await new Promise(f=>setTimeout(f,1e3)),j=await this.fetch.get(`${c}.json`,{":depth":"5"}),Object.keys(j).some(f=>!f.startsWith("jcr:")&&!f.startsWith("sling:")&&!f.startsWith("cq:")&&f!=="layout"&&f!=="showSeparator"&&f!=="columns"&&f!=="separator")||(p.log("No default structure detected immediately, waiting longer..."),await new Promise(f=>setTimeout(f,1500)),j=await this.fetch.get(`${c}.json`,{":depth":"5"})),b={};const u=(f,w,I=0)=>{I>3||Object.keys(f).forEach(E=>{if(!E.startsWith("jcr:")&&!E.startsWith("sling:")&&!E.startsWith("cq:")&&E!=="layout"&&E!=="showSeparator"&&E!=="columns"&&E!=="separator"){const R=f[E];if(R&&typeof R=="object"&&!Array.isArray(R)){const W=w?`${w}/${E}`:E;if(R["sling:resourceType"]){const D=R["sling:resourceType"];D.includes("aemmcp-cc-container")||D.includes("columncontrol")||E.startsWith("col_")||E.match(/^col_\d+$/)?b[E]={path:`${c}/${W}`,resourceType:D,type:"column",isContainer:R["cq:isContainer"]===!0||R["cq:isContainer"]==="true"}:b[E]={path:`${c}/${W}`,resourceType:D,isContainer:R["cq:isContainer"]===!0||R["cq:isContainer"]==="true"},u(R,W,I+1)}else(E.startsWith("col_")||E.match(/^col_\d+$/)||E.startsWith("column")||E.match(/^column\d+$/)||E.includes("container")||E.includes("parsys")||E.includes("Column")||E.includes("Container"))&&(b[E]={path:`${c}/${W}`,type:"container",children:Object.keys(R).filter(D=>!D.startsWith("jcr:")&&!D.startsWith("sling:")&&!D.startsWith("cq:"))},u(R,W,I+1))}}})};u(j,""),Object.keys(b).length>0?p.log(`Container structure detected: ${Object.keys(b).join(", ")}`):p.log("Container component created but no default structure detected yet")}}}catch(d){p.warn(`Could not check container status: ${d.message}`)}return y({success:!0,pagePath:t,previewUrl:this.getPreviewUrl(t),componentPath:c,resourceType:n,isContainer:S,containerStructure:b||void 0,componentDefinition:{path:a.componentPath||"Not found",requiredProperties:a.requiredProperties,validationPassed:a.requiredProperties.length===0||a.requiredProperties.every(d=>d in s&&s[d]!==null&&s[d]!==void 0&&s[d]!==""),hasTemplate:h!==null,templatePath:h?`${a.componentPath}/cq:template`:void 0,templateChildNodesCount:Object.keys(T).length,fieldDefinitions:Object.keys(a.fieldDefinitions).length>0?a.fieldDefinitions:void 0},containerPath:i,componentName:l,properties:s,verification:j,timestamp:new Date().toISOString()},"addComponent")},"addComponent")}async deleteComponent(e){return C(async()=>{const{componentPath:t}=e;if(!v(t,this.aemConfig))throw $(P.INVALID_PARAMETERS,`Invalid component path: ${String(t)}`,{componentPath:t});let n=!1;try{const r=new URLSearchParams;r.append(":operation","delete"),await this.fetch.post(t,r),n=!0}catch(r){if(r?.status===405||r?.response?.status===405||r?.status===403||r?.response?.status===403)try{await this.fetch.delete(t),n=!0}catch(o){throw p.error("Both POST and DELETE failed:",r.response?.status,o.response?.status),r}else throw p.error("DELETE failed:",r.response?.status,r.response?.data),r}return y({success:n,deletedPath:t,timestamp:new Date().toISOString()},"deleteComponent")},"deleteComponent")}async unpublishContent(e){return C(async()=>{const{contentPaths:t,unpublishTree:n=!1}=e;if(!t||Array.isArray(t)&&t.length===0)throw $(P.INVALID_PARAMETERS,"Content paths array is required and cannot be empty",{contentPaths:t});const r=[];for(const o of Array.isArray(t)?t:[t])try{const s=new URLSearchParams;s.append("cmd","Deactivate"),s.append("path",o),s.append("ignoredeactivated","false"),s.append("onlymodified","false"),n&&s.append("deep","true");const a=await this.fetch.post("/bin/replicate.json",s);r.push({path:o,success:!0,response:a})}catch(s){r.push({path:o,success:!1,error:s.message})}return y({success:r.every(o=>o.success),results:r,unpublishedPaths:t,unpublishTree:n,timestamp:new Date().toISOString()},"unpublishContent")},"unpublishContent")}async activatePage(e){return C(async()=>{const{pagePath:t,activateTree:n=!1}=e;if(!v(t,this.aemConfig))throw $(P.INVALID_PARAMETERS,`Invalid page path: ${String(t)}`,{pagePath:t});try{const r=new URLSearchParams;r.append("cmd","Activate"),r.append("path",t);let o;return n?(r.append("ignoredeactivated","false"),r.append("onlymodified","false"),r.append("deep","true"),o=await this.fetch.post("/libs/replication/treeactivation.html",r)):o=await this.fetch.post("/bin/replicate.json",r),y({success:!0,activatedPath:t,activateTree:n,response:o,timestamp:new Date().toISOString()},"activatePage")}catch(r){try{const o=await this.fetch.post("/bin/wcmcommand",{cmd:"activate",path:t,ignoredeactivated:!1,onlymodified:!1});return y({success:!0,activatedPath:t,activateTree:n,response:o,fallbackUsed:"WCM Command",timestamp:new Date().toISOString()},"activatePage")}catch{throw M(r,"activatePage")}}},"activatePage")}async deactivatePage(e){return C(async()=>{const{pagePath:t,deactivateTree:n=!1}=e;if(!v(t,this.aemConfig))throw $(P.INVALID_PARAMETERS,`Invalid page path: ${String(t)}`,{pagePath:t});try{const r=new URLSearchParams;r.append("cmd","Deactivate"),r.append("path",t),r.append("ignoredeactivated","false"),r.append("onlymodified","false"),n&&r.append("deep","true");const o=await this.fetch.post("/bin/replicate.json",r);return y({success:!0,deactivatedPath:t,deactivateTree:n,response:o,timestamp:new Date().toISOString()},"deactivatePage")}catch(r){try{const o=await this.fetch.post("/bin/wcmcommand",{cmd:"deactivate",path:t,ignoredeactivated:!1,onlymodified:!1});return y({success:!0,deactivatedPath:t,deactivateTree:n,response:o,fallbackUsed:"WCM Command",timestamp:new Date().toISOString()},"deactivatePage")}catch{throw M(r,"deactivatePage")}}},"deactivatePage")}async updateAsset(e){return C(async()=>{const{assetPath:t,metadata:n,fileContent:r,mimeType:o}=e;if(!v(t,this.aemConfig))throw $(P.INVALID_PARAMETERS,`Invalid asset path: ${String(t)}`,{assetPath:t});const s=new URLSearchParams;r&&(s.append("file",r),o&&s.append("jcr:content/jcr:mimeType",o)),n&&typeof n=="object"&&Object.entries(n).forEach(([a,i])=>{s.append(`jcr:content/metadata/${a}`,String(i))});try{const a=await this.fetch.post(t,s),i=await this.fetch.get(`${t}.json`);return y({success:!0,assetPath:t,updatedMetadata:n,updateResponse:a,assetData:i,timestamp:new Date().toISOString()},"updateAsset")}catch(a){throw M(a,"updateAsset")}},"updateAsset")}async deleteAsset(e){return C(async()=>{const{assetPath:t,force:n=!1}=e;if(!v(t,this.aemConfig))throw $(P.INVALID_PARAMETERS,`Invalid asset path: ${String(t)}`,{assetPath:t});return await this.fetch.delete(t),y({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",r="/settings/wcm/templates";return t=t.replace(/\/+$/,""),t.startsWith("/content/")&&(t=t.replace("/content","")),t.startsWith(n)||(t=`${n}/${t.replace(/^\//,"")}`),t.endsWith(r)||(t+=r),t}async getTemplates(e){return C(async()=>{if(e)try{const t=this.getTemplatesPath(e);if(!t)throw $(P.INVALID_PARAMETERS,`Cannot determine configuration path for site: ${e}`,{sitePath:e});p.log("Looking for site-specific templates at:",t);const n=await this.fetch.get(`${t}.2.json`),r=[];return n&&typeof n=="object"&&Object.entries(n).forEach(([o,s])=>{o.startsWith("jcr:")||o.startsWith("sling:")||s&&typeof s=="object"&&s["jcr:content"]&&r.push({name:o,path:`${t}/${o}`,title:s["jcr:content"]["jcr:title"]||o,description:s["jcr:content"]["jcr:description"],allowedPaths:s["jcr:content"].allowedPaths,ranking:s["jcr:content"].ranking||0})}),y({sitePath:e,templates:r,totalCount:r.length,source:"site-specific"},"getTemplates")}catch{}try{const t=["/apps/wcm/core/content/sites/templates","/libs/wcm/core/content/sites/templates"],n=[];for(const r of t)try{const o=await this.fetch.get(`${r}.json`,{":depth":"2"});o&&typeof o=="object"&&Object.entries(o).forEach(([s,a])=>{s.startsWith("jcr:")||s.startsWith("sling:")||a&&typeof a=="object"&&n.push({name:s,path:`${r}/${s}`,title:a["jcr:content"]?.["jcr:title"]||s,description:a["jcr:content"]?.["jcr:description"],allowedPaths:a["jcr:content"]?.allowedPaths,ranking:a["jcr:content"]?.ranking||0,source:r.includes("/apps/")?"apps":"libs"})})}catch{}return y({sitePath:e||"global",templates:n,totalCount:n.length,source:"global"},"getTemplates")}catch(t){throw M(t,"getTemplates")}},"getTemplates")}async getTemplateStructure(e){return C(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||[]},r=(o,s="")=>{if(!(!o||typeof o!="object")){if(o.components){const a=Object.keys(o.components);n.allowedComponents.push(...a)}Object.entries(o).forEach(([a,i])=>{typeof i=="object"&&i!==null&&!a.startsWith("jcr:")&&r(i,s?`${s}/${a}`:a)})}};return r(n.policies),n.allowedComponents=[...new Set(n.allowedComponents)],y({templatePath:e,structure:n,fullData:t},"getTemplateStructure")}catch(t){throw M(t,"getTemplateStructure")}},"getTemplateStructure")}async bulkUpdateComponents(e){return C(async()=>{const{updates:t,validateFirst:n=!0,continueOnError:r=!1}=e;if(!Array.isArray(t)||t.length===0)throw $(P.INVALID_PARAMETERS,"Updates array is required and cannot be empty");const o=[];if(n)for(const a of t)try{await this.fetch.get(`${a.componentPath}.json`)}catch(i){if(i.response?.status===404&&(o.push({componentPath:a.componentPath,success:!1,error:`Component not found: ${a.componentPath}`,phase:"validation"}),!r))return y({success:!1,message:"Bulk update failed during validation phase",results:o,totalUpdates:t.length,successfulUpdates:0},"bulkUpdateComponents")}let s=0;for(const a of t)try{const i=await this.updateComponent({componentPath:a.componentPath,properties:a.properties});o.push({componentPath:a.componentPath,success:!0,result:i,phase:"update"}),s++}catch(i){if(o.push({componentPath:a.componentPath,success:!1,error:i.message,phase:"update"}),!r)break}return y({success:s===t.length,message:`Bulk update completed: ${s}/${t.length} successful`,results:o,totalUpdates:t.length,successfulUpdates:s,failedUpdates:t.length-s},"bulkUpdateComponents")},"bulkUpdateComponents")}async convertComponents(e){return C(async()=>{const{pagePath:t,sourceResourceType:n,targetResourceType:r,requiredProperties:o={},continueOnError:s=!0}=e;if(!t||typeof t!="string")throw $(P.INVALID_PARAMETERS,"Page path is required and must be a string");if(!n||typeof n!="string")throw $(P.INVALID_PARAMETERS,"Source resource type is required and must be a string");if(!r||typeof r!="string")throw $(P.INVALID_PARAMETERS,"Target resource type is required and must be a string");if(!v(t,this.aemConfig))throw $(P.INVALID_PATH,`Page path '${t}' is not within allowed content roots`);p.log(`Scanning page ${t} for components with resourceType: ${n}`);const i=await this.scanPageComponents(t),c=(i.data?.components||i.components||[]).filter(b=>b.resourceType===n);if(c.length===0)return y({message:`No components found with resourceType: ${n} on page ${t}`,pagePath:t,sourceResourceType:n,targetResourceType:r,componentsFound:0,componentsConverted:0},"convertComponents");p.log(`Found ${c.length} components with resourceType: ${n}`);const A=(await this.getComponentDefinition(r)).requiredProperties||[],T=[];if(A.length>0&&(A.forEach(b=>{(!(b in o)||o[b]===null||o[b]===void 0||o[b]==="")&&T.push(b)}),T.length>0))return y({message:"Target component requires properties that are not provided",pagePath:t,sourceResourceType:n,targetResourceType:r,componentsFound:c.length,componentsConverted:0,targetComponentRequiredProperties:A,missingRequiredProperties:T,providedProperties:Object.keys(o),note:"Please provide the missing required properties in the requiredProperties parameter and retry"},"convertComponents");const m=[];let j=0,S=0;for(const b of c)try{let d;b.path.startsWith("/")?d=b.path:b.path.startsWith("jcr:content")?d=`${t}/${b.path}`:d=`${t}/${b.path}`,p.log(`Processing component at: ${d}`),p.log(`Deleting source component at: ${d}`),await this.deleteComponent({componentPath:d}),p.log(`Creating target component at: ${d}`);const g=new URLSearchParams;g.append("jcr:primaryType","nt:unstructured"),g.append("sling:resourceType",r),Object.entries(o).forEach(([f,w])=>{if(w!=null){const I=f.startsWith("./")?f.substring(2):f;Array.isArray(w)?w.forEach(E=>{g.append(I,E.toString())}):typeof w=="object"?g.append(I,JSON.stringify(w)):g.append(I,w.toString())}}),await this.fetch.post(d,g,{headers:{Accept:"application/json"}});const u=await this.fetch.get(`${d}.json`);if(!u||!u["sling:resourceType"]||u["sling:resourceType"]!==r)throw new Error("Component creation verification failed: resourceType mismatch");m.push({sourceComponentPath:d,targetComponentPath:d,success:!0,message:`Successfully converted component from ${n} to ${r}`}),j++,p.log(`\u2705 Successfully converted component at: ${d}`)}catch(d){const g=d.message||String(d);if(p.error(`Failed to convert component at ${b.path}: ${g}`),m.push({sourceComponentPath:b.path,success:!1,error:g}),S++,!s)return y({message:"Conversion stopped due to error (continueOnError=false)",pagePath:t,sourceResourceType:n,targetResourceType:r,componentsFound:c.length,componentsConverted:j,componentsFailed:S,results:m},"convertComponents")}return y({message:`Converted ${j} of ${c.length} components from ${n} to ${r}`,pagePath:t,sourceResourceType:n,targetResourceType:r,componentsFound:c.length,componentsConverted:j,componentsFailed:S,results:m},"convertComponents")},"convertComponents")}async bulkConvertComponents(e){return C(async()=>{const{pagePaths:t,searchPath:n,depth:r=2,limit:o=50,sourceResourceType:s,targetResourceType:a,requiredProperties:i={},continueOnError:l=!0}=e;if(!s||typeof s!="string")throw $(P.INVALID_PARAMETERS,"Source resource type is required and must be a string");if(!a||typeof a!="string")throw $(P.INVALID_PARAMETERS,"Target resource type is required and must be a string");let c=[];if(t&&Array.isArray(t)&&t.length>0)c=t,p.log(`Processing ${c.length} specified pages`);else if(n){if(!v(n,this.aemConfig))throw $(P.INVALID_PATH,`Search path '${n}' is not within allowed content roots`);p.log(`Searching for pages under ${n} with depth ${r}`);const d=await this.listPages(n,r,o),g=d.data?.pages||d.pages||[];if(g.length===0)return y({message:`No pages found under ${n}`,searchPath:n,sourceResourceType:s,targetResourceType:a,pagesProcessed:0,pagesSucceeded:0,pagesFailed:0,totalComponentsConverted:0},"bulkConvertComponents");c=g.map(u=>u.path||u["@path"]).filter(u=>u),p.log(`Found ${c.length} pages to process`)}else throw $(P.INVALID_PARAMETERS,"Either pagePaths array or searchPath must be provided");if(c.length===0)return y({message:"No pages to process",sourceResourceType:s,targetResourceType:a,pagesProcessed:0,pagesSucceeded:0,pagesFailed:0,totalComponentsConverted:0},"bulkConvertComponents");const h=[];let A=0,T=0,m=0,j=0,S=0;for(const b of c)try{p.log(`Processing page: ${b}`);const g=await this.convertComponents({pagePath:b,sourceResourceType:s,targetResourceType:a,requiredProperties:i,continueOnError:l}),u=g.data||g;if(g.success!==!1){const f=u.componentsFound||0,w=u.componentsConverted||0,I=u.componentsFailed||0;m+=f,j+=w,S+=I,f>0&&A++,h.push({pagePath:b,success:!0,componentsFound:f,componentsConverted:w,componentsFailed:I,message:u.message||"Processed successfully"})}else T++,h.push({pagePath:b,success:!1,error:u.message||"Conversion failed",componentsFound:0,componentsConverted:0,componentsFailed:0})}catch(d){const g=d.message||String(d);if(p.error(`Failed to process page ${b}: ${g}`),T++,h.push({pagePath:b,success:!1,error:g,componentsFound:0,componentsConverted:0,componentsFailed:0}),!l)return y({message:"Bulk conversion stopped due to error (continueOnError=false)",sourceResourceType:s,targetResourceType:a,pagesProcessed:c.length,pagesSucceeded:A,pagesFailed:T,totalComponentsFound:m,totalComponentsConverted:j,totalComponentsFailed:S,pageResults:h},"bulkConvertComponents")}return y({message:`Bulk conversion completed: ${A} pages succeeded, ${T} pages failed. Total components converted: ${j}`,sourceResourceType:s,targetResourceType:a,pagesProcessed:c.length,pagesSucceeded:A,pagesFailed:T,totalComponentsFound:m,totalComponentsConverted:j,totalComponentsFailed:S,pageResults:h},"bulkConvertComponents")},"bulkConvertComponents")}async getNodeContent(e,t=1){return C(async()=>{const n=`${e}.json`,r=await this.fetch.get(n,{":depth":t.toString()});return{path:e,depth:t,content:r,timestamp:new Date().toISOString()}},"getNodeContent")}async getAvailableTemplates(e){return C(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 r=`${t}/settings/wcm/templates`;try{const o=await this.fetch.get(`${r}.3.json`),s=[];return o&&typeof o=="object"&&Object.entries(o).forEach(([a,i])=>{if(!(a.startsWith("jcr:")||a.startsWith("sling:"))&&i&&typeof i=="object"&&i["jcr:content"]){const l=`${r}/${a}`,c=i["jcr:content"],h=i?.structure?.["jcr:content"]||{};s.push({name:a,path:l,title:c["jcr:title"]||a,description:c["jcr:description"]||"",thumbnail:c.thumbnail||"",allowedPaths:c.allowedPaths||[],status:c.status||"enabled",ranking:c.ranking||0,templateType:c.templateType||"page",resourceType:h["sling:resourceType"]||"",lastModified:c["cq:lastModified"],createdBy:c["jcr:createdBy"]})}}),s.sort((a,i)=>a.ranking!==i.ranking?i.ranking-a.ranking:a.name.localeCompare(i.name)),y({parentPath:e,templatesPath:r,templates:s,totalCount:s.length,availableTemplates:s.filter(a=>a.status==="enabled")},"getAvailableTemplates")}catch(o){if(o.response?.status===404){const s="/libs/wcm/foundation/templates",a=await this.fetch.get(`${s}.json`,{":depth":"2"}),i=[];return a&&typeof a=="object"&&Object.entries(a).forEach(([l,c])=>{l.startsWith("jcr:")||l.startsWith("sling:")||c&&typeof c=="object"&&i.push({name:l,path:`${s}/${l}`,title:c["jcr:title"]||l,description:c["jcr:description"]||"Global template",status:"enabled",ranking:0,templateType:"page",isGlobal:!0})}),y({parentPath:e,templatesPath:s,templates:i,totalCount:i.length,availableTemplates:i,fallbackUsed:!0},"getAvailableTemplates")}throw o}},"getAvailableTemplates")}async createPageWithTemplate(e){return C(async()=>{const{parentPath:t,title:n,template:r,name:o,properties:s={},resourceType:a=""}=e;if(!v(t,this.aemConfig))throw $(P.INVALID_PARAMETERS,`Invalid parent path: ${String(t)}`,{parentPath:t});if(!o&&!n)throw $(P.INVALID_PARAMETERS,'Either "name" or "title" must be provided to create a page. Please provide at least one of these parameters.',{parentPath:t,providedParams:{name:o,title:n}});const i=n||(o?o.replace(/-/g," ").replace(/\b\w/g,f=>f.toUpperCase()):"");let l=r,c=a;if(!l){const w=(await this.getAvailableTemplates(t)).data.availableTemplates;if(w.length===0)throw $(P.INVALID_PARAMETERS,"No templates available for this path",{parentPath:t});const I=w[0];l=I.path,!c&&I.resourceType&&(c=I.resourceType),p.log(`\u{1F3AF} Auto-selected template: ${l} (${w[0].title})`,c)}let h=null;try{const f=await this.fetch.get(`${l}.json`);p.log(`\u2705 Template verified: ${l}`,f);try{const w=await this.fetch.get(`${l}.infinity.json`);if(!c&&w){const I=w.structure?.["jcr:content"];if(I&&I["sling:resourceType"])c=I["sling:resourceType"],p.log(`\u{1F4CB} Extracted resourceType from template structure: ${c}`);else{const E=w["jcr:content"];E&&E["sling:resourceType"]&&(c=E["sling:resourceType"],p.log(`\u{1F4CB} Extracted resourceType from template jcr:content: ${c}`))}}w&&w["jcr:content"]&&w.initial?(h=w.initial,p.log(`\u{1F4CB} Found initial content node at template/initial: ${l}`)):p.warn(`\u26A0\uFE0F No initial content found in template at /initial: ${l}`)}catch(w){p.warn(`Could not fetch template structure: ${w.message}`)}}catch(f){throw p.error("Template verification failed:",f.message,f),f?.response?.status===404?$(P.INVALID_PARAMETERS,`Template not found: ${l}`,{template:l}):M(f,"createPageWithTemplate")}try{await this.validateTemplate(l,t),p.log(`\u2705 Template validation passed for ${l} at ${t}`)}catch(f){throw f}const A=o||(i?i.replace(/\s+/g,"-").toLowerCase():""),T=`${t}/${A}`;try{const f=await this.fetch.get(`${T}.json`);if(f&&(f["jcr:primaryType"]==="cq:Page"||f["jcr:content"]))throw $(P.INVALID_PARAMETERS,`Page already exists at path: ${T}. Cannot overwrite existing page. Please use a different name or delete the existing page first.`,{pagePath:T,parentPath:t,pageName:A,existingPage:!0})}catch(f){if(f.code===P.INVALID_PARAMETERS&&f.message?.includes("already exists"))throw f;f.response?.status!==404&&!f.message?.includes("404")&&p.warn(`Could not check if page exists at ${T}: ${f.message}`)}const m={"jcr:primaryType":"cq:Page","jcr:content":{"jcr:primaryType":"cq:PageContent","jcr:title":i,"cq:template":l,"sling:resourceType":c||"foundation/components/page","cq:lastModified":new Date().toISOString(),"jcr:createdBy":"admin","jcr:created":new Date().toISOString(),"cq:lastModifiedBy":"admin",...s}};if(h&&h["jcr:content"]){const f=h["jcr:content"];Object.entries(f).forEach(([w,I])=>{w==="jcr:created"||w==="jcr:createdBy"||w==="jcr:title"||w==="cq:template"||w.startsWith("jcr:")&&w!=="jcr:primaryType"||typeof I=="object"&&!Array.isArray(I)&&!w.startsWith("jcr:")&&!w.startsWith("sling:")&&!w.startsWith("cq:")||m["jcr:content"][w]||(m["jcr:content"][w]=I)}),p.log("\u{1F4E6} Merged initial content properties from template")}const j=new URLSearchParams;j.append("jcr:primaryType","cq:Page"),await this.fetch.post(T,j);const S=new URLSearchParams;if(Object.entries(m["jcr:content"]).forEach(([f,w])=>{if(!(f==="jcr:created"||f==="jcr:createdBy"))if(typeof w=="object"&&w!==null&&!Array.isArray(w)){if(!f.startsWith("jcr:")&&!f.startsWith("sling:")&&!f.startsWith("cq:"))return;S.append(f,JSON.stringify(w))}else S.append(f,String(w))}),await this.fetch.post(`${T}/jcr:content`,S),h&&h["jcr:content"]){const f=`${T}/jcr:content`,I=h["jcr:content"],E=async(R,W,D=10)=>{if(!(D<=0)){for(const[x,L]of Object.entries(W))if(!(x.startsWith("jcr:")||x.startsWith("sling:")||x.startsWith("cq:")||x.startsWith("rep:")||x.startsWith("oak:"))&&L&&typeof L=="object"&&!Array.isArray(L)){const q=`${R}/${x}`,O=L;try{try{await this.fetch.get(`${q}.json`),O&&typeof O=="object"&&await E(q,O,D-1)}catch{const _=new URLSearchParams;O["jcr:primaryType"]?_.append("jcr:primaryType",O["jcr:primaryType"]):_.append("jcr:primaryType","nt:unstructured"),Object.entries(O).forEach(([F,N])=>{F!=="jcr:primaryType"&&(F.startsWith("jcr:")&&F!=="jcr:primaryType"||typeof N=="object"&&!Array.isArray(N)||N!=null&&(Array.isArray(N)?N.forEach(U=>{_.append(F,String(U))}):_.append(F,String(N))))}),await this.fetch.post(q,_),p.log(`\u2705 Created initial node: ${q}`),await E(q,O,D-1)}}catch(V){p.warn(`Could not create initial node ${q}: ${V.message}`)}}}};await E(f,I),p.log("\u2705 Created initial content structure from template under jcr:content")}const b=await this.fetch.get(`${T}.json`),d=b["jcr:content"]!==void 0;let g=!1;try{g=(await this.fetch.get(`${T}.html`)).status===200}catch{g=!1}const u={hasErrors:!1,errors:[]};return y({success:!0,pagePath:T,previewUrl:this.getPreviewUrl(T),title:n,templateUsed:l,jcrContentCreated:d,pageAccessible:g,errorLogCheck:u,creationDetails:{timestamp:new Date().toISOString(),steps:["Template validation completed","Template initial content fetched","Page node created","jcr:content node created",h?"Initial content structure created from template":"No initial content in template","Page structure verified","Accessibility check completed"],initialContentCreated:h!==null},pageStructure:b.data},"createPageWithTemplate")},"createPageWithTemplate")}async validateTemplate(e,t){return C(async()=>{try{let n;try{n=await this.fetch.get(`${e}.2.json`)}catch(m){try{n=await this.fetch.get(`${e}.infinity.json`)}catch(j){throw $(P.INVALID_PARAMETERS,`Template not found or inaccessible: ${e}`,{templatePath:e,fetchError:m.message,infinityError:j.message})}}if(!n||typeof n!="object")throw $(P.INVALID_PARAMETERS,"Invalid template structure: template data is not an object",{templatePath:e});const r=n["jcr:content"];if(!r||typeof r!="object")throw $(P.INVALID_PARAMETERS,"Invalid template structure: jcr:content not found",{templatePath:e,templateDataKeys:Object.keys(n)});const o=r.allowedPaths,s=Array.isArray(o)?o:o?[o]:[],a=r.allowedParents,i=Array.isArray(a)?a:a?[a]:[];let l=s.length===0;s.length>0&&(l=s.some(m=>{if(m.includes("(")||m.includes("*")||m.includes("?"))try{return new RegExp(m).test(t)}catch{return t.startsWith(m.replace(/[()*?]/g,""))}return t.startsWith(m)}));let c=!0,h=null,A=null;if(i.length>0)try{const m=await this.fetch.get(`${t}.2.json`);m&&m["jcr:content"]?(h=m["jcr:content"]["cq:template"]||null,h?(c=i.includes(h),c||(A=`Template '${e}' cannot be used under parent page with template '${h}'. Allowed parent templates: ${i.join(", ")}`)):(c=!1,A=`Template '${e}' requires a parent page with one of the allowed templates, but parent page at '${t}' has no template. Allowed parent templates: ${i.join(", ")}`)):(c=!1,A=`Template '${e}' requires a parent page with one of the allowed templates, but '${t}' is not a page. Allowed parent templates: ${i.join(", ")}`)}catch(m){m.response?.status===404?(c=!1,A=`Template '${e}' requires a parent page with one of the allowed templates, but parent path '${t}' does not exist. Allowed parent templates: ${i.join(", ")}`):(p.warn(`Could not validate parent path ${t}: ${m.message}`),c=!1,A=`Could not validate parent path '${t}': ${m.message}. Template '${e}' requires a parent page with one of the allowed templates: ${i.join(", ")}`)}if(!(l&&c)){const m=[];throw l||m.push(`Path '${t}' is not allowed. Allowed paths: ${s.join(", ")}`),!c&&A&&m.push(A),$(P.INVALID_PARAMETERS,`Template '${e}' cannot be used at '${t}'. ${m.join(" ")}`,{templatePath:e,targetPath:t,allowedPaths:s,allowedParents:i,parentTemplate:h,pathAllowed:l,parentAllowed:c})}return y({templatePath:e,targetPath:t,isValid:!0,templateTitle:r["jcr:title"]||"Untitled Template",templateDescription:r["jcr:description"]||"",allowedPaths:s,allowedParents:i,parentTemplate:h,restrictions:{hasPathRestrictions:s.length>0,hasParentRestrictions:i.length>0,allowedPaths:s,allowedParents:i,pathAllowed:l,parentAllowed:c}},"validateTemplate")}catch(n){throw n.code===P.INVALID_PARAMETERS?n:n.response?.status===404?$(P.INVALID_PARAMETERS,`Template not found: ${e}`,{templatePath:e}):M(n,"validateTemplate")}},"validateTemplate")}templateCache=new Map;templateCacheExpiry=new Map;TEMPLATE_CACHE_TTL=300*1e3;async getTemplateMetadata(e,t=!0){return C(async()=>{if(t&&this.templateCache.has(e)){const s=this.templateCacheExpiry.get(e)||0;if(Date.now()<s)return y({...this.templateCache.get(e),fromCache:!0},"getTemplateMetadata")}const n=await this.fetch.get(`${e}.json`);if(!n||!n["jcr:content"])throw $(P.INVALID_PARAMETERS,"Invalid template structure",{templatePath:e});const r=n["jcr:content"],o={templatePath:e,title:r["jcr:title"]||"Untitled Template",description:r["jcr:description"]||"",thumbnail:r.thumbnail||"",allowedPaths:r.allowedPaths||[],status:r.status||"enabled",ranking:r.ranking||0,templateType:r.templateType||"page",lastModified:r["cq:lastModified"],createdBy:r["jcr:createdBy"],policies:r.policies||{},structure:r.structure||{},initialContent:r.initial||{}};return t&&(this.templateCache.set(e,o),this.templateCacheExpiry.set(e,Date.now()+this.TEMPLATE_CACHE_TTL)),y(o,"getTemplateMetadata")},"getTemplateMetadata")}clearTemplateCache(){this.templateCache.clear(),this.templateCacheExpiry.clear(),console.log("\u{1F5D1}\uFE0F Template cache cleared")}async getComponents(e){return C(async()=>{const t=e||this.aemConfig.components.componentPaths?.projectRoot1||"/apps/aemmcp/base/components";p.log(`Fetching components from root path: ${t}`);const n=[],r=async(o,s=5)=>{if(!(s<=0))try{const a=await this.fetch.get(`${o}.${Math.min(s,3)}.json`);if(a&&typeof a=="object")for(const[i,l]of Object.entries(a)){const c=l;if(!(i.startsWith("jcr:")||i.startsWith("sling:")||i.startsWith("rep:")||i.startsWith("oak:"))&&c&&typeof c=="object"){const h=`${o}/${i}`,A=c["jcr:primaryType"],T=c._cq_dialog!==void 0,m=c[".content.xml"]!==void 0||c["component.html"]!==void 0||c["component.js"]!==void 0||c["component.css"]!==void 0;if(T||m||A==="cq:Component"){let j=i,S="",b="",d="";if(c["jcr:title"]?j=c["jcr:title"]:c["jcr:content"]?.["jcr:title"]&&(j=c["jcr:content"]["jcr:title"]),c["jcr:description"]?S=c["jcr:description"]:c["jcr:content"]?.["jcr:description"]&&(S=c["jcr:content"]["jcr:description"]),c.componentGroup&&(b=c.componentGroup),d=h.replace("/apps/","").replace("/libs/",""),c._cq_dialog)try{const g=await this.fetch.get(`${h}/_cq_dialog.json`,{":depth":"2"});g&&g["jcr:title"]&&(j=g["jcr:title"]||j),g&&g["jcr:description"]&&(S=g["jcr:description"]||S)}catch{}n.push({name:i,title:j,description:S,path:h,resourceType:d,componentGroup:b||"General",primaryType:A,hasDialog:T})}else await r(h,s-1)}}}catch(a){a.message?.includes("404")?p.warn(`Path not found: ${o}`):p.warn(`Error fetching components from ${o}: ${a.message}`)}};return await r(t,5),n.sort((o,s)=>o.name.localeCompare(s.name)),p.log(`Found ${n.length} components from ${t}`),y({rootPath:t,components:n,totalCount:n.length},"getComponents")},"getComponents")}async listWorkflowModels(){return C(async()=>{const e=await this.fetch.get("/etc/workflow/models.json"),t=Array.isArray(e)?e:[],n={request_for_activation:"Publish/activate pages",request_for_deactivation:"Unpublish/deactivate pages",request_for_deletion:"Delete pages",request_for_deletion_without_deactivation:"Delete pages without unpublishing first","dam/update_asset":"Update DAM assets","dam/dam-update-language-copy":"Update language copies of assets","dam/dam-create-language-copy":"Create language copies of assets","wcm-translation/translate-language-copy":"Translate language copies","wcm-translation/create_language_copy":"Create language copies","wcm-translation/prepare_translation_project":"Prepare translation project","wcm-translation/sync_translation_job":"Sync translation job","wcm-translation/update_language_copy":"Update language copy",activationmodel:"Activation workflow model",scheduled_activation:"Scheduled activation",scheduled_deactivation:"Scheduled deactivation"},r=t.map(o=>{const s=o.uri||"",a=s.replace("/var/workflow/models/",""),i=n[a]||"Custom workflow model";return{uri:s,modelId:a,description:i,...o}});return y({models:r,totalCount:r.length,commonWorkflows:Object.entries(n).map(([o,s])=>({modelId:o,uri:`/var/workflow/models/${o}`,description:s}))},"listWorkflowModels")},"listWorkflowModels")}async startWorkflow(e,t,n="JCR_PATH"){return C(async()=>{const r=e.startsWith("/var/workflow/models/")?e:`/var/workflow/models/${e}`,o=new URLSearchParams;o.append("model",r),o.append("payloadType",n),o.append("payload",t);const s=await this.fetch.postWithHeaders("/etc/workflow/instances",o,{headers:{Accept:"application/json"}});if(!s.ok&&s.status!==201){const c=await s.text();throw $(P.INVALID_PARAMETERS,`Failed to start workflow: ${s.status} - ${c}`)}let a=null,i=null;const l=s.headers.get("Location");if(l){a=l.startsWith("http")?new URL(l).pathname:l;const c=a.split("/").filter(h=>h);c.length>0&&(i=c[c.length-1])}else try{const c=await s.text();if(c){const h=JSON.parse(c);if(h&&h.uri){a=h.uri;const A=a.split("/").filter(T=>T);A.length>0&&(i=A[A.length-1])}}}catch{p.log("Workflow created (201), but response is not JSON. Location header:",l||"not found")}return y({modelId:e,modelUri:r,payload:t,payloadType:n,instanceId:i,instancePath:a,locationHeader:l,status:s.status,message:"Workflow instance started successfully"},"startWorkflow")},"startWorkflow")}async listWorkflowInstances(e){return C(async()=>{const t=e?`/etc/workflow/instances.${e}.json`:"/etc/workflow/instances.json",n=await this.fetch.get(t),r=Array.isArray(n)?n:n?.instances||[];return y({instances:r,totalCount:r.length,state:e||"all",timestamp:new Date().toISOString()},"listWorkflowInstances")},"listWorkflowInstances")}async getWorkflowInstance(e){return C(async()=>{const t=e.startsWith("/var/workflow/instances/")?e:`/var/workflow/instances/${e}`,n=await this.fetch.get(`${t}.json`);return y({instanceId:e,instancePath:t,instance:n,timestamp:new Date().toISOString()},"getWorkflowInstance")},"getWorkflowInstance")}async updateWorkflowInstanceState(e,t){return C(async()=>{if(!["RUNNING","SUSPENDED","ABORTED"].includes(t))throw $(P.INVALID_PARAMETERS,`Invalid state: ${t}. Must be RUNNING, SUSPENDED, or ABORTED`);const n=e.startsWith("/var/workflow/instances/")?e:`/var/workflow/instances/${e}`,r=new URLSearchParams;r.append("state",t);const o=await this.fetch.post(n,r,{headers:{Accept:"application/json"}});return y({instanceId:e,instancePath:n,newState:t,response:o,message:`Workflow instance state updated to ${t}`},"updateWorkflowInstanceState")},"updateWorkflowInstanceState")}async getInboxItems(){return C(async()=>{const e=await this.fetch.get("/bin/workflow/inbox.json"),t=e?.items||e||[];return y({items:t,totalCount:Array.isArray(t)?t.length:0,timestamp:new Date().toISOString()},"getInboxItems")},"getInboxItems")}async completeWorkItem(e,t,n){return C(async()=>{let r=t||"";if(!r){const i=(await this.fetch.get(`${e}.routes.json`))?.routes||[];if(i.length===0)throw $(P.INVALID_PARAMETERS,"No routes available for this work item");const l=i[0];if(!l?.rid)throw $(P.INVALID_PARAMETERS,"No valid route ID found in available routes");r=l.rid,p.log(`No route specified, using first available route: ${l.label||"Unknown"} (${r})`)}const o=new URLSearchParams;o.append("item",e),o.append("route",r),n&&o.append("comment",n);const s=await this.fetch.post("/bin/workflow/inbox",o,{headers:{Accept:"application/json"}});return y({workItemPath:e,routeId:r,comment:n,response:s,message:"Work item completed successfully"},"completeWorkItem")},"completeWorkItem")}async delegateWorkItem(e,t){return C(async()=>{const n=new URLSearchParams;n.append("item",e),n.append("delegatee",t);const r=await this.fetch.post("/bin/workflow/inbox",n,{headers:{Accept:"application/json"}});return y({workItemPath:e,delegatee:t,response:r,message:`Work item delegated to ${t}`},"delegateWorkItem")},"delegateWorkItem")}async getWorkItemRoutes(e){return C(async()=>{const n=(await this.fetch.get(`${e}.routes.json`))?.routes||[];return y({workItemPath:e,routes:n,totalCount:n.length,timestamp:new Date().toISOString()},"getWorkItemRoutes")},"getWorkItemRoutes")}async getContentFragment(e){return this.contentFragments.getContentFragment(e)}async listContentFragments(e){return this.contentFragments.listContentFragments(e)}async manageContentFragment(e){return this.contentFragments.manageContentFragment(e)}async manageContentFragmentVariation(e){return this.contentFragments.manageContentFragmentVariation(e)}async getExperienceFragment(e){return this.experienceFragments.getExperienceFragment(e)}async listExperienceFragments(e){return this.experienceFragments.listExperienceFragments(e)}async manageExperienceFragment(e){return this.experienceFragments.manageExperienceFragment(e)}async manageExperienceFragmentVariation(e){return this.experienceFragments.manageExperienceFragmentVariation(e)}}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";import{createSuccessResponse as d,safeExecute as p,createAEMError as m,AEM_ERROR_CODES as l}from"./aem.errors.js";export class ContentFragmentManager{fetch;isAEMaaCS;constructor(t,a){this.fetch=t,this.isAEMaaCS=a}async getContentFragment(t){return p(async()=>{if(this.isAEMaaCS){const a=await this.fetch.get("/adobe/sites/cf/fragments",{path:t}),e=a.items?.[0]||a;return d(this.normalizeFragment(e),"getContentFragment")}else{const a=await this.fetch.get(`/api/assets${t}.json`);return d(this.normalizeFragmentFrom65(a,t),"getContentFragment")}},"getContentFragment")}normalizeFragment(t){return{path:t.path||t.id,title:t.title,model:t.model?.path||t.model,description:t.description||"",fields:this.extractFields(t),variations:this.extractVariations(t),metadata:{created:t.created?.at,modified:t.modified?.at,createdBy:t.created?.by,status:t.status}}}normalizeFragmentFrom65(t,a){const e=t.properties?.elements||{},n=t.properties?.variations||{};return{path:a,title:t.properties?.title||t.properties?.["jcr:title"]||"",model:t.properties?.["cq:model"]||"",description:t.properties?.description||"",fields:Object.entries(e).map(([o,r])=>({name:o,value:r.value??r[":value"]??"",type:r[":type"]||"text"})),variations:Object.entries(n).map(([o,r])=>({name:o,title:r.title||o,fields:Object.entries(r.elements||{}).map(([s,c])=>({name:s,value:c.value??c[":value"]??"",type:c[":type"]||"text"}))})),metadata:{created:t.properties?.["jcr:created"],modified:t.properties?.["jcr:lastModified"]||t.properties?.["cq:lastModified"],createdBy:t.properties?.["jcr:createdBy"],status:t.properties?.["cq:lastReplicationAction"]||"not published"}}}extractFields(t){const a=t.fields||t.elements||[];return Array.isArray(a)?a.map(e=>({name:e.name,value:e.values?.[0]??e.value??"",type:e.type||"text"})):Object.entries(a).map(([e,n])=>({name:e,value:n.values?.[0]??n.value??"",type:n.type||"text"}))}extractVariations(t){const a=t.variations||[];return Array.isArray(a)?a.map(e=>({name:e.name||e.id,title:e.title||e.name||"",fields:this.extractFields(e)})):Object.entries(a).map(([e,n])=>({name:e,title:n.title||e,fields:this.extractFields(n)}))}async listContentFragments(t){const{path:a,model:e,limit:n=20,offset:o=0}=t;return p(async()=>{if(this.isAEMaaCS){const r={parentPath:a,limit:n};e&&(r.modelId=e),o>0&&(r.offset=o);const s=await this.fetch.get("/adobe/sites/cf/fragments",r),c=s.items||[];return d({fragments:c.map(i=>({path:i.path||i.id,title:i.title,model:i.model?.path||i.model,modified:i.modified?.at,status:i.status})),totalCount:s.total||c.length,limit:n,offset:o},"listContentFragments")}else{const r={type:"dam:Asset",path:a,"p.limit":n,"p.offset":o,orderby:"@jcr:content/jcr:lastModified","orderby.sort":"desc"};e&&(r.property="jcr:content/data/cq:model",r["property.value"]=e);const s=await this.fetch.get("/bin/querybuilder.json",r),c=s.hits||[];return d({fragments:c.map(i=>({path:i.path,title:i["jcr:content"]?.["jcr:title"]||i.name,model:i["jcr:content"]?.data?.["cq:model"]||"",modified:i["jcr:content"]?.["jcr:lastModified"]||"",status:i["jcr:content"]?.["cq:lastReplicationAction"]||"not published"})),totalCount:s.total||c.length,limit:n,offset:o},"listContentFragments")}},"listContentFragments")}async manageContentFragment(t){const{action:a}=t;switch(a){case"create":return this.createContentFragment(t);case"update":return this.updateContentFragment(t);case"delete":return this.deleteContentFragment(t);default:throw m(l.INVALID_PARAMETERS,`Invalid action: ${a}. Must be "create", "update", or "delete".`)}}async createContentFragment(t){const{parentPath:a,title:e,model:n,fields:o,description:r,name:s}=t;if(!a||!e||!n)throw m(l.INVALID_PARAMETERS,"create requires parentPath, title, and model");const c=s||e.toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-|-$/g,"");return p(async()=>{if(this.isAEMaaCS){const i={title:e,model:n,description:r||""};o&&(i.fields=Object.entries(o).map(([g,h])=>({name:g,value:h})));const f=await this.fetch.post(`/adobe/sites/cf/fragments?parentPath=${encodeURIComponent(a)}&name=${encodeURIComponent(c)}`,i);return d({action:"create",path:f.path||`${a}/${c}`,title:e,model:n},"manageContentFragment")}else{const i=new URLSearchParams;if(i.append("./jcr:primaryType","dam:Asset"),i.append("./jcr:content/jcr:primaryType","dam:AssetContent"),i.append("./jcr:content/jcr:title",e),i.append("./jcr:content/data/jcr:primaryType","nt:unstructured"),i.append("./jcr:content/data/cq:model",n),r&&i.append("./jcr:content/data/description",r),o)for(const[g,h]of Object.entries(o))i.append(`./jcr:content/data/master/${g}`,String(h));const f=`${a}/${c}`;return await this.fetch.post(f,i),d({action:"create",path:f,title:e,model:n},"manageContentFragment")}},"createContentFragment")}async updateContentFragment(t){const{fragmentPath:a,fields:e,description:n,title:o}=t;if(!a)throw m(l.INVALID_PARAMETERS,"update requires fragmentPath");return p(async()=>{if(this.isAEMaaCS){const r={};return o&&(r.title=o),n&&(r.description=n),e&&(r.fields=Object.entries(e).map(([s,c])=>({name:s,value:c}))),await this.fetch.put(`/adobe/sites/cf/fragments?path=${encodeURIComponent(a)}`,r),d({action:"update",path:a},"manageContentFragment")}else{const r=new URLSearchParams;if(o&&r.append("./jcr:content/jcr:title",o),n&&r.append("./jcr:content/data/description",n),e)for(const[s,c]of Object.entries(e))r.append(`./jcr:content/data/master/${s}`,String(c));return await this.fetch.post(a,r),d({action:"update",path:a},"manageContentFragment")}},"updateContentFragment")}async deleteContentFragment(t){const{fragmentPath:a,force:e}=t;if(!a)throw m(l.INVALID_PARAMETERS,"delete requires fragmentPath");return p(async()=>{if(this.isAEMaaCS){const n=`/adobe/sites/cf/fragments?path=${encodeURIComponent(a)}${e?"&force=true":""}`;return await this.fetch.delete(n),d({action:"delete",path:a},"manageContentFragment")}else{const n=new URLSearchParams;return n.append(":operation","delete"),await this.fetch.post(a,n),d({action:"delete",path:a},"manageContentFragment")}},"deleteContentFragment")}async manageContentFragmentVariation(t){const{action:a,fragmentPath:e,variationName:n,title:o,fields:r}=t;return p(async()=>{switch(a){case"create":{if(!o)throw m(l.INVALID_PARAMETERS,"create requires title");if(this.isAEMaaCS)await this.fetch.post(`/adobe/sites/cf/fragments?path=${encodeURIComponent(e)}/variations`,{name:n,title:o,fields:r?Object.entries(r).map(([s,c])=>({name:s,value:c})):void 0});else{const s=new URLSearchParams;if(s.append("./jcr:primaryType","nt:unstructured"),s.append("./jcr:title",o),r)for(const[c,i]of Object.entries(r))s.append(`./${c}`,String(i));await this.fetch.post(`${e}/jcr:content/data/${n}`,s)}return d({action:"create",fragmentPath:e,variationName:n,title:o},"manageContentFragmentVariation")}case"update":{if(this.isAEMaaCS){const s={};o&&(s.title=o),r&&(s.fields=Object.entries(r).map(([c,i])=>({name:c,value:i}))),await this.fetch.put(`/adobe/sites/cf/fragments?path=${encodeURIComponent(e)}/variations/${n}`,s)}else{const s=new URLSearchParams;if(o&&s.append("./jcr:title",o),r)for(const[c,i]of Object.entries(r))s.append(`./${c}`,String(i));await this.fetch.post(`${e}/jcr:content/data/${n}`,s)}return d({action:"update",fragmentPath:e,variationName:n},"manageContentFragmentVariation")}case"delete":{if(this.isAEMaaCS)await this.fetch.delete(`/adobe/sites/cf/fragments?path=${encodeURIComponent(e)}/variations/${n}`);else{const s=new URLSearchParams;s.append(":operation","delete"),await this.fetch.post(`${e}/jcr:content/data/${n}`,s)}return d({action:"delete",fragmentPath:e,variationName:n},"manageContentFragmentVariation")}default:throw m(l.INVALID_PARAMETERS,`Invalid action: ${a}. Must be "create", "update", or "delete".`)}},"manageContentFragmentVariation")}}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";import{createSuccessResponse as m,safeExecute as d,createAEMError as l,AEM_ERROR_CODES as g}from"./aem.errors.js";import{LOGGER as j}from"../utils/logger.js";export class ExperienceFragmentManager{fetch;host;constructor(c,e){this.fetch=c,this.host=e}getPreviewUrl(c){return`${this.host}${c}.html?wcmmode=disabled`}async getExperienceFragment(c){return d(async()=>{const e=await this.fetch.get(`${c}.infinity.json`),n=e["jcr:content"]||{},o=[];for(const[r,a]of Object.entries(e)){if(r.startsWith("jcr:")||r.startsWith("rep:")||typeof a!="object")continue;const p=a["jcr:content"];if(!p)continue;const i=p["cq:xfVariantType"];i&&o.push({name:r,type:i,path:`${c}/${r}`,title:p["jcr:title"]||r})}return m({path:c,title:n["jcr:title"]||"",template:n["cq:template"]||"",description:n["jcr:description"]||"",variations:o,tags:n["cq:tags"]||[],lastModified:n["cq:lastModified"]||n["jcr:lastModified"]||"",status:n["cq:lastReplicationAction"]||"not published"},"getExperienceFragment")},"getExperienceFragment")}async listExperienceFragments(c){const{path:e="/content/experience-fragments",template:n,limit:o=20,offset:r=0}=c;return d(async()=>{const a={type:"cq:Page",path:e,property:"jcr:content/sling:resourceType","property.value":"cq/experience-fragments/components/experiencefragment","p.limit":o,"p.offset":r,orderby:"@jcr:content/cq:lastModified","orderby.sort":"desc"};n&&(a["2_property"]="jcr:content/cq:template",a["2_property.value"]=n);const s=await this.fetch.get("/bin/querybuilder.json",a),p=s.hits||[];return m({fragments:p.map(i=>({path:i.path,title:i["jcr:content"]?.["jcr:title"]||i.name,variationCount:Object.keys(i).filter(t=>!t.startsWith("jcr:")&&!t.startsWith("rep:")).length,lastModified:i["jcr:content"]?.["cq:lastModified"]||""})),totalCount:s.total||p.length,limit:o,offset:r},"listExperienceFragments")},"listExperienceFragments")}async manageExperienceFragment(c){const{action:e}=c;switch(e){case"create":return this.createExperienceFragment(c);case"update":return this.updateExperienceFragment(c);case"delete":return this.deleteExperienceFragment(c);default:throw l(g.INVALID_PARAMETERS,`Invalid action: ${e}. Must be "create", "update", or "delete".`)}}async createExperienceFragment(c){const{parentPath:e,title:n,template:o,description:r,tags:a,name:s}=c;if(!e||!n||!o)throw l(g.INVALID_PARAMETERS,"create requires parentPath, title, and template");const p=s||n.toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-|-$/g,""),i=`${e}/${p}`;return d(async()=>{const t=new URLSearchParams;t.append("./jcr:primaryType","cq:Page"),t.append("./jcr:content/jcr:primaryType","cq:PageContent"),t.append("./jcr:content/jcr:title",n),t.append("./jcr:content/sling:resourceType","cq/experience-fragments/components/experiencefragment"),t.append("./jcr:content/cq:template",o),r&&t.append("./jcr:content/jcr:description",r),a?.length&&a.forEach(h=>t.append("./jcr:content/cq:tags",h)),await this.fetch.post(i,t);const f=new URLSearchParams;return f.append("./jcr:primaryType","cq:Page"),f.append("./jcr:content/jcr:primaryType","cq:PageContent"),f.append("./jcr:content/jcr:title","Master"),f.append("./jcr:content/sling:resourceType","cq/experience-fragments/components/xfpage"),f.append("./jcr:content/cq:xfVariantType","web"),await this.fetch.post(`${i}/master`,f),m({action:"create",path:i,title:n,previewUrl:this.getPreviewUrl(i)},"manageExperienceFragment")},"createExperienceFragment")}async updateExperienceFragment(c){const{xfPath:e,title:n,description:o,tags:r}=c;if(!e)throw l(g.INVALID_PARAMETERS,"update requires xfPath");return d(async()=>{const a=new URLSearchParams;return n&&a.append("./jcr:content/jcr:title",n),o&&a.append("./jcr:content/jcr:description",o),r?.length&&r.forEach(s=>a.append("./jcr:content/cq:tags",s)),await this.fetch.post(e,a),m({action:"update",path:e},"manageExperienceFragment")},"updateExperienceFragment")}async deleteExperienceFragment(c){const{xfPath:e,force:n}=c;if(!e)throw l(g.INVALID_PARAMETERS,"delete requires xfPath");return d(async()=>{if(!n)try{const a=(await this.fetch.get(`${e}.references.json`))?.pages?.filter(s=>s.path!==e)||[];if(a.length>0)throw l(g.INVALID_PARAMETERS,`Cannot delete: XF is referenced by ${a.length} page(s): ${a.map(s=>s.path).join(", ")}. Use force=true to delete anyway.`)}catch(r){if(r.code===g.INVALID_PARAMETERS)throw r;j.warn(`Could not check references for ${e}: ${r.message}`)}const o=new URLSearchParams;return o.append(":operation","delete"),await this.fetch.post(e,o),m({action:"delete",path:e},"manageExperienceFragment")},"deleteExperienceFragment")}async manageExperienceFragmentVariation(c){const{action:e,xfPath:n,variationName:o,variationType:r="web",title:a,template:s,force:p}=c,i=`${n}/${o}`;return d(async()=>{switch(e){case"create":{if(!a)throw l(g.INVALID_PARAMETERS,"create requires title");const t=new URLSearchParams;return t.append("./jcr:primaryType","cq:Page"),t.append("./jcr:content/jcr:primaryType","cq:PageContent"),t.append("./jcr:content/jcr:title",a),t.append("./jcr:content/sling:resourceType","cq/experience-fragments/components/xfpage"),t.append("./jcr:content/cq:xfVariantType",r),s&&t.append("./jcr:content/cq:template",s),await this.fetch.post(i,t),m({action:"create",xfPath:n,variationName:o,variationPath:i,variationType:r,title:a},"manageExperienceFragmentVariation")}case"update":{const t=new URLSearchParams;return a&&t.append("./jcr:content/jcr:title",a),r&&t.append("./jcr:content/cq:xfVariantType",r),await this.fetch.post(i,t),m({action:"update",xfPath:n,variationName:o,variationPath:i},"manageExperienceFragmentVariation")}case"delete":{const t=new URLSearchParams;return t.append(":operation","delete"),await this.fetch.post(i,t),m({action:"delete",xfPath:n,variationName:o,variationPath:i},"manageExperienceFragmentVariation")}default:throw l(g.INVALID_PARAMETERS,`Invalid action: ${e}. Must be "create", "update", or "delete".`)}},"manageExperienceFragmentVariation")}}
|
package/dist/aem/aem.fetch.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";import{getAccessToken as p}from"./aem.auth.js";import{LOGGER as l}from"../utils/logger.js";export class AEMFetch{fetch;config;token;tokenExpiry;constructor(n){this.config=n,this.fetch=null,this.token="",this.tokenExpiry=0}async init(){this.token=await this.getAuthToken(this.config.auth),this.fetch=this.getFetchInstance()}getFetchInstance(){return(n,e={})=>{const
|
|
1
|
+
"use strict";import{getAccessToken as p}from"./aem.auth.js";import{LOGGER as l}from"../utils/logger.js";export class AEMFetch{fetch;config;token;tokenExpiry;constructor(n){this.config=n,this.fetch=null,this.token="",this.tokenExpiry=0}async init(){this.token=await this.getAuthToken(this.config.auth),this.fetch=this.getFetchInstance()}getFetchInstance(){return(n,e={})=>{const t=e.headers instanceof Headers?new Headers(e.headers):new Headers(e.headers||{});this.config.auth.clientId&&!this.config.auth.username?t.set("Authorization",`Bearer ${this.token}`):t.set("Authorization",`Basic ${this.token}`),t.has("Accept")||t.set("Accept","application/json"),t.has("Content-Type")||t.set("Content-Type","application/json");const{headers:i,...r}=e;return fetch(n,{...r,headers:t})}}async getAuthToken(n){if(n.clientId&&n.clientSecret){const e=Date.now();if(this.token&&e<this.tokenExpiry)return this.token;const t=await p(n.clientId,n.clientSecret,n.scope);return this.token=t.access_token,this.tokenExpiry=e+(t.expires_in-60)*1e3,this.token}if(n.username&&n.password)return Buffer.from(`${n.username}:${n.password}`).toString("base64");throw new Error("No authentication credentials provided")}async refreshAuthToken(){this.token="",this.tokenExpiry=0,this.token=await this.getAuthToken(this.config.auth)}getTimeoutOptions(n){let e,t,a;const i=n||this.config.timeout;return i&&(e=new AbortController,a=e.signal,t=setTimeout(()=>e.abort(),i)),{signal:a,timeoutId:t}}buildUrlWithParams(n,e){const t=this.config.host.endsWith("/")?this.config.host.slice(0,-1):this.config.host,a=n.startsWith("/")?n:`/${n}`,i=`${t}${a}`;if(!e||Object.keys(e).length===0)return i;const r=new URL(i);return Object.entries(e).forEach(([s,c])=>{c!=null&&r.searchParams.append(s,String(c))}),r.toString()}async request(n,e={},t,a){if(!this.fetch)throw new Error("AEMFetch not initialized. Call await init(config) before making requests.");const{timeoutId:i,signal:r}=this.getTimeoutOptions(t);t&&(e.signal=r),e.redirect=e.redirect||"follow";let s;try{if(s=await this.fetch(n,e),s.status===401&&(l.warn(`AEM request to ${n} returned 401 Unauthorized. Attempting to refresh token...`),await this.refreshAuthToken(),s=await this.fetch(n,e)),s.status>=300&&s.status<400&&!s.ok){const o=s.headers.get("Location");if(o){l.warn(`Redirect detected (${s.status}) from ${n} to ${o}`);const h=o.startsWith("http")?o:`${this.config.host}${o}`;s=await this.fetch(h,{...e,redirect:"follow"})}}if(!s.ok){const o=s.clone();let h=`AEM ${e.method||"GET"} failed: ${s.status}`,u=null;try{if(u=await o.text(),u&&u.trim().length>0)try{const f=JSON.parse(u);h=`AEM ${e.method||"GET"} failed: ${s.status} - ${JSON.stringify(f)}`}catch{h=`AEM ${e.method||"GET"} failed: ${s.status} - ${u}`}}catch{}const d=new Error(h);throw d.status=s.status,d.response={status:s.status,data:u||null},d}if(s.status===204||s.status===200){const o=s.headers.get("content-type")||"",h=s.headers.get("content-length");if(e.method==="DELETE"&&(!h||h==="0"))return{};if(!o.includes("application/json")&&(!h||h==="0"))return{}}if(a)return s.text();const c=await s.text();if(!c||c.trim().length===0)return{};try{return JSON.parse(c)}catch(o){if(e.method==="DELETE"&&s.status>=200&&s.status<300)return l.warn(`DELETE response was not JSON, but status ${s.status} indicates success`),{success:!0,status:s.status};throw new Error(`Failed to parse response as JSON: ${o.message}. Response: ${c.substring(0,200)}`)}}finally{i&&clearTimeout(i)}}async get(n,e,t={},a,i){const r=this.buildUrlWithParams(n,e);return this.request(r,t,a,i)}async post(n,e,t={},a,i){let r;const s=t.headers instanceof Headers?new Headers(t.headers):new Headers(t.headers||{});e instanceof URLSearchParams?(r=e,s.set("Content-Type","application/x-www-form-urlencoded")):(r=JSON.stringify(e),s.has("Content-Type")||s.set("Content-Type","application/json"));const c=this.buildUrlWithParams(n),{headers:o,...h}=t;return this.request(c,{...h,method:"POST",body:r,headers:s},a,i)}async delete(n,e={},t){const a=this.buildUrlWithParams(n);return this.request(a,{...e,method:"DELETE"},t)}async put(n,e,t={},a){let i;const r=t.headers instanceof Headers?new Headers(t.headers):new Headers(t.headers||{});e instanceof URLSearchParams?(i=e,r.set("Content-Type","application/x-www-form-urlencoded")):(i=JSON.stringify(e),r.has("Content-Type")||r.set("Content-Type","application/json"));const s=this.buildUrlWithParams(n),{headers:c,...o}=t;return this.request(s,{...o,method:"PUT",body:i,headers:r},a)}async postWithHeaders(n,e,t={},a){if(!this.fetch)throw new Error("AEMFetch not initialized. Call await init() before making requests.");let i;const r=t.headers instanceof Headers?new Headers(t.headers):new Headers(t.headers||{});e instanceof URLSearchParams?(i=e,r.set("Content-Type","application/x-www-form-urlencoded")):(i=JSON.stringify(e),r.has("Content-Type")||r.set("Content-Type","application/json"));const s=this.buildUrlWithParams(n),{timeoutId:c,signal:o}=this.getTimeoutOptions(a);a&&(t.signal=o);try{const h=await this.fetch(s,{...t,method:"POST",body:i,headers:r});return h.status===401?(await this.refreshAuthToken(),await this.fetch(s,{...t,method:"POST",body:i,headers:new Headers(r)})):h}finally{c&&clearTimeout(c)}}}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";import{AEMConnector as i}from"../aem/aem.connector.js";import{handleAEMHttpError as c}from"../aem/aem.errors.js";import{toolSchemas as s}from"./mcp.tools.js";import{LOGGER as
|
|
1
|
+
"use strict";import{AEMConnector as i}from"../aem/aem.connector.js";import{handleAEMHttpError as c}from"../aem/aem.errors.js";import{toolSchemas as s}from"./mcp.tools.js";import{LOGGER as a}from"../utils/logger.js";export class MCPRequestHandler{aemConnector;config;constructor(n){this.config=n,this.aemConnector=new i(n)}async init(){this.aemConnector.isInitialized?a.log("AEM Connector already initialized."):(await this.aemConnector.init(),a.log("AEM Connector initialized."))}async handleRequest(n,e){const o=s[n];if(o){const t=o.safeParse(e);if(!t.success)throw new Error(`Invalid input for ${n}: ${t.error.issues.map(r=>`${r.path.join(".")}: ${r.message}`).join(", ")}`);e=t.data}try{await this.init()}catch(t){throw a.error("ERROR initializing MCP Server",t.message),c(t,"MCP Server Initialization")}try{switch(n){case"updateComponent":return await this.aemConnector.updateComponent(e);case"scanPageComponents":return await this.aemConnector.scanPageComponents(e.pagePath);case"fetchSites":return await this.aemConnector.fetchSites();case"fetchLanguageMasters":return await this.aemConnector.fetchLanguageMasters(e.site);case"fetchAvailableLocales":return await this.aemConnector.fetchAvailableLocales(e.site);case"getAllTextContent":return await this.aemConnector.getAllTextContent(e.pagePath);case"getPageTextContent":return await this.aemConnector.getPageTextContent(e.pagePath);case"getPageImages":return await this.aemConnector.getPageImages(e.pagePath);case"updateImagePath":return await this.aemConnector.updateImagePath(e.componentPath,e.newImagePath);case"getPageContent":return await this.aemConnector.getPageContent(e.pagePath);case"listPages":return await this.aemConnector.listPages(e.siteRoot||e.path||"/content",e.depth||1,e.limit||20);case"getNodeContent":return await this.aemConnector.getNodeContent(e.path,e.depth||1);case"listChildren":return await this.aemConnector.listChildren(e.path);case"getPageProperties":return await this.aemConnector.getPageProperties(e.pagePath);case"searchContent":return await this.aemConnector.searchContent(e);case"executeJCRQuery":return await this.aemConnector.executeJCRQuery(e.query,e.limit);case"getAssetMetadata":return await this.aemConnector.getAssetMetadata(e.assetPath);case"enhancedPageSearch":return await this.aemConnector.searchContent({fulltext:e.searchTerm,path:e.basePath,type:"cq:Page",limit:20});case"createPage":return await this.aemConnector.createPage(e);case"deletePage":return await this.aemConnector.deletePage(e);case"createComponent":return await this.aemConnector.createComponent(e);case"addComponent":return await this.aemConnector.addComponent(e);case"deleteComponent":return await this.aemConnector.deleteComponent(e);case"unpublishContent":return await this.aemConnector.unpublishContent(e);case"activatePage":return await this.aemConnector.activatePage(e);case"deactivatePage":return await this.aemConnector.deactivatePage(e);case"updateAsset":return await this.aemConnector.updateAsset(e);case"deleteAsset":return await this.aemConnector.deleteAsset(e);case"getTemplates":return await this.aemConnector.getTemplates(e.sitePath);case"getTemplateStructure":return await this.aemConnector.getTemplateStructure(e.templatePath);case"getComponents":return await this.aemConnector.getComponents(e.path);case"bulkUpdateComponents":return await this.aemConnector.bulkUpdateComponents(e);case"convertComponents":return await this.aemConnector.convertComponents(e);case"bulkConvertComponents":return await this.aemConnector.bulkConvertComponents(e);case"listWorkflowModels":return await this.aemConnector.listWorkflowModels();case"startWorkflow":return await this.aemConnector.startWorkflow(e.modelId,e.payload,e.payloadType);case"listWorkflowInstances":return await this.aemConnector.listWorkflowInstances(e.state);case"getWorkflowInstance":return await this.aemConnector.getWorkflowInstance(e.instanceId);case"updateWorkflowInstanceState":return await this.aemConnector.updateWorkflowInstanceState(e.instanceId,e.state);case"getInboxItems":return await this.aemConnector.getInboxItems();case"completeWorkItem":return await this.aemConnector.completeWorkItem(e.workItemPath,e.routeId,e.comment);case"delegateWorkItem":return await this.aemConnector.delegateWorkItem(e.workItemPath,e.delegatee);case"getWorkItemRoutes":return await this.aemConnector.getWorkItemRoutes(e.workItemPath);case"getContentFragment":return await this.aemConnector.getContentFragment(e.path);case"listContentFragments":return await this.aemConnector.listContentFragments(e);case"manageContentFragment":return await this.aemConnector.manageContentFragment(e);case"manageContentFragmentVariation":return await this.aemConnector.manageContentFragmentVariation(e);case"getExperienceFragment":return await this.aemConnector.getExperienceFragment(e.path);case"listExperienceFragments":return await this.aemConnector.listExperienceFragments(e);case"manageExperienceFragment":return await this.aemConnector.manageExperienceFragment(e);case"manageExperienceFragmentVariation":return await this.aemConnector.manageExperienceFragmentVariation(e);default:throw new Error(`Unknown method: ${n}`)}}catch(t){throw a.error(`Error in tool ${n}:`,t.message),t}}}
|
package/dist/mcp/mcp.tools.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";import{z as e}from"zod";import{zodToJsonSchema as s}from"zod-to-json-schema";const i={getAllTextContent:e.object({pagePath:e.string().describe("Path to the page")}).passthrough(),getPageTextContent:e.object({pagePath:e.string().describe("Path to the page")}).passthrough(),getPageImages:e.object({pagePath:e.string().describe("Path to the page")}).passthrough(),updateImagePath:e.object({componentPath:e.string().describe("Path to the image component"),newImagePath:e.string().describe("New image path")}).passthrough(),getPageContent:e.object({pagePath:e.string().describe("Path to the page")}).passthrough(),getNodeContent:e.object({path:e.string().describe("JCR node path"),depth:e.number().optional().describe("Depth to traverse")}).passthrough(),listChildren:e.object({path:e.string().describe("Parent node path")}).passthrough(),getPageProperties:e.object({pagePath:e.string().describe("Path to the page")}).passthrough()},p={fetchSites:e.object({}).passthrough(),fetchLanguageMasters:e.object({site:e.string().describe("Site name")}).passthrough(),fetchAvailableLocales:e.object({site:e.string().describe("Site name")}).passthrough()},c={listPages:e.object({siteRoot:e.string().optional().describe("Site root path"),depth:e.number().optional().describe("Depth to traverse"),limit:e.number().optional().describe("Maximum number of results")}).passthrough(),createPage:e.object({parentPath:e.string().describe("Parent path"),title:e.string().describe("Page title"),template:e.string().describe("Template path"),resourceType:e.string().optional().describe("Optional: Will be extracted from template if not provided"),name:e.string().optional().describe("Page name"),properties:e.record(e.unknown()).optional().describe("Additional properties")}).passthrough(),deletePage:e.object({pagePath:e.string().describe("Path to the page to delete"),force:e.boolean().optional().describe("Force deletion")}).passthrough(),activatePage:e.object({pagePath:e.string().describe("Path to the page"),activateTree:e.boolean().optional().describe("Activate entire tree")}).passthrough(),deactivatePage:e.object({pagePath:e.string().describe("Path to the page"),deactivateTree:e.boolean().optional().describe("Deactivate entire tree")}).passthrough(),unpublishContent:e.object({contentPaths:e.array(e.string()).describe("Paths to unpublish"),unpublishTree:e.boolean().optional().describe("Unpublish tree")}).passthrough()},l={updateComponent:e.object({componentPath:e.string().describe("Path to the component"),properties:e.record(e.unknown()).describe("Properties to update")}).passthrough(),scanPageComponents:e.object({pagePath:e.string().describe("Path to the page to scan")}).passthrough(),createComponent:e.object({pagePath:e.string().describe("Path to the page"),componentType:e.string().describe("Component type"),resourceType:e.string().describe("Resource type"),properties:e.record(e.unknown()).optional().describe("Component properties"),name:e.string().optional().describe("Component name")}).passthrough(),addComponent:e.object({pagePath:e.string().describe("Path to the existing page (e.g., /content/site/en/page)"),resourceType:e.string().describe("Sling resource type of the component (required)"),containerPath:e.string().optional().describe("Optional: specific container path (defaults to root/container)"),name:e.string().optional().describe("Optional: component node name (auto-generated if not provided)"),properties:e.record(e.unknown()).optional().describe("Optional: component properties to set")}).passthrough(),deleteComponent:e.object({componentPath:e.string().describe("Path to the component to delete"),force:e.boolean().optional().describe("Force deletion")}).passthrough(),getComponents:e.object({path:e.string().optional().describe("Optional: Component root path to fetch components from. If not provided, uses the configured default path.")}).passthrough(),bulkUpdateComponents:e.object({updates:e.array(e.object({componentPath:e.string(),properties:e.record(e.unknown())})).describe("Array of component updates"),validateFirst:e.boolean().optional().describe("Validate before updating"),continueOnError:e.boolean().optional().describe("Continue on individual failures")}).passthrough(),convertComponents:e.object({pagePath:e.string().describe("Path to the page containing components to convert"),sourceResourceType:e.string().describe("The resource type to search for and convert"),targetResourceType:e.string().describe("The resource type to convert to"),requiredProperties:e.record(e.unknown()).optional().describe("Optional: Required property values for the target component"),continueOnError:e.boolean().optional().describe("Optional: Continue converting even if some fail (default: true)")}).passthrough(),bulkConvertComponents:e.object({pagePaths:e.array(e.string()).optional().describe("Array of page paths to process"),searchPath:e.string().optional().describe("Optional: Base path to search for pages"),depth:e.number().optional().describe("Optional: Depth to search when using searchPath (default: 2)"),limit:e.number().optional().describe("Optional: Maximum number of pages to process (default: 50)"),sourceResourceType:e.string().describe("The resource type to search for and convert"),targetResourceType:e.string().describe("The resource type to convert to"),requiredProperties:e.record(e.unknown()).optional().describe("Optional: Required property values for the target component"),continueOnError:e.boolean().optional().describe("Optional: Continue processing pages even if some fail (default: true)")}).passthrough()},h={getAssetMetadata:e.object({assetPath:e.string().describe("Path to the asset")}).passthrough(),updateAsset:e.object({assetPath:e.string().describe("Path to the asset"),metadata:e.record(e.unknown()).optional().describe("Metadata to update"),fileContent:e.string().optional().describe("File content"),mimeType:e.string().optional().describe("MIME type")}).passthrough(),deleteAsset:e.object({assetPath:e.string().describe("Path to the asset to delete"),force:e.boolean().optional().describe("Force deletion")}).passthrough()},g={searchContent:e.object({type:e.string().optional().describe("Content type"),fulltext:e.string().optional().describe("Fulltext search term"),path:e.string().optional().describe("Search path"),limit:e.number().optional().describe("Maximum number of results")}).passthrough(),executeJCRQuery:e.object({query:e.string().describe("JCR query"),limit:e.number().optional().describe("Maximum number of results")}).passthrough(),enhancedPageSearch:e.object({searchTerm:e.string().describe("Search term"),basePath:e.string().describe("Base path for search"),includeAlternateLocales:e.boolean().optional().describe("Include alternate locales")}).passthrough()},d={getTemplates:e.object({sitePath:e.string().optional().describe("Site path")}).passthrough(),getTemplateStructure:e.object({templatePath:e.string().describe("Template path")}).passthrough()},u={listWorkflowModels:e.object({}).passthrough(),startWorkflow:e.object({modelId:e.string().describe('Workflow model ID (e.g., "request_for_activation")'),payload:e.string().describe("JCR path or URL to process"),payloadType:e.string().optional().describe('Type of payload (default: "JCR_PATH")')}).passthrough(),listWorkflowInstances:e.object({state:e.string().optional().describe("Optional: Filter by state (RUNNING, SUSPENDED, ABORTED, COMPLETED)")}).passthrough(),getWorkflowInstance:e.object({instanceId:e.string().describe("Workflow instance ID or full path")}).passthrough(),updateWorkflowInstanceState:e.object({instanceId:e.string().describe("Workflow instance ID or full path"),state:e.enum(["RUNNING","SUSPENDED","ABORTED"]).describe("New state for the workflow instance")}).passthrough(),getInboxItems:e.object({}).passthrough(),completeWorkItem:e.object({workItemPath:e.string().describe("Path to the work item"),routeId:e.string().optional().describe("Optional: Route ID to advance to"),comment:e.string().optional().describe("Optional: Comment for the completion")}).passthrough(),delegateWorkItem:e.object({workItemPath:e.string().describe("Path to the work item"),delegatee:e.string().describe("User or group to delegate to")}).passthrough(),getWorkItemRoutes:e.object({workItemPath:e.string().describe("Path to the work item")}).passthrough()};export const toolSchemas={...i,...p,...c,...l,...h,...g,...d,...u},toolDescriptions={updateComponent:"Update component properties in AEM",scanPageComponents:"Scan a page to discover all components and their properties",fetchSites:"Get all available sites in AEM",fetchLanguageMasters:"Get language masters for a specific site",fetchAvailableLocales:"Get available locales for a site",getAllTextContent:"Get all text content from a page including titles, text components, and descriptions",getPageTextContent:"Get text content from a specific page",getPageImages:"Get all images from a page, including those within Experience Fragments",updateImagePath:"Update the image path for an image component and verify the update",getPageContent:"Get all content from a page including Experience Fragments and Content Fragments",listPages:"List all pages under a site root",getNodeContent:"Legacy: Get JCR node content",listChildren:"Legacy: List child nodes",getPageProperties:"Get page properties",searchContent:"Search content using Query Builder",executeJCRQuery:"Execute JCR query",getAssetMetadata:"Get asset metadata",enhancedPageSearch:"Intelligent page search with comprehensive fallback strategies and cross-section search",createPage:"Create a new page in AEM. The resourceType will be automatically extracted from the template structure if not provided.",deletePage:"Delete a page from AEM",createComponent:"Create a new component on a page",addComponent:"Add a component to an existing page. Automatically finds the appropriate container (root/container) and adds the component there.",deleteComponent:"Delete a component from AEM",unpublishContent:"Unpublish content from the publish environment",activatePage:"Activate (publish) a single page",deactivatePage:"Deactivate (unpublish) a single page",updateAsset:"Update an existing asset in AEM DAM",deleteAsset:"Delete an asset from AEM DAM",getTemplates:"Get available page templates",getTemplateStructure:"Get detailed structure of a specific template",getComponents:"Get all components from the configured component root path (projectRoot1) or a specified path. Shows component name, title, description, resource type, and other metadata.",bulkUpdateComponents:"Update multiple components in a single operation with validation and rollback support",convertComponents:"Find all components of a specific resource type on a page, delete them, and create new components of another type at the same location. Returns required properties if target component needs them.",bulkConvertComponents:"Convert components across multiple pages. Find all components of a specific resource type on multiple pages, delete them, and create new components of another type at the same location.",listWorkflowModels:"List all available workflow models in AEM. Returns common workflows like request_for_activation (publish), request_for_deactivation (unpublish), request_for_deletion (delete pages), and others.",startWorkflow:"Start a workflow instance. Common workflows: request_for_activation (publish pages), request_for_deactivation (unpublish pages), request_for_deletion (delete pages).",listWorkflowInstances:"List workflow instances, optionally filtered by state",getWorkflowInstance:"Get details of a specific workflow instance by ID",updateWorkflowInstanceState:"Update workflow instance state (RUNNING, SUSPENDED, ABORTED)",getInboxItems:"Get all work items in the inbox (work items assigned to current user)",completeWorkItem:"Complete or advance a work item to the next step in the workflow",delegateWorkItem:"Delegate a work item to another user or group",getWorkItemRoutes:"Get available routes for a work item (to see what steps are available)"};function m(){return Object.keys(toolSchemas).map(t=>{const{$schema:o,...a}=s(toolSchemas[t],{target:"jsonSchema7"});return{name:t,description:toolDescriptions[t],inputSchema:a}})}export const tools=m();export function injectInstanceParam(t,o,a){return t.map(n=>{const r=n.inputSchema;return{...n,inputSchema:{...r,properties:{...r.properties||{},instance:{type:"string",description:`Target AEM instance. Available: ${o.join(", ")}. Default: "${a}"`,enum:o}}}}})}
|
|
1
|
+
"use strict";import{z as e}from"zod";import{zodToJsonSchema as i}from"zod-to-json-schema";const s={getAllTextContent:e.object({pagePath:e.string().describe("Path to the page")}).passthrough(),getPageTextContent:e.object({pagePath:e.string().describe("Path to the page")}).passthrough(),getPageImages:e.object({pagePath:e.string().describe("Path to the page")}).passthrough(),updateImagePath:e.object({componentPath:e.string().describe("Path to the image component"),newImagePath:e.string().describe("New image path")}).passthrough(),getPageContent:e.object({pagePath:e.string().describe("Path to the page")}).passthrough(),getNodeContent:e.object({path:e.string().describe("JCR node path"),depth:e.number().optional().describe("Depth to traverse")}).passthrough(),listChildren:e.object({path:e.string().describe("Parent node path")}).passthrough(),getPageProperties:e.object({pagePath:e.string().describe("Path to the page")}).passthrough()},c={fetchSites:e.object({}).passthrough(),fetchLanguageMasters:e.object({site:e.string().describe("Site name")}).passthrough(),fetchAvailableLocales:e.object({site:e.string().describe("Site name")}).passthrough()},p={listPages:e.object({siteRoot:e.string().optional().describe("Site root path"),depth:e.number().optional().describe("Depth to traverse"),limit:e.number().optional().describe("Maximum number of results")}).passthrough(),createPage:e.object({parentPath:e.string().describe("Parent path"),title:e.string().describe("Page title"),template:e.string().describe("Template path"),resourceType:e.string().optional().describe("Optional: Will be extracted from template if not provided"),name:e.string().optional().describe("Page name"),properties:e.record(e.unknown()).optional().describe("Additional properties")}).passthrough(),deletePage:e.object({pagePath:e.string().describe("Path to the page to delete"),force:e.boolean().optional().describe("Force deletion")}).passthrough(),activatePage:e.object({pagePath:e.string().describe("Path to the page"),activateTree:e.boolean().optional().describe("Activate entire tree")}).passthrough(),deactivatePage:e.object({pagePath:e.string().describe("Path to the page"),deactivateTree:e.boolean().optional().describe("Deactivate entire tree")}).passthrough(),unpublishContent:e.object({contentPaths:e.array(e.string()).describe("Paths to unpublish"),unpublishTree:e.boolean().optional().describe("Unpublish tree")}).passthrough()},l={updateComponent:e.object({componentPath:e.string().describe("Path to the component"),properties:e.record(e.unknown()).describe("Properties to update")}).passthrough(),scanPageComponents:e.object({pagePath:e.string().describe("Path to the page to scan")}).passthrough(),createComponent:e.object({pagePath:e.string().describe("Path to the page"),componentType:e.string().describe("Component type"),resourceType:e.string().describe("Resource type"),properties:e.record(e.unknown()).optional().describe("Component properties"),name:e.string().optional().describe("Component name")}).passthrough(),addComponent:e.object({pagePath:e.string().describe("Path to the existing page (e.g., /content/site/en/page)"),resourceType:e.string().describe("Sling resource type of the component (required)"),containerPath:e.string().optional().describe("Optional: specific container path (defaults to root/container)"),name:e.string().optional().describe("Optional: component node name (auto-generated if not provided)"),properties:e.record(e.unknown()).optional().describe("Optional: component properties to set")}).passthrough(),deleteComponent:e.object({componentPath:e.string().describe("Path to the component to delete"),force:e.boolean().optional().describe("Force deletion")}).passthrough(),getComponents:e.object({path:e.string().optional().describe("Optional: Component root path to fetch components from. If not provided, uses the configured default path.")}).passthrough(),bulkUpdateComponents:e.object({updates:e.array(e.object({componentPath:e.string(),properties:e.record(e.unknown())})).describe("Array of component updates"),validateFirst:e.boolean().optional().describe("Validate before updating"),continueOnError:e.boolean().optional().describe("Continue on individual failures")}).passthrough(),convertComponents:e.object({pagePath:e.string().describe("Path to the page containing components to convert"),sourceResourceType:e.string().describe("The resource type to search for and convert"),targetResourceType:e.string().describe("The resource type to convert to"),requiredProperties:e.record(e.unknown()).optional().describe("Optional: Required property values for the target component"),continueOnError:e.boolean().optional().describe("Optional: Continue converting even if some fail (default: true)")}).passthrough(),bulkConvertComponents:e.object({pagePaths:e.array(e.string()).optional().describe("Array of page paths to process"),searchPath:e.string().optional().describe("Optional: Base path to search for pages"),depth:e.number().optional().describe("Optional: Depth to search when using searchPath (default: 2)"),limit:e.number().optional().describe("Optional: Maximum number of pages to process (default: 50)"),sourceResourceType:e.string().describe("The resource type to search for and convert"),targetResourceType:e.string().describe("The resource type to convert to"),requiredProperties:e.record(e.unknown()).optional().describe("Optional: Required property values for the target component"),continueOnError:e.boolean().optional().describe("Optional: Continue processing pages even if some fail (default: true)")}).passthrough()},d={getAssetMetadata:e.object({assetPath:e.string().describe("Path to the asset")}).passthrough(),updateAsset:e.object({assetPath:e.string().describe("Path to the asset"),metadata:e.record(e.unknown()).optional().describe("Metadata to update"),fileContent:e.string().optional().describe("File content"),mimeType:e.string().optional().describe("MIME type")}).passthrough(),deleteAsset:e.object({assetPath:e.string().describe("Path to the asset to delete"),force:e.boolean().optional().describe("Force deletion")}).passthrough()},g={searchContent:e.object({type:e.string().optional().describe("Content type"),fulltext:e.string().optional().describe("Fulltext search term"),path:e.string().optional().describe("Search path"),limit:e.number().optional().describe("Maximum number of results")}).passthrough(),executeJCRQuery:e.object({query:e.string().describe("JCR query"),limit:e.number().optional().describe("Maximum number of results")}).passthrough(),enhancedPageSearch:e.object({searchTerm:e.string().describe("Search term"),basePath:e.string().describe("Base path for search"),includeAlternateLocales:e.boolean().optional().describe("Include alternate locales")}).passthrough()},h={getTemplates:e.object({sitePath:e.string().optional().describe("Site path")}).passthrough(),getTemplateStructure:e.object({templatePath:e.string().describe("Template path")}).passthrough()},m={listWorkflowModels:e.object({}).passthrough(),startWorkflow:e.object({modelId:e.string().describe('Workflow model ID (e.g., "request_for_activation")'),payload:e.string().describe("JCR path or URL to process"),payloadType:e.string().optional().describe('Type of payload (default: "JCR_PATH")')}).passthrough(),listWorkflowInstances:e.object({state:e.string().optional().describe("Optional: Filter by state (RUNNING, SUSPENDED, ABORTED, COMPLETED)")}).passthrough(),getWorkflowInstance:e.object({instanceId:e.string().describe("Workflow instance ID or full path")}).passthrough(),updateWorkflowInstanceState:e.object({instanceId:e.string().describe("Workflow instance ID or full path"),state:e.enum(["RUNNING","SUSPENDED","ABORTED"]).describe("New state for the workflow instance")}).passthrough(),getInboxItems:e.object({}).passthrough(),completeWorkItem:e.object({workItemPath:e.string().describe("Path to the work item"),routeId:e.string().optional().describe("Optional: Route ID to advance to"),comment:e.string().optional().describe("Optional: Comment for the completion")}).passthrough(),delegateWorkItem:e.object({workItemPath:e.string().describe("Path to the work item"),delegatee:e.string().describe("User or group to delegate to")}).passthrough(),getWorkItemRoutes:e.object({workItemPath:e.string().describe("Path to the work item")}).passthrough()},u={getContentFragment:e.object({path:e.string().describe("Path to the content fragment in DAM (e.g., /content/dam/site/cf/my-article)")}).passthrough(),listContentFragments:e.object({path:e.string().describe("Parent path to search under (e.g., /content/dam/site/cf)"),model:e.string().optional().describe("Filter by CF model path"),limit:e.number().optional().describe("Max results (default: 20)"),offset:e.number().optional().describe("Pagination offset (default: 0)")}).passthrough(),manageContentFragment:e.object({action:e.enum(["create","update","delete"]).describe("Action to perform"),fragmentPath:e.string().optional().describe("Path to existing CF (required for update/delete)"),parentPath:e.string().optional().describe("Parent folder in DAM (required for create)"),title:e.string().optional().describe("Fragment title (required for create)"),name:e.string().optional().describe("Node name (auto-generated from title if omitted)"),model:e.string().optional().describe("CF model path (required for create)"),fields:e.record(e.unknown()).optional().describe("Field values as { fieldName: value }"),description:e.string().optional().describe("Fragment description"),force:e.boolean().optional().describe("Force delete even if referenced")}).passthrough(),manageContentFragmentVariation:e.object({action:e.enum(["create","update","delete"]).describe("Action to perform"),fragmentPath:e.string().describe("Path to the parent content fragment"),variationName:e.string().describe("Variation identifier"),title:e.string().optional().describe("Variation title (required for create)"),fields:e.record(e.unknown()).optional().describe("Field overrides as { fieldName: value }")}).passthrough()},b={getExperienceFragment:e.object({path:e.string().describe("Path to the experience fragment page")}).passthrough(),listExperienceFragments:e.object({path:e.string().optional().describe("Root path (default: /content/experience-fragments)"),template:e.string().optional().describe("Filter by template path"),limit:e.number().optional().describe("Max results (default: 20)"),offset:e.number().optional().describe("Pagination offset (default: 0)")}).passthrough(),manageExperienceFragment:e.object({action:e.enum(["create","update","delete"]).describe("Action to perform"),xfPath:e.string().optional().describe("Existing XF path (required for update/delete)"),parentPath:e.string().optional().describe("Parent path for new XF (required for create)"),name:e.string().optional().describe("Node name (auto-generated from title if omitted)"),title:e.string().optional().describe("XF title (required for create)"),template:e.string().optional().describe("XF template path (required for create)"),description:e.string().optional().describe("XF description"),tags:e.array(e.string()).optional().describe("Tags to apply"),force:e.boolean().optional().describe("Force delete even if referenced")}).passthrough(),manageExperienceFragmentVariation:e.object({action:e.enum(["create","update","delete"]).describe("Action to perform"),xfPath:e.string().describe("Parent experience fragment path"),variationName:e.string().describe("Variation identifier"),variationType:e.enum(["web","email","social","custom"]).optional().describe("Variation type (default: web)"),title:e.string().optional().describe("Variation title (required for create)"),template:e.string().optional().describe("Template for the variation"),force:e.boolean().optional().describe("Force deletion")}).passthrough()};export const toolSchemas={...s,...c,...p,...l,...d,...g,...h,...m,...u,...b},toolDescriptions={updateComponent:"Update component properties in AEM",scanPageComponents:"Scan a page to discover all components and their properties",fetchSites:"Get all available sites in AEM",fetchLanguageMasters:"Get language masters for a specific site",fetchAvailableLocales:"Get available locales for a site",getAllTextContent:"Get all text content from a page including titles, text components, and descriptions",getPageTextContent:"Get text content from a specific page",getPageImages:"Get all images from a page, including those within Experience Fragments",updateImagePath:"Update the image path for an image component and verify the update",getPageContent:"Get all content from a page including Experience Fragments and Content Fragments",listPages:"List all pages under a site root",getNodeContent:"Legacy: Get JCR node content",listChildren:"Legacy: List child nodes",getPageProperties:"Get page properties",searchContent:"Search content using Query Builder",executeJCRQuery:"Execute JCR query",getAssetMetadata:"Get asset metadata",enhancedPageSearch:"Intelligent page search with comprehensive fallback strategies and cross-section search",createPage:"Create a new page in AEM. The resourceType will be automatically extracted from the template structure if not provided.",deletePage:"Delete a page from AEM",createComponent:"Create a new component on a page",addComponent:"Add a component to an existing page. Automatically finds the appropriate container (root/container) and adds the component there.",deleteComponent:"Delete a component from AEM",unpublishContent:"Unpublish content from the publish environment",activatePage:"Activate (publish) a single page",deactivatePage:"Deactivate (unpublish) a single page",updateAsset:"Update an existing asset in AEM DAM",deleteAsset:"Delete an asset from AEM DAM",getTemplates:"Get available page templates",getTemplateStructure:"Get detailed structure of a specific template",getComponents:"Get all components from the configured component root path (projectRoot1) or a specified path. Shows component name, title, description, resource type, and other metadata.",bulkUpdateComponents:"Update multiple components in a single operation with validation and rollback support",convertComponents:"Find all components of a specific resource type on a page, delete them, and create new components of another type at the same location. Returns required properties if target component needs them.",bulkConvertComponents:"Convert components across multiple pages. Find all components of a specific resource type on multiple pages, delete them, and create new components of another type at the same location.",listWorkflowModels:"List all available workflow models in AEM. Returns common workflows like request_for_activation (publish), request_for_deactivation (unpublish), request_for_deletion (delete pages), and others.",startWorkflow:"Start a workflow instance. Common workflows: request_for_activation (publish pages), request_for_deactivation (unpublish pages), request_for_deletion (delete pages).",listWorkflowInstances:"List workflow instances, optionally filtered by state",getWorkflowInstance:"Get details of a specific workflow instance by ID",updateWorkflowInstanceState:"Update workflow instance state (RUNNING, SUSPENDED, ABORTED)",getInboxItems:"Get all work items in the inbox (work items assigned to current user)",completeWorkItem:"Complete or advance a work item to the next step in the workflow",delegateWorkItem:"Delegate a work item to another user or group",getWorkItemRoutes:"Get available routes for a work item (to see what steps are available)",getContentFragment:"Get a content fragment with all fields, variations, and metadata",listContentFragments:"List content fragments under a path with optional model filter",manageContentFragment:"Create, update, or delete a content fragment. Use action param to specify operation.",manageContentFragmentVariation:"Create, update, or delete a variation within a content fragment",getExperienceFragment:"Get an experience fragment with all variations, components, and metadata",listExperienceFragments:"List experience fragments under a path with optional template filter",manageExperienceFragment:"Create, update, or delete an experience fragment. Auto-creates master variation on create.",manageExperienceFragmentVariation:"Create, update, or delete a variation within an experience fragment"};function f(){return Object.keys(toolSchemas).map(t=>{const{$schema:o,...a}=i(toolSchemas[t],{target:"jsonSchema7"});return{name:t,description:toolDescriptions[t],inputSchema:a}})}export const tools=f();export function injectInstanceParam(t,o,a){return t.map(n=>{const r=n.inputSchema;return{...n,inputSchema:{...r,properties:{...r.properties||{},instance:{type:"string",description:`Target AEM instance. Available: ${o.join(", ")}. Default: "${a}"`,enum:o}}}}})}
|