guniweb-sap-mcp 0.8.0 → 0.8.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.
Files changed (2) hide show
  1. package/dist/index.js +52 -52
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -1,8 +1,8 @@
1
1
  #!/usr/bin/env node
2
- import {readFileSync,existsSync,watchFile,watch,unwatchFile,mkdirSync,writeFileSync,renameSync,unlinkSync}from'fs';import {StdioServerTransport}from'@modelcontextprotocol/sdk/server/stdio.js';import eo from'pino';import {minimatch}from'minimatch';import {z as z$1}from'zod/v4';import {lookup}from'dns/promises';import {connect}from'tls';import sn,{isAxiosError}from'axios';import {AsyncLocalStorage}from'async_hooks';import {randomUUID,randomBytes,timingSafeEqual,createHash}from'crypto';import {jwtVerify,decodeJwt,createRemoteJWKSet}from'jose';import {SignedXml}from'xml-crypto';import {Agent}from'https';import {createServer}from'http';import {resolve,join,dirname,isAbsolute}from'path';import {z as z$2}from'zod';import {readFile}from'fs/promises';import {createRequire}from'module';import {pathToFileURL}from'url';import {XMLParser,XMLBuilder}from'fast-xml-parser';import {McpServer,ResourceTemplate}from'@modelcontextprotocol/sdk/server/mcp.js';import {StreamableHTTPServerTransport}from'@modelcontextprotocol/sdk/server/streamableHttp.js';import di from'express';var Vn=16;function Me(t,e,n,r=process.env){if(t)return t;let s=r[e];if(s)return s;let i=r[n];if(i)return readFileSync(i,"utf-8")}function Wn(t=process.argv){let e={},n=t.indexOf("--expose");if(n!==-1&&n<t.length-1){let r=t[n+1].split(",").map(s=>s.trim()).filter(s=>s.length>0);e.expose=r.length>0?r:void 0;}return yi(t,e)}function yi(t,e){let n=t.indexOf("--webhook-port");n!==-1&&n<t.length-1&&(e.webhookPort=Number.parseInt(t[n+1],10));let r=t.indexOf("--webhook-secret");r!==-1&&r<t.length-1&&(e.webhookSecret=t[r+1]),!e.webhookSecret&&process.env.SAP_WEBHOOK_SECRET&&(e.webhookSecret=process.env.SAP_WEBHOOK_SECRET),e.webhookSecret!==void 0&&e.webhookSecret.trim().length===0&&(e.webhookSecret=void 0);let s=t.indexOf("--webhook-host");if(s!==-1&&s<t.length-1&&(e.webhookHost=t[s+1]),!e.webhookHost&&process.env.SAP_WEBHOOK_HOST&&(e.webhookHost=process.env.SAP_WEBHOOK_HOST),process.env.SAP_WEBHOOK_MAX_BODY_BYTES){let A=Number.parseInt(process.env.SAP_WEBHOOK_MAX_BODY_BYTES,10);Number.isFinite(A)&&A>0&&(e.webhookMaxBodyBytes=A);}let i=t.indexOf("--max-request-bytes");if(i!==-1&&i<t.length-1){let A=Number.parseInt(t[i+1],10);Number.isFinite(A)&&A>0&&(e.maxRequestBytes=A);}if(e.maxRequestBytes===void 0&&process.env.SAP_MCP_MAX_REQUEST_BYTES){let A=Number.parseInt(process.env.SAP_MCP_MAX_REQUEST_BYTES,10);Number.isFinite(A)&&A>0&&(e.maxRequestBytes=A);}let o=t.indexOf("--transport");if(o!==-1&&o<t.length-1){let A=t[o+1];(A==="stdio"||A==="http"||A==="sse")&&(e.transport=A);}if(e.transport===void 0){let A=process.env.SAP_MCP_TRANSPORT?.trim();(A==="stdio"||A==="http"||A==="sse")&&(e.transport=A);}let a=t.indexOf("--port");if(a!==-1&&a<t.length-1&&(e.port=Number.parseInt(t[a+1],10)),e.port===void 0&&process.env.SAP_MCP_PORT){let A=Number.parseInt(process.env.SAP_MCP_PORT,10);Number.isFinite(A)&&A>0&&A<=65535&&(e.port=A);}let d=t.indexOf("--api-key");d!==-1&&d<t.length-1&&(e.apiKey=t[d+1]);let l=["sndpor","sndprt","sndprn","rcvpor","rcvprt","rcvprn"];for(let A of l){let ne=t.indexOf(`--${A}`);ne!==-1&&ne<t.length-1&&(e[A]=t[ne+1]);}let c=t.indexOf("--catalog-v2-url");c!==-1&&c<t.length-1&&(e.catalogV2Url=t[c+1]),!e.catalogV2Url&&process.env.ODATA_V2_CATALOG_PATH&&(e.catalogV2Url=process.env.ODATA_V2_CATALOG_PATH);let u=t.indexOf("--catalog-v4-url");u!==-1&&u<t.length-1&&(e.catalogV4Url=t[u+1]);let p=t.includes("--allow-write")||process.env.SAP_MCP_ALLOW_WRITE==="true";e.readOnly=!p,e.allowWriteExplicit=p;let m=t.indexOf("--tool-timeout"),g=m!==-1&&m<t.length-1?t[m+1]:process.env.SAP_MCP_TOOL_TIMEOUT;if(g!==void 0){let A=Number.parseInt(g,10);if(!Number.isFinite(A)||A<0)throw new Error(`--tool-timeout muss eine Zahl in Sekunden sein (0 schaltet das Budget ab), war: "${g}"`);e.toolTimeoutSeconds=A;}let f=t.indexOf("--cache-dir"),h=f!==-1&&f<t.length-1?t[f+1]:process.env.SAP_CACHE_DIR;h&&h.trim().length>0&&(e.cacheDir=h.trim());let S=t.indexOf("--governance");if(S!==-1&&S<t.length-1){let A=t[S+1];A&&A.trim().length>0&&(e.governanceModule=A.trim());}let y=t.indexOf("--concurrency"),E=y!==-1&&y<t.length-1?t[y+1]:process.env.SAP_CONCURRENCY;if(E!==void 0){let A=Number.parseInt(E,10);if(!Number.isFinite(A)||A<1)throw new Error(`--concurrency muss eine Zahl >= 1 sein, war: "${E}"`);e.concurrency=A;}let b=t.indexOf("--destinations"),v=b!==-1&&b<t.length-1?t[b+1]:process.env.SAP_MCP_DESTINATIONS;v&&v.trim().length>0&&(e.destinationsFile=v.trim());let M=t.indexOf("--admin-token"),fe=M!==-1&&M<t.length-1?t[M+1]:process.env.SAP_MCP_ADMIN_TOKEN;if(fe&&fe.trim().length>0){let A=fe.trim();if(A.length<Vn)throw new Error(`--admin-token / SAP_MCP_ADMIN_TOKEN muss mindestens ${Vn} Zeichen lang sein (z. B. openssl rand -base64 32).`);e.adminToken=A;}(t.includes("--demo")||process.env.SAP_MCP_DEMO==="true")&&(e.demo=true);let ui=t.indexOf("--help"),pi=t.indexOf("-h");(ui!==-1||pi!==-1)&&(e.help=true);let Vt=t.indexOf("--tiers");if(Vt!==-1&&Vt<t.length-1){let A=t[Vt+1].split(",").map(ne=>ne.trim()).filter(ne=>ne.length>0);e.tiers=A.length>0?A:void 0;}let Wt=t.indexOf("--destination-name");Wt!==-1&&Wt<t.length-1&&(e.destinationName=t[Wt+1]),!e.destinationName&&process.env.SAP_DESTINATION_NAME&&(e.destinationName=process.env.SAP_DESTINATION_NAME);let Gt=t.indexOf("--destination-service-url");Gt!==-1&&Gt<t.length-1&&(e.destinationServiceUrl=t[Gt+1]),!e.destinationServiceUrl&&process.env.SAP_DESTINATION_SERVICE_URL&&(e.destinationServiceUrl=process.env.SAP_DESTINATION_SERVICE_URL);let qt=t.indexOf("--issuer");qt!==-1&&qt<t.length-1&&(e.issuer=t[qt+1]),!e.issuer&&process.env.SAP_ISSUER&&(e.issuer=process.env.SAP_ISSUER);let Kt=t.indexOf("--name-id-format");Kt!==-1&&Kt<t.length-1&&(e.nameIdFormat=t[Kt+1]),!e.nameIdFormat&&process.env.SAP_NAME_ID_FORMAT&&(e.nameIdFormat=process.env.SAP_NAME_ID_FORMAT);let zt=t.indexOf("--private-key"),mi=zt!==-1&&zt<t.length-1?t[zt+1]:void 0;e.privateKey=Me(mi,"SAP_PRIVATE_KEY","SAP_PRIVATE_KEY_FILE");let Yt=t.indexOf("--certificate"),fi=Yt!==-1&&Yt<t.length-1?t[Yt+1]:void 0;e.certificate=Me(fi,"SAP_CERTIFICATE","SAP_CERTIFICATE_FILE");let Xt=t.indexOf("--clock-skew");Xt!==-1&&Xt<t.length-1&&(e.clockSkew=Number.parseInt(t[Xt+1],10)),e.clockSkew===void 0&&process.env.SAP_CLOCK_SKEW&&(e.clockSkew=Number.parseInt(process.env.SAP_CLOCK_SKEW,10));let Jt=t.indexOf("--assertion-lifetime");return Jt!==-1&&Jt<t.length-1&&(e.assertionLifetime=Number.parseInt(t[Jt+1],10)),e.assertionLifetime===void 0&&process.env.SAP_ASSERTION_LIFETIME&&(e.assertionLifetime=Number.parseInt(process.env.SAP_ASSERTION_LIFETIME,10)),e}function Zt(t){return !!(t.sndprn&&t.rcvprn)}function K(t,e){return !e||e.length===0?true:e.some(n=>minimatch(t,n))}function Gn(t){if(t==="sse")throw new Error("--transport sse (bzw. SAP_MCP_TRANSPORT=sse) wurde in 0.8.0 entfernt: Die MCP-Spezifikation 2026-07-28 f\xFChrt HTTP+SSE als veraltet. Verwende --transport http (Streamable HTTP, Endpunkt /mcp); der n8n-Node und aktuelle MCP-Clients sprechen ihn.")}var qn=z$1.object({tlsVerify:z$1.boolean().default(true),clientCert:z$1.string().optional(),clientKey:z$1.string().optional(),clientKeyPassphrase:z$1.string().optional(),requestTimeoutMs:z$1.number().int().positive().default(3e4),caCertPath:z$1.string().optional()}).superRefine((t,e)=>{let n=t.clientCert!==void 0,r=t.clientKey!==void 0;n!==r&&e.addIssue({code:"custom",message:n?"SAP_CLIENT_CERT/PATH set without matching SAP_CLIENT_KEY/PATH":"SAP_CLIENT_KEY/PATH set without matching SAP_CLIENT_CERT/PATH",path:["clientKey"]});});function Qt(t=process.env){let e=t.SAP_TLS_VERIFY!=="false",n=t.SAP_CA_CERT?.trim();n&&!t.NODE_EXTRA_CA_CERTS&&(process.env.NODE_EXTRA_CA_CERTS=n);let r=Me(void 0,"SAP_CLIENT_CERT","SAP_CLIENT_CERT_PATH",t),s=Me(void 0,"SAP_CLIENT_KEY","SAP_CLIENT_KEY_PATH",t),i=t.SAP_CLIENT_KEY_PASSPHRASE,o=t.SAP_HTTP_TIMEOUT_MS!==void 0?Number.parseInt(t.SAP_HTTP_TIMEOUT_MS,10):void 0,a={tlsVerify:e,...n?{caCertPath:n}:{},...r!==void 0?{clientCert:r}:{},...s!==void 0?{clientKey:s}:{},...i!==void 0?{clientKeyPassphrase:i}:{},...o!==void 0?{requestTimeoutMs:o}:{}},d=qn.safeParse(a);if(!d.success){let l=d.error.issues.map(c=>` - ${c.path.join(".")||"root"}: ${c.message}`).join(`
2
+ import {readFileSync,existsSync,watchFile,watch,unwatchFile,mkdirSync,writeFileSync,renameSync,unlinkSync}from'fs';import {StdioServerTransport}from'@modelcontextprotocol/sdk/server/stdio.js';import uo from'pino';import {minimatch}from'minimatch';import {z as z$1}from'zod/v4';import {lookup}from'dns/promises';import {connect}from'tls';import dn,{isAxiosError}from'axios';import {AsyncLocalStorage}from'async_hooks';import {randomUUID,randomBytes,timingSafeEqual,createHash}from'crypto';import {jwtVerify,decodeJwt,createRemoteJWKSet}from'jose';import {SignedXml}from'xml-crypto';import {Agent}from'https';import {createServer}from'http';import {resolve,join,dirname,isAbsolute}from'path';import {z as z$2}from'zod';import {readFile}from'fs/promises';import {createRequire}from'module';import {pathToFileURL}from'url';import {XMLParser,XMLBuilder}from'fast-xml-parser';import {McpServer,ResourceTemplate}from'@modelcontextprotocol/sdk/server/mcp.js';import {StreamableHTTPServerTransport}from'@modelcontextprotocol/sdk/server/streamableHttp.js';import wi from'express';var zn=16;function $e(t,e,n,r=process.env){if(t)return t;let s=r[e];if(s)return s;let i=r[n];if(i)return readFileSync(i,"utf-8")}function Yn(t=process.argv){let e={},n=t.indexOf("--expose");if(n!==-1&&n<t.length-1){let r=t[n+1].split(",").map(s=>s.trim()).filter(s=>s.length>0);e.expose=r.length>0?r:void 0;}return Ri(t,e)}function Ri(t,e){let n=t.indexOf("--webhook-port");n!==-1&&n<t.length-1&&(e.webhookPort=Number.parseInt(t[n+1],10));let r=t.indexOf("--webhook-secret");r!==-1&&r<t.length-1&&(e.webhookSecret=t[r+1]),!e.webhookSecret&&process.env.SAP_WEBHOOK_SECRET&&(e.webhookSecret=process.env.SAP_WEBHOOK_SECRET),e.webhookSecret!==void 0&&e.webhookSecret.trim().length===0&&(e.webhookSecret=void 0);let s=t.indexOf("--webhook-host");if(s!==-1&&s<t.length-1&&(e.webhookHost=t[s+1]),!e.webhookHost&&process.env.SAP_WEBHOOK_HOST&&(e.webhookHost=process.env.SAP_WEBHOOK_HOST),process.env.SAP_WEBHOOK_MAX_BODY_BYTES){let A=Number.parseInt(process.env.SAP_WEBHOOK_MAX_BODY_BYTES,10);Number.isFinite(A)&&A>0&&(e.webhookMaxBodyBytes=A);}let i=t.indexOf("--max-request-bytes");if(i!==-1&&i<t.length-1){let A=Number.parseInt(t[i+1],10);Number.isFinite(A)&&A>0&&(e.maxRequestBytes=A);}if(e.maxRequestBytes===void 0&&process.env.SAP_MCP_MAX_REQUEST_BYTES){let A=Number.parseInt(process.env.SAP_MCP_MAX_REQUEST_BYTES,10);Number.isFinite(A)&&A>0&&(e.maxRequestBytes=A);}let o=t.indexOf("--transport");if(o!==-1&&o<t.length-1){let A=t[o+1];(A==="stdio"||A==="http"||A==="sse")&&(e.transport=A);}if(e.transport===void 0){let A=process.env.SAP_MCP_TRANSPORT?.trim();(A==="stdio"||A==="http"||A==="sse")&&(e.transport=A);}let a=t.indexOf("--port");if(a!==-1&&a<t.length-1&&(e.port=Number.parseInt(t[a+1],10)),e.port===void 0&&process.env.SAP_MCP_PORT){let A=Number.parseInt(process.env.SAP_MCP_PORT,10);Number.isFinite(A)&&A>0&&A<=65535&&(e.port=A);}let d=t.indexOf("--api-key");d!==-1&&d<t.length-1&&(e.apiKey=t[d+1]);let l=["sndpor","sndprt","sndprn","rcvpor","rcvprt","rcvprn"];for(let A of l){let oe=t.indexOf(`--${A}`);oe!==-1&&oe<t.length-1&&(e[A]=t[oe+1]);}let c=t.indexOf("--catalog-v2-url");c!==-1&&c<t.length-1&&(e.catalogV2Url=t[c+1]),!e.catalogV2Url&&process.env.ODATA_V2_CATALOG_PATH&&(e.catalogV2Url=process.env.ODATA_V2_CATALOG_PATH);let u=t.indexOf("--catalog-v4-url");u!==-1&&u<t.length-1&&(e.catalogV4Url=t[u+1]);let p=t.includes("--allow-write")||process.env.SAP_MCP_ALLOW_WRITE==="true";e.readOnly=!p,e.allowWriteExplicit=p;let m=t.indexOf("--tool-timeout"),f=m!==-1&&m<t.length-1?t[m+1]:process.env.SAP_MCP_TOOL_TIMEOUT;if(f!==void 0){let A=Number.parseInt(f,10);if(!Number.isFinite(A)||A<0)throw new Error(`--tool-timeout muss eine Zahl in Sekunden sein (0 schaltet das Budget ab), war: "${f}"`);e.toolTimeoutSeconds=A;}let g=t.indexOf("--cache-dir"),h=g!==-1&&g<t.length-1?t[g+1]:process.env.SAP_CACHE_DIR;h&&h.trim().length>0&&(e.cacheDir=h.trim());let b=t.indexOf("--governance");if(b!==-1&&b<t.length-1){let A=t[b+1];A&&A.trim().length>0&&(e.governanceModule=A.trim());}let y=t.indexOf("--concurrency"),E=y!==-1&&y<t.length-1?t[y+1]:process.env.SAP_CONCURRENCY;if(E!==void 0){let A=Number.parseInt(E,10);if(!Number.isFinite(A)||A<1)throw new Error(`--concurrency muss eine Zahl >= 1 sein, war: "${E}"`);e.concurrency=A;}let S=t.indexOf("--destinations"),v=S!==-1&&S<t.length-1?t[S+1]:process.env.SAP_MCP_DESTINATIONS;v&&v.trim().length>0&&(e.destinationsFile=v.trim());let x=t.indexOf("--admin-token"),G=x!==-1&&x<t.length-1?t[x+1]:process.env.SAP_MCP_ADMIN_TOKEN;if(G&&G.trim().length>0){let A=G.trim();if(A.length<zn)throw new Error(`--admin-token / SAP_MCP_ADMIN_TOKEN muss mindestens ${zn} Zeichen lang sein (z. B. openssl rand -base64 32).`);e.adminToken=A;}(t.includes("--demo")||process.env.SAP_MCP_DEMO==="true")&&(e.demo=true);let st=t.indexOf("--help"),it=t.indexOf("-h");(st!==-1||it!==-1)&&(e.help=true);let Ue=t.indexOf("--tiers");if(Ue!==-1&&Ue<t.length-1){let A=t[Ue+1].split(",").map(oe=>oe.trim()).filter(oe=>oe.length>0);e.tiers=A.length>0?A:void 0;}let zt=t.indexOf("--destination-name");zt!==-1&&zt<t.length-1&&(e.destinationName=t[zt+1]),!e.destinationName&&process.env.SAP_DESTINATION_NAME&&(e.destinationName=process.env.SAP_DESTINATION_NAME);let Yt=t.indexOf("--destination-service-url");Yt!==-1&&Yt<t.length-1&&(e.destinationServiceUrl=t[Yt+1]),!e.destinationServiceUrl&&process.env.SAP_DESTINATION_SERVICE_URL&&(e.destinationServiceUrl=process.env.SAP_DESTINATION_SERVICE_URL);let Xt=t.indexOf("--issuer");Xt!==-1&&Xt<t.length-1&&(e.issuer=t[Xt+1]),!e.issuer&&process.env.SAP_ISSUER&&(e.issuer=process.env.SAP_ISSUER);let Jt=t.indexOf("--name-id-format");Jt!==-1&&Jt<t.length-1&&(e.nameIdFormat=t[Jt+1]),!e.nameIdFormat&&process.env.SAP_NAME_ID_FORMAT&&(e.nameIdFormat=process.env.SAP_NAME_ID_FORMAT);let Zt=t.indexOf("--private-key"),vi=Zt!==-1&&Zt<t.length-1?t[Zt+1]:void 0;e.privateKey=$e(vi,"SAP_PRIVATE_KEY","SAP_PRIVATE_KEY_FILE");let Qt=t.indexOf("--certificate"),Ai=Qt!==-1&&Qt<t.length-1?t[Qt+1]:void 0;e.certificate=$e(Ai,"SAP_CERTIFICATE","SAP_CERTIFICATE_FILE");let en=t.indexOf("--clock-skew");en!==-1&&en<t.length-1&&(e.clockSkew=Number.parseInt(t[en+1],10)),e.clockSkew===void 0&&process.env.SAP_CLOCK_SKEW&&(e.clockSkew=Number.parseInt(process.env.SAP_CLOCK_SKEW,10));let tn=t.indexOf("--assertion-lifetime");return tn!==-1&&tn<t.length-1&&(e.assertionLifetime=Number.parseInt(t[tn+1],10)),e.assertionLifetime===void 0&&process.env.SAP_ASSERTION_LIFETIME&&(e.assertionLifetime=Number.parseInt(process.env.SAP_ASSERTION_LIFETIME,10)),e}function nn(t){return !!(t.sndprn&&t.rcvprn)}function z(t,e){return !e||e.length===0?true:e.some(n=>minimatch(t,n))}function Xn(t){if(t==="sse")throw new Error("--transport sse (bzw. SAP_MCP_TRANSPORT=sse) wurde in 0.8.0 entfernt: Die MCP-Spezifikation 2026-07-28 f\xFChrt HTTP+SSE als veraltet. Verwende --transport http (Streamable HTTP, Endpunkt /mcp); der n8n-Node und aktuelle MCP-Clients sprechen ihn.")}var Jn=z$1.object({tlsVerify:z$1.boolean().default(true),clientCert:z$1.string().optional(),clientKey:z$1.string().optional(),clientKeyPassphrase:z$1.string().optional(),requestTimeoutMs:z$1.number().int().positive().default(3e4),caCertPath:z$1.string().optional()}).superRefine((t,e)=>{let n=t.clientCert!==void 0,r=t.clientKey!==void 0;n!==r&&e.addIssue({code:"custom",message:n?"SAP_CLIENT_CERT/PATH set without matching SAP_CLIENT_KEY/PATH":"SAP_CLIENT_KEY/PATH set without matching SAP_CLIENT_CERT/PATH",path:["clientKey"]});});function rn(t=process.env){let e=t.SAP_TLS_VERIFY!=="false",n=t.SAP_CA_CERT?.trim();n&&!t.NODE_EXTRA_CA_CERTS&&(process.env.NODE_EXTRA_CA_CERTS=n);let r=$e(void 0,"SAP_CLIENT_CERT","SAP_CLIENT_CERT_PATH",t),s=$e(void 0,"SAP_CLIENT_KEY","SAP_CLIENT_KEY_PATH",t),i=t.SAP_CLIENT_KEY_PASSPHRASE,o=t.SAP_HTTP_TIMEOUT_MS!==void 0?Number.parseInt(t.SAP_HTTP_TIMEOUT_MS,10):void 0,a={tlsVerify:e,...n?{caCertPath:n}:{},...r!==void 0?{clientCert:r}:{},...s!==void 0?{clientKey:s}:{},...i!==void 0?{clientKeyPassphrase:i}:{},...o!==void 0?{requestTimeoutMs:o}:{}},d=Jn.safeParse(a);if(!d.success){let l=d.error.issues.map(c=>` - ${c.path.join(".")||"root"}: ${c.message}`).join(`
3
3
  `);throw new Error(`Invalid HTTP options:
4
- ${l}`)}return d.data}function tt(t){let e={name:t.name,url:t.baseUrl,sapClient:t.sapClient};switch(t.authType){case "basic":return {...e,auth:{type:"basic",username:t.username,password:t.password}};case "user-basic":throw new Error(`Destination "${t.name}" verlangt eine pers\xF6nliche SAP-Anmeldung (authType user-basic): SAP-Benutzer und -Passwort kommen je Anfrage \xFCber X-SAP-Username/X-SAP-Password \u2014 ohne sie gibt es keinen technischen Fallback.`);case "oauth2":return {...e,auth:{type:"oauth2",clientId:t.clientId,clientSecret:t.clientSecret,tokenServiceUrl:t.tokenServiceUrl}};case "apikey":return {...e,headers:{APIKey:t.apiKey},auth:{type:"apikey",apiKey:t.apiKey}};case "ias":return {...e,auth:{type:"ias",clientId:t.clientId,clientSecret:t.clientSecret,tenantUrl:t.tenantUrl}};case "xsuaa":return {...e,auth:{type:"xsuaa",clientId:t.clientId,clientSecret:t.clientSecret,xsuaaUrl:t.xsuaaUrl}};case "btp-principal":return {...e,auth:{type:"btp-principal",destinationName:t.destinationName,destinationServiceUrl:t.destinationServiceUrl,clientId:t.clientId,clientSecret:t.clientSecret,tokenServiceUrl:t.tokenServiceUrl}};case "saml-bearer":return {...e,auth:{type:"saml-bearer",tokenServiceUrl:t.tokenServiceUrl,clientId:t.clientId,issuer:t.issuer,nameIdFormat:t.nameIdFormat,privateKey:t.privateKey,certificate:t.certificate,clockSkew:t.clockSkew,assertionLifetime:t.assertionLifetime}}}}var se=new AsyncLocalStorage;function Kn(){return randomBytes(6).toString("hex")}function ge(){return se.getStore()}function zn(t,e){return se.run(t,e)}function nt(){let t=se.getStore();if(t)return t.sapCalls.count+=1,t.correlationId}function Yn(t){let e=se.getStore();if(!e?.mutatingCalls)return;let n=(t??"get").toLowerCase();n!=="get"&&n!=="head"&&(e.mutatingCalls.count+=1);}function Xn(t=Date.now()){let e=se.getStore();if(e?.deadline)return Math.max(0,e.deadline-t)}function rt(){return se.getStore()?.signal?.aborted??false}var F=class extends Error{timedOut;constructor(e,n){super(e?`Zeitbudget f\xFCr ${n??"den Tool-Aufruf"} \xFCberschritten \u2014 abgebrochen.`:`Client hat die Verbindung verworfen \u2014 ${n??"der Tool-Aufruf"} wurde abgebrochen.`),this.name="ToolCallAbortedError",this.timedOut=e;}};function st(){let t=se.getStore();if(!t?.signal?.aborted)return;let e=t.signal.reason?.name==="TimeoutError";throw new F(e,t.toolName)}function Jn(t,e){if(!e||e<=0)return {signal:t,deadline:void 0};let n=AbortSignal.timeout(e),r=Date.now()+e;return t?{signal:AbortSignal.any([t,n]),deadline:r}:{signal:n,deadline:r}}function he(t){if(t==null)return {code:"UNKNOWN",message:"Unknown SAP error",details:[],rawResponse:t};if(typeof t=="string")return {code:"UNKNOWN",message:t,details:[],rawResponse:t};let n=t.error;if(!n)return {code:"UNKNOWN",message:"Unknown SAP error",details:[],rawResponse:t};let r=n.message,s;r&&typeof r=="object"&&"value"in r?s=r.value??"Unknown error":typeof r=="string"?s=r:s="Unknown error";let a=(n.innererror?.errordetails??[]).map(d=>({code:d.code??"",message:d.message??"",severity:d.severity??"error",target:d.target}));return {code:n.code??"UNKNOWN",message:s,target:n.target,details:a,rawResponse:t}}function en(t){if(typeof t!="string")return false;let e=t.trimStart().slice(0,200).toLowerCase();return e.startsWith("<!doctype")||e.startsWith("<html")||e.includes("<title")}function tn(t){let e=ie(t).toLowerCase();return /anmeldung fehlgeschlagen|anmeldefehler|logon (error|failed)|login failed|unauthori[sz]ed/.test(e)}var nn="Benutzer und Passwort pr\xFCfen. Ist sap-client gesetzt? Ohne Mandant lehnt das Gateway die Anmeldung ebenfalls ab. Bei pers\xF6nlicher Anmeldung (user-basic): SAP-Benutzer/-Passwort im n8n-Credential pr\xFCfen \u2014 und nicht mehrfach probieren, SAP sperrt die Kennung nach wenigen Fehlversuchen.";function wi(t){return /no authorization for operation\s+\d+\s+on object/i.test(t)}var Ai="SAP-KBA 3421507 nennt daf\xFCr zwei Ursachen, und keine ist die Berechtigung: (1) der Objektschl\xFCssel ist falsch formatiert \u2014 er geht zehnstellig mit f\xFChrenden Nullen hinaus, z. B. 0000012345 statt 12345; (2) der BusinessObjectTypeName passt nicht zum Objekt (Kundenauftrag: BUS2032). Dritte M\xF6glichkeit: Kopfzeile gegen Abfrageparameter verwechselt \u2014 beim schreibenden POST sind es Kopfzeilen, beim lesenden Aufruf Abfrageparameter. Erst danach lohnt der Blick in PFCG/SU53.";function ie(t){let e=/<title[^>]*>([^<]{1,200})<\/title>/i.exec(t)?.[1]?.trim();return e||t.replace(/<script[\s\S]*?<\/script>/gi," ").replace(/<style[\s\S]*?<\/style>/gi," ").replace(/<[^>]+>/g," ").replace(/\s+/g," ").trim().slice(0,200)||"HTML-Seite ohne verwertbaren Text"}function vi(t){return /\/IW[A-Z]+\/[A-Z_]+\/\d+/i.exec(t)?.[0]}var Ei=new Set(["UNABLE_TO_GET_ISSUER_CERT_LOCALLY","UNABLE_TO_VERIFY_LEAF_SIGNATURE","SELF_SIGNED_CERT_IN_CHAIN","DEPTH_ZERO_SELF_SIGNED_CERT","CERT_UNTRUSTED"]);function Ci(t){let e=t?.code;if(typeof e=="string")return e;let n=t?.cause;if(typeof n?.code=="string")return n.code}function Ri(t){let n=(t?.cause?.cert??t?.cert)?.issuer?.CN;return typeof n=="string"?n:void 0}function ye(t,e){if(t instanceof F)return {code:t.timedOut?"TOOL_TIMEOUT":"ABORTED",message:t.message};let n=Ci(t);if(n&&Ei.has(n)){let i=Ri(t);return {code:"TLS_CHAIN_INCOMPLETE",message:i?`Die Zertifikatskette ist nicht vollst\xE4ndig verifizierbar (${n}). Aussteller: ${i}.`:`Die Zertifikatskette ist nicht vollst\xE4ndig verifizierbar (${n}).`,guidance:"Root-CA \xFCber SAP_CA_CERT=<pfad> einbinden (intern NODE_EXTRA_CA_CERTS). Welches Zertifikat fehlt, zeigt `test-connection` (Stufe TLS) oder `openssl s_client -connect <host>:<port> -showcerts`. SAP_TLS_VERIFY=false ist kein Ersatz \u2014 es schaltet die Pr\xFCfung nur ab."}}if(n==="ENOTFOUND"||n==="EAI_AGAIN")return {code:"DNS_FAILED",message:`Der SAP-Host ist nicht aufl\xF6sbar (${n}).`,guidance:"SAP_BASE_URL pr\xFCfen. Im Container zus\xE4tzlich die DNS-Konfiguration."};if(n==="ECONNREFUSED")return {code:"CONNECTION_REFUSED",message:"Der SAP-Host nimmt keine Verbindung auf dem angegebenen Port an.",guidance:"Port in SAP_BASE_URL pr\xFCfen (HTTPS-Port des ICM, oft 44300 oder 8443)."};if(n==="ECONNABORTED"||n==="ETIMEDOUT")return {code:"TIMEOUT",message:"Das SAP-System hat nicht rechtzeitig geantwortet.",guidance:"Anfrage eingrenzen (top/skip, filter) oder SAP_HTTP_TIMEOUT_MS erh\xF6hen \u2014 aber unterhalb der kleinsten Client-Grenze bleiben."};if(isAxiosError(t)&&t.response)return Pi(t.response.status,t.response.data,e);let r=t;if(typeof r?.message=="string"&&r.message.length>0)return en(r.message)?tn(r.message)?{code:"AUTH_FAILED",message:`Anmeldung abgelehnt (SAP-Anmeldeseite: ${ie(r.message)}).`,guidance:nn}:{code:"HTML_RESPONSE",message:`SAP hat eine HTML-Seite statt Daten geliefert: ${ie(r.message)}`,guidance:"Meist eine abgelehnte Anmeldung oder ein ung\xFCltiger Pfad. Ist sap-client gesetzt? Ist der Service in /IWFND/MAINT_SERVICE aktiviert?"}:{code:typeof r.code=="string"?r.code:"ERROR",message:r.message};if(t instanceof Error)return en(t.message)?tn(t.message)?{code:"AUTH_FAILED",message:`Anmeldung abgelehnt (SAP-Anmeldeseite: ${ie(t.message)}).`,guidance:nn}:{code:"HTML_RESPONSE",message:`SAP hat eine HTML-Seite statt Daten geliefert: ${ie(t.message)}`,guidance:"Meist eine abgelehnte Anmeldung oder ein ung\xFCltiger Pfad. Ist sap-client gesetzt? Ist der Service in /IWFND/MAINT_SERVICE aktiviert?"}:{code:"ERROR",message:t.message};if(typeof t=="string")return {code:"ERROR",message:t};let s=t===void 0?void 0:JSON.stringify(t);return {code:"ERROR",message:s?`Unerwarteter Fehler ohne Meldung: ${s}`:"Der Aufruf schlug fehl, ohne einen Fehler zu hinterlassen. Das Serverlog zeigt unter derselben Korrelations-ID, welche SAP-Aufrufe beteiligt waren."}}function Pi(t,e,n){let r=typeof e=="string"?e:JSON.stringify(e??""),s=vi(r);if(s?.toUpperCase().includes("/IWFND/MED/170")){let o=n?.serviceUrl?`Service ${n.serviceUrl}`:"Der Service";return {code:"SERVICE_NOT_REGISTERED",httpStatus:t,sapCode:s,message:`${o} ist im Gateway nicht registriert.`,guidance:"Aktivierung in Transaktion /IWFND/MAINT_SERVICE n\xF6tig. Das ist kein Berechtigungsproblem \u2014 PFCG und SU53 f\xFChren hier nicht weiter."}}if(wi(r))return {code:"MEDIA_OBJECT_MISMATCH",httpStatus:t,...s?{sapCode:s}:{},message:Zn(e)??"SAP meldet fehlende Berechtigung f\xFCr das Objekt \u2014 meist ist es aber der Objektschl\xFCssel oder der Objekttyp.",guidance:Ai};if(t===401)return {code:"AUTH_FAILED",httpStatus:401,...s?{sapCode:s}:{},message:"Anmeldung abgelehnt.",guidance:'Ist sap-client gesetzt? Ohne Mandant antwortet das Gateway mit 401 \u201EAnmeldung fehlgeschlagen" statt mit einer Mandantenmeldung. Sonst Benutzer und Passwort pr\xFCfen.'};if(t===403)return {code:"FORBIDDEN",httpStatus:403,...s?{sapCode:s}:{},message:Zn(e)??"Zugriff verweigert.",guidance:"Berechtigungen in PFCG pr\xFCfen, Trace \xFCber SU53. Bei OData-Services zus\xE4tzlich das Objekt S_SERVICE."};if(t===404)return {code:"NOT_FOUND",httpStatus:404,...s?{sapCode:s}:{},message:n?.serviceUrl?`Unter ${n.serviceUrl} liegt nichts.`:"Der angeforderte Pfad existiert auf diesem System nicht.",guidance:"Pfad \xFCber sap_discover_services pr\xFCfen. Ein Service kann existieren, aber nicht aktiviert sein (/IWFND/MAINT_SERVICE)."};if(en(e))return tn(e)?{code:"AUTH_FAILED",httpStatus:t,message:`Anmeldung abgelehnt (SAP-Anmeldeseite, HTTP ${t}: ${ie(e)}).`,guidance:nn}:{code:"HTML_RESPONSE",httpStatus:t,message:`SAP hat eine HTML-Fehlerseite geliefert (HTTP ${t}): ${ie(e)}`,guidance:"Der Pfad wird von SAP nicht als OData-Service beantwortet. Bei Katalogpfaden sap_discover_services statt sap_query verwenden."};let i=he(e);return {code:i.code&&i.code!=="UNKNOWN"?i.code:`HTTP_${t}`,httpStatus:t,...s?{sapCode:s}:{},message:i.message&&i.message!=="Unknown error"&&i.message!=="Unknown SAP error"?i.message:`SAP antwortete mit HTTP ${t} ohne verwertbare Fehlermeldung.`,...i.details.length>0?{guidance:i.details.map(o=>`${o.code}: ${o.message}`).join(" | ")}:{}}}function Zn(t){let e=he(t);if(e.message&&!(e.message==="Unknown error"||e.message==="Unknown SAP error"))return e.message}var Oi=5e3;function Qn(t){let e=t?.issuer?.CN??t?.issuer?.O;return Array.isArray(e)?e.join(", ")||void 0:typeof e=="string"?e:void 0}function O(t,e,n,r,s){return {stage:t,status:n,detail:r,durationMs:Date.now()-e,...s?.guidance?{guidance:s.guidance}:{},...s?.info?{info:s.info}:{}}}function Ii(t){try{let e=new URL(t),n=e.protocol==="https:";return {host:e.hostname,port:e.port?Number(e.port):n?443:80,isTls:n}}catch{return}}async function Di(t,e){let n=Date.now();try{let{address:r,family:s}=await e(t);return O("dns",n,"ok",`${t} l\xF6st auf ${r} auf.`,{info:{address:r,family:s}})}catch(r){let s=ye(r);return O("dns",n,"failed",`${t} ist nicht aufl\xF6sbar.`,{guidance:s.guidance??"SAP_BASE_URL pr\xFCfen. Im Container zus\xE4tzlich die DNS-Konfiguration des Docker-Netzes."})}}async function Ni(t,e,n,r,s){let i=Date.now(),o=a=>new Promise((d,l)=>{let c=s({host:t,port:e,rejectUnauthorized:a,servername:t},()=>{let u=c.getPeerCertificate(true);c.destroy(),d(u);});c.setTimeout(r,()=>{c.destroy(),l(Object.assign(new Error(`TLS-Handshake nach ${r} ms ohne Antwort`),{code:"ETIMEDOUT"}));}),c.on("error",u=>{c.destroy(),l(u);});});try{let a=await o(n),d=Qn(a);return O("tls",i,"ok",n?`TLS-Verbindung steht, Zertifikatskette ist verifizierbar.${d?` Aussteller: ${d}.`:""}`:`TLS-Verbindung steht. Die Zertifikatspr\xFCfung ist \xFCber SAP_TLS_VERIFY=false abgeschaltet \u2014 die Kette wurde NICHT verifiziert.${d?` Aussteller: ${d}.`:""}`,{info:{verified:n,...d?{issuer:d}:{},...a?.subject?.CN?{subject:String(a.subject.CN)}:{},...a?.valid_to?{validTo:a.valid_to}:{}}})}catch(a){let d=ye(a);if(d.code==="TLS_CHAIN_INCOMPLETE"){let l;try{let c=await o(!1);l=Qn(c);}catch{}return O("tls",i,"failed",l?`Die Zertifikatskette ist nicht vollst\xE4ndig verifizierbar. Aussteller des Serverzertifikats: ${l}.`:"Die Zertifikatskette ist nicht vollst\xE4ndig verifizierbar.",{guidance:d.guidance,...l?{info:{issuer:l}}:{}})}return O("tls",i,"failed",d.message,{guidance:d.guidance})}}async function xi(t,e){let n=Date.now();try{let r=await t.request({method:"get",url:"/sap/opu/odata/IWFND/CATALOGSERVICE;v=2/",headers:{Accept:"application/json"},params:{$format:"json"}});return [O("auth",n,"ok","Anmeldung am Gateway erfolgreich."),O("client",n,"ok",e?`Mandant ${e} wird an jede Anfrage geh\xE4ngt und vom Gateway angenommen.`:"Kein SAP_CLIENT konfiguriert \u2014 das System hat die Anfrage dennoch angenommen. Auf mandantenabh\xE4ngigen Systemen sollte er gesetzt sein.",{info:{sapClient:e??null}}),O("catalog",n,"ok",`Servicekatalog erreichbar (HTTP ${r.status}).`)]}catch(r){let s=ye(r),i=s.httpStatus===401||s.code==="AUTH_FAILED";return i&&!e?[O("auth",n,"ok","Zugangsdaten wurden gesendet."),O("client",n,"failed",'Das Gateway lehnt die Anmeldung ab, und SAP_CLIENT ist nicht gesetzt. Gemessen antwortet das Gateway ohne sap-client mit 401 \u201EAnmeldung fehlgeschlagen" statt mit einer Mandantenmeldung.',{guidance:"SAP_CLIENT setzen (z. B. 100) und erneut pr\xFCfen. Bleibt der 401 bestehen, liegt es an Benutzer oder Passwort."}),O("catalog",n,"skipped","Nicht gepr\xFCft \u2014 die Anmeldung scheiterte zuvor.")]:i?[O("auth",n,"failed","Anmeldung abgelehnt.",{guidance:`Benutzer und Passwort pr\xFCfen. Mandant ${e} wird gesendet \u2014 bei Zweifeln in SU01 pr\xFCfen, ob der Benutzer in diesem Mandanten existiert und nicht gesperrt ist.`}),O("client",n,"skipped","Nicht gepr\xFCft \u2014 die Anmeldung scheiterte zuvor."),O("catalog",n,"skipped","Nicht gepr\xFCft \u2014 die Anmeldung scheiterte zuvor.")]:[O("auth",n,"ok","Anmeldung am Gateway erfolgreich."),O("client",n,"ok",e?`Mandant ${e} angenommen.`:"Kein Mandant konfiguriert."),O("catalog",n,"failed",s.message,{guidance:s.guidance??"Katalogdienst in /IWFND/MAINT_SERVICE pr\xFCfen. Der Server probiert drei bekannte Katalogpfade durch."})]}}async function ot(t,e){let n=Date.now(),r=e.budgetMs??Oi,s=e.deps?.lookup??lookup,i=e.deps?.connectTls??connect,o=[],a=Ii(e.baseUrl);if(!a)return o.push(O("dns",n,"failed",`SAP_BASE_URL ist keine g\xFCltige URL: "${e.baseUrl}"`,{guidance:"Erwartet wird etwa https://host.example.com:44300 \u2014 mit Schema und ohne Pfad."}),...["tls","auth","client","catalog"].map(d=>O(d,n,"skipped","Nicht gepr\xFCft \u2014 die Basis-URL ist unbrauchbar."))),it(o,n);if(o.push(await Di(a.host,s)),o[0].status==="failed")return o.push(...["tls","auth","client","catalog"].map(d=>O(d,n,"skipped","Nicht gepr\xFCft \u2014 der Name war nicht aufl\xF6sbar."))),it(o,n);if(a.isTls){let d=Math.max(500,r-(Date.now()-n));if(o.push(await Ni(a.host,a.port,e.tlsVerify!==false,d,i)),o[o.length-1].status==="failed")return o.push(...["auth","client","catalog"].map(l=>O(l,n,"skipped","Nicht gepr\xFCft \u2014 die TLS-Stufe scheiterte zuvor."))),it(o,n)}else o.push(O("tls",n,"skipped","Nicht gepr\xFCft \u2014 SAP_BASE_URL verwendet http, nicht https."));return o.push(...await xi(t,e.sapClient)),it(o,n)}function it(t,e){let n=t.find(r=>r.status==="failed");return {status:n?"failed":"connected",...n?{failedStage:n.stage}:{},stages:t,durationMs:Date.now()-e,timestamp:new Date().toISOString()}}var Se=class{constructor(e,n,r,s=60){this.tokenUrl=e;this.clientId=n;this.clientSecret=r;this.bufferSeconds=s;}cachedToken=null;expiresAt=0;pendingFetch=null;async getToken(e){if(this.cachedToken&&Date.now()<this.expiresAt)return this.cachedToken;if(this.pendingFetch)return this.pendingFetch;this.pendingFetch=this.fetchToken();try{return await this.pendingFetch}finally{this.pendingFetch=null;}}async fetchToken(){let e=await sn.post(this.tokenUrl,new URLSearchParams({grant_type:"client_credentials"}),{auth:{username:this.clientId,password:this.clientSecret},headers:{"Content-Type":"application/x-www-form-urlencoded"}}),{access_token:n,expires_in:r}=e.data;return this.cachedToken=n,this.expiresAt=Date.now()+(r-this.bufferSeconds)*1e3,n}};function rn(t){return createHash("sha256").update(t).digest("hex")}var Ue=class{constructor(e=100){this.maxSize=e;}cache=new Map;get(e){let n=this.cache.get(e);return n?Date.now()>=n.expiresAt?(this.cache.delete(e),null):(this.cache.delete(e),this.cache.set(e,n),n.token):null}set(e,n,r){if(this.cache.has(e))this.cache.delete(e);else if(this.cache.size>=this.maxSize){let s=this.cache.keys().next().value;s!==void 0&&this.cache.delete(s);}this.cache.set(e,{token:n,expiresAt:r});}},at=class{clientTokenManager;cache;config;constructor(e){this.config=e,this.clientTokenManager=new Se(e.tokenServiceUrl,e.clientId,e.clientSecret),this.cache=new Ue;}async getToken(e){if(!e)return this.clientTokenManager.getToken();let n=rn(e),r=this.cache.get(n);return r||this.exchangeToken(e,n)}async exchangeToken(e,n){let r=await this.clientTokenManager.getToken(),s=`${this.config.destinationServiceUrl}/destination-configuration/v1/destinations/${this.config.destinationName}`,o=(await sn.get(s,{headers:{Authorization:`Bearer ${r}`,"X-user-token":e}})).data.authTokens;if(!o?.length)throw new Error(`Destination '${this.config.destinationName}': no authTokens in response`);let a=o[0];if(a.error)throw new Error(`Destination '${this.config.destinationName}' token exchange failed: ${a.error}`);let d=parseInt(a.expires_in,10),l=Number.isFinite(d)&&d>0?d:3600,c=Date.now()+(l-60)*1e3;return this.cache.set(n,a.value,c),a.value}};var $e=class{constructor(e,n){this.config=e;this.discoveryClient=n;this.bufferSeconds=e.bufferSeconds??60;}cachedToken=null;expiresAt=0;pendingFetch=null;jwks=null;bufferSeconds;async getToken(e){if(this.cachedToken&&Date.now()<this.expiresAt)return this.cachedToken;if(this.pendingFetch)return this.pendingFetch;this.pendingFetch=this.fetchAndValidateToken();try{return await this.pendingFetch}finally{this.pendingFetch=null;}}async fetchAndValidateToken(){let e=await this.discoveryClient.discover(this.config.issuerUrl),n=await sn.post(e.token_endpoint,new URLSearchParams({grant_type:"client_credentials"}),{auth:{username:this.config.clientId,password:this.config.clientSecret},headers:{"Content-Type":"application/x-www-form-urlencoded"}}),{access_token:r,expires_in:s}=n.data;return await this.validateJwt(r,e.jwks_uri,e.issuer),this.cachedToken=r,this.expiresAt=Date.now()+(s-this.bufferSeconds)*1e3,r}async validateJwt(e,n,r){this.jwks||(this.jwks=createRemoteJWKSet(new URL(n)));let{payload:s}=await jwtVerify(e,this.jwks,{issuer:r});return s}};var oe=class{constructor(e=36e5){this.ttlMs=e;}cache=new Map;async discover(e){let n=e.replace(/\/+$/,""),r=this.cache.get(n);if(r&&Date.now()<r.expiresAt)return r.document;let s=`${n}/.well-known/openid-configuration`,o=(await sn.get(s,{timeout:1e4,headers:{Accept:"application/json"}})).data;if(!o.token_endpoint||!o.jwks_uri)throw new Error(`OIDC discovery document at ${s} is missing required fields (token_endpoint, jwks_uri)`);return this.cache.set(n,{document:o,expiresAt:Date.now()+this.ttlMs}),o}clearCache(){this.cache.clear();}};var qi={email:"urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress",sapUsername:"urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified"};function er(t,e){if(!t.includes("-----BEGIN")||!t.includes("-----END"))throw new Error(`Invalid PEM format for ${e}. Expected PEM-encoded content starting with -----BEGIN`)}function Ki(t){return `<saml:Assertion xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" ID="${t.assertionId}" IssueInstant="${t.authnInstant}" Version="2.0"><saml:Issuer>${t.issuer}</saml:Issuer><saml:Subject><saml:NameID Format="${t.nameIdFormat}">${t.nameId}</saml:NameID><saml:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer"><saml:SubjectConfirmationData NotOnOrAfter="${t.notOnOrAfter}" Recipient="${t.recipient}"/></saml:SubjectConfirmation></saml:Subject><saml:Conditions NotBefore="${t.notBefore}" NotOnOrAfter="${t.notOnOrAfter}"><saml:AudienceRestriction><saml:Audience>${t.audience}</saml:Audience></saml:AudienceRestriction></saml:Conditions><saml:AuthnStatement AuthnInstant="${t.authnInstant}"><saml:AuthnContext><saml:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport</saml:AuthnContextClassRef></saml:AuthnContext></saml:AuthnStatement></saml:Assertion>`}function zi(t,e,n){let r=new SignedXml({privateKey:e,publicCert:n});return r.signatureAlgorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256",r.canonicalizationAlgorithm="http://www.w3.org/2001/10/xml-exc-c14n#",r.addReference({xpath:"//*[local-name(.)='Assertion']",digestAlgorithm:"http://www.w3.org/2001/04/xmlenc#sha256",transforms:["http://www.w3.org/2000/09/xmldsig#enveloped-signature","http://www.w3.org/2001/10/xml-exc-c14n#"]}),r.computeSignature(t,{location:{reference:"//*[local-name(.)='Issuer']",action:"after"}}),r.getSignedXml()}var ct=class{cache;config;constructor(e){er(e.privateKey,"private key"),er(e.certificate,"certificate"),this.config={...e,clockSkew:e.clockSkew??120,assertionLifetime:e.assertionLifetime??300},this.cache=new Ue;}async getToken(e){if(!e)throw new Error("saml-bearer auth requires a user token for principal propagation");let n=rn(e),r=this.cache.get(n);return r||this.exchangeToken(e,n)}resolveNameId(e,n){return n==="email"?e.email??e.sub??"":e.sub??""}async exchangeToken(e,n){let r=decodeJwt(e),s=Date.now(),i=this.resolveNameId({sub:r.sub,email:r.email},this.config.nameIdFormat),o=qi[this.config.nameIdFormat],a=new Date(s-this.config.clockSkew*1e3).toISOString(),d=new Date(s+this.config.assertionLifetime*1e3).toISOString(),l=new Date(s).toISOString(),c=Ki({assertionId:`_${randomUUID()}`,issuer:this.config.issuer,nameId:i,nameIdFormat:o,recipient:this.config.tokenServiceUrl,audience:this.config.clientId,notBefore:a,notOnOrAfter:d,authnInstant:l}),u=zi(c,this.config.privateKey,this.config.certificate),p=Buffer.from(u).toString("base64"),m=await sn.post(this.config.tokenServiceUrl,new URLSearchParams({grant_type:"urn:ietf:params:oauth:grant-type:saml2-bearer",assertion:p,client_id:this.config.clientId}).toString(),{headers:{"Content-Type":"application/x-www-form-urlencoded"}}),{access_token:g,expires_in:f}=m.data,h=typeof f=="number"&&f>0?f:3600,S=Date.now()+(h-60)*1e3;return this.cache.set(n,g,S),g}};var Yi="[geschwaerzt]",Xi=new Set(["accept","accept-encoding","content-type","content-length","if-match","if-none-match","x-http-method","x-requested-with"]);function tr(t){let e="'(?:[^']|'')*'",n=new RegExp(`\\b(guid|datetimeoffset|datetime|time|binary|X)${e}|${e}|\\b\\d+(?:\\.\\d+)?[dfmDFM]?\\b`,"gi");return t.replace(n,(r,s)=>s?`${s}'<${s}>'`:r.startsWith("'")?"'<str>'":"<num>")}function Ji(t){return t.replace(/\(([^)]*)\)/g,(e,n)=>`(${tr(n)})`)}function Zi(t){if(t===null||typeof t!="object")return t;let e={};for(let[n,r]of Object.entries(t))e[n]=Xi.has(n.toLowerCase())?r:Yi;return e}var dt={paths:["headers","url",'params["$filter"]','params["$search"]'],censor:(t,e)=>{let n=e[e.length-1];return n==="headers"?Zi(t):typeof t!="string"?t:n==="url"?Ji(t):tr(t)}};function nr(t){if(t.tlsVerify===false||t.clientCert!==void 0)return new Agent({rejectUnauthorized:t.tlsVerify!==false,...t.clientCert?{cert:t.clientCert}:{},...t.clientKey?{key:t.clientKey}:{},...t.clientKeyPassphrase?{passphrase:t.clientKeyPassphrase}:{}})}var to=3e4,J=eo({name:"sap-http-client",redact:dt,transport:{target:"pino/file",options:{destination:2}}});function no(t,e){return typeof t=="string"?t.trimStart().startsWith("<!DOCTYPE"):Buffer.isBuffer(t)?String(e?.["content-type"]??"").includes("text/html")?true:t.subarray(0,32).toString("latin1").trimStart().startsWith("<!DOCTYPE"):false}function ro(t){return t.startsWith("http://")||t.startsWith("https://")}function so(t){let e=t.replace(/\/+$/,"");try{let n=new URL(e),r=n.pathname.replace(/\/+$/,"");return {origin:`${n.protocol}//${n.host}`,path:r}}catch{return {origin:e,path:""}}}var be=class{constructor(e,n={}){this.destination=e;switch(this.httpsAgent=nr(n),this.requestTimeoutMs=n.requestTimeoutMs??to,e.auth.type){case "oauth2":this.tokenManager=new Se(e.auth.tokenServiceUrl,e.auth.clientId,e.auth.clientSecret);break;case "ias":this.tokenManager=new $e({issuerUrl:e.auth.tenantUrl,clientId:e.auth.clientId,clientSecret:e.auth.clientSecret},new oe);break;case "xsuaa":this.tokenManager=new $e({issuerUrl:e.auth.xsuaaUrl,clientId:e.auth.clientId,clientSecret:e.auth.clientSecret},new oe);break;case "btp-principal":this.tokenManager=new at({destinationName:e.auth.destinationName,destinationServiceUrl:e.auth.destinationServiceUrl,clientId:e.auth.clientId,clientSecret:e.auth.clientSecret,tokenServiceUrl:e.auth.tokenServiceUrl});break;case "saml-bearer":this.tokenManager=new ct({tokenServiceUrl:e.auth.tokenServiceUrl,clientId:e.auth.clientId,issuer:e.auth.issuer,nameIdFormat:e.auth.nameIdFormat,privateKey:e.auth.privateKey,certificate:e.auth.certificate,clockSkew:e.auth.clockSkew,assertionLifetime:e.auth.assertionLifetime});break;default:this.tokenManager=null;}}tokenManager;userContext=null;httpsAgent;requestTimeoutMs;async request(e){st();let n=e.method!=="get",r=ge(),s=nt();Yn(e.method);let i={...e.params};this.destination.sapClient&&(i["sap-client"]=this.destination.sapClient);let o=e.userContext??this.userContext??void 0,a=await this.buildAuthHeaders(o),d=this.destination.headers??{},l={};if(n){let p=await this.fetchCsrfToken({...d,...a},e.url);p.token&&(l={"x-csrf-token":p.token},p.cookies&&(l.Cookie=p.cookies));}let c={...d,...a,...l,...e.headers},u={method:e.method,url:this.resolveUrl(e.url),data:e.data,headers:c,params:Object.keys(i).length>0?i:void 0,...e.responseType?{responseType:e.responseType}:{},httpsAgent:this.httpsAgent,timeout:this.effectiveTimeoutMs(),signal:r?.signal,beforeRedirect:p=>{this.httpsAgent&&(p.agent=this.httpsAgent);let m=p.headers??{};for(let[g,f]of Object.entries(c))m[g]||(m[g]=f);}};J.info({...s?{correlationId:s,tool:r?.toolName}:{},...r?.traceId?{traceId:r.traceId}:{},method:u.method,url:u.url,headers:u.headers,params:u.params,hasAuth:!!u.headers.Authorization||!!u.headers.APIKey},"SAP HTTP request outgoing");try{let p=await sn(u);if(J.info({...s?{correlationId:s}:{},status:p.status,contentType:p.headers["content-type"]},"SAP HTTP response OK"),no(p.data,p.headers))throw new Error("SAP returned an HTML page instead of JSON. This usually means authentication failed or the URL path is invalid.");return {data:p.data,headers:p.headers,status:p.status}}catch(p){if(isAxiosError(p)&&p.response){let m=e.expectedStatuses?.includes(p.response.status)??false;(m?J.info.bind(J):J.error.bind(J))({...s?{correlationId:s}:{},status:p.response.status,statusText:p.response.statusText,contentType:p.response.headers?.["content-type"],url:u.url,...m?{expected:true}:{},dataType:typeof p.response.data,dataLength:typeof p.response.data=="string"?p.response.data.length:void 0},m?"SAP HTTP response (expected)":"SAP HTTP response ERROR");}else p instanceof Error&&J.error({message:p.message,name:p.name},"SAP HTTP connection error");if(n&&this.isCsrf403(p)){st();try{let m=await this.fetchCsrfToken({...d,...a},e.url),g={...u.headers};m.token&&(g["x-csrf-token"]=m.token,m.cookies&&(g.Cookie=m.cookies)),nt();let f=await sn({...u,headers:g});return {data:f.data,headers:f.headers,status:f.status}}catch(m){throw this.toSapError(m)}}throw this.toSapError(p)}}async buildAuthHeaders(e){switch(this.destination.auth.type){case "basic":return {Authorization:`Basic ${Buffer.from(`${this.destination.auth.username}:${this.destination.auth.password}`).toString("base64")}`};case "saml-bearer":case "btp-principal":case "oauth2":case "ias":case "xsuaa":return {Authorization:`Bearer ${await this.tokenManager.getToken(e?.token)}`};case "apikey":return {APIKey:this.destination.auth.apiKey};default:return {}}}resolveUrl(e){if(ro(e))return e;let{origin:n,path:r}=so(this.destination.url);return r&&(e===r||e.startsWith(`${r}/`))?`${n}${e}`:`${this.destination.url}${e}`}async fetchCsrfToken(e,n){let r=this.destination.url,s=[];if(n){let i=n.replace(/\/[^/]*$/,"/");i!=="/"&&i!==n&&s.push(this.resolveUrl(i));}s.push(`${r}/`,r);for(let i of s){st(),nt();try{let o={...e,"x-csrf-token":"fetch"},a={};this.destination.sapClient&&(a["sap-client"]=this.destination.sapClient);let d=await sn.get(i,{headers:o,params:Object.keys(a).length>0?a:void 0,validateStatus:()=>!0,timeout:this.effectiveTimeoutMs(),signal:ge()?.signal,httpsAgent:this.httpsAgent,beforeRedirect:c=>{this.httpsAgent&&(c.agent=this.httpsAgent);let u=c.headers??{};for(let[p,m]of Object.entries(o))u[p]||(u[p]=m);}}),l=d.headers["x-csrf-token"];if(J.debug({url:i,status:d.status,hasToken:!!l},"CSRF token fetch result"),l&&l.toLowerCase()!=="required"){let u=(d.headers["set-cookie"]??[]).map(p=>p.split(";")[0]).join("; ");return {token:l,cookies:u}}}catch{}}return {token:"",cookies:""}}isCsrf403(e){return isAxiosError(e)&&e.response?.status===403}effectiveTimeoutMs(){let e=Xn();return e===void 0?this.requestTimeoutMs:Math.max(1,Math.min(this.requestTimeoutMs,e))}toSapError(e){if(e instanceof F)return {code:e.timedOut?"TOOL_TIMEOUT":"ABORTED",message:e.message,details:[],rawResponse:void 0};if(isAxiosError(e)&&(e.code==="ERR_CANCELED"||e.name==="CanceledError")){let n=ge()?.signal?.reason?.name==="TimeoutError";return {code:n?"TOOL_TIMEOUT":"ABORTED",message:n?"Zeitbudget des Tool-Aufrufs \xFCberschritten \u2014 laufender SAP-Aufruf abgebrochen.":"Client hat die Verbindung verworfen \u2014 laufender SAP-Aufruf abgebrochen.",details:[],rawResponse:void 0}}return isAxiosError(e)&&(e.code==="ECONNABORTED"||e.code==="ETIMEDOUT")?{code:"TIMEOUT",message:`SAP request exceeded ${this.requestTimeoutMs} ms (SAP_HTTP_TIMEOUT_MS): ${e.message}`,details:[],rawResponse:void 0}:isAxiosError(e)&&e.response?he(e.response.data):e instanceof Error?{code:"CONNECTION_ERROR",message:e.message,details:[],rawResponse:void 0}:he(e)}};function rr(t,e){e||t.warn({sapClient:null},'SAP_CLIENT ist nicht gesetzt. Auf mandantenabh\xE4ngigen Systemen antwortet das Gateway ohne sap-client mit 401 \u201EAnmeldung fehlgeschlagen" \u2014 was wie ein falsches Passwort aussieht, aber keines ist. Bei Anmeldeproblemen zuerst SAP_CLIENT setzen (z. B. 100).');}async function sr(t,e,n,r){try{let s=new be(tt(e),n),i=await ot(s,{baseUrl:e.baseUrl,sapClient:e.sapClient,tlsVerify:n.tlsVerify,...r?{deps:r}:{}});for(let o of i.stages){let a={stage:o.stage,status:o.status,durationMs:o.durationMs,...o.info??{},...o.guidance?{guidance:o.guidance}:{}};o.status==="failed"?t.warn(a,`Selbsttest ${o.stage}: ${o.detail}`):t.info(a,`Selbsttest ${o.stage}: ${o.detail}`);}i.status==="connected"?t.info({durationMs:i.durationMs,sapClient:e.sapClient??null},"Selbsttest bestanden: Namensaufl\xF6sung, TLS, Anmeldung, Mandant und Katalog sind in Ordnung"):t.warn({failedStage:i.failedStage,durationMs:i.durationMs},`Selbsttest gescheitert in Stufe \u201E${i.failedStage}". Der Server l\xE4uft weiter \u2014 Tool-Aufrufe werden bis zur Behebung fehlschlagen. Einzelheiten liefert das Tool test-connection.`);}catch(s){t.warn({err:s instanceof Error?s.message:String(s)},"Selbsttest konnte nicht ausgef\xFChrt werden. Der Server l\xE4uft weiter.");}}function ae(t){return `/Date(${Date.parse(t.length===10?`${t}T00:00:00Z`:t)})/`}var w=(t,e,n,r=true)=>({name:t,type:"Edm.String",maxLength:e,...n?{label:n}:{},nullable:r}),Be=(t,e,n=15,r=3)=>({name:t,type:"Edm.Decimal",precision:n,scale:r,...e?{label:e}:{}}),ce=(t,e)=>({name:t,type:"Edm.DateTime",precision:7,...e?{label:e}:{}}),ir=(t,e)=>({name:t,type:"Edm.Boolean",...e?{label:e}:{}}),cn="/sap/opu/odata/sap",io={technicalName:"API_BUSINESS_PARTNER",title:"Business Partner (A2X)",description:"Business partners, customers and suppliers with their addresses.",path:`${cn}/API_BUSINESS_PARTNER`,namespace:"API_BUSINESS_PARTNER",entityTypes:[{set:"A_BusinessPartner",keys:["BusinessPartner"],autoKey:{prefix:"10",width:7},properties:[w("BusinessPartner",10,"Business Partner",false),w("Customer",10,"Customer"),w("Supplier",10,"Supplier"),w("BusinessPartnerCategory",1,"BP Category"),w("BusinessPartnerFullName",81,"Full Name"),w("BusinessPartnerName",81,"Name"),w("OrganizationBPName1",40,"Organization Name 1"),w("FirstName",40,"First Name"),w("LastName",40,"Last Name"),w("BusinessPartnerGrouping",4,"Grouping"),w("SearchTerm1",20,"Search Term"),w("Industry",4,"Industry"),w("CreatedByUser",12,"Created By"),ce("CreationDate","Created On"),ir("IsMarkedForArchiving","Archiving Flag")],navigations:[{name:"to_BusinessPartnerAddress",target:"A_BusinessPartnerAddress",multiplicity:"*",join:[["BusinessPartner","BusinessPartner"]]}]},{set:"A_BusinessPartnerAddress",keys:["BusinessPartner","AddressID"],autoKey:{prefix:"2",width:5},properties:[w("BusinessPartner",10,"Business Partner",false),w("AddressID",10,"Address ID",false),ce("ValidityStartDate","Valid From"),ce("ValidityEndDate","Valid To"),w("StreetName",60,"Street"),w("HouseNumber",10,"House Number"),w("PostalCode",10,"Postal Code"),w("CityName",40,"City"),w("Country",3,"Country"),w("Region",3,"Region"),w("Language",2,"Language")],navigations:[{name:"to_BusinessPartner",target:"A_BusinessPartner",multiplicity:"1",join:[["BusinessPartner","BusinessPartner"]]}]}],functionImports:[]},oo={technicalName:"API_SALES_ORDER_SRV",title:"Sales Order (A2X)",description:"Sales orders with items \u2014 read, create (deep insert), change, release.",path:`${cn}/API_SALES_ORDER_SRV`,namespace:"API_SALES_ORDER_SRV",entityTypes:[{set:"A_SalesOrder",keys:["SalesOrder"],autoKey:{prefix:"45",width:7},properties:[w("SalesOrder",10,"Sales Order",false),w("SalesOrderType",4,"Order Type"),w("SalesOrganization",4,"Sales Organization"),w("DistributionChannel",2,"Distribution Channel"),w("OrganizationDivision",2,"Division"),w("SoldToParty",10,"Sold-to Party"),w("PurchaseOrderByCustomer",35,"Customer Reference"),w("CreatedByUser",12,"Created By"),ce("CreationDate","Created On"),ce("LastChangeDateTime","Last Changed"),ce("RequestedDeliveryDate","Requested Delivery Date"),Be("TotalNetAmount","Net Value",16,3),w("TransactionCurrency",5,"Currency"),w("OverallSDProcessStatus",1,"Overall Status"),w("OverallDeliveryStatus",1,"Delivery Status")],navigations:[{name:"to_Item",target:"A_SalesOrderItem",multiplicity:"*",join:[["SalesOrder","SalesOrder"]]}]},{set:"A_SalesOrderItem",keys:["SalesOrder","SalesOrderItem"],properties:[w("SalesOrder",10,"Sales Order",false),w("SalesOrderItem",6,"Item",false),w("Material",40,"Material"),w("SalesOrderItemText",40,"Item Description"),w("SalesOrderItemCategory",4,"Item Category"),Be("RequestedQuantity","Order Quantity",15,3),w("RequestedQuantityUnit",3,"Unit"),Be("NetAmount","Net Value",16,3),w("TransactionCurrency",5,"Currency"),w("ProductionPlant",4,"Plant")],navigations:[{name:"to_SalesOrder",target:"A_SalesOrder",multiplicity:"1",join:[["SalesOrder","SalesOrder"]]}]}],functionImports:[{name:"ReleaseSalesOrder",httpMethod:"POST",parameters:[{name:"SalesOrder",type:"Edm.String"}],returnType:"API_SALES_ORDER_SRV.A_SalesOrderType",entitySet:"A_SalesOrder"},{name:"GetOpenSalesOrderCount",httpMethod:"GET",parameters:[{name:"SoldToParty",type:"Edm.String",nullable:true}],returnType:"Edm.Int32"}]},ao={technicalName:"API_PRODUCT_SRV",title:"Product Master (A2X)",description:"Products (materials) with descriptions.",path:`${cn}/API_PRODUCT_SRV`,namespace:"API_PRODUCT_SRV",entityTypes:[{set:"A_Product",keys:["Product"],autoKey:{prefix:"DEMO-",width:8},properties:[w("Product",40,"Product",false),w("ProductType",4,"Product Type"),w("ProductGroup",9,"Product Group"),w("BaseUnit",3,"Base Unit"),Be("GrossWeight","Gross Weight",13,3),Be("NetWeight","Net Weight",13,3),w("WeightUnit",3,"Weight Unit"),w("CreatedByUser",12,"Created By"),ce("CreationDate","Created On"),ir("IsMarkedForDeletion","Deletion Flag")],navigations:[{name:"to_Description",target:"A_ProductDescription",multiplicity:"*",join:[["Product","Product"]]}]},{set:"A_ProductDescription",keys:["Product","Language"],properties:[w("Product",40,"Product",false),w("Language",2,"Language",false),w("ProductDescription",40,"Description")],navigations:[]}],functionImports:[]},lt=[io,oo,ao],on="MCP_DEMO",co=[["1000001","2","Nordlicht Maschinenbau GmbH","","Hafenstra\xDFe","12","20457","Hamburg","HH","C","MACH","2024-03-04"],["1000002","2","Weberei Hartmann & S\xF6hne KG","","M\xFChlweg","3","91522","Ansbach","BY","C","TEXT","2024-03-11"],["1000003","2","Fr\xE4nkische Pr\xE4zisionstechnik AG","","Industriestra\xDFe","48","90411","N\xFCrnberg","BY","C","MACH","2024-04-02"],["1000004","2","Altm\xFChl Kunststoffwerk GmbH","","Am Kanal","7","91710","Gunzenhausen","BY","C","CHEM","2024-04-19"],["1000005","2","Seenland Logistik GmbH & Co. KG","","Frankenstra\xDFe","101","91781","Wei\xDFenburg","BY","C","TRAN","2024-05-06"],["1000006","2","Brauerei Hopfenkranz OHG","","Brauhausgasse","2","91154","Roth","BY","C","FOOD","2024-05-21"],["1000007","2","Rothsee Elektronik GmbH","","Gewerbering","15","91126","Schwabach","BY","C","ELEC","2024-06-03"],["1000008","2","Hesselberg Metallbau e.K.","","Bahnhofstra\xDFe","33","91717","Wassertr\xFCdingen","BY","C","MACH","2024-06-17"],["1000009","2","Bavaria Sensorik AG","","Technologiepark","9","91058","Erlangen","BY","C","ELEC","2024-07-01"],["1000010","2","Kastner Werkzeugbau GmbH","","Schmiedeweg","21","90762","F\xFCrth","BY","C","MACH","2024-07-15"],["1000011","2","M\xF6belwerkstatt Lindenhof GmbH","","Lindenallee","5","97070","W\xFCrzburg","BY","C","WOOD","2024-08-05"],["1000012","2","Steinbach Automotive GmbH","","Werkstra\xDFe","60","93055","Regensburg","BY","C","AUTO","2024-08-19"],["1000013","2","Tauber Verpackungen GmbH","","Ringstra\xDFe","18","91541","Rothenburg ob der Tauber","BY","C","PACK","2024-09-02"],["1000014","1","Anna","Berger","Rosenweg","4","96047","Bamberg","BY","C","","2024-09-16"],["1000015","1","Markus","Vogel","Am Stadtpark","11","89073","Ulm","BW","C","","2024-10-07"],["1000016","1","Sabine","Kr\xFCger","Elbchaussee","250","22605","Hamburg","HH","C","","2024-10-21"],["1000017","2","Ruhrstahl Handels GmbH","","Kruppstra\xDFe","77","45143","Essen","NW","S","META","2024-02-05"],["1000018","2","Elbe Chemie AG","","Chemiepark","1","01067","Dresden","SN","S","CHEM","2024-02-12"],["1000019","2","NordPack Verpackungssysteme GmbH","","Hansaring","40","28195","Bremen","HB","S","PACK","2024-02-19"],["1000020","2","Donau Kunststoffe GmbH","","Donaustra\xDFe","88","94032","Passau","BY","B","CHEM","2024-02-26"]],lo=[["PUMP-100","FERT","PUMPS","ST","42.500","39.800","Kreiselpumpe 100 l/min","Centrifugal pump 100 l/min",1890],["MOTOR-15KW","FERT","DRIVES","ST","118.000","112.500","Drehstrommotor 15 kW","Three-phase motor 15 kW",2450],["SENSOR-T200","HAWA","SENSOR","ST","0.180","0.150","Temperatursensor PT100 -50..200 \xB0C","Temperature sensor PT100 -50..200 \xB0C",64.5],["VALVE-DN50","FERT","VALVES","ST","6.400","6.100","Absperrventil DN50 PN16","Shut-off valve DN50 PN16",312],["HOUSING-AL3","HALB","PARTS","ST","2.900","2.700","Aluminiumgeh\xE4use Gr\xF6\xDFe 3","Aluminium housing size 3",148],["PLC-B200","HAWA","CONTROL","ST","1.100","0.950","Steuerung SPS B200","PLC controller B200",985],["CABLE-5M","HAWA","CABLE","ST","0.600","0.550","Anschlusskabel 5 m geschirmt","Connection cable 5 m shielded",27.9],["FILTER-F40","HAWA","FILTER","ST","0.900","0.800","Filtereinsatz F40","Filter cartridge F40",45],["SEAL-KIT-3","HAWA","PARTS","ST","0.250","0.200","Dichtungssatz Baugr\xF6\xDFe 3","Seal kit size 3",38],["BRACKET-XL","HALB","PARTS","ST","3.300","3.100","Wandhalterung XL verzinkt","Wall bracket XL galvanised",72]],uo=[["4500001","1000001","PO-2026-0117","2026-01-08","2026-01-29","C","C",[["PUMP-100",2],["SEAL-KIT-3",4]]],["4500002","1000003","BEST-88123","2026-01-12","2026-02-05","C","C",[["MOTOR-15KW",1],["CABLE-5M",6],["PLC-B200",1]]],["4500003","1000007","RE-2026-014","2026-01-19","2026-02-10","C","C",[["SENSOR-T200",25],["CABLE-5M",25]]],["4500004","1000004","AK-4471","2026-02-02","2026-02-27","C","C",[["VALVE-DN50",8],["SEAL-KIT-3",8]]],["4500005","1000009","BS-2026-0301","2026-02-16","2026-03-13","C","B",[["SENSOR-T200",120],["HOUSING-AL3",40],["BRACKET-XL",40]]],["4500006","1000012","SA-77201","2026-03-03","2026-03-31","B","B",[["MOTOR-15KW",3],["PLC-B200",3],["CABLE-5M",12]]],["4500007","1000010","KW-2026-19","2026-03-10","2026-04-07","B","A",[["PUMP-100",1],["FILTER-F40",10]]],["4500008","1000005","SL-0209","2026-03-24","2026-04-14","B","A",[["BRACKET-XL",30],["HOUSING-AL3",12]]],["4500009","1000002","WH-2026-04","2026-04-06","2026-05-04","B","A",[["MOTOR-15KW",2],["SENSOR-T200",10]]],["4500010","1000014","","2026-04-14","2026-04-28","C","C",[["FILTER-F40",2],["SEAL-KIT-3",1]]],["4500011","1000011","ML-3350","2026-05-05","2026-06-02","A","A",[["VALVE-DN50",4],["PUMP-100",1],["CABLE-5M",4]]],["4500012","1000013","TV-2026-0888","2026-05-18","2026-06-15","A","A",[["PLC-B200",2],["SENSOR-T200",40],["CABLE-5M",40],["BRACKET-XL",8]]],["4500013","1000015","","2026-06-01","2026-06-22","A","A",[["FILTER-F40",5]]],["4500014","1000006","HK-2026-11","2026-06-15","2026-07-13","A","A",[["PUMP-100",3],["VALVE-DN50",6],["SEAL-KIT-3",6]]],["4500015","1000008","HM-0521","2026-07-01","2026-07-29","A","A",[["MOTOR-15KW",1],["HOUSING-AL3",20],["PLC-B200",1]]]];function an(t,e=3){return t.toFixed(e)}function dn(){let t=[],e=[];for(let[d,l,c,u,p,m,g,f,h,S,y,E]of co){let b=l==="1",v=b?`${c} ${u}`:c;t.push({BusinessPartner:d,Customer:S==="C"||S==="B"?d:"",Supplier:S==="S"||S==="B"?d:"",BusinessPartnerCategory:l,BusinessPartnerFullName:v,BusinessPartnerName:v,OrganizationBPName1:b?"":c,FirstName:b?c:"",LastName:b?u:"",BusinessPartnerGrouping:b?"BP02":"BP01",SearchTerm1:(b?u:c.split(" ")[0]).toUpperCase().slice(0,20),Industry:y,CreatedByUser:on,CreationDate:ae(E),IsMarkedForArchiving:false}),e.push({BusinessPartner:d,AddressID:String(2e4+t.length),ValidityStartDate:ae(E),ValidityEndDate:ae("9999-12-31"),StreetName:p,HouseNumber:m,PostalCode:g,CityName:f,Country:"DE",Region:h,Language:"DE"});}let n=[],r=[],s=new Map,i=new Map;lo.forEach(([d,l,c,u,p,m,g,f,h],S)=>{s.set(d,h),i.set(d,f),n.push({Product:d,ProductType:l,ProductGroup:c,BaseUnit:u,GrossWeight:p,NetWeight:m,WeightUnit:"KG",CreatedByUser:on,CreationDate:ae(`2023-11-${String(6+S).padStart(2,"0")}`),IsMarkedForDeletion:false}),r.push({Product:d,Language:"DE",ProductDescription:g}),r.push({Product:d,Language:"EN",ProductDescription:f});});let o=[],a=[];for(let[d,l,c,u,p,m,g,f]of uo){let h=0;f.forEach(([S,y],E)=>{let b=y*(s.get(S)??0);h+=b,a.push({SalesOrder:d,SalesOrderItem:String((E+1)*10),Material:S,SalesOrderItemText:i.get(S)??S,SalesOrderItemCategory:"TAN",RequestedQuantity:an(y),RequestedQuantityUnit:"ST",NetAmount:an(b),TransactionCurrency:"EUR",ProductionPlant:"1010"});}),o.push({SalesOrder:d,SalesOrderType:"OR",SalesOrganization:"1010",DistributionChannel:"10",OrganizationDivision:"00",SoldToParty:l,PurchaseOrderByCustomer:c,CreatedByUser:on,CreationDate:ae(u),LastChangeDateTime:ae(`${u}T09:30:00Z`),RequestedDeliveryDate:ae(p),TotalNetAmount:an(h),TransactionCurrency:"EUR",OverallSDProcessStatus:m,OverallDeliveryStatus:g});}return {A_BusinessPartner:t,A_BusinessPartnerAddress:e,A_SalesOrder:o,A_SalesOrderItem:a,A_Product:n,A_ProductDescription:r}}function po(t){return t.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;")}function mo(t,e){return `assoc_${t.set}_${e}`}function or(t){let e=t.namespace,n=[],r=[],s=[];for(let a of t.entityTypes){let d=a.properties.map(c=>{let u=[`Name="${c.name}"`,`Type="${c.type}"`,`Nullable="${c.nullable===false||a.keys.includes(c.name)?"false":"true"}"`];return c.maxLength!==void 0&&u.push(`MaxLength="${c.maxLength}"`),c.precision!==void 0&&u.push(`Precision="${c.precision}"`),c.scale!==void 0&&u.push(`Scale="${c.scale}"`),c.label&&u.push(`sap:label="${po(c.label)}"`),a.keys.includes(c.name)&&u.push('sap:creatable="true" sap:updatable="false"'),` <Property ${u.join(" ")}/>`}).join(`
5
- `),l=a.navigations.map(c=>{let u=mo(a,c.name),p=`FromRole_${u}`,m=`ToRole_${u}`;return r.push(` <Association Name="${u}" sap:content-version="1">
4
+ ${l}`)}return d.data}function ot(t){let e={name:t.name,url:t.baseUrl,sapClient:t.sapClient};switch(t.authType){case "basic":return {...e,auth:{type:"basic",username:t.username,password:t.password}};case "user-basic":throw new Error(`Destination "${t.name}" verlangt eine pers\xF6nliche SAP-Anmeldung (authType user-basic): SAP-Benutzer und -Passwort kommen je Anfrage \xFCber X-SAP-Username/X-SAP-Password \u2014 ohne sie gibt es keinen technischen Fallback.`);case "oauth2":return {...e,auth:{type:"oauth2",clientId:t.clientId,clientSecret:t.clientSecret,tokenServiceUrl:t.tokenServiceUrl}};case "apikey":return {...e,headers:{APIKey:t.apiKey},auth:{type:"apikey",apiKey:t.apiKey}};case "ias":return {...e,auth:{type:"ias",clientId:t.clientId,clientSecret:t.clientSecret,tenantUrl:t.tenantUrl}};case "xsuaa":return {...e,auth:{type:"xsuaa",clientId:t.clientId,clientSecret:t.clientSecret,xsuaaUrl:t.xsuaaUrl}};case "btp-principal":return {...e,auth:{type:"btp-principal",destinationName:t.destinationName,destinationServiceUrl:t.destinationServiceUrl,clientId:t.clientId,clientSecret:t.clientSecret,tokenServiceUrl:t.tokenServiceUrl}};case "saml-bearer":return {...e,auth:{type:"saml-bearer",tokenServiceUrl:t.tokenServiceUrl,clientId:t.clientId,issuer:t.issuer,nameIdFormat:t.nameIdFormat,privateKey:t.privateKey,certificate:t.certificate,clockSkew:t.clockSkew,assertionLifetime:t.assertionLifetime}}}}var Q=new AsyncLocalStorage;function Zn(){return randomBytes(6).toString("hex")}function ye(){return Q.getStore()}function Qn(t,e){return Q.run(t,e)}function at(){let t=Q.getStore();if(t)return t.sapCalls.count+=1,t.correlationId}function er(t){let e=Q.getStore();if(!e?.mutatingCalls)return;let n=(t??"get").toLowerCase();n!=="get"&&n!=="head"&&(e.mutatingCalls.count+=1);}function _i(t){if(!t)return;let e=t;try{e=new URL(t,"http://x").pathname;}catch{}let n=decodeURIComponent(e.split("/").filter(Boolean).at(-1)??"");return /^[A-Za-z_][\w.]*\(.*\)$/.test(n)?n:void 0}function Le(t,e){if(!t||typeof t!="object")return;let n=e.toLowerCase();for(let[r,s]of Object.entries(t))if(r.toLowerCase()===n){if(typeof s=="string")return s;if(Array.isArray(s)&&typeof s[0]=="string")return s[0]}}function ct(t){let e=Q.getStore();if(!e?.created)return;let n=_i(t);n&&(e.created.entity=n);}function tr(t=Date.now()){let e=Q.getStore();if(e?.deadline)return Math.max(0,e.deadline-t)}function dt(){return Q.getStore()?.signal?.aborted??false}var F=class extends Error{timedOut;constructor(e,n){super(e?`Zeitbudget f\xFCr ${n??"den Tool-Aufruf"} \xFCberschritten \u2014 abgebrochen.`:`Client hat die Verbindung verworfen \u2014 ${n??"der Tool-Aufruf"} wurde abgebrochen.`),this.name="ToolCallAbortedError",this.timedOut=e;}};function lt(){let t=Q.getStore();if(!t?.signal?.aborted)return;let e=t.signal.reason?.name==="TimeoutError";throw new F(e,t.toolName)}function nr(t,e){if(!e||e<=0)return {signal:t,deadline:void 0};let n=AbortSignal.timeout(e),r=Date.now()+e;return t?{signal:AbortSignal.any([t,n]),deadline:r}:{signal:n,deadline:r}}function Se(t){if(t==null)return {code:"UNKNOWN",message:"Unknown SAP error",details:[],rawResponse:t};if(typeof t=="string")return {code:"UNKNOWN",message:t,details:[],rawResponse:t};let n=t.error;if(!n)return {code:"UNKNOWN",message:"Unknown SAP error",details:[],rawResponse:t};let r=n.message,s;r&&typeof r=="object"&&"value"in r?s=r.value??"Unknown error":typeof r=="string"?s=r:s="Unknown error";let a=(n.innererror?.errordetails??[]).map(d=>({code:d.code??"",message:d.message??"",severity:d.severity??"error",target:d.target}));return {code:n.code??"UNKNOWN",message:s,target:n.target,details:a,rawResponse:t}}function sn(t){if(typeof t!="string")return false;let e=t.trimStart().slice(0,200).toLowerCase();return e.startsWith("<!doctype")||e.startsWith("<html")||e.includes("<title")}function on(t){let e=ce(t).toLowerCase();return /anmeldung fehlgeschlagen|anmeldefehler|logon (error|failed)|login failed|unauthori[sz]ed/.test(e)}var an="Benutzer und Passwort pr\xFCfen. Ist sap-client gesetzt? Ohne Mandant lehnt das Gateway die Anmeldung ebenfalls ab. Bei pers\xF6nlicher Anmeldung (user-basic): SAP-Benutzer/-Passwort im n8n-Credential pr\xFCfen \u2014 und nicht mehrfach probieren, SAP sperrt die Kennung nach wenigen Fehlversuchen.";function Ii(t){return /no authorization for operation\s+\d+\s+on object/i.test(t)}var Ni="SAP-KBA 3421507 nennt daf\xFCr zwei Ursachen, und keine ist die Berechtigung: (1) der Objektschl\xFCssel ist falsch formatiert \u2014 er geht zehnstellig mit f\xFChrenden Nullen hinaus, z. B. 0000012345 statt 12345; (2) der BusinessObjectTypeName passt nicht zum Objekt (Kundenauftrag: BUS2032). Dritte M\xF6glichkeit: Kopfzeile gegen Abfrageparameter verwechselt \u2014 beim schreibenden POST sind es Kopfzeilen, beim lesenden Aufruf Abfrageparameter. Erst danach lohnt der Blick in PFCG/SU53.";function ce(t){let e=/<title[^>]*>([^<]{1,200})<\/title>/i.exec(t)?.[1]?.trim();return e||t.replace(/<script[\s\S]*?<\/script>/gi," ").replace(/<style[\s\S]*?<\/style>/gi," ").replace(/<[^>]+>/g," ").replace(/\s+/g," ").trim().slice(0,200)||"HTML-Seite ohne verwertbaren Text"}function Di(t){return /\/IW[A-Z]+\/[A-Z_]+\/\d+/i.exec(t)?.[0]}var xi=new Set(["UNABLE_TO_GET_ISSUER_CERT_LOCALLY","UNABLE_TO_VERIFY_LEAF_SIGNATURE","SELF_SIGNED_CERT_IN_CHAIN","DEPTH_ZERO_SELF_SIGNED_CERT","CERT_UNTRUSTED"]);function Mi(t){let e=t?.code;if(typeof e=="string")return e;let n=t?.cause;if(typeof n?.code=="string")return n.code}function Ui(t){let n=(t?.cause?.cert??t?.cert)?.issuer?.CN;return typeof n=="string"?n:void 0}function be(t,e){if(t instanceof F)return {code:t.timedOut?"TOOL_TIMEOUT":"ABORTED",message:t.message};let n=Mi(t);if(n&&xi.has(n)){let i=Ui(t);return {code:"TLS_CHAIN_INCOMPLETE",message:i?`Die Zertifikatskette ist nicht vollst\xE4ndig verifizierbar (${n}). Aussteller: ${i}.`:`Die Zertifikatskette ist nicht vollst\xE4ndig verifizierbar (${n}).`,guidance:"Root-CA \xFCber SAP_CA_CERT=<pfad> einbinden (intern NODE_EXTRA_CA_CERTS). Welches Zertifikat fehlt, zeigt `test-connection` (Stufe TLS) oder `openssl s_client -connect <host>:<port> -showcerts`. SAP_TLS_VERIFY=false ist kein Ersatz \u2014 es schaltet die Pr\xFCfung nur ab."}}if(n==="ENOTFOUND"||n==="EAI_AGAIN")return {code:"DNS_FAILED",message:`Der SAP-Host ist nicht aufl\xF6sbar (${n}).`,guidance:"SAP_BASE_URL pr\xFCfen. Im Container zus\xE4tzlich die DNS-Konfiguration."};if(n==="ECONNREFUSED")return {code:"CONNECTION_REFUSED",message:"Der SAP-Host nimmt keine Verbindung auf dem angegebenen Port an.",guidance:"Port in SAP_BASE_URL pr\xFCfen (HTTPS-Port des ICM, oft 44300 oder 8443)."};if(n==="ECONNABORTED"||n==="ETIMEDOUT")return {code:"TIMEOUT",message:"Das SAP-System hat nicht rechtzeitig geantwortet.",guidance:"Anfrage eingrenzen (top/skip, filter) oder SAP_HTTP_TIMEOUT_MS erh\xF6hen \u2014 aber unterhalb der kleinsten Client-Grenze bleiben."};if(isAxiosError(t)&&t.response)return $i(t.response.status,t.response.data,e);let r=t;if(typeof r?.message=="string"&&r.message.length>0)return sn(r.message)?on(r.message)?{code:"AUTH_FAILED",message:`Anmeldung abgelehnt (SAP-Anmeldeseite: ${ce(r.message)}).`,guidance:an}:{code:"HTML_RESPONSE",message:`SAP hat eine HTML-Seite statt Daten geliefert: ${ce(r.message)}`,guidance:"Meist eine abgelehnte Anmeldung oder ein ung\xFCltiger Pfad. Ist sap-client gesetzt? Ist der Service in /IWFND/MAINT_SERVICE aktiviert?"}:{code:typeof r.code=="string"?r.code:"ERROR",message:r.message};if(t instanceof Error)return sn(t.message)?on(t.message)?{code:"AUTH_FAILED",message:`Anmeldung abgelehnt (SAP-Anmeldeseite: ${ce(t.message)}).`,guidance:an}:{code:"HTML_RESPONSE",message:`SAP hat eine HTML-Seite statt Daten geliefert: ${ce(t.message)}`,guidance:"Meist eine abgelehnte Anmeldung oder ein ung\xFCltiger Pfad. Ist sap-client gesetzt? Ist der Service in /IWFND/MAINT_SERVICE aktiviert?"}:{code:"ERROR",message:t.message};if(typeof t=="string")return {code:"ERROR",message:t};let s=t===void 0?void 0:JSON.stringify(t);return {code:"ERROR",message:s?`Unerwarteter Fehler ohne Meldung: ${s}`:"Der Aufruf schlug fehl, ohne einen Fehler zu hinterlassen. Das Serverlog zeigt unter derselben Korrelations-ID, welche SAP-Aufrufe beteiligt waren."}}function $i(t,e,n){let r=typeof e=="string"?e:JSON.stringify(e??""),s=Di(r);if(s?.toUpperCase().includes("/IWFND/MED/170")){let o=n?.serviceUrl?`Service ${n.serviceUrl}`:"Der Service";return {code:"SERVICE_NOT_REGISTERED",httpStatus:t,sapCode:s,message:`${o} ist im Gateway nicht registriert.`,guidance:"Aktivierung in Transaktion /IWFND/MAINT_SERVICE n\xF6tig. Das ist kein Berechtigungsproblem \u2014 PFCG und SU53 f\xFChren hier nicht weiter."}}if(Ii(r))return {code:"MEDIA_OBJECT_MISMATCH",httpStatus:t,...s?{sapCode:s}:{},message:rr(e)??"SAP meldet fehlende Berechtigung f\xFCr das Objekt \u2014 meist ist es aber der Objektschl\xFCssel oder der Objekttyp.",guidance:Ni};if(t===401)return {code:"AUTH_FAILED",httpStatus:401,...s?{sapCode:s}:{},message:"Anmeldung abgelehnt.",guidance:'Ist sap-client gesetzt? Ohne Mandant antwortet das Gateway mit 401 \u201EAnmeldung fehlgeschlagen" statt mit einer Mandantenmeldung. Sonst Benutzer und Passwort pr\xFCfen.'};if(t===403)return {code:"FORBIDDEN",httpStatus:403,...s?{sapCode:s}:{},message:rr(e)??"Zugriff verweigert.",guidance:"Berechtigungen in PFCG pr\xFCfen, Trace \xFCber SU53. Bei OData-Services zus\xE4tzlich das Objekt S_SERVICE."};if(t===404)return {code:"NOT_FOUND",httpStatus:404,...s?{sapCode:s}:{},message:n?.serviceUrl?`Unter ${n.serviceUrl} liegt nichts.`:"Der angeforderte Pfad existiert auf diesem System nicht.",guidance:"Pfad \xFCber sap_discover_services pr\xFCfen. Ein Service kann existieren, aber nicht aktiviert sein (/IWFND/MAINT_SERVICE)."};if(sn(e))return on(e)?{code:"AUTH_FAILED",httpStatus:t,message:`Anmeldung abgelehnt (SAP-Anmeldeseite, HTTP ${t}: ${ce(e)}).`,guidance:an}:{code:"HTML_RESPONSE",httpStatus:t,message:`SAP hat eine HTML-Fehlerseite geliefert (HTTP ${t}): ${ce(e)}`,guidance:"Der Pfad wird von SAP nicht als OData-Service beantwortet. Bei Katalogpfaden sap_discover_services statt sap_query verwenden."};let i=Se(e);return {code:i.code&&i.code!=="UNKNOWN"?i.code:`HTTP_${t}`,httpStatus:t,...s?{sapCode:s}:{},message:i.message&&i.message!=="Unknown error"&&i.message!=="Unknown SAP error"?i.message:`SAP antwortete mit HTTP ${t} ohne verwertbare Fehlermeldung.`,...i.details.length>0?{guidance:i.details.map(o=>`${o.code}: ${o.message}`).join(" | ")}:{}}}function rr(t){let e=Se(t);if(e.message&&!(e.message==="Unknown error"||e.message==="Unknown SAP error"))return e.message}var Fi=5e3;function sr(t){let e=t?.issuer?.CN??t?.issuer?.O;return Array.isArray(e)?e.join(", ")||void 0:typeof e=="string"?e:void 0}function O(t,e,n,r,s){return {stage:t,status:n,detail:r,durationMs:Date.now()-e,...s?.guidance?{guidance:s.guidance}:{},...s?.info?{info:s.info}:{}}}function Hi(t){try{let e=new URL(t),n=e.protocol==="https:";return {host:e.hostname,port:e.port?Number(e.port):n?443:80,isTls:n}}catch{return}}async function ji(t,e){let n=Date.now();try{let{address:r,family:s}=await e(t);return O("dns",n,"ok",`${t} l\xF6st auf ${r} auf.`,{info:{address:r,family:s}})}catch(r){let s=be(r);return O("dns",n,"failed",`${t} ist nicht aufl\xF6sbar.`,{guidance:s.guidance??"SAP_BASE_URL pr\xFCfen. Im Container zus\xE4tzlich die DNS-Konfiguration des Docker-Netzes."})}}async function Vi(t,e,n,r,s){let i=Date.now(),o=a=>new Promise((d,l)=>{let c=s({host:t,port:e,rejectUnauthorized:a,servername:t},()=>{let u=c.getPeerCertificate(true);c.destroy(),d(u);});c.setTimeout(r,()=>{c.destroy(),l(Object.assign(new Error(`TLS-Handshake nach ${r} ms ohne Antwort`),{code:"ETIMEDOUT"}));}),c.on("error",u=>{c.destroy(),l(u);});});try{let a=await o(n),d=sr(a);return O("tls",i,"ok",n?`TLS-Verbindung steht, Zertifikatskette ist verifizierbar.${d?` Aussteller: ${d}.`:""}`:`TLS-Verbindung steht. Die Zertifikatspr\xFCfung ist \xFCber SAP_TLS_VERIFY=false abgeschaltet \u2014 die Kette wurde NICHT verifiziert.${d?` Aussteller: ${d}.`:""}`,{info:{verified:n,...d?{issuer:d}:{},...a?.subject?.CN?{subject:String(a.subject.CN)}:{},...a?.valid_to?{validTo:a.valid_to}:{}}})}catch(a){let d=be(a);if(d.code==="TLS_CHAIN_INCOMPLETE"){let l;try{let c=await o(!1);l=sr(c);}catch{}return O("tls",i,"failed",l?`Die Zertifikatskette ist nicht vollst\xE4ndig verifizierbar. Aussteller des Serverzertifikats: ${l}.`:"Die Zertifikatskette ist nicht vollst\xE4ndig verifizierbar.",{guidance:d.guidance,...l?{info:{issuer:l}}:{}})}return O("tls",i,"failed",d.message,{guidance:d.guidance})}}async function Wi(t,e){let n=Date.now();try{let r=await t.request({method:"get",url:"/sap/opu/odata/IWFND/CATALOGSERVICE;v=2/",headers:{Accept:"application/json"},params:{$format:"json"}});return [O("auth",n,"ok","Anmeldung am Gateway erfolgreich."),O("client",n,"ok",e?`Mandant ${e} wird an jede Anfrage geh\xE4ngt und vom Gateway angenommen.`:"Kein SAP_CLIENT konfiguriert \u2014 das System hat die Anfrage dennoch angenommen. Auf mandantenabh\xE4ngigen Systemen sollte er gesetzt sein.",{info:{sapClient:e??null}}),O("catalog",n,"ok",`Servicekatalog erreichbar (HTTP ${r.status}).`)]}catch(r){let s=be(r),i=s.httpStatus===401||s.code==="AUTH_FAILED";return i&&!e?[O("auth",n,"ok","Zugangsdaten wurden gesendet."),O("client",n,"failed",'Das Gateway lehnt die Anmeldung ab, und SAP_CLIENT ist nicht gesetzt. Gemessen antwortet das Gateway ohne sap-client mit 401 \u201EAnmeldung fehlgeschlagen" statt mit einer Mandantenmeldung.',{guidance:"SAP_CLIENT setzen (z. B. 100) und erneut pr\xFCfen. Bleibt der 401 bestehen, liegt es an Benutzer oder Passwort."}),O("catalog",n,"skipped","Nicht gepr\xFCft \u2014 die Anmeldung scheiterte zuvor.")]:i?[O("auth",n,"failed","Anmeldung abgelehnt.",{guidance:`Benutzer und Passwort pr\xFCfen. Mandant ${e} wird gesendet \u2014 bei Zweifeln in SU01 pr\xFCfen, ob der Benutzer in diesem Mandanten existiert und nicht gesperrt ist.`}),O("client",n,"skipped","Nicht gepr\xFCft \u2014 die Anmeldung scheiterte zuvor."),O("catalog",n,"skipped","Nicht gepr\xFCft \u2014 die Anmeldung scheiterte zuvor.")]:[O("auth",n,"ok","Anmeldung am Gateway erfolgreich."),O("client",n,"ok",e?`Mandant ${e} angenommen.`:"Kein Mandant konfiguriert."),O("catalog",n,"failed",s.message,{guidance:s.guidance??"Katalogdienst in /IWFND/MAINT_SERVICE pr\xFCfen. Der Server probiert drei bekannte Katalogpfade durch."})]}}async function pt(t,e){let n=Date.now(),r=e.budgetMs??Fi,s=e.deps?.lookup??lookup,i=e.deps?.connectTls??connect,o=[],a=Hi(e.baseUrl);if(!a)return o.push(O("dns",n,"failed",`SAP_BASE_URL ist keine g\xFCltige URL: "${e.baseUrl}"`,{guidance:"Erwartet wird etwa https://host.example.com:44300 \u2014 mit Schema und ohne Pfad."}),...["tls","auth","client","catalog"].map(d=>O(d,n,"skipped","Nicht gepr\xFCft \u2014 die Basis-URL ist unbrauchbar."))),ut(o,n);if(o.push(await ji(a.host,s)),o[0].status==="failed")return o.push(...["tls","auth","client","catalog"].map(d=>O(d,n,"skipped","Nicht gepr\xFCft \u2014 der Name war nicht aufl\xF6sbar."))),ut(o,n);if(a.isTls){let d=Math.max(500,r-(Date.now()-n));if(o.push(await Vi(a.host,a.port,e.tlsVerify!==false,d,i)),o[o.length-1].status==="failed")return o.push(...["auth","client","catalog"].map(l=>O(l,n,"skipped","Nicht gepr\xFCft \u2014 die TLS-Stufe scheiterte zuvor."))),ut(o,n)}else o.push(O("tls",n,"skipped","Nicht gepr\xFCft \u2014 SAP_BASE_URL verwendet http, nicht https."));return o.push(...await Wi(t,e.sapClient)),ut(o,n)}function ut(t,e){let n=t.find(r=>r.status==="failed");return {status:n?"failed":"connected",...n?{failedStage:n.stage}:{},stages:t,durationMs:Date.now()-e,timestamp:new Date().toISOString()}}var we=class{constructor(e,n,r,s=60){this.tokenUrl=e;this.clientId=n;this.clientSecret=r;this.bufferSeconds=s;}cachedToken=null;expiresAt=0;pendingFetch=null;async getToken(e){if(this.cachedToken&&Date.now()<this.expiresAt)return this.cachedToken;if(this.pendingFetch)return this.pendingFetch;this.pendingFetch=this.fetchToken();try{return await this.pendingFetch}finally{this.pendingFetch=null;}}async fetchToken(){let e=await dn.post(this.tokenUrl,new URLSearchParams({grant_type:"client_credentials"}),{auth:{username:this.clientId,password:this.clientSecret},headers:{"Content-Type":"application/x-www-form-urlencoded"}}),{access_token:n,expires_in:r}=e.data;return this.cachedToken=n,this.expiresAt=Date.now()+(r-this.bufferSeconds)*1e3,n}};function cn(t){return createHash("sha256").update(t).digest("hex")}var Be=class{constructor(e=100){this.maxSize=e;}cache=new Map;get(e){let n=this.cache.get(e);return n?Date.now()>=n.expiresAt?(this.cache.delete(e),null):(this.cache.delete(e),this.cache.set(e,n),n.token):null}set(e,n,r){if(this.cache.has(e))this.cache.delete(e);else if(this.cache.size>=this.maxSize){let s=this.cache.keys().next().value;s!==void 0&&this.cache.delete(s);}this.cache.set(e,{token:n,expiresAt:r});}},mt=class{clientTokenManager;cache;config;constructor(e){this.config=e,this.clientTokenManager=new we(e.tokenServiceUrl,e.clientId,e.clientSecret),this.cache=new Be;}async getToken(e){if(!e)return this.clientTokenManager.getToken();let n=cn(e),r=this.cache.get(n);return r||this.exchangeToken(e,n)}async exchangeToken(e,n){let r=await this.clientTokenManager.getToken(),s=`${this.config.destinationServiceUrl}/destination-configuration/v1/destinations/${this.config.destinationName}`,o=(await dn.get(s,{headers:{Authorization:`Bearer ${r}`,"X-user-token":e}})).data.authTokens;if(!o?.length)throw new Error(`Destination '${this.config.destinationName}': no authTokens in response`);let a=o[0];if(a.error)throw new Error(`Destination '${this.config.destinationName}' token exchange failed: ${a.error}`);let d=parseInt(a.expires_in,10),l=Number.isFinite(d)&&d>0?d:3600,c=Date.now()+(l-60)*1e3;return this.cache.set(n,a.value,c),a.value}};var Fe=class{constructor(e,n){this.config=e;this.discoveryClient=n;this.bufferSeconds=e.bufferSeconds??60;}cachedToken=null;expiresAt=0;pendingFetch=null;jwks=null;bufferSeconds;async getToken(e){if(this.cachedToken&&Date.now()<this.expiresAt)return this.cachedToken;if(this.pendingFetch)return this.pendingFetch;this.pendingFetch=this.fetchAndValidateToken();try{return await this.pendingFetch}finally{this.pendingFetch=null;}}async fetchAndValidateToken(){let e=await this.discoveryClient.discover(this.config.issuerUrl),n=await dn.post(e.token_endpoint,new URLSearchParams({grant_type:"client_credentials"}),{auth:{username:this.config.clientId,password:this.config.clientSecret},headers:{"Content-Type":"application/x-www-form-urlencoded"}}),{access_token:r,expires_in:s}=n.data;return await this.validateJwt(r,e.jwks_uri,e.issuer),this.cachedToken=r,this.expiresAt=Date.now()+(s-this.bufferSeconds)*1e3,r}async validateJwt(e,n,r){this.jwks||(this.jwks=createRemoteJWKSet(new URL(n)));let{payload:s}=await jwtVerify(e,this.jwks,{issuer:r});return s}};var de=class{constructor(e=36e5){this.ttlMs=e;}cache=new Map;async discover(e){let n=e.replace(/\/+$/,""),r=this.cache.get(n);if(r&&Date.now()<r.expiresAt)return r.document;let s=`${n}/.well-known/openid-configuration`,o=(await dn.get(s,{timeout:1e4,headers:{Accept:"application/json"}})).data;if(!o.token_endpoint||!o.jwks_uri)throw new Error(`OIDC discovery document at ${s} is missing required fields (token_endpoint, jwks_uri)`);return this.cache.set(n,{document:o,expiresAt:Date.now()+this.ttlMs}),o}clearCache(){this.cache.clear();}};var no={email:"urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress",sapUsername:"urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified"};function ir(t,e){if(!t.includes("-----BEGIN")||!t.includes("-----END"))throw new Error(`Invalid PEM format for ${e}. Expected PEM-encoded content starting with -----BEGIN`)}function ro(t){return `<saml:Assertion xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" ID="${t.assertionId}" IssueInstant="${t.authnInstant}" Version="2.0"><saml:Issuer>${t.issuer}</saml:Issuer><saml:Subject><saml:NameID Format="${t.nameIdFormat}">${t.nameId}</saml:NameID><saml:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer"><saml:SubjectConfirmationData NotOnOrAfter="${t.notOnOrAfter}" Recipient="${t.recipient}"/></saml:SubjectConfirmation></saml:Subject><saml:Conditions NotBefore="${t.notBefore}" NotOnOrAfter="${t.notOnOrAfter}"><saml:AudienceRestriction><saml:Audience>${t.audience}</saml:Audience></saml:AudienceRestriction></saml:Conditions><saml:AuthnStatement AuthnInstant="${t.authnInstant}"><saml:AuthnContext><saml:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport</saml:AuthnContextClassRef></saml:AuthnContext></saml:AuthnStatement></saml:Assertion>`}function so(t,e,n){let r=new SignedXml({privateKey:e,publicCert:n});return r.signatureAlgorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256",r.canonicalizationAlgorithm="http://www.w3.org/2001/10/xml-exc-c14n#",r.addReference({xpath:"//*[local-name(.)='Assertion']",digestAlgorithm:"http://www.w3.org/2001/04/xmlenc#sha256",transforms:["http://www.w3.org/2000/09/xmldsig#enveloped-signature","http://www.w3.org/2001/10/xml-exc-c14n#"]}),r.computeSignature(t,{location:{reference:"//*[local-name(.)='Issuer']",action:"after"}}),r.getSignedXml()}var ft=class{cache;config;constructor(e){ir(e.privateKey,"private key"),ir(e.certificate,"certificate"),this.config={...e,clockSkew:e.clockSkew??120,assertionLifetime:e.assertionLifetime??300},this.cache=new Be;}async getToken(e){if(!e)throw new Error("saml-bearer auth requires a user token for principal propagation");let n=cn(e),r=this.cache.get(n);return r||this.exchangeToken(e,n)}resolveNameId(e,n){return n==="email"?e.email??e.sub??"":e.sub??""}async exchangeToken(e,n){let r=decodeJwt(e),s=Date.now(),i=this.resolveNameId({sub:r.sub,email:r.email},this.config.nameIdFormat),o=no[this.config.nameIdFormat],a=new Date(s-this.config.clockSkew*1e3).toISOString(),d=new Date(s+this.config.assertionLifetime*1e3).toISOString(),l=new Date(s).toISOString(),c=ro({assertionId:`_${randomUUID()}`,issuer:this.config.issuer,nameId:i,nameIdFormat:o,recipient:this.config.tokenServiceUrl,audience:this.config.clientId,notBefore:a,notOnOrAfter:d,authnInstant:l}),u=so(c,this.config.privateKey,this.config.certificate),p=Buffer.from(u).toString("base64"),m=await dn.post(this.config.tokenServiceUrl,new URLSearchParams({grant_type:"urn:ietf:params:oauth:grant-type:saml2-bearer",assertion:p,client_id:this.config.clientId}).toString(),{headers:{"Content-Type":"application/x-www-form-urlencoded"}}),{access_token:f,expires_in:g}=m.data,h=typeof g=="number"&&g>0?g:3600,b=Date.now()+(h-60)*1e3;return this.cache.set(n,f,b),f}};var io="[geschwaerzt]",oo=new Set(["accept","accept-encoding","content-type","content-length","if-match","if-none-match","x-http-method","x-requested-with"]);function or(t){let e="'(?:[^']|'')*'",n=new RegExp(`\\b(guid|datetimeoffset|datetime|time|binary|X)${e}|${e}|\\b\\d+(?:\\.\\d+)?[dfmDFM]?\\b`,"gi");return t.replace(n,(r,s)=>s?`${s}'<${s}>'`:r.startsWith("'")?"'<str>'":"<num>")}function ao(t){return t.replace(/\(([^)]*)\)/g,(e,n)=>`(${or(n)})`)}function co(t){if(t===null||typeof t!="object")return t;let e={};for(let[n,r]of Object.entries(t))e[n]=oo.has(n.toLowerCase())?r:io;return e}var gt={paths:["headers","url",'params["$filter"]','params["$search"]'],censor:(t,e)=>{let n=e[e.length-1];return n==="headers"?co(t):typeof t!="string"?t:n==="url"?ao(t):or(t)}};function ar(t){if(t.tlsVerify===false||t.clientCert!==void 0)return new Agent({rejectUnauthorized:t.tlsVerify!==false,...t.clientCert?{cert:t.clientCert}:{},...t.clientKey?{key:t.clientKey}:{},...t.clientKeyPassphrase?{passphrase:t.clientKeyPassphrase}:{}})}var po=3e4,ee=uo({name:"sap-http-client",redact:gt,transport:{target:"pino/file",options:{destination:2}}});function mo(t,e){return typeof t=="string"?t.trimStart().startsWith("<!DOCTYPE"):Buffer.isBuffer(t)?String(e?.["content-type"]??"").includes("text/html")?true:t.subarray(0,32).toString("latin1").trimStart().startsWith("<!DOCTYPE"):false}function fo(t){return t.startsWith("http://")||t.startsWith("https://")}function go(t){let e=t.replace(/\/+$/,"");try{let n=new URL(e),r=n.pathname.replace(/\/+$/,"");return {origin:`${n.protocol}//${n.host}`,path:r}}catch{return {origin:e,path:""}}}var Te=class{constructor(e,n={}){this.destination=e;switch(this.httpsAgent=ar(n),this.requestTimeoutMs=n.requestTimeoutMs??po,e.auth.type){case "oauth2":this.tokenManager=new we(e.auth.tokenServiceUrl,e.auth.clientId,e.auth.clientSecret);break;case "ias":this.tokenManager=new Fe({issuerUrl:e.auth.tenantUrl,clientId:e.auth.clientId,clientSecret:e.auth.clientSecret},new de);break;case "xsuaa":this.tokenManager=new Fe({issuerUrl:e.auth.xsuaaUrl,clientId:e.auth.clientId,clientSecret:e.auth.clientSecret},new de);break;case "btp-principal":this.tokenManager=new mt({destinationName:e.auth.destinationName,destinationServiceUrl:e.auth.destinationServiceUrl,clientId:e.auth.clientId,clientSecret:e.auth.clientSecret,tokenServiceUrl:e.auth.tokenServiceUrl});break;case "saml-bearer":this.tokenManager=new ft({tokenServiceUrl:e.auth.tokenServiceUrl,clientId:e.auth.clientId,issuer:e.auth.issuer,nameIdFormat:e.auth.nameIdFormat,privateKey:e.auth.privateKey,certificate:e.auth.certificate,clockSkew:e.auth.clockSkew,assertionLifetime:e.auth.assertionLifetime});break;default:this.tokenManager=null;}}tokenManager;userContext=null;httpsAgent;requestTimeoutMs;async request(e){lt();let n=e.method!=="get",r=ye(),s=at();er(e.method);let i={...e.params};this.destination.sapClient&&(i["sap-client"]=this.destination.sapClient);let o=e.userContext??this.userContext??void 0,a=await this.buildAuthHeaders(o),d=this.destination.headers??{},l={};if(n){let p=await this.fetchCsrfToken({...d,...a},e.url);p.token&&(l={"x-csrf-token":p.token},p.cookies&&(l.Cookie=p.cookies));}let c={...d,...a,...l,...e.headers},u={method:e.method,url:this.resolveUrl(e.url),data:e.data,headers:c,params:Object.keys(i).length>0?i:void 0,...e.responseType?{responseType:e.responseType}:{},httpsAgent:this.httpsAgent,timeout:this.effectiveTimeoutMs(),signal:r?.signal,beforeRedirect:p=>{this.httpsAgent&&(p.agent=this.httpsAgent);let m=p.headers??{};for(let[f,g]of Object.entries(c))m[f]||(m[f]=g);}};ee.info({...s?{correlationId:s,tool:r?.toolName}:{},...r?.traceId?{traceId:r.traceId}:{},method:u.method,url:u.url,headers:u.headers,params:u.params,hasAuth:!!u.headers.Authorization||!!u.headers.APIKey},"SAP HTTP request outgoing");try{let p=await dn(u);if(ee.info({...s?{correlationId:s}:{},status:p.status,contentType:p.headers["content-type"]},"SAP HTTP response OK"),mo(p.data,p.headers))throw new Error("SAP returned an HTML page instead of JSON. This usually means authentication failed or the URL path is invalid.");return {data:p.data,headers:p.headers,status:p.status}}catch(p){if(isAxiosError(p)&&p.response){let m=e.expectedStatuses?.includes(p.response.status)??false;(m?ee.info.bind(ee):ee.error.bind(ee))({...s?{correlationId:s}:{},status:p.response.status,statusText:p.response.statusText,contentType:p.response.headers?.["content-type"],url:u.url,...m?{expected:true}:{},dataType:typeof p.response.data,dataLength:typeof p.response.data=="string"?p.response.data.length:void 0},m?"SAP HTTP response (expected)":"SAP HTTP response ERROR");}else p instanceof Error&&ee.error({message:p.message,name:p.name},"SAP HTTP connection error");if(n&&this.isCsrf403(p)){lt();try{let m=await this.fetchCsrfToken({...d,...a},e.url),f={...u.headers};m.token&&(f["x-csrf-token"]=m.token,m.cookies&&(f.Cookie=m.cookies)),at();let g=await dn({...u,headers:f});return {data:g.data,headers:g.headers,status:g.status}}catch(m){throw this.toSapError(m)}}throw this.toSapError(p)}}async buildAuthHeaders(e){switch(this.destination.auth.type){case "basic":return {Authorization:`Basic ${Buffer.from(`${this.destination.auth.username}:${this.destination.auth.password}`).toString("base64")}`};case "saml-bearer":case "btp-principal":case "oauth2":case "ias":case "xsuaa":return {Authorization:`Bearer ${await this.tokenManager.getToken(e?.token)}`};case "apikey":return {APIKey:this.destination.auth.apiKey};default:return {}}}resolveUrl(e){if(fo(e))return e;let{origin:n,path:r}=go(this.destination.url);return r&&(e===r||e.startsWith(`${r}/`))?`${n}${e}`:`${this.destination.url}${e}`}async fetchCsrfToken(e,n){let r=this.destination.url,s=[];if(n){let i=n.replace(/\/[^/]*$/,"/");i!=="/"&&i!==n&&s.push(this.resolveUrl(i));}s.push(`${r}/`,r);for(let i of s){lt(),at();try{let o={...e,"x-csrf-token":"fetch"},a={};this.destination.sapClient&&(a["sap-client"]=this.destination.sapClient);let d=await dn.get(i,{headers:o,params:Object.keys(a).length>0?a:void 0,validateStatus:()=>!0,timeout:this.effectiveTimeoutMs(),signal:ye()?.signal,httpsAgent:this.httpsAgent,beforeRedirect:c=>{this.httpsAgent&&(c.agent=this.httpsAgent);let u=c.headers??{};for(let[p,m]of Object.entries(o))u[p]||(u[p]=m);}}),l=d.headers["x-csrf-token"];if(ee.debug({url:i,status:d.status,hasToken:!!l},"CSRF token fetch result"),l&&l.toLowerCase()!=="required"){let u=(d.headers["set-cookie"]??[]).map(p=>p.split(";")[0]).join("; ");return {token:l,cookies:u}}}catch{}}return {token:"",cookies:""}}isCsrf403(e){return isAxiosError(e)&&e.response?.status===403}effectiveTimeoutMs(){let e=tr();return e===void 0?this.requestTimeoutMs:Math.max(1,Math.min(this.requestTimeoutMs,e))}toSapError(e){if(e instanceof F)return {code:e.timedOut?"TOOL_TIMEOUT":"ABORTED",message:e.message,details:[],rawResponse:void 0};if(isAxiosError(e)&&(e.code==="ERR_CANCELED"||e.name==="CanceledError")){let n=ye()?.signal?.reason?.name==="TimeoutError";return {code:n?"TOOL_TIMEOUT":"ABORTED",message:n?"Zeitbudget des Tool-Aufrufs \xFCberschritten \u2014 laufender SAP-Aufruf abgebrochen.":"Client hat die Verbindung verworfen \u2014 laufender SAP-Aufruf abgebrochen.",details:[],rawResponse:void 0}}return isAxiosError(e)&&(e.code==="ECONNABORTED"||e.code==="ETIMEDOUT")?{code:"TIMEOUT",message:`SAP request exceeded ${this.requestTimeoutMs} ms (SAP_HTTP_TIMEOUT_MS): ${e.message}`,details:[],rawResponse:void 0}:isAxiosError(e)&&e.response?Se(e.response.data):e instanceof Error?{code:"CONNECTION_ERROR",message:e.message,details:[],rawResponse:void 0}:Se(e)}};function cr(t,e){e||t.warn({sapClient:null},'SAP_CLIENT ist nicht gesetzt. Auf mandantenabh\xE4ngigen Systemen antwortet das Gateway ohne sap-client mit 401 \u201EAnmeldung fehlgeschlagen" \u2014 was wie ein falsches Passwort aussieht, aber keines ist. Bei Anmeldeproblemen zuerst SAP_CLIENT setzen (z. B. 100).');}async function dr(t,e,n,r){try{let s=new Te(ot(e),n),i=await pt(s,{baseUrl:e.baseUrl,sapClient:e.sapClient,tlsVerify:n.tlsVerify,...r?{deps:r}:{}});for(let o of i.stages){let a={stage:o.stage,status:o.status,durationMs:o.durationMs,...o.info??{},...o.guidance?{guidance:o.guidance}:{}};o.status==="failed"?t.warn(a,`Selbsttest ${o.stage}: ${o.detail}`):t.info(a,`Selbsttest ${o.stage}: ${o.detail}`);}i.status==="connected"?t.info({durationMs:i.durationMs,sapClient:e.sapClient??null},"Selbsttest bestanden: Namensaufl\xF6sung, TLS, Anmeldung, Mandant und Katalog sind in Ordnung"):t.warn({failedStage:i.failedStage,durationMs:i.durationMs},`Selbsttest gescheitert in Stufe \u201E${i.failedStage}". Der Server l\xE4uft weiter \u2014 Tool-Aufrufe werden bis zur Behebung fehlschlagen. Einzelheiten liefert das Tool test-connection.`);}catch(s){t.warn({err:s instanceof Error?s.message:String(s)},"Selbsttest konnte nicht ausgef\xFChrt werden. Der Server l\xE4uft weiter.");}}function le(t){return `/Date(${Date.parse(t.length===10?`${t}T00:00:00Z`:t)})/`}var T=(t,e,n,r=true)=>({name:t,type:"Edm.String",maxLength:e,...n?{label:n}:{},nullable:r}),je=(t,e,n=15,r=3)=>({name:t,type:"Edm.Decimal",precision:n,scale:r,...e?{label:e}:{}}),ue=(t,e)=>({name:t,type:"Edm.DateTime",precision:7,...e?{label:e}:{}}),lr=(t,e)=>({name:t,type:"Edm.Boolean",...e?{label:e}:{}}),pn="/sap/opu/odata/sap",ho={technicalName:"API_BUSINESS_PARTNER",title:"Business Partner (A2X)",description:"Business partners, customers and suppliers with their addresses.",path:`${pn}/API_BUSINESS_PARTNER`,namespace:"API_BUSINESS_PARTNER",entityTypes:[{set:"A_BusinessPartner",keys:["BusinessPartner"],autoKey:{prefix:"10",width:7},properties:[T("BusinessPartner",10,"Business Partner",false),T("Customer",10,"Customer"),T("Supplier",10,"Supplier"),T("BusinessPartnerCategory",1,"BP Category"),T("BusinessPartnerFullName",81,"Full Name"),T("BusinessPartnerName",81,"Name"),T("OrganizationBPName1",40,"Organization Name 1"),T("FirstName",40,"First Name"),T("LastName",40,"Last Name"),T("BusinessPartnerGrouping",4,"Grouping"),T("SearchTerm1",20,"Search Term"),T("Industry",4,"Industry"),T("CreatedByUser",12,"Created By"),ue("CreationDate","Created On"),lr("IsMarkedForArchiving","Archiving Flag")],navigations:[{name:"to_BusinessPartnerAddress",target:"A_BusinessPartnerAddress",multiplicity:"*",join:[["BusinessPartner","BusinessPartner"]]}]},{set:"A_BusinessPartnerAddress",keys:["BusinessPartner","AddressID"],autoKey:{prefix:"2",width:5},properties:[T("BusinessPartner",10,"Business Partner",false),T("AddressID",10,"Address ID",false),ue("ValidityStartDate","Valid From"),ue("ValidityEndDate","Valid To"),T("StreetName",60,"Street"),T("HouseNumber",10,"House Number"),T("PostalCode",10,"Postal Code"),T("CityName",40,"City"),T("Country",3,"Country"),T("Region",3,"Region"),T("Language",2,"Language")],navigations:[{name:"to_BusinessPartner",target:"A_BusinessPartner",multiplicity:"1",join:[["BusinessPartner","BusinessPartner"]]}]}],functionImports:[]},yo={technicalName:"API_SALES_ORDER_SRV",title:"Sales Order (A2X)",description:"Sales orders with items \u2014 read, create (deep insert), change, release.",path:`${pn}/API_SALES_ORDER_SRV`,namespace:"API_SALES_ORDER_SRV",entityTypes:[{set:"A_SalesOrder",keys:["SalesOrder"],autoKey:{prefix:"45",width:7},properties:[T("SalesOrder",10,"Sales Order",false),T("SalesOrderType",4,"Order Type"),T("SalesOrganization",4,"Sales Organization"),T("DistributionChannel",2,"Distribution Channel"),T("OrganizationDivision",2,"Division"),T("SoldToParty",10,"Sold-to Party"),T("PurchaseOrderByCustomer",35,"Customer Reference"),T("CreatedByUser",12,"Created By"),ue("CreationDate","Created On"),ue("LastChangeDateTime","Last Changed"),ue("RequestedDeliveryDate","Requested Delivery Date"),je("TotalNetAmount","Net Value",16,3),T("TransactionCurrency",5,"Currency"),T("OverallSDProcessStatus",1,"Overall Status"),T("OverallDeliveryStatus",1,"Delivery Status")],navigations:[{name:"to_Item",target:"A_SalesOrderItem",multiplicity:"*",join:[["SalesOrder","SalesOrder"]]}]},{set:"A_SalesOrderItem",keys:["SalesOrder","SalesOrderItem"],properties:[T("SalesOrder",10,"Sales Order",false),T("SalesOrderItem",6,"Item",false),T("Material",40,"Material"),T("SalesOrderItemText",40,"Item Description"),T("SalesOrderItemCategory",4,"Item Category"),je("RequestedQuantity","Order Quantity",15,3),T("RequestedQuantityUnit",3,"Unit"),je("NetAmount","Net Value",16,3),T("TransactionCurrency",5,"Currency"),T("ProductionPlant",4,"Plant")],navigations:[{name:"to_SalesOrder",target:"A_SalesOrder",multiplicity:"1",join:[["SalesOrder","SalesOrder"]]}]}],functionImports:[{name:"ReleaseSalesOrder",httpMethod:"POST",parameters:[{name:"SalesOrder",type:"Edm.String"}],returnType:"API_SALES_ORDER_SRV.A_SalesOrderType",entitySet:"A_SalesOrder"},{name:"GetOpenSalesOrderCount",httpMethod:"GET",parameters:[{name:"SoldToParty",type:"Edm.String",nullable:true}],returnType:"Edm.Int32"}]},So={technicalName:"API_PRODUCT_SRV",title:"Product Master (A2X)",description:"Products (materials) with descriptions.",path:`${pn}/API_PRODUCT_SRV`,namespace:"API_PRODUCT_SRV",entityTypes:[{set:"A_Product",keys:["Product"],autoKey:{prefix:"DEMO-",width:8},properties:[T("Product",40,"Product",false),T("ProductType",4,"Product Type"),T("ProductGroup",9,"Product Group"),T("BaseUnit",3,"Base Unit"),je("GrossWeight","Gross Weight",13,3),je("NetWeight","Net Weight",13,3),T("WeightUnit",3,"Weight Unit"),T("CreatedByUser",12,"Created By"),ue("CreationDate","Created On"),lr("IsMarkedForDeletion","Deletion Flag")],navigations:[{name:"to_Description",target:"A_ProductDescription",multiplicity:"*",join:[["Product","Product"]]}]},{set:"A_ProductDescription",keys:["Product","Language"],properties:[T("Product",40,"Product",false),T("Language",2,"Language",false),T("ProductDescription",40,"Description")],navigations:[]}],functionImports:[]},ht=[ho,yo,So],ln="MCP_DEMO",bo=[["1000001","2","Nordlicht Maschinenbau GmbH","","Hafenstra\xDFe","12","20457","Hamburg","HH","C","MACH","2024-03-04"],["1000002","2","Weberei Hartmann & S\xF6hne KG","","M\xFChlweg","3","91522","Ansbach","BY","C","TEXT","2024-03-11"],["1000003","2","Fr\xE4nkische Pr\xE4zisionstechnik AG","","Industriestra\xDFe","48","90411","N\xFCrnberg","BY","C","MACH","2024-04-02"],["1000004","2","Altm\xFChl Kunststoffwerk GmbH","","Am Kanal","7","91710","Gunzenhausen","BY","C","CHEM","2024-04-19"],["1000005","2","Seenland Logistik GmbH & Co. KG","","Frankenstra\xDFe","101","91781","Wei\xDFenburg","BY","C","TRAN","2024-05-06"],["1000006","2","Brauerei Hopfenkranz OHG","","Brauhausgasse","2","91154","Roth","BY","C","FOOD","2024-05-21"],["1000007","2","Rothsee Elektronik GmbH","","Gewerbering","15","91126","Schwabach","BY","C","ELEC","2024-06-03"],["1000008","2","Hesselberg Metallbau e.K.","","Bahnhofstra\xDFe","33","91717","Wassertr\xFCdingen","BY","C","MACH","2024-06-17"],["1000009","2","Bavaria Sensorik AG","","Technologiepark","9","91058","Erlangen","BY","C","ELEC","2024-07-01"],["1000010","2","Kastner Werkzeugbau GmbH","","Schmiedeweg","21","90762","F\xFCrth","BY","C","MACH","2024-07-15"],["1000011","2","M\xF6belwerkstatt Lindenhof GmbH","","Lindenallee","5","97070","W\xFCrzburg","BY","C","WOOD","2024-08-05"],["1000012","2","Steinbach Automotive GmbH","","Werkstra\xDFe","60","93055","Regensburg","BY","C","AUTO","2024-08-19"],["1000013","2","Tauber Verpackungen GmbH","","Ringstra\xDFe","18","91541","Rothenburg ob der Tauber","BY","C","PACK","2024-09-02"],["1000014","1","Anna","Berger","Rosenweg","4","96047","Bamberg","BY","C","","2024-09-16"],["1000015","1","Markus","Vogel","Am Stadtpark","11","89073","Ulm","BW","C","","2024-10-07"],["1000016","1","Sabine","Kr\xFCger","Elbchaussee","250","22605","Hamburg","HH","C","","2024-10-21"],["1000017","2","Ruhrstahl Handels GmbH","","Kruppstra\xDFe","77","45143","Essen","NW","S","META","2024-02-05"],["1000018","2","Elbe Chemie AG","","Chemiepark","1","01067","Dresden","SN","S","CHEM","2024-02-12"],["1000019","2","NordPack Verpackungssysteme GmbH","","Hansaring","40","28195","Bremen","HB","S","PACK","2024-02-19"],["1000020","2","Donau Kunststoffe GmbH","","Donaustra\xDFe","88","94032","Passau","BY","B","CHEM","2024-02-26"]],wo=[["PUMP-100","FERT","PUMPS","ST","42.500","39.800","Kreiselpumpe 100 l/min","Centrifugal pump 100 l/min",1890],["MOTOR-15KW","FERT","DRIVES","ST","118.000","112.500","Drehstrommotor 15 kW","Three-phase motor 15 kW",2450],["SENSOR-T200","HAWA","SENSOR","ST","0.180","0.150","Temperatursensor PT100 -50..200 \xB0C","Temperature sensor PT100 -50..200 \xB0C",64.5],["VALVE-DN50","FERT","VALVES","ST","6.400","6.100","Absperrventil DN50 PN16","Shut-off valve DN50 PN16",312],["HOUSING-AL3","HALB","PARTS","ST","2.900","2.700","Aluminiumgeh\xE4use Gr\xF6\xDFe 3","Aluminium housing size 3",148],["PLC-B200","HAWA","CONTROL","ST","1.100","0.950","Steuerung SPS B200","PLC controller B200",985],["CABLE-5M","HAWA","CABLE","ST","0.600","0.550","Anschlusskabel 5 m geschirmt","Connection cable 5 m shielded",27.9],["FILTER-F40","HAWA","FILTER","ST","0.900","0.800","Filtereinsatz F40","Filter cartridge F40",45],["SEAL-KIT-3","HAWA","PARTS","ST","0.250","0.200","Dichtungssatz Baugr\xF6\xDFe 3","Seal kit size 3",38],["BRACKET-XL","HALB","PARTS","ST","3.300","3.100","Wandhalterung XL verzinkt","Wall bracket XL galvanised",72]],To=[["4500001","1000001","PO-2026-0117","2026-01-08","2026-01-29","C","C",[["PUMP-100",2],["SEAL-KIT-3",4]]],["4500002","1000003","BEST-88123","2026-01-12","2026-02-05","C","C",[["MOTOR-15KW",1],["CABLE-5M",6],["PLC-B200",1]]],["4500003","1000007","RE-2026-014","2026-01-19","2026-02-10","C","C",[["SENSOR-T200",25],["CABLE-5M",25]]],["4500004","1000004","AK-4471","2026-02-02","2026-02-27","C","C",[["VALVE-DN50",8],["SEAL-KIT-3",8]]],["4500005","1000009","BS-2026-0301","2026-02-16","2026-03-13","C","B",[["SENSOR-T200",120],["HOUSING-AL3",40],["BRACKET-XL",40]]],["4500006","1000012","SA-77201","2026-03-03","2026-03-31","B","B",[["MOTOR-15KW",3],["PLC-B200",3],["CABLE-5M",12]]],["4500007","1000010","KW-2026-19","2026-03-10","2026-04-07","B","A",[["PUMP-100",1],["FILTER-F40",10]]],["4500008","1000005","SL-0209","2026-03-24","2026-04-14","B","A",[["BRACKET-XL",30],["HOUSING-AL3",12]]],["4500009","1000002","WH-2026-04","2026-04-06","2026-05-04","B","A",[["MOTOR-15KW",2],["SENSOR-T200",10]]],["4500010","1000014","","2026-04-14","2026-04-28","C","C",[["FILTER-F40",2],["SEAL-KIT-3",1]]],["4500011","1000011","ML-3350","2026-05-05","2026-06-02","A","A",[["VALVE-DN50",4],["PUMP-100",1],["CABLE-5M",4]]],["4500012","1000013","TV-2026-0888","2026-05-18","2026-06-15","A","A",[["PLC-B200",2],["SENSOR-T200",40],["CABLE-5M",40],["BRACKET-XL",8]]],["4500013","1000015","","2026-06-01","2026-06-22","A","A",[["FILTER-F40",5]]],["4500014","1000006","HK-2026-11","2026-06-15","2026-07-13","A","A",[["PUMP-100",3],["VALVE-DN50",6],["SEAL-KIT-3",6]]],["4500015","1000008","HM-0521","2026-07-01","2026-07-29","A","A",[["MOTOR-15KW",1],["HOUSING-AL3",20],["PLC-B200",1]]]];function un(t,e=3){return t.toFixed(e)}function mn(){let t=[],e=[];for(let[d,l,c,u,p,m,f,g,h,b,y,E]of bo){let S=l==="1",v=S?`${c} ${u}`:c;t.push({BusinessPartner:d,Customer:b==="C"||b==="B"?d:"",Supplier:b==="S"||b==="B"?d:"",BusinessPartnerCategory:l,BusinessPartnerFullName:v,BusinessPartnerName:v,OrganizationBPName1:S?"":c,FirstName:S?c:"",LastName:S?u:"",BusinessPartnerGrouping:S?"BP02":"BP01",SearchTerm1:(S?u:c.split(" ")[0]).toUpperCase().slice(0,20),Industry:y,CreatedByUser:ln,CreationDate:le(E),IsMarkedForArchiving:false}),e.push({BusinessPartner:d,AddressID:String(2e4+t.length),ValidityStartDate:le(E),ValidityEndDate:le("9999-12-31"),StreetName:p,HouseNumber:m,PostalCode:f,CityName:g,Country:"DE",Region:h,Language:"DE"});}let n=[],r=[],s=new Map,i=new Map;wo.forEach(([d,l,c,u,p,m,f,g,h],b)=>{s.set(d,h),i.set(d,g),n.push({Product:d,ProductType:l,ProductGroup:c,BaseUnit:u,GrossWeight:p,NetWeight:m,WeightUnit:"KG",CreatedByUser:ln,CreationDate:le(`2023-11-${String(6+b).padStart(2,"0")}`),IsMarkedForDeletion:false}),r.push({Product:d,Language:"DE",ProductDescription:f}),r.push({Product:d,Language:"EN",ProductDescription:g});});let o=[],a=[];for(let[d,l,c,u,p,m,f,g]of To){let h=0;g.forEach(([b,y],E)=>{let S=y*(s.get(b)??0);h+=S,a.push({SalesOrder:d,SalesOrderItem:String((E+1)*10),Material:b,SalesOrderItemText:i.get(b)??b,SalesOrderItemCategory:"TAN",RequestedQuantity:un(y),RequestedQuantityUnit:"ST",NetAmount:un(S),TransactionCurrency:"EUR",ProductionPlant:"1010"});}),o.push({SalesOrder:d,SalesOrderType:"OR",SalesOrganization:"1010",DistributionChannel:"10",OrganizationDivision:"00",SoldToParty:l,PurchaseOrderByCustomer:c,CreatedByUser:ln,CreationDate:le(u),LastChangeDateTime:le(`${u}T09:30:00Z`),RequestedDeliveryDate:le(p),TotalNetAmount:un(h),TransactionCurrency:"EUR",OverallSDProcessStatus:m,OverallDeliveryStatus:f});}return {A_BusinessPartner:t,A_BusinessPartnerAddress:e,A_SalesOrder:o,A_SalesOrderItem:a,A_Product:n,A_ProductDescription:r}}function vo(t){return t.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;")}function Ao(t,e){return `assoc_${t.set}_${e}`}function ur(t){let e=t.namespace,n=[],r=[],s=[];for(let a of t.entityTypes){let d=a.properties.map(c=>{let u=[`Name="${c.name}"`,`Type="${c.type}"`,`Nullable="${c.nullable===false||a.keys.includes(c.name)?"false":"true"}"`];return c.maxLength!==void 0&&u.push(`MaxLength="${c.maxLength}"`),c.precision!==void 0&&u.push(`Precision="${c.precision}"`),c.scale!==void 0&&u.push(`Scale="${c.scale}"`),c.label&&u.push(`sap:label="${vo(c.label)}"`),a.keys.includes(c.name)&&u.push('sap:creatable="true" sap:updatable="false"'),` <Property ${u.join(" ")}/>`}).join(`
5
+ `),l=a.navigations.map(c=>{let u=Ao(a,c.name),p=`FromRole_${u}`,m=`ToRole_${u}`;return r.push(` <Association Name="${u}" sap:content-version="1">
6
6
  <End Type="${e}.${a.set}Type" Multiplicity="1" Role="${p}"/>
7
7
  <End Type="${e}.${c.target}Type" Multiplicity="${c.multiplicity}" Role="${m}"/>
8
8
  </Association>`),s.push(` <AssociationSet Name="${u}" Association="${e}.${u}" sap:creatable="false" sap:updatable="false" sap:deletable="false" sap:content-version="1">
@@ -38,31 +38,31 @@ ${o}`:""}
38
38
  </Schema>
39
39
  </edmx:DataServices>
40
40
  </edmx:Edmx>
41
- `}var x=class extends Error{constructor(e){super(e),this.name="ODataSyntaxError";}},ar=new Set(["and","or","not","eq","ne","gt","ge","lt","le"]);function fo(t){let e=[],n=0;for(;n<t.length;){let r=t[n];if(/\s/.test(r)){n++;continue}if(r==="("){e.push({kind:"lparen"}),n++;continue}if(r===")"){e.push({kind:"rparen"}),n++;continue}if(r===","){e.push({kind:"comma"}),n++;continue}if(r==="'"){let{value:s,end:i}=cr(t,n);e.push({kind:"string",value:s}),n=i;continue}if(/[0-9]/.test(r)||r==="-"&&/[0-9]/.test(t[n+1]??"")){let s=/^-?\d+(?:\.\d+)?(?:[eE][+-]?\d+)?[mMdDfFlL]?/.exec(t.slice(n));if(!s)throw new x(`Ung\xFCltige Zahl an Position ${n}.`);e.push({kind:"number",value:Number(s[0].replace(/[mMdDfFlL]$/,""))}),n+=s[0].length;continue}if(/[A-Za-z_]/.test(r)){let i=/^[A-Za-z_][A-Za-z0-9_./]*/.exec(t.slice(n))[0];if(n+=i.length,t[n]==="'"){let{value:o,end:a}=cr(t,n);n=a;let d=i.toLowerCase();if(d==="datetime"||d==="datetimeoffset"){let l=lr(o);if(Number.isNaN(l))throw new x(`Ung\xFCltiges datetime-Literal '${o}'.`);e.push({kind:"datetime",value:l});}else if(d==="guid"||d==="x"||d==="binary"||d==="time")e.push({kind:"string",value:o});else throw new x(`Unbekanntes Literal-Pr\xE4fix '${i}'.`);continue}e.push({kind:"ident",value:i});continue}throw new x(`Unerwartetes Zeichen '${r}' an Position ${n}.`)}return e}function cr(t,e){let n=e+1,r="";for(;n<t.length;){let s=t[n];if(s==="'"){if(t[n+1]==="'"){r+="'",n+=2;continue}return {value:r,end:n+1}}r+=s,n++;}throw new x("Zeichenkette ohne schlie\xDFendes Apostroph.")}function lr(t){let e=/[zZ]|[+-]\d{2}:\d{2}$/.test(t)?t:`${t}Z`;return Date.parse(e)}var go=new Set(["substringof","startswith","endswith","tolower","toupper"]),ln=class{constructor(e){this.tokens=e;}pos=0;parse(){if(this.tokens.length===0)throw new x("Leerer $filter-Ausdruck.");let e=this.parseOr();if(this.pos<this.tokens.length)throw new x(`Unerwartetes Token nach dem Ausdruck: ${dr(this.peek())}.`);return e}peek(){return this.tokens[this.pos]}isKeyword(e){let n=this.peek();return n?.kind==="ident"&&n.value.toLowerCase()===e}parseOr(){let e=this.parseAnd();for(;this.isKeyword("or");)this.pos++,e={type:"or",left:e,right:this.parseAnd()};return e}parseAnd(){let e=this.parseNot();for(;this.isKeyword("and");)this.pos++,e={type:"and",left:e,right:this.parseNot()};return e}parseNot(){return this.isKeyword("not")?(this.pos++,{type:"not",operand:this.parseNot()}):this.parseComparison()}parseComparison(){let e=this.parsePrimary(),n=this.peek();if(n?.kind==="ident"){let r=n.value.toLowerCase();if(r==="eq"||r==="ne"||r==="gt"||r==="ge"||r==="lt"||r==="le"){this.pos++;let s=this.parsePrimary();return {type:"compare",op:r,left:e,right:s}}if(!ar.has(r))throw new x(`Unbekannter Operator '${n.value}'.`)}return e}parsePrimary(){let e=this.peek();if(!e)throw new x("Ausdruck endet unerwartet.");if(e.kind==="lparen"){this.pos++;let n=this.parseOr();if(this.peek()?.kind!=="rparen")throw new x("Schlie\xDFende Klammer fehlt.");return this.pos++,n}if(e.kind==="string")return this.pos++,{type:"literal",value:e.value};if(e.kind==="number")return this.pos++,{type:"literal",value:e.value};if(e.kind==="datetime")return this.pos++,{type:"literal",value:e.value,datetime:true};if(e.kind==="ident"){let n=e.value.toLowerCase();if(n==="true"||n==="false")return this.pos++,{type:"literal",value:n==="true"};if(n==="null")return this.pos++,{type:"literal",value:null};if(ar.has(n))throw new x(`Operand erwartet, aber '${e.value}' gefunden.`);if(this.pos++,this.peek()?.kind==="lparen"){if(!go.has(n))throw new x(`Unbekannte Funktion '${e.value}'.`);this.pos++;let r=[];if(this.peek()?.kind!=="rparen")for(r.push(this.parseOr());this.peek()?.kind==="comma";)this.pos++,r.push(this.parseOr());if(this.peek()?.kind!=="rparen")throw new x(`Schlie\xDFende Klammer nach ${e.value}(...) fehlt.`);return this.pos++,{type:"call",fn:n,args:r}}return {type:"field",path:e.value}}throw new x(`Unerwartetes Token ${dr(e)}.`)}};function dr(t){if(!t)return "(Ende)";switch(t.kind){case "lparen":return "'('";case "rparen":return "')'";case "comma":return "','";default:return `'${String(t.value)}'`}}var ho=/^\/Date\((-?\d+)(?:[+-]\d{4})?\)\/$/;function yo(t,e){let n=t;for(let r of e.split("/")){if(n===null||typeof n!="object")return null;n=n[r];}return n===void 0?null:n}function z(t,e){switch(t.type){case "and":return Te(z(t.left,e))&&Te(z(t.right,e));case "or":return Te(z(t.left,e))||Te(z(t.right,e));case "not":return !Te(z(t.operand,e));case "literal":return t.datetime?{datetime:t.value}:t.value;case "field":return yo(e,t.path);case "call":{let n=t.args.map(s=>z(s,e)),r=s=>s==null?"":String(s);switch(t.fn){case "substringof":return r(n[1]).includes(r(n[0]));case "startswith":return r(n[0]).startsWith(r(n[1]));case "endswith":return r(n[0]).endsWith(r(n[1]));case "tolower":return r(n[0]).toLowerCase();case "toupper":return r(n[0]).toUpperCase();default:throw new x(`Unbekannte Funktion '${t.fn}'.`)}}case "compare":{let[n,r]=So(z(t.left,e),z(t.right,e));switch(t.op){case "eq":return n===r;case "ne":return n!==r;case "gt":return n!==null&&r!==null&&n>r;case "ge":return n!==null&&r!==null&&n>=r;case "lt":return n!==null&&r!==null&&n<r;case "le":return n!==null&&r!==null&&n<=r}}}}function Te(t){return t===true}function So(t,e){let n=i=>typeof i=="object"&&i!==null&&"datetime"in i;if(n(t)||n(e)){let i=o=>{if(n(o))return o.datetime;if(typeof o=="number")return o;if(typeof o=="string"){let a=ho.exec(o);if(a)return Number(a[1]);let d=lr(o);return Number.isNaN(d)?null:d}return null};return [i(t),i(e)]}let r=i=>{if(typeof i=="number")return i;if(typeof i=="string"&&i.trim()!==""&&!Number.isNaN(Number(i)))return Number(i)};if((typeof t=="number"||typeof e=="number")&&!(t===null||e===null)){let i=r(t),o=r(e);if(i!==void 0&&o!==void 0)return [i,o]}let s=i=>i===void 0?null:typeof i=="object"&&i!==null?String(i):i;return [s(t),s(e)]}function ur(t){let e=new ln(fo(t)).parse();return n=>Te(z(e,n))}var we=class extends Error{constructor(e){super(e),this.name="ODataUrlError";}};function ut(t){let e=t.trim();if(e.startsWith("'"))return bo(e);let n=/^(guid|datetime|datetimeoffset|time|X|binary)'(.*)'$/is.exec(e);return n?n[2].replace(/''/g,"'"):/^-?\d+(\.\d+)?[mMdDfFlL]?$/.test(e)?Number(e.replace(/[mMdDfFlL]$/,"")):e==="true"?true:e==="false"?false:e}function bo(t){if(!t.endsWith("'")||t.length<2)throw new we(`Zeichenkette ohne schlie\xDFendes Apostroph: ${t}`);return t.slice(1,-1).replace(/''/g,"'")}function To(t){let e=un(t);return Ao(e,",").map(r=>{let s=vo(r,"=");return s===-1?{value:ut(r)}:{name:r.slice(0,s).trim(),value:ut(r.slice(s+1))}})}function pn(t){let e=t.replace(/^\/+|\/+$/g,""),n=e.indexOf("("),r=e.indexOf("/"),s,i,o;if(n!==-1&&(r===-1||n<r)){s=e.slice(0,n);let l=wo(e,n);i=To(e.slice(n+1,l)),o=e.slice(l+1);}else r!==-1?(s=e.slice(0,r),o=e.slice(r)):(s=e,o="");let a=o.split("/").map(l=>un(l)).filter(l=>l.length>0),d={entitySet:un(s),segments:a};return i&&(d.key=i),d}function wo(t,e){let n=false;for(let r=e+1;r<t.length;r++){let s=t[r];if(s==="'"){n=!n;continue}if(!n&&s===")")return r}throw new we(`Schlie\xDFende Klammer fehlt in: ${t}`)}function Ao(t,e){let n=[],r="",s=false;for(let i=0;i<t.length;i++){let o=t[i];if(o==="'"){s=!s,r+=o;continue}if(!s&&o===e){n.push(r),r="";continue}r+=o;}return n.push(r),n.filter(i=>i.trim().length>0)}function vo(t,e){let n=false;for(let r=0;r<t.length;r++)if(t[r]==="'")n=!n;else if(!n&&t[r]===e)return r;return -1}function un(t){try{return decodeURIComponent(t)}catch{return t}}var pt="DEMO",gn="demo",hn="100",Fe="/sap/opu/odata/IWFND/CATALOGSERVICE;v=2",Eo="/sap/opu/odata4/",T=class extends Error{constructor(n,r,s,i={}){super(s);this.status=n;this.code=r;this.headers=i;}},mt=class{constructor(e={}){this.options=e;for(let n of lt)for(let r of n.entityTypes)this.types.set(r.set,{type:r,service:n});}data=dn();versions=new Map;csrfToken=randomBytes(16).toString("base64url");cookie=`SAP_SESSIONID_DEMO_100=${randomBytes(12).toString("base64url")}`;types=new Map;nextNumber=new Map;reset(){this.data=dn(),this.versions.clear(),this.nextNumber.clear();}rows(e){return this.data[e]??[]}handle(e){let r={base:this.options.baseUrl??`http://${e.headers.host??"127.0.0.1"}`,inBatch:false};try{return this.dispatch(e,r)}catch(s){return this.errorResponse(s)}}dispatch(e,n){let r=e.method.toUpperCase(),s=new URL(e.url,n.base),i=s.pathname.replace(/\/+$/,"")||"/",o=s.searchParams;n.inBatch||this.checkAuth(e.headers,o);let d=(e.headers["x-csrf-token"]??"").toLowerCase()==="fetch"?{"x-csrf-token":this.csrfToken,"set-cookie":`${this.cookie}; path=/`}:{},l=r==="HEAD",c=l?"GET":r,u=c==="POST"&&(e.headers["x-http-method"]??"").toUpperCase()==="MERGE"?"MERGE":c;if(u!=="GET"&&!n.inBatch&&e.headers["x-csrf-token"]!==this.csrfToken)throw new T(403,"HTTP/403","CSRF token validation failed",{"x-csrf-token":"Required"});let m;if(i===Fe||i.startsWith(`${Fe}/`))m=this.handleCatalog(u,i.slice(Fe.length),o,n);else {if(i.startsWith(Eo))throw new T(404,"HTTP/404",`Resource not found for segment '${i}'`);{let g=lt.find(f=>i===f.path||i.startsWith(`${f.path}/`));if(!g)throw new T(404,"/IWFND/CM_MGW/002",`Resource not found for the segment '${i}'`);m=this.handleService(g,u,i.slice(g.path.length),o,e,n);}}return m.headers={...m.headers,...d},l&&(m.body=""),m}checkAuth(e,n){let r=e.authorization??"",s=`Basic ${Buffer.from(`${this.options.username??pt}:${this.options.password??gn}`).toString("base64")}`,i=a=>new T(401,"HTTP/401",a,{"www-authenticate":'Basic realm="SAP NetWeaver Application Server [DEMO/100]"'});if(r!==s)throw i("Anmeldung fehlgeschlagen");let o=n.get("sap-client");if(o!==(this.options.sapClient??hn))throw i(o?`Mandant ${o} existiert nicht`:"Anmeldung fehlgeschlagen")}handleCatalog(e,n,r,s){if(e!=="GET")throw new T(405,"HTTP/405","Method not allowed on catalog");let i=n.replace(/^\/+/,"");if(i==="")return this.json(200,{d:{EntitySets:["ServiceCollection"]}});if(i==="$metadata")return this.xml(200,'<?xml version="1.0" encoding="utf-8"?><edmx:Edmx Version="1.0" xmlns:edmx="http://schemas.microsoft.com/ado/2007/06/edmx"><edmx:DataServices m:DataServiceVersion="2.0" xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata"><Schema Namespace="CATALOGSERVICE" xmlns="http://schemas.microsoft.com/ado/2008/09/edm"><EntityType Name="Service"><Key><PropertyRef Name="ID"/></Key><Property Name="ID" Type="Edm.String" Nullable="false"/><Property Name="TechnicalServiceName" Type="Edm.String"/><Property Name="Title" Type="Edm.String"/><Property Name="Description" Type="Edm.String"/><Property Name="ServiceUrl" Type="Edm.String"/><Property Name="TechnicalServiceVersion" Type="Edm.String"/></EntityType><EntityContainer Name="CATALOGSERVICE_Entities" m:IsDefaultEntityContainer="true"><EntitySet Name="ServiceCollection" EntityType="CATALOGSERVICE.Service"/></EntityContainer></Schema></edmx:DataServices></edmx:Edmx>');let o=pn(i);if(o.entitySet!=="ServiceCollection")throw new T(404,"/IWFND/CM_MGW/002",`Resource not found for the segment '${i}'`);let a=[...lt].map(u=>({__metadata:{id:`${s.base}${Fe}/ServiceCollection('${u.technicalName}_0001')`,uri:`${s.base}${Fe}/ServiceCollection('${u.technicalName}_0001')`,type:"CATALOGSERVICE.Service"},ID:`${u.technicalName}_0001`,TechnicalServiceName:u.technicalName,Title:u.title,Description:u.description,ServiceUrl:`${s.base}${u.path}`,TechnicalServiceVersion:"0001",MetadataUrl:`${s.base}${u.path}/$metadata`}));if(o.key){let u=String(o.key[0]?.value??""),p=a.find(m=>m.ID===u);if(!p)throw new T(404,"/IWFND/CM_MGW/002",`Service '${u}' not found`);return this.json(200,{d:p})}let d=fr(r),{rows:l,count:c}=mn(a,d);return this.json(200,{d:{results:l,...d.inlinecount==="allpages"?{__count:String(c)}:{}}})}handleService(e,n,r,s,i,o){let a=r.replace(/^\/+/,"");if(a===""){if(n!=="GET")throw new T(405,"HTTP/405","Method not allowed");return this.json(200,{d:{EntitySets:e.entityTypes.map(l=>l.set)}})}if(a==="$metadata")return this.xml(200,or(e));if(a==="$batch"){if(n!=="POST")throw new T(405,"HTTP/405","Method not allowed on $batch");return this.handleBatch(e,i,o)}let d=e.functionImports.find(l=>l.name===a);if(d){if(n!==d.httpMethod&&!(n==="MERGE"&&d.httpMethod==="POST"))throw new T(405,"HTTP/405",`Function import ${d.name} requires ${d.httpMethod}`);return this.handleFunctionImport(e,d.name,s,o)}return this.handleEntity(e,n,a,s,i,o)}handleFunctionImport(e,n,r,s){let i=e.functionImports.find(a=>a.name===n),o={};for(let a of i.parameters){let d=r.get(a.name);if(d===null){if(!a.nullable)throw new T(400,"/IWBEP/CX_MGW_TECH_EXCEPTION",`Parameter '${a.name}' is missing`);continue}o[a.name]=ut(d);}if(n==="ReleaseSalesOrder"){let a=String(o.SalesOrder??""),d=this.rows("A_SalesOrder").find(l=>l.SalesOrder===a);if(!d)throw new T(404,"SD/001",`Sales order ${a} does not exist`);if(d.OverallSDProcessStatus==="C")throw new T(400,"SD/002",`Sales order ${a} is already completed and cannot be released`);return d.OverallSDProcessStatus="B",d.LastChangeDateTime=`/Date(${Date.now()})/`,this.bump("A_SalesOrder",d),this.json(200,{d:this.present(e,this.typeOf("A_SalesOrder"),d,s,{})})}if(n==="GetOpenSalesOrderCount"){let a=o.SoldToParty===void 0?void 0:String(o.SoldToParty),d=this.rows("A_SalesOrder").filter(l=>l.OverallSDProcessStatus!=="C"&&(a===void 0||l.SoldToParty===a)).length;return this.json(200,{d:{GetOpenSalesOrderCount:d}})}throw new T(501,"HTTP/501",`Function import ${n} not implemented`)}handleEntity(e,n,r,s,i,o){let a=i.body,d=i.headers["if-match"],l;try{l=pn(r);}catch(h){throw h instanceof we?new T(400,"/IWCOR/CX_DS_URI_SYNTAX_ERROR",h.message):h}let c=e.entityTypes.find(h=>h.set===l.entitySet);if(!c)throw new T(404,"/IWFND/CM_MGW/002",`Resource not found for the segment '${l.entitySet}'`);let u=fr(s),p=this.rows(c.set),m;if(l.key&&(m=this.find(c,l.key),!m))throw new T(404,"/IWBEP/CM_MGW_RT/020",`Resource not found for the segment '${c.set}'`);let g=[...l.segments],f=false;if(g[g.length-1]==="$count"&&(f=true,g.pop()),g.length>0){if(!m)throw new T(400,"/IWCOR/CX_DS_URI_SYNTAX_ERROR","Navigation requires a key");if(g.length>1)throw new T(501,"HTTP/501","Only one navigation level is supported");let h=c.navigations.find(E=>E.name===g[0]);if(!h)throw new T(404,"/IWFND/CM_MGW/002",`Resource not found for the segment '${g[0]}'`);let S=this.typeOf(h.target),y=this.related(m,h);if(h.multiplicity==="1"){if(m=y[0],!m)throw new T(404,"/IWBEP/CM_MGW_RT/020",`No ${h.target} for this ${c.set}`);c=S,p=[];}else p=y,m=void 0,c=S;}switch(n){case "GET":{if(m){let y=this.json(200,{d:this.present(e,c,m,o,u)});return y.headers.etag=this.etag(c,m),y}if(f){let y=mn(p,{...u,top:void 0,skip:void 0,raw:u.raw});return {status:200,headers:{"content-type":"text/plain"},body:String(y.count)}}let{rows:h,count:S}=mn(p,u);return this.json(200,{d:{results:h.map(y=>this.present(e,c,y,o,u)),...u.inlinecount==="allpages"?{__count:String(S)}:{}}})}case "POST":{if(m||l.key)throw new T(405,"HTTP/405","POST on a single entity is not allowed (use MERGE/PATCH)");if(c.creatable===false)throw new T(405,"HTTP/405",`${c.set} is not creatable`);let h=this.parseBody(a),S=this.create(c,h,o),y=this.json(201,{d:this.present(e,c,S,o,{expand:this.deepExpands(c,h)})});return y.headers.location=this.uri(o,e,c,S),y.headers.etag=this.etag(c,S),y}case "MERGE":case "PATCH":case "PUT":{if(!m)throw new T(405,"HTTP/405",`${n} requires a single entity`);if(c.updatable===false)throw new T(405,"HTTP/405",`${c.set} is not updatable`);this.checkIfMatch(c,m,d);let h=this.parseBody(a);return this.update(c,m,h,n==="PUT"),{status:204,headers:{etag:this.etag(c,m),dataserviceversion:"2.0"},body:""}}case "DELETE":{if(!m)throw new T(405,"HTTP/405","DELETE requires a single entity");if(c.deletable===false)throw new T(405,"HTTP/405",`${c.set} is not deletable`);return this.checkIfMatch(c,m,d),this.remove(c,m),{status:204,headers:{dataserviceversion:"2.0"},body:""}}default:throw new T(405,"HTTP/405",`Method ${n} not allowed`)}}parseBody(e){if(!e||e.trim()==="")throw new T(400,"/IWCOR/CX_DS_BODY_MISSING","Request body is empty");let n;try{n=JSON.parse(e);}catch{throw new T(400,"/IWCOR/CX_DS_JSON_SYNTAX_ERROR","Request body is not valid JSON")}if(n===null||typeof n!="object"||Array.isArray(n))throw new T(400,"/IWCOR/CX_DS_JSON_SYNTAX_ERROR","Request body must be a JSON object");let r=n;return "d"in r&&typeof r.d=="object"&&r.d!==null&&Object.keys(r).length===1?r.d:r}create(e,n,r,s={}){let i={},o=[];for(let[a,d]of Object.entries(n)){if(a==="__metadata")continue;let l=e.navigations.find(u=>u.name===a);if(l){if(l.multiplicity!=="*")continue;let u=Array.isArray(d)?d:d&&typeof d=="object"&&Array.isArray(d.results)?d.results:[];o.push({nav:l,children:u});continue}let c=e.properties.find(u=>u.name===a);if(!c)throw new T(400,"/IWBEP/CX_MGW_TECH_EXCEPTION",`Property '${a}' is invalid`);i[a]=this.coerce(c.name,c.type,d);}Object.assign(i,s);for(let a of e.keys)(i[a]===void 0||i[a]==="")&&(i[a]=this.nextKey(e,a,i));if(this.find(e,e.keys.map(a=>({name:a,value:i[a]}))))throw new T(400,"/IWBEP/CX_MGW_BUSI_EXCEPTION",`${e.set} with this key already exists`);for(let a of e.properties)i[a.name]===void 0&&(i[a.name]=this.emptyValue(a.type));this.defaults(e,i),this.rows(e.set).push(i),this.bump(e.set,i);for(let{nav:a,children:d}of o){let l=this.typeOf(a.target),c={};for(let[u,p]of a.join)c[p]=i[u];for(let u of d)this.create(l,u,r,c);}return this.recalculate(e,i),i}update(e,n,r,s){let i={};for(let[o,a]of Object.entries(r)){if(o==="__metadata"||e.navigations.some(l=>l.name===o))continue;let d=e.properties.find(l=>l.name===o);if(!d)throw new T(400,"/IWBEP/CX_MGW_TECH_EXCEPTION",`Property '${o}' is invalid`);if(e.keys.includes(o)&&this.coerce(o,d.type,a)!==n[o])throw new T(400,"/IWBEP/CX_MGW_BUSI_EXCEPTION",`Key property '${o}' cannot be changed`);i[o]=this.coerce(d.name,d.type,a);}if(s)for(let o of e.properties)!e.keys.includes(o.name)&&!(o.name in i)&&(n[o.name]=this.emptyValue(o.type));if(Object.assign(n,i),(e.set==="A_SalesOrder"||e.set==="A_SalesOrderItem")&&(n.LastChangeDateTime=`/Date(${Date.now()})/`,e.set==="A_SalesOrderItem")){let o=this.rows("A_SalesOrder").find(a=>a.SalesOrder===n.SalesOrder);o&&this.recalculate(this.typeOf("A_SalesOrder"),o);}this.bump(e.set,n);}remove(e,n){let r=this.rows(e.set),s=r.indexOf(n);s!==-1&&r.splice(s,1),this.versions.delete(this.versionKey(e.set,n));for(let i of e.navigations){if(i.multiplicity!=="*")continue;let o=this.typeOf(i.target);for(let a of this.related(n,i))this.remove(o,a);}}checkIfMatch(e,n,r){if(r===void 0||r.trim()==="*")return;let s=this.etag(e,n);if(!r.split(",").map(o=>o.trim()).map(o=>o.startsWith("W/")?o:`W/${o}`).includes(s))throw new T(412,"/IWBEP/CM_MGW_RT/021","The entity has been changed by another user; reload and retry (ETag mismatch)")}handleBatch(e,n,r){let s=n.headers["content-type"]??"",i=/boundary=("?)([^";]+)\1/i.exec(s)?.[2];if(!i||!n.body)throw new T(400,"/IWCOR/CX_DS_BATCH","multipart/mixed body with boundary expected");let o=`batchresponse_${randomUUID()}`,a=[];for(let d of gr(n.body,i)){let l=/content-type:\s*multipart\/mixed;\s*boundary=("?)([^";\r\n]+)\1/i.exec(d);if(l){let c=l[2],u=d.indexOf(`\r
41
+ `}var M=class extends Error{constructor(e){super(e),this.name="ODataSyntaxError";}},pr=new Set(["and","or","not","eq","ne","gt","ge","lt","le"]);function Eo(t){let e=[],n=0;for(;n<t.length;){let r=t[n];if(/\s/.test(r)){n++;continue}if(r==="("){e.push({kind:"lparen"}),n++;continue}if(r===")"){e.push({kind:"rparen"}),n++;continue}if(r===","){e.push({kind:"comma"}),n++;continue}if(r==="'"){let{value:s,end:i}=mr(t,n);e.push({kind:"string",value:s}),n=i;continue}if(/[0-9]/.test(r)||r==="-"&&/[0-9]/.test(t[n+1]??"")){let s=/^-?\d+(?:\.\d+)?(?:[eE][+-]?\d+)?[mMdDfFlL]?/.exec(t.slice(n));if(!s)throw new M(`Ung\xFCltige Zahl an Position ${n}.`);e.push({kind:"number",value:Number(s[0].replace(/[mMdDfFlL]$/,""))}),n+=s[0].length;continue}if(/[A-Za-z_]/.test(r)){let i=/^[A-Za-z_][A-Za-z0-9_./]*/.exec(t.slice(n))[0];if(n+=i.length,t[n]==="'"){let{value:o,end:a}=mr(t,n);n=a;let d=i.toLowerCase();if(d==="datetime"||d==="datetimeoffset"){let l=gr(o);if(Number.isNaN(l))throw new M(`Ung\xFCltiges datetime-Literal '${o}'.`);e.push({kind:"datetime",value:l});}else if(d==="guid"||d==="x"||d==="binary"||d==="time")e.push({kind:"string",value:o});else throw new M(`Unbekanntes Literal-Pr\xE4fix '${i}'.`);continue}e.push({kind:"ident",value:i});continue}throw new M(`Unerwartetes Zeichen '${r}' an Position ${n}.`)}return e}function mr(t,e){let n=e+1,r="";for(;n<t.length;){let s=t[n];if(s==="'"){if(t[n+1]==="'"){r+="'",n+=2;continue}return {value:r,end:n+1}}r+=s,n++;}throw new M("Zeichenkette ohne schlie\xDFendes Apostroph.")}function gr(t){let e=/[zZ]|[+-]\d{2}:\d{2}$/.test(t)?t:`${t}Z`;return Date.parse(e)}var Co=new Set(["substringof","startswith","endswith","tolower","toupper"]),fn=class{constructor(e){this.tokens=e;}pos=0;parse(){if(this.tokens.length===0)throw new M("Leerer $filter-Ausdruck.");let e=this.parseOr();if(this.pos<this.tokens.length)throw new M(`Unerwartetes Token nach dem Ausdruck: ${fr(this.peek())}.`);return e}peek(){return this.tokens[this.pos]}isKeyword(e){let n=this.peek();return n?.kind==="ident"&&n.value.toLowerCase()===e}parseOr(){let e=this.parseAnd();for(;this.isKeyword("or");)this.pos++,e={type:"or",left:e,right:this.parseAnd()};return e}parseAnd(){let e=this.parseNot();for(;this.isKeyword("and");)this.pos++,e={type:"and",left:e,right:this.parseNot()};return e}parseNot(){return this.isKeyword("not")?(this.pos++,{type:"not",operand:this.parseNot()}):this.parseComparison()}parseComparison(){let e=this.parsePrimary(),n=this.peek();if(n?.kind==="ident"){let r=n.value.toLowerCase();if(r==="eq"||r==="ne"||r==="gt"||r==="ge"||r==="lt"||r==="le"){this.pos++;let s=this.parsePrimary();return {type:"compare",op:r,left:e,right:s}}if(!pr.has(r))throw new M(`Unbekannter Operator '${n.value}'.`)}return e}parsePrimary(){let e=this.peek();if(!e)throw new M("Ausdruck endet unerwartet.");if(e.kind==="lparen"){this.pos++;let n=this.parseOr();if(this.peek()?.kind!=="rparen")throw new M("Schlie\xDFende Klammer fehlt.");return this.pos++,n}if(e.kind==="string")return this.pos++,{type:"literal",value:e.value};if(e.kind==="number")return this.pos++,{type:"literal",value:e.value};if(e.kind==="datetime")return this.pos++,{type:"literal",value:e.value,datetime:true};if(e.kind==="ident"){let n=e.value.toLowerCase();if(n==="true"||n==="false")return this.pos++,{type:"literal",value:n==="true"};if(n==="null")return this.pos++,{type:"literal",value:null};if(pr.has(n))throw new M(`Operand erwartet, aber '${e.value}' gefunden.`);if(this.pos++,this.peek()?.kind==="lparen"){if(!Co.has(n))throw new M(`Unbekannte Funktion '${e.value}'.`);this.pos++;let r=[];if(this.peek()?.kind!=="rparen")for(r.push(this.parseOr());this.peek()?.kind==="comma";)this.pos++,r.push(this.parseOr());if(this.peek()?.kind!=="rparen")throw new M(`Schlie\xDFende Klammer nach ${e.value}(...) fehlt.`);return this.pos++,{type:"call",fn:n,args:r}}return {type:"field",path:e.value}}throw new M(`Unerwartetes Token ${fr(e)}.`)}};function fr(t){if(!t)return "(Ende)";switch(t.kind){case "lparen":return "'('";case "rparen":return "')'";case "comma":return "','";default:return `'${String(t.value)}'`}}var Ro=/^\/Date\((-?\d+)(?:[+-]\d{4})?\)\/$/;function Po(t,e){let n=t;for(let r of e.split("/")){if(n===null||typeof n!="object")return null;n=n[r];}return n===void 0?null:n}function Y(t,e){switch(t.type){case "and":return ve(Y(t.left,e))&&ve(Y(t.right,e));case "or":return ve(Y(t.left,e))||ve(Y(t.right,e));case "not":return !ve(Y(t.operand,e));case "literal":return t.datetime?{datetime:t.value}:t.value;case "field":return Po(e,t.path);case "call":{let n=t.args.map(s=>Y(s,e)),r=s=>s==null?"":String(s);switch(t.fn){case "substringof":return r(n[1]).includes(r(n[0]));case "startswith":return r(n[0]).startsWith(r(n[1]));case "endswith":return r(n[0]).endsWith(r(n[1]));case "tolower":return r(n[0]).toLowerCase();case "toupper":return r(n[0]).toUpperCase();default:throw new M(`Unbekannte Funktion '${t.fn}'.`)}}case "compare":{let[n,r]=ko(Y(t.left,e),Y(t.right,e));switch(t.op){case "eq":return n===r;case "ne":return n!==r;case "gt":return n!==null&&r!==null&&n>r;case "ge":return n!==null&&r!==null&&n>=r;case "lt":return n!==null&&r!==null&&n<r;case "le":return n!==null&&r!==null&&n<=r}}}}function ve(t){return t===true}function ko(t,e){let n=i=>typeof i=="object"&&i!==null&&"datetime"in i;if(n(t)||n(e)){let i=o=>{if(n(o))return o.datetime;if(typeof o=="number")return o;if(typeof o=="string"){let a=Ro.exec(o);if(a)return Number(a[1]);let d=gr(o);return Number.isNaN(d)?null:d}return null};return [i(t),i(e)]}let r=i=>{if(typeof i=="number")return i;if(typeof i=="string"&&i.trim()!==""&&!Number.isNaN(Number(i)))return Number(i)};if((typeof t=="number"||typeof e=="number")&&!(t===null||e===null)){let i=r(t),o=r(e);if(i!==void 0&&o!==void 0)return [i,o]}let s=i=>i===void 0?null:typeof i=="object"&&i!==null?String(i):i;return [s(t),s(e)]}function hr(t){let e=new fn(Eo(t)).parse();return n=>ve(Y(e,n))}var Ae=class extends Error{constructor(e){super(e),this.name="ODataUrlError";}};function yt(t){let e=t.trim();if(e.startsWith("'"))return _o(e);let n=/^(guid|datetime|datetimeoffset|time|X|binary)'(.*)'$/is.exec(e);return n?n[2].replace(/''/g,"'"):/^-?\d+(\.\d+)?[mMdDfFlL]?$/.test(e)?Number(e.replace(/[mMdDfFlL]$/,"")):e==="true"?true:e==="false"?false:e}function _o(t){if(!t.endsWith("'")||t.length<2)throw new Ae(`Zeichenkette ohne schlie\xDFendes Apostroph: ${t}`);return t.slice(1,-1).replace(/''/g,"'")}function Oo(t){let e=gn(t);return No(e,",").map(r=>{let s=Do(r,"=");return s===-1?{value:yt(r)}:{name:r.slice(0,s).trim(),value:yt(r.slice(s+1))}})}function hn(t){let e=t.replace(/^\/+|\/+$/g,""),n=e.indexOf("("),r=e.indexOf("/"),s,i,o;if(n!==-1&&(r===-1||n<r)){s=e.slice(0,n);let l=Io(e,n);i=Oo(e.slice(n+1,l)),o=e.slice(l+1);}else r!==-1?(s=e.slice(0,r),o=e.slice(r)):(s=e,o="");let a=o.split("/").map(l=>gn(l)).filter(l=>l.length>0),d={entitySet:gn(s),segments:a};return i&&(d.key=i),d}function Io(t,e){let n=false;for(let r=e+1;r<t.length;r++){let s=t[r];if(s==="'"){n=!n;continue}if(!n&&s===")")return r}throw new Ae(`Schlie\xDFende Klammer fehlt in: ${t}`)}function No(t,e){let n=[],r="",s=false;for(let i=0;i<t.length;i++){let o=t[i];if(o==="'"){s=!s,r+=o;continue}if(!s&&o===e){n.push(r),r="";continue}r+=o;}return n.push(r),n.filter(i=>i.trim().length>0)}function Do(t,e){let n=false;for(let r=0;r<t.length;r++)if(t[r]==="'")n=!n;else if(!n&&t[r]===e)return r;return -1}function gn(t){try{return decodeURIComponent(t)}catch{return t}}var St="DEMO",bn="demo",wn="100",Ve="/sap/opu/odata/IWFND/CATALOGSERVICE;v=2",xo="/sap/opu/odata4/",w=class extends Error{constructor(n,r,s,i={}){super(s);this.status=n;this.code=r;this.headers=i;}},bt=class{constructor(e={}){this.options=e;for(let n of ht)for(let r of n.entityTypes)this.types.set(r.set,{type:r,service:n});}data=mn();versions=new Map;csrfToken=randomBytes(16).toString("base64url");cookie=`SAP_SESSIONID_DEMO_100=${randomBytes(12).toString("base64url")}`;types=new Map;nextNumber=new Map;reset(){this.data=mn(),this.versions.clear(),this.nextNumber.clear();}rows(e){return this.data[e]??[]}handle(e){let r={base:this.options.baseUrl??`http://${e.headers.host??"127.0.0.1"}`,inBatch:false};try{return this.dispatch(e,r)}catch(s){return this.errorResponse(s)}}dispatch(e,n){let r=e.method.toUpperCase(),s=new URL(e.url,n.base),i=s.pathname.replace(/\/+$/,"")||"/",o=s.searchParams;n.inBatch||this.checkAuth(e.headers,o);let d=(e.headers["x-csrf-token"]??"").toLowerCase()==="fetch"?{"x-csrf-token":this.csrfToken,"set-cookie":`${this.cookie}; path=/`}:{},l=r==="HEAD",c=l?"GET":r,u=c==="POST"&&(e.headers["x-http-method"]??"").toUpperCase()==="MERGE"?"MERGE":c;if(u!=="GET"&&!n.inBatch&&e.headers["x-csrf-token"]!==this.csrfToken)throw new w(403,"HTTP/403","CSRF token validation failed",{"x-csrf-token":"Required"});let m;if(i===Ve||i.startsWith(`${Ve}/`))m=this.handleCatalog(u,i.slice(Ve.length),o,n);else {if(i.startsWith(xo))throw new w(404,"HTTP/404",`Resource not found for segment '${i}'`);{let f=ht.find(g=>i===g.path||i.startsWith(`${g.path}/`));if(!f)throw new w(404,"/IWFND/CM_MGW/002",`Resource not found for the segment '${i}'`);m=this.handleService(f,u,i.slice(f.path.length),o,e,n);}}return m.headers={...m.headers,...d},l&&(m.body=""),m}checkAuth(e,n){let r=e.authorization??"",s=`Basic ${Buffer.from(`${this.options.username??St}:${this.options.password??bn}`).toString("base64")}`,i=a=>new w(401,"HTTP/401",a,{"www-authenticate":'Basic realm="SAP NetWeaver Application Server [DEMO/100]"'});if(r!==s)throw i("Anmeldung fehlgeschlagen");let o=n.get("sap-client");if(o!==(this.options.sapClient??wn))throw i(o?`Mandant ${o} existiert nicht`:"Anmeldung fehlgeschlagen")}handleCatalog(e,n,r,s){if(e!=="GET")throw new w(405,"HTTP/405","Method not allowed on catalog");let i=n.replace(/^\/+/,"");if(i==="")return this.json(200,{d:{EntitySets:["ServiceCollection"]}});if(i==="$metadata")return this.xml(200,'<?xml version="1.0" encoding="utf-8"?><edmx:Edmx Version="1.0" xmlns:edmx="http://schemas.microsoft.com/ado/2007/06/edmx"><edmx:DataServices m:DataServiceVersion="2.0" xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata"><Schema Namespace="CATALOGSERVICE" xmlns="http://schemas.microsoft.com/ado/2008/09/edm"><EntityType Name="Service"><Key><PropertyRef Name="ID"/></Key><Property Name="ID" Type="Edm.String" Nullable="false"/><Property Name="TechnicalServiceName" Type="Edm.String"/><Property Name="Title" Type="Edm.String"/><Property Name="Description" Type="Edm.String"/><Property Name="ServiceUrl" Type="Edm.String"/><Property Name="TechnicalServiceVersion" Type="Edm.String"/></EntityType><EntityContainer Name="CATALOGSERVICE_Entities" m:IsDefaultEntityContainer="true"><EntitySet Name="ServiceCollection" EntityType="CATALOGSERVICE.Service"/></EntityContainer></Schema></edmx:DataServices></edmx:Edmx>');let o=hn(i);if(o.entitySet!=="ServiceCollection")throw new w(404,"/IWFND/CM_MGW/002",`Resource not found for the segment '${i}'`);let a=[...ht].map(u=>({__metadata:{id:`${s.base}${Ve}/ServiceCollection('${u.technicalName}_0001')`,uri:`${s.base}${Ve}/ServiceCollection('${u.technicalName}_0001')`,type:"CATALOGSERVICE.Service"},ID:`${u.technicalName}_0001`,TechnicalServiceName:u.technicalName,Title:u.title,Description:u.description,ServiceUrl:`${s.base}${u.path}`,TechnicalServiceVersion:"0001",MetadataUrl:`${s.base}${u.path}/$metadata`}));if(o.key){let u=String(o.key[0]?.value??""),p=a.find(m=>m.ID===u);if(!p)throw new w(404,"/IWFND/CM_MGW/002",`Service '${u}' not found`);return this.json(200,{d:p})}let d=br(r),{rows:l,count:c}=yn(a,d);return this.json(200,{d:{results:l,...d.inlinecount==="allpages"?{__count:String(c)}:{}}})}handleService(e,n,r,s,i,o){let a=r.replace(/^\/+/,"");if(a===""){if(n!=="GET")throw new w(405,"HTTP/405","Method not allowed");return this.json(200,{d:{EntitySets:e.entityTypes.map(l=>l.set)}})}if(a==="$metadata")return this.xml(200,ur(e));if(a==="$batch"){if(n!=="POST")throw new w(405,"HTTP/405","Method not allowed on $batch");return this.handleBatch(e,i,o)}let d=e.functionImports.find(l=>l.name===a);if(d){if(n!==d.httpMethod&&!(n==="MERGE"&&d.httpMethod==="POST"))throw new w(405,"HTTP/405",`Function import ${d.name} requires ${d.httpMethod}`);return this.handleFunctionImport(e,d.name,s,o)}return this.handleEntity(e,n,a,s,i,o)}handleFunctionImport(e,n,r,s){let i=e.functionImports.find(a=>a.name===n),o={};for(let a of i.parameters){let d=r.get(a.name);if(d===null){if(!a.nullable)throw new w(400,"/IWBEP/CX_MGW_TECH_EXCEPTION",`Parameter '${a.name}' is missing`);continue}o[a.name]=yt(d);}if(n==="ReleaseSalesOrder"){let a=String(o.SalesOrder??""),d=this.rows("A_SalesOrder").find(l=>l.SalesOrder===a);if(!d)throw new w(404,"SD/001",`Sales order ${a} does not exist`);if(d.OverallSDProcessStatus==="C")throw new w(400,"SD/002",`Sales order ${a} is already completed and cannot be released`);return d.OverallSDProcessStatus="B",d.LastChangeDateTime=`/Date(${Date.now()})/`,this.bump("A_SalesOrder",d),this.json(200,{d:this.present(e,this.typeOf("A_SalesOrder"),d,s,{})})}if(n==="GetOpenSalesOrderCount"){let a=o.SoldToParty===void 0?void 0:String(o.SoldToParty),d=this.rows("A_SalesOrder").filter(l=>l.OverallSDProcessStatus!=="C"&&(a===void 0||l.SoldToParty===a)).length;return this.json(200,{d:{GetOpenSalesOrderCount:d}})}throw new w(501,"HTTP/501",`Function import ${n} not implemented`)}handleEntity(e,n,r,s,i,o){let a=i.body,d=i.headers["if-match"],l;try{l=hn(r);}catch(h){throw h instanceof Ae?new w(400,"/IWCOR/CX_DS_URI_SYNTAX_ERROR",h.message):h}let c=e.entityTypes.find(h=>h.set===l.entitySet);if(!c)throw new w(404,"/IWFND/CM_MGW/002",`Resource not found for the segment '${l.entitySet}'`);let u=br(s),p=this.rows(c.set),m;if(l.key&&(m=this.find(c,l.key),!m))throw new w(404,"/IWBEP/CM_MGW_RT/020",`Resource not found for the segment '${c.set}'`);let f=[...l.segments],g=false;if(f[f.length-1]==="$count"&&(g=true,f.pop()),f.length>0){if(!m)throw new w(400,"/IWCOR/CX_DS_URI_SYNTAX_ERROR","Navigation requires a key");if(f.length>1)throw new w(501,"HTTP/501","Only one navigation level is supported");let h=c.navigations.find(E=>E.name===f[0]);if(!h)throw new w(404,"/IWFND/CM_MGW/002",`Resource not found for the segment '${f[0]}'`);let b=this.typeOf(h.target),y=this.related(m,h);if(h.multiplicity==="1"){if(m=y[0],!m)throw new w(404,"/IWBEP/CM_MGW_RT/020",`No ${h.target} for this ${c.set}`);c=b,p=[];}else p=y,m=void 0,c=b;}switch(n){case "GET":{if(m){let y=this.json(200,{d:this.present(e,c,m,o,u)});return y.headers.etag=this.etag(c,m),y}if(g){let y=yn(p,{...u,top:void 0,skip:void 0,raw:u.raw});return {status:200,headers:{"content-type":"text/plain"},body:String(y.count)}}let{rows:h,count:b}=yn(p,u);return this.json(200,{d:{results:h.map(y=>this.present(e,c,y,o,u)),...u.inlinecount==="allpages"?{__count:String(b)}:{}}})}case "POST":{if(m||l.key)throw new w(405,"HTTP/405","POST on a single entity is not allowed (use MERGE/PATCH)");if(c.creatable===false)throw new w(405,"HTTP/405",`${c.set} is not creatable`);let h=this.parseBody(a),b=this.create(c,h,o),y=this.json(201,{d:this.present(e,c,b,o,{expand:this.deepExpands(c,h)})});return y.headers.location=this.uri(o,e,c,b),y.headers.etag=this.etag(c,b),y}case "MERGE":case "PATCH":case "PUT":{if(!m)throw new w(405,"HTTP/405",`${n} requires a single entity`);if(c.updatable===false)throw new w(405,"HTTP/405",`${c.set} is not updatable`);this.checkIfMatch(c,m,d);let h=this.parseBody(a);return this.update(c,m,h,n==="PUT"),{status:204,headers:{etag:this.etag(c,m),dataserviceversion:"2.0"},body:""}}case "DELETE":{if(!m)throw new w(405,"HTTP/405","DELETE requires a single entity");if(c.deletable===false)throw new w(405,"HTTP/405",`${c.set} is not deletable`);return this.checkIfMatch(c,m,d),this.remove(c,m),{status:204,headers:{dataserviceversion:"2.0"},body:""}}default:throw new w(405,"HTTP/405",`Method ${n} not allowed`)}}parseBody(e){if(!e||e.trim()==="")throw new w(400,"/IWCOR/CX_DS_BODY_MISSING","Request body is empty");let n;try{n=JSON.parse(e);}catch{throw new w(400,"/IWCOR/CX_DS_JSON_SYNTAX_ERROR","Request body is not valid JSON")}if(n===null||typeof n!="object"||Array.isArray(n))throw new w(400,"/IWCOR/CX_DS_JSON_SYNTAX_ERROR","Request body must be a JSON object");let r=n;return "d"in r&&typeof r.d=="object"&&r.d!==null&&Object.keys(r).length===1?r.d:r}create(e,n,r,s={}){let i={},o=[];for(let[a,d]of Object.entries(n)){if(a==="__metadata")continue;let l=e.navigations.find(u=>u.name===a);if(l){if(l.multiplicity!=="*")continue;let u=Array.isArray(d)?d:d&&typeof d=="object"&&Array.isArray(d.results)?d.results:[];o.push({nav:l,children:u});continue}let c=e.properties.find(u=>u.name===a);if(!c)throw new w(400,"/IWBEP/CX_MGW_TECH_EXCEPTION",`Property '${a}' is invalid`);i[a]=this.coerce(c.name,c.type,d);}Object.assign(i,s);for(let a of e.keys)(i[a]===void 0||i[a]==="")&&(i[a]=this.nextKey(e,a,i));if(this.find(e,e.keys.map(a=>({name:a,value:i[a]}))))throw new w(400,"/IWBEP/CX_MGW_BUSI_EXCEPTION",`${e.set} with this key already exists`);for(let a of e.properties)i[a.name]===void 0&&(i[a.name]=this.emptyValue(a.type));this.defaults(e,i),this.rows(e.set).push(i),this.bump(e.set,i);for(let{nav:a,children:d}of o){let l=this.typeOf(a.target),c={};for(let[u,p]of a.join)c[p]=i[u];for(let u of d)this.create(l,u,r,c);}return this.recalculate(e,i),i}update(e,n,r,s){let i={};for(let[o,a]of Object.entries(r)){if(o==="__metadata"||e.navigations.some(l=>l.name===o))continue;let d=e.properties.find(l=>l.name===o);if(!d)throw new w(400,"/IWBEP/CX_MGW_TECH_EXCEPTION",`Property '${o}' is invalid`);if(e.keys.includes(o)&&this.coerce(o,d.type,a)!==n[o])throw new w(400,"/IWBEP/CX_MGW_BUSI_EXCEPTION",`Key property '${o}' cannot be changed`);i[o]=this.coerce(d.name,d.type,a);}if(s)for(let o of e.properties)!e.keys.includes(o.name)&&!(o.name in i)&&(n[o.name]=this.emptyValue(o.type));if(Object.assign(n,i),(e.set==="A_SalesOrder"||e.set==="A_SalesOrderItem")&&(n.LastChangeDateTime=`/Date(${Date.now()})/`,e.set==="A_SalesOrderItem")){let o=this.rows("A_SalesOrder").find(a=>a.SalesOrder===n.SalesOrder);o&&this.recalculate(this.typeOf("A_SalesOrder"),o);}this.bump(e.set,n);}remove(e,n){let r=this.rows(e.set),s=r.indexOf(n);s!==-1&&r.splice(s,1),this.versions.delete(this.versionKey(e.set,n));for(let i of e.navigations){if(i.multiplicity!=="*")continue;let o=this.typeOf(i.target);for(let a of this.related(n,i))this.remove(o,a);}}checkIfMatch(e,n,r){if(r===void 0||r.trim()==="*")return;let s=this.etag(e,n);if(!r.split(",").map(o=>o.trim()).map(o=>o.startsWith("W/")?o:`W/${o}`).includes(s))throw new w(412,"/IWBEP/CM_MGW_RT/021","The entity has been changed by another user; reload and retry (ETag mismatch)")}handleBatch(e,n,r){let s=n.headers["content-type"]??"",i=/boundary=("?)([^";]+)\1/i.exec(s)?.[2];if(!i||!n.body)throw new w(400,"/IWCOR/CX_DS_BATCH","multipart/mixed body with boundary expected");let o=`batchresponse_${randomUUID()}`,a=[];for(let d of wr(n.body,i)){let l=/content-type:\s*multipart\/mixed;\s*boundary=("?)([^";\r\n]+)\1/i.exec(d);if(l){let c=l[2],u=d.indexOf(`\r
42
42
  \r
43
- `),p=u===-1?"":d.slice(u+4),m=this.snapshot(),g=[],f;for(let h of gr(p,c)){let S=this.runBatchPart(e,h,r);if(S.status>=400){f=S;break}g.push(S);}if(f)this.restore(m),a.push(`--${o}\r
44
- ${fn(f)}`);else {let h=`changesetresponse_${randomUUID()}`,S=g.map(y=>`--${h}\r
45
- ${fn(y)}`);a.push(`--${o}\r
43
+ `),p=u===-1?"":d.slice(u+4),m=this.snapshot(),f=[],g;for(let h of wr(p,c)){let b=this.runBatchPart(e,h,r);if(b.status>=400){g=b;break}f.push(b);}if(g)this.restore(m),a.push(`--${o}\r
44
+ ${Sn(g)}`);else {let h=`changesetresponse_${randomUUID()}`,b=f.map(y=>`--${h}\r
45
+ ${Sn(y)}`);a.push(`--${o}\r
46
46
  Content-Type: multipart/mixed; boundary=${h}\r
47
47
  \r
48
- ${S.join(`\r
48
+ ${b.join(`\r
49
49
  `)}\r
50
50
  --${h}--`);}continue}a.push(`--${o}\r
51
- ${fn(this.runBatchPart(e,d,r))}`);}return a.push(`--${o}--`),{status:202,headers:{"content-type":`multipart/mixed; boundary=${o}`,dataserviceversion:"2.0"},body:`${a.join(`\r
51
+ ${Sn(this.runBatchPart(e,d,r))}`);}return a.push(`--${o}--`),{status:202,headers:{"content-type":`multipart/mixed; boundary=${o}`,dataserviceversion:"2.0"},body:`${a.join(`\r
52
52
  `)}\r
53
- `}}runBatchPart(e,n,r){let s=Ro(n);if(!s)return this.errorResponse(new T(400,"/IWCOR/CX_DS_BATCH","Malformed batch part"));let i=/^https?:\/\//.test(s.url)||s.url.startsWith("/")?s.url:`${e.path}/${s.url}`;try{return this.dispatch({method:s.method,url:i,headers:s.headers,body:s.body},{...r,inBatch:!0})}catch(o){return this.errorResponse(o)}}snapshot(){return {data:Object.fromEntries(Object.entries(this.data).map(([e,n])=>[e,n.map(r=>({...r}))])),versions:new Map(this.versions)}}restore(e){this.data=e.data,this.versions=e.versions;}present(e,n,r,s,i){let o=this.uri(s,e,n,r),a={__metadata:{id:o,uri:o,type:`${e.namespace}.${n.set}Type`,etag:this.etag(n,r)}},d=i.select&&i.select.length>0?new Set(i.select.map(c=>c.split("/")[0])):void 0;if(d){for(let c of d)if(!n.properties.some(u=>u.name===c)&&!n.navigations.some(u=>u.name===c))throw new T(400,"/IWBEP/CX_MGW_TECH_EXCEPTION",`Property '${c}' is invalid for $select`)}for(let c of n.properties)d&&!d.has(c.name)||(a[c.name]=r[c.name]??null);let l=new Set((i.expand??[]).map(c=>c.split("/")[0]));for(let c of l)if(!n.navigations.some(u=>u.name===c))throw new T(400,"/IWBEP/CX_MGW_TECH_EXCEPTION",`Navigation property '${c}' is invalid for $expand`);for(let c of n.navigations)if(!(d&&!d.has(c.name)&&!l.has(c.name)))if(l.has(c.name)){let u=this.typeOf(c.target),p=this.types.get(c.target).service,m=this.related(r,c).map(g=>this.present(p,u,g,s,{}));a[c.name]=c.multiplicity==="*"?{results:m}:m[0]??null;}else a[c.name]={__deferred:{uri:`${o}/${c.name}`}};return a}uri(e,n,r,s){let i=r.keys.length===1?`'${encodeURIComponent(String(s[r.keys[0]]))}'`:r.keys.map(o=>`${o}='${encodeURIComponent(String(s[o]))}'`).join(",");return `${e.base}${n.path}/${r.set}(${i})`}json(e,n){return {status:e,headers:{"content-type":"application/json; charset=utf-8",dataserviceversion:"2.0"},body:JSON.stringify(n)}}xml(e,n){return {status:e,headers:{"content-type":"application/xml",dataserviceversion:"2.0"},body:n}}errorResponse(e){return e instanceof x&&(e=new T(400,"/IWCOR/CX_DS_EXPR_SYNTAX_ERROR",`Invalid $filter: ${e.message}`)),e instanceof T?{status:e.status,headers:{"content-type":"application/json; charset=utf-8",dataserviceversion:"2.0",...e.headers},body:JSON.stringify({error:{code:e.code,message:{lang:"en",value:e.message},innererror:{application:{component_id:"DEMO",service_namespace:"/SAP/",service_id:"MOCK",service_version:"0001"},errordetails:[]}}})}:{status:500,headers:{"content-type":"application/json; charset=utf-8"},body:JSON.stringify({error:{code:"HTTP/500",message:{lang:"en",value:e instanceof Error?e.message:String(e)}}})}}typeOf(e){let n=this.types.get(e);if(!n)throw new T(404,"/IWFND/CM_MGW/002",`Entity set ${e} unknown`);return n.type}find(e,n){let r={};if(n.length===1&&n[0].name===void 0)r[e.keys[0]]=String(n[0].value);else for(let s of n){if(!s.name||!e.keys.includes(s.name))throw new T(400,"/IWCOR/CX_DS_URI_SYNTAX_ERROR",`Invalid key '${s.name??s.value}' for ${e.set}`);r[s.name]=String(s.value);}if(Object.keys(r).length!==e.keys.length)throw new T(400,"/IWCOR/CX_DS_URI_SYNTAX_ERROR",`Key of ${e.set} needs ${e.keys.join(", ")}`);return this.rows(e.set).find(s=>e.keys.every(i=>String(s[i])===r[i]))}related(e,n){return this.rows(n.target).filter(r=>n.join.every(([s,i])=>r[i]===e[s]))}nextKey(e,n,r){if(e.set==="A_SalesOrderItem"&&n==="SalesOrderItem"){let l=this.rows(e.set).filter(c=>c.SalesOrder===r.SalesOrder).reduce((c,u)=>Math.max(c,Number(u.SalesOrderItem)||0),0);return String(l+10)}if(e.set==="A_ProductDescription"&&n==="Language")return "EN";let s=e.autoKey;if(!s)throw new T(400,"/IWBEP/CX_MGW_BUSI_EXCEPTION",`Key '${n}' of ${e.set} is required`);let i=this.nextNumber.get(e.set);if(i===void 0){let d=this.rows(e.set).map(l=>String(l[n])).filter(l=>l.startsWith(s.prefix)).map(l=>Number(l.slice(s.prefix.length))).filter(l=>Number.isFinite(l));i=(d.length>0?Math.max(...d):0)+1;}this.nextNumber.set(e.set,i+1);let o=String(i).padStart(Math.max(1,s.width-s.prefix.length),"0"),a=`${s.prefix}${o}`;return this.rows(e.set).some(d=>String(d[n])===a)?this.nextKey(e,n,r):a}coerce(e,n,r){if(r==null)return null;switch(n){case "Edm.Boolean":if(typeof r=="boolean")return r;if(r==="true"||r==="X")return true;if(r==="false"||r==="")return false;throw new T(400,"/IWCOR/CX_DS_JSON_SYNTAX_ERROR",`Property '${e}' expects a boolean`);case "Edm.Decimal":{let s=Number(r);if(typeof r=="boolean"||Number.isNaN(s))throw new T(400,"/IWCOR/CX_DS_JSON_SYNTAX_ERROR",`Property '${e}' expects a decimal number`);return s.toFixed(3)}case "Edm.Int32":{let s=Number(r);if(!Number.isInteger(s))throw new T(400,"/IWCOR/CX_DS_JSON_SYNTAX_ERROR",`Property '${e}' expects an integer`);return s}case "Edm.DateTime":{if(typeof r=="string"&&/^\/Date\(-?\d+/.test(r))return r;let s=typeof r=="number"?r:Date.parse(String(r));if(Number.isNaN(s))throw new T(400,"/IWCOR/CX_DS_JSON_SYNTAX_ERROR",`Property '${e}' expects a date (ISO 8601 or /Date(ms)/)`);return `/Date(${s})/`}default:return String(r)}}emptyValue(e){switch(e){case "Edm.Boolean":return false;case "Edm.Decimal":return "0.000";case "Edm.Int32":return 0;case "Edm.DateTime":return null;default:return ""}}defaults(e,n){let r=`/Date(${Date.now()})/`;if(e.properties.some(s=>s.name==="CreationDate")&&!n.CreationDate&&(n.CreationDate=r),e.properties.some(s=>s.name==="CreatedByUser")&&!n.CreatedByUser&&(n.CreatedByUser=pt),e.set==="A_SalesOrder"&&(n.SalesOrderType||="OR",n.SalesOrganization||="1010",n.DistributionChannel||="10",n.OrganizationDivision||="00",n.TransactionCurrency||="EUR",n.OverallSDProcessStatus||="A",n.OverallDeliveryStatus||="A",n.LastChangeDateTime||=r),e.set==="A_SalesOrderItem"&&(n.SalesOrderItemCategory||="TAN",n.RequestedQuantityUnit||="ST",n.TransactionCurrency||="EUR",n.ProductionPlant||="1010",!n.SalesOrderItemText)){let s=this.rows("A_ProductDescription").find(i=>i.Product===n.Material&&i.Language==="EN");n.SalesOrderItemText=s?.ProductDescription??n.Material??"";}if(e.set==="A_BusinessPartner"){n.BusinessPartnerCategory||="2";let s=String(n.BusinessPartnerName||n.OrganizationBPName1||`${n.FirstName??""} ${n.LastName??""}`.trim());n.BusinessPartnerName||=s,n.BusinessPartnerFullName||=s,n.BusinessPartnerGrouping||=n.BusinessPartnerCategory==="1"?"BP02":"BP01";}e.set==="A_BusinessPartnerAddress"&&(n.Country||="DE",n.Language||="DE",n.ValidityStartDate||=r,n.ValidityEndDate||="/Date(253402214400000)/"),e.set==="A_Product"&&(n.ProductType||="HAWA",n.BaseUnit||="ST",n.WeightUnit||="KG");}recalculate(e,n){if(e.set!=="A_SalesOrder")return;let s=this.rows("A_SalesOrderItem").filter(i=>i.SalesOrder===n.SalesOrder).reduce((i,o)=>i+Number(o.NetAmount??0),0);n.TotalNetAmount=s.toFixed(3);}versionKey(e,n){let r=this.typeOf(e);return `${e}|${r.keys.map(s=>String(n[s])).join("|")}`}bump(e,n){let r=this.versionKey(e,n);this.versions.set(r,(this.versions.get(r)??1)+1);}etag(e,n){return `W/"${this.versions.get(this.versionKey(e.set,n))??1}"`}deepExpands(e,n){return e.navigations.filter(r=>r.name in n).map(r=>r.name)}};function fr(t){let e=s=>{let i=t.get(s);if(i===null)return;let o=Number(i);if(!Number.isInteger(o)||o<0)throw new T(400,"/IWCOR/CX_DS_URI_SYNTAX_ERROR",`Invalid value '${i}' for ${s}`);return o},n=s=>{let i=t.get(s);if(!(i===null||i.trim()===""))return i.split(",").map(o=>o.trim()).filter(o=>o.length>0)},r=t.get("$inlinecount")??void 0;if(r!==void 0&&r!=="allpages"&&r!=="none")throw new T(400,"/IWCOR/CX_DS_URI_SYNTAX_ERROR",`Invalid value '${r}' for $inlinecount`);return {filter:t.get("$filter")??void 0,orderby:t.get("$orderby")??void 0,top:e("$top"),skip:e("$skip"),select:n("$select"),expand:n("$expand"),inlinecount:r,raw:t}}function mn(t,e){let n=t;if(e.filter&&(n=n.filter(ur(e.filter))),e.orderby){let o=e.orderby.split(",").map(a=>{let[d,l]=a.trim().split(/\s+/);if(!d)throw new T(400,"/IWCOR/CX_DS_URI_SYNTAX_ERROR","Empty $orderby clause");return {field:d,desc:(l??"asc").toLowerCase()==="desc"}});n=[...n].sort((a,d)=>{for(let{field:l,desc:c}of o){let u=Co(a[l],d[l]);if(u!==0)return c?-u:u}return 0});}let r=n.length,s=e.skip??0,i=e.top;return n=n.slice(s,i===void 0?void 0:s+i),{rows:n,count:r}}function Co(t,e){if(t===e)return 0;if(t==null)return -1;if(e==null)return 1;let n=Number(t),r=Number(e),s=typeof t=="string"?/^\/Date\((-?\d+)/.exec(t)?.[1]:void 0,i=typeof e=="string"?/^\/Date\((-?\d+)/.exec(e)?.[1]:void 0;return s!==void 0&&i!==void 0?Number(s)-Number(i):!Number.isNaN(n)&&!Number.isNaN(r)&&String(t).trim()!==""&&String(e).trim()!==""?n-r:String(t)<String(e)?-1:1}function gr(t,e){let n=[],r=`--${e}`,s=t.split(r);for(let i=1;i<s.length;i++){let o=s[i];if(o.startsWith("--"))break;o=o.replace(/^\r?\n/,"").replace(/\r?\n$/,""),o.trim().length>0&&n.push(o);}return n}function Ro(t){let e=t.replace(/\r\n/g,`
53
+ `}}runBatchPart(e,n,r){let s=Uo(n);if(!s)return this.errorResponse(new w(400,"/IWCOR/CX_DS_BATCH","Malformed batch part"));let i=/^https?:\/\//.test(s.url)||s.url.startsWith("/")?s.url:`${e.path}/${s.url}`;try{return this.dispatch({method:s.method,url:i,headers:s.headers,body:s.body},{...r,inBatch:!0})}catch(o){return this.errorResponse(o)}}snapshot(){return {data:Object.fromEntries(Object.entries(this.data).map(([e,n])=>[e,n.map(r=>({...r}))])),versions:new Map(this.versions)}}restore(e){this.data=e.data,this.versions=e.versions;}present(e,n,r,s,i){let o=this.uri(s,e,n,r),a={__metadata:{id:o,uri:o,type:`${e.namespace}.${n.set}Type`,etag:this.etag(n,r)}},d=i.select&&i.select.length>0?new Set(i.select.map(c=>c.split("/")[0])):void 0;if(d){for(let c of d)if(!n.properties.some(u=>u.name===c)&&!n.navigations.some(u=>u.name===c))throw new w(400,"/IWBEP/CX_MGW_TECH_EXCEPTION",`Property '${c}' is invalid for $select`)}for(let c of n.properties)d&&!d.has(c.name)||(a[c.name]=r[c.name]??null);let l=new Set((i.expand??[]).map(c=>c.split("/")[0]));for(let c of l)if(!n.navigations.some(u=>u.name===c))throw new w(400,"/IWBEP/CX_MGW_TECH_EXCEPTION",`Navigation property '${c}' is invalid for $expand`);for(let c of n.navigations)if(!(d&&!d.has(c.name)&&!l.has(c.name)))if(l.has(c.name)){let u=this.typeOf(c.target),p=this.types.get(c.target).service,m=this.related(r,c).map(f=>this.present(p,u,f,s,{}));a[c.name]=c.multiplicity==="*"?{results:m}:m[0]??null;}else a[c.name]={__deferred:{uri:`${o}/${c.name}`}};return a}uri(e,n,r,s){let i=r.keys.length===1?`'${encodeURIComponent(String(s[r.keys[0]]))}'`:r.keys.map(o=>`${o}='${encodeURIComponent(String(s[o]))}'`).join(",");return `${e.base}${n.path}/${r.set}(${i})`}json(e,n){return {status:e,headers:{"content-type":"application/json; charset=utf-8",dataserviceversion:"2.0"},body:JSON.stringify(n)}}xml(e,n){return {status:e,headers:{"content-type":"application/xml",dataserviceversion:"2.0"},body:n}}errorResponse(e){return e instanceof M&&(e=new w(400,"/IWCOR/CX_DS_EXPR_SYNTAX_ERROR",`Invalid $filter: ${e.message}`)),e instanceof w?{status:e.status,headers:{"content-type":"application/json; charset=utf-8",dataserviceversion:"2.0",...e.headers},body:JSON.stringify({error:{code:e.code,message:{lang:"en",value:e.message},innererror:{application:{component_id:"DEMO",service_namespace:"/SAP/",service_id:"MOCK",service_version:"0001"},errordetails:[]}}})}:{status:500,headers:{"content-type":"application/json; charset=utf-8"},body:JSON.stringify({error:{code:"HTTP/500",message:{lang:"en",value:e instanceof Error?e.message:String(e)}}})}}typeOf(e){let n=this.types.get(e);if(!n)throw new w(404,"/IWFND/CM_MGW/002",`Entity set ${e} unknown`);return n.type}find(e,n){let r={};if(n.length===1&&n[0].name===void 0)r[e.keys[0]]=String(n[0].value);else for(let s of n){if(!s.name||!e.keys.includes(s.name))throw new w(400,"/IWCOR/CX_DS_URI_SYNTAX_ERROR",`Invalid key '${s.name??s.value}' for ${e.set}`);r[s.name]=String(s.value);}if(Object.keys(r).length!==e.keys.length)throw new w(400,"/IWCOR/CX_DS_URI_SYNTAX_ERROR",`Key of ${e.set} needs ${e.keys.join(", ")}`);return this.rows(e.set).find(s=>e.keys.every(i=>String(s[i])===r[i]))}related(e,n){return this.rows(n.target).filter(r=>n.join.every(([s,i])=>r[i]===e[s]))}nextKey(e,n,r){if(e.set==="A_SalesOrderItem"&&n==="SalesOrderItem"){let l=this.rows(e.set).filter(c=>c.SalesOrder===r.SalesOrder).reduce((c,u)=>Math.max(c,Number(u.SalesOrderItem)||0),0);return String(l+10)}if(e.set==="A_ProductDescription"&&n==="Language")return "EN";let s=e.autoKey;if(!s)throw new w(400,"/IWBEP/CX_MGW_BUSI_EXCEPTION",`Key '${n}' of ${e.set} is required`);let i=this.nextNumber.get(e.set);if(i===void 0){let d=this.rows(e.set).map(l=>String(l[n])).filter(l=>l.startsWith(s.prefix)).map(l=>Number(l.slice(s.prefix.length))).filter(l=>Number.isFinite(l));i=(d.length>0?Math.max(...d):0)+1;}this.nextNumber.set(e.set,i+1);let o=String(i).padStart(Math.max(1,s.width-s.prefix.length),"0"),a=`${s.prefix}${o}`;return this.rows(e.set).some(d=>String(d[n])===a)?this.nextKey(e,n,r):a}coerce(e,n,r){if(r==null)return null;switch(n){case "Edm.Boolean":if(typeof r=="boolean")return r;if(r==="true"||r==="X")return true;if(r==="false"||r==="")return false;throw new w(400,"/IWCOR/CX_DS_JSON_SYNTAX_ERROR",`Property '${e}' expects a boolean`);case "Edm.Decimal":{let s=Number(r);if(typeof r=="boolean"||Number.isNaN(s))throw new w(400,"/IWCOR/CX_DS_JSON_SYNTAX_ERROR",`Property '${e}' expects a decimal number`);return s.toFixed(3)}case "Edm.Int32":{let s=Number(r);if(!Number.isInteger(s))throw new w(400,"/IWCOR/CX_DS_JSON_SYNTAX_ERROR",`Property '${e}' expects an integer`);return s}case "Edm.DateTime":{if(typeof r=="string"&&/^\/Date\(-?\d+/.test(r))return r;let s=typeof r=="number"?r:Date.parse(String(r));if(Number.isNaN(s))throw new w(400,"/IWCOR/CX_DS_JSON_SYNTAX_ERROR",`Property '${e}' expects a date (ISO 8601 or /Date(ms)/)`);return `/Date(${s})/`}default:return String(r)}}emptyValue(e){switch(e){case "Edm.Boolean":return false;case "Edm.Decimal":return "0.000";case "Edm.Int32":return 0;case "Edm.DateTime":return null;default:return ""}}defaults(e,n){let r=`/Date(${Date.now()})/`;if(e.properties.some(s=>s.name==="CreationDate")&&!n.CreationDate&&(n.CreationDate=r),e.properties.some(s=>s.name==="CreatedByUser")&&!n.CreatedByUser&&(n.CreatedByUser=St),e.set==="A_SalesOrder"&&(n.SalesOrderType||="OR",n.SalesOrganization||="1010",n.DistributionChannel||="10",n.OrganizationDivision||="00",n.TransactionCurrency||="EUR",n.OverallSDProcessStatus||="A",n.OverallDeliveryStatus||="A",n.LastChangeDateTime||=r),e.set==="A_SalesOrderItem"&&(n.SalesOrderItemCategory||="TAN",n.RequestedQuantityUnit||="ST",n.TransactionCurrency||="EUR",n.ProductionPlant||="1010",!n.SalesOrderItemText)){let s=this.rows("A_ProductDescription").find(i=>i.Product===n.Material&&i.Language==="EN");n.SalesOrderItemText=s?.ProductDescription??n.Material??"";}if(e.set==="A_BusinessPartner"){n.BusinessPartnerCategory||="2";let s=String(n.BusinessPartnerName||n.OrganizationBPName1||`${n.FirstName??""} ${n.LastName??""}`.trim());n.BusinessPartnerName||=s,n.BusinessPartnerFullName||=s,n.BusinessPartnerGrouping||=n.BusinessPartnerCategory==="1"?"BP02":"BP01";}e.set==="A_BusinessPartnerAddress"&&(n.Country||="DE",n.Language||="DE",n.ValidityStartDate||=r,n.ValidityEndDate||="/Date(253402214400000)/"),e.set==="A_Product"&&(n.ProductType||="HAWA",n.BaseUnit||="ST",n.WeightUnit||="KG");}recalculate(e,n){if(e.set!=="A_SalesOrder")return;let s=this.rows("A_SalesOrderItem").filter(i=>i.SalesOrder===n.SalesOrder).reduce((i,o)=>i+Number(o.NetAmount??0),0);n.TotalNetAmount=s.toFixed(3);}versionKey(e,n){let r=this.typeOf(e);return `${e}|${r.keys.map(s=>String(n[s])).join("|")}`}bump(e,n){let r=this.versionKey(e,n);this.versions.set(r,(this.versions.get(r)??1)+1);}etag(e,n){return `W/"${this.versions.get(this.versionKey(e.set,n))??1}"`}deepExpands(e,n){return e.navigations.filter(r=>r.name in n).map(r=>r.name)}};function br(t){let e=s=>{let i=t.get(s);if(i===null)return;let o=Number(i);if(!Number.isInteger(o)||o<0)throw new w(400,"/IWCOR/CX_DS_URI_SYNTAX_ERROR",`Invalid value '${i}' for ${s}`);return o},n=s=>{let i=t.get(s);if(!(i===null||i.trim()===""))return i.split(",").map(o=>o.trim()).filter(o=>o.length>0)},r=t.get("$inlinecount")??void 0;if(r!==void 0&&r!=="allpages"&&r!=="none")throw new w(400,"/IWCOR/CX_DS_URI_SYNTAX_ERROR",`Invalid value '${r}' for $inlinecount`);return {filter:t.get("$filter")??void 0,orderby:t.get("$orderby")??void 0,top:e("$top"),skip:e("$skip"),select:n("$select"),expand:n("$expand"),inlinecount:r,raw:t}}function yn(t,e){let n=t;if(e.filter&&(n=n.filter(hr(e.filter))),e.orderby){let o=e.orderby.split(",").map(a=>{let[d,l]=a.trim().split(/\s+/);if(!d)throw new w(400,"/IWCOR/CX_DS_URI_SYNTAX_ERROR","Empty $orderby clause");return {field:d,desc:(l??"asc").toLowerCase()==="desc"}});n=[...n].sort((a,d)=>{for(let{field:l,desc:c}of o){let u=Mo(a[l],d[l]);if(u!==0)return c?-u:u}return 0});}let r=n.length,s=e.skip??0,i=e.top;return n=n.slice(s,i===void 0?void 0:s+i),{rows:n,count:r}}function Mo(t,e){if(t===e)return 0;if(t==null)return -1;if(e==null)return 1;let n=Number(t),r=Number(e),s=typeof t=="string"?/^\/Date\((-?\d+)/.exec(t)?.[1]:void 0,i=typeof e=="string"?/^\/Date\((-?\d+)/.exec(e)?.[1]:void 0;return s!==void 0&&i!==void 0?Number(s)-Number(i):!Number.isNaN(n)&&!Number.isNaN(r)&&String(t).trim()!==""&&String(e).trim()!==""?n-r:String(t)<String(e)?-1:1}function wr(t,e){let n=[],r=`--${e}`,s=t.split(r);for(let i=1;i<s.length;i++){let o=s[i];if(o.startsWith("--"))break;o=o.replace(/^\r?\n/,"").replace(/\r?\n$/,""),o.trim().length>0&&n.push(o);}return n}function Uo(t){let e=t.replace(/\r\n/g,`
54
54
  `),n=/^(GET|POST|PUT|PATCH|DELETE|MERGE|HEAD)\s+(\S+)\s+HTTP\/1\.\d\s*$/im.exec(e);if(!n)return;let r=e.slice(n.index+n[0].length).replace(/^\n/,""),s=r.indexOf(`
55
55
 
56
56
  `),i=s===-1?r:r.slice(0,s),o=s===-1?void 0:r.slice(s+2).trim()||void 0,a={};for(let d of i.split(`
57
- `)){let l=d.indexOf(":");l!==-1&&(a[d.slice(0,l).trim().toLowerCase()]=d.slice(l+1).trim());}return {method:n[1].toUpperCase(),url:n[2],headers:a,body:o}}var Po={200:"OK",201:"Created",202:"Accepted",204:"No Content",400:"Bad Request",401:"Unauthorized",403:"Forbidden",404:"Not Found",405:"Method Not Allowed",412:"Precondition Failed",500:"Internal Server Error",501:"Not Implemented"};function fn(t){let e=["Content-Type: application/http","Content-Transfer-Encoding: binary","",`HTTP/1.1 ${t.status} ${Po[t.status]??""}`.trimEnd()];for(let[n,r]of Object.entries(t.headers))e.push(`${n}: ${r}`);return e.push(`Content-Length: ${Buffer.byteLength(t.body,"utf8")}`),e.push(""),e.push(t.body),e.join(`\r
58
- `)}function hr(t){return {name:"default",baseUrl:t,authType:"basic",username:pt,password:gn,sapClient:hn}}async function yr(t={}){let e=new mt,n=createServer((i,o)=>{let a=[];i.on("data",d=>a.push(d)),i.on("end",()=>{let d={};for(let[c,u]of Object.entries(i.headers))d[c.toLowerCase()]=Array.isArray(u)?u.join(", "):u;let l=e.handle({method:i.method??"GET",url:i.url??"/",headers:d,body:a.length>0?Buffer.concat(a).toString("utf8"):void 0});o.writeHead(l.status,l.headers),o.end(l.body);});});await new Promise((i,o)=>{n.once("error",o),n.listen(t.port??0,"127.0.0.1",()=>i());});let r=n.address(),s=typeof r=="object"&&r!==null?r.port:t.port??0;return {baseUrl:`http://127.0.0.1:${s}`,port:s,mock:e,close:()=>new Promise((i,o)=>{n.close(a=>a?o(a):i());})}}var Z=z$2.object({name:z$2.string().default("default"),baseUrl:z$2.url(),sapClient:z$2.string().optional()}),_o=Z.extend({authType:z$2.literal("basic"),username:z$2.string().min(1),password:z$2.string().min(1)}),Oo=Z.extend({authType:z$2.literal("user-basic")}),Io=Z.extend({authType:z$2.literal("oauth2"),clientId:z$2.string().min(1),clientSecret:z$2.string().min(1),tokenServiceUrl:z$2.url()}),Do=Z.extend({authType:z$2.literal("apikey"),apiKey:z$2.string().min(1)}),No=Z.extend({authType:z$2.literal("ias"),tenantUrl:z$2.url(),clientId:z$2.string().min(1),clientSecret:z$2.string().min(1)}),xo=Z.extend({authType:z$2.literal("xsuaa"),xsuaaUrl:z$2.url(),clientId:z$2.string().min(1),clientSecret:z$2.string().min(1)}),Mo=Z.extend({authType:z$2.literal("btp-principal"),destinationName:z$2.string().min(1),destinationServiceUrl:z$2.url(),clientId:z$2.string().min(1),clientSecret:z$2.string().min(1),tokenServiceUrl:z$2.url()}),Uo=Z.extend({authType:z$2.literal("saml-bearer"),tokenServiceUrl:z$2.url(),clientId:z$2.string().min(1),issuer:z$2.string().min(1),nameIdFormat:z$2.enum(["email","sapUsername"]).default("email"),privateKey:z$2.string().min(1),certificate:z$2.string().min(1),clockSkew:z$2.coerce.number().int().nonnegative().default(120),assertionLifetime:z$2.coerce.number().int().positive().default(300)}),Ae=z$2.discriminatedUnion("authType",[_o,Oo,Io,Do,No,xo,Mo,Uo]);function He(t=process.env){let e={name:t.SAP_CONNECTION_NAME??"default",baseUrl:t.SAP_BASE_URL,authType:t.SAP_AUTH_TYPE?.toLowerCase(),sapClient:t.SAP_CLIENT,username:t.SAP_USERNAME,password:t.SAP_PASSWORD,clientId:t.SAP_CLIENT_ID,clientSecret:t.SAP_CLIENT_SECRET,tokenServiceUrl:t.SAP_TOKEN_SERVICE_URL,apiKey:t.SAP_API_KEY,tenantUrl:t.SAP_TENANT_URL,xsuaaUrl:t.SAP_XSUAA_URL,destinationName:t.SAP_DESTINATION_NAME,destinationServiceUrl:t.SAP_DESTINATION_SERVICE_URL,issuer:t.SAP_ISSUER,nameIdFormat:t.SAP_NAME_ID_FORMAT,privateKey:t.SAP_PRIVATE_KEY,certificate:t.SAP_CERTIFICATE,clockSkew:t.SAP_CLOCK_SKEW,assertionLifetime:t.SAP_ASSERTION_LIFETIME},n=Object.fromEntries(Object.entries(e).filter(([s,i])=>i!==void 0)),r=Ae.safeParse(n);if(!r.success){let s=r.error.issues.map(i=>` - ${i.path.join(".")||"root"}: ${i.message}`).join(`
57
+ `)){let l=d.indexOf(":");l!==-1&&(a[d.slice(0,l).trim().toLowerCase()]=d.slice(l+1).trim());}return {method:n[1].toUpperCase(),url:n[2],headers:a,body:o}}var $o={200:"OK",201:"Created",202:"Accepted",204:"No Content",400:"Bad Request",401:"Unauthorized",403:"Forbidden",404:"Not Found",405:"Method Not Allowed",412:"Precondition Failed",500:"Internal Server Error",501:"Not Implemented"};function Sn(t){let e=["Content-Type: application/http","Content-Transfer-Encoding: binary","",`HTTP/1.1 ${t.status} ${$o[t.status]??""}`.trimEnd()];for(let[n,r]of Object.entries(t.headers))e.push(`${n}: ${r}`);return e.push(`Content-Length: ${Buffer.byteLength(t.body,"utf8")}`),e.push(""),e.push(t.body),e.join(`\r
58
+ `)}function Tr(t){return {name:"default",baseUrl:t,authType:"basic",username:St,password:bn,sapClient:wn}}async function vr(t={}){let e=new bt,n=createServer((i,o)=>{let a=[];i.on("data",d=>a.push(d)),i.on("end",()=>{let d={};for(let[c,u]of Object.entries(i.headers))d[c.toLowerCase()]=Array.isArray(u)?u.join(", "):u;let l=e.handle({method:i.method??"GET",url:i.url??"/",headers:d,body:a.length>0?Buffer.concat(a).toString("utf8"):void 0});o.writeHead(l.status,l.headers),o.end(l.body);});});await new Promise((i,o)=>{n.once("error",o),n.listen(t.port??0,"127.0.0.1",()=>i());});let r=n.address(),s=typeof r=="object"&&r!==null?r.port:t.port??0;return {baseUrl:`http://127.0.0.1:${s}`,port:s,mock:e,close:()=>new Promise((i,o)=>{n.close(a=>a?o(a):i());})}}var te=z$2.object({name:z$2.string().default("default"),baseUrl:z$2.url(),sapClient:z$2.string().optional()}),Bo=te.extend({authType:z$2.literal("basic"),username:z$2.string().min(1),password:z$2.string().min(1)}),Fo=te.extend({authType:z$2.literal("user-basic")}),Ho=te.extend({authType:z$2.literal("oauth2"),clientId:z$2.string().min(1),clientSecret:z$2.string().min(1),tokenServiceUrl:z$2.url()}),jo=te.extend({authType:z$2.literal("apikey"),apiKey:z$2.string().min(1)}),Vo=te.extend({authType:z$2.literal("ias"),tenantUrl:z$2.url(),clientId:z$2.string().min(1),clientSecret:z$2.string().min(1)}),Wo=te.extend({authType:z$2.literal("xsuaa"),xsuaaUrl:z$2.url(),clientId:z$2.string().min(1),clientSecret:z$2.string().min(1)}),Go=te.extend({authType:z$2.literal("btp-principal"),destinationName:z$2.string().min(1),destinationServiceUrl:z$2.url(),clientId:z$2.string().min(1),clientSecret:z$2.string().min(1),tokenServiceUrl:z$2.url()}),qo=te.extend({authType:z$2.literal("saml-bearer"),tokenServiceUrl:z$2.url(),clientId:z$2.string().min(1),issuer:z$2.string().min(1),nameIdFormat:z$2.enum(["email","sapUsername"]).default("email"),privateKey:z$2.string().min(1),certificate:z$2.string().min(1),clockSkew:z$2.coerce.number().int().nonnegative().default(120),assertionLifetime:z$2.coerce.number().int().positive().default(300)}),Ee=z$2.discriminatedUnion("authType",[Bo,Fo,Ho,jo,Vo,Wo,Go,qo]);function We(t=process.env){let e={name:t.SAP_CONNECTION_NAME??"default",baseUrl:t.SAP_BASE_URL,authType:t.SAP_AUTH_TYPE?.toLowerCase(),sapClient:t.SAP_CLIENT,username:t.SAP_USERNAME,password:t.SAP_PASSWORD,clientId:t.SAP_CLIENT_ID,clientSecret:t.SAP_CLIENT_SECRET,tokenServiceUrl:t.SAP_TOKEN_SERVICE_URL,apiKey:t.SAP_API_KEY,tenantUrl:t.SAP_TENANT_URL,xsuaaUrl:t.SAP_XSUAA_URL,destinationName:t.SAP_DESTINATION_NAME,destinationServiceUrl:t.SAP_DESTINATION_SERVICE_URL,issuer:t.SAP_ISSUER,nameIdFormat:t.SAP_NAME_ID_FORMAT,privateKey:t.SAP_PRIVATE_KEY,certificate:t.SAP_CERTIFICATE,clockSkew:t.SAP_CLOCK_SKEW,assertionLifetime:t.SAP_ASSERTION_LIFETIME},n=Object.fromEntries(Object.entries(e).filter(([s,i])=>i!==void 0)),r=Ee.safeParse(n);if(!r.success){let s=r.error.issues.map(i=>` - ${i.path.join(".")||"root"}: ${i.message}`).join(`
59
59
  `);throw new Error(`Invalid SAP connection configuration:
60
60
  ${s}
61
61
 
62
- Set the required SAP_* environment variables.`)}return r.data}var yn=/^[A-Za-z0-9][A-Za-z0-9_.-]{0,63}$/,$o=z$2.enum(["core","odata","idoc","rfc"]),Lo=z$2.object({readOnly:z$2.boolean().optional(),tiers:z$2.array($o).min(1).optional()}).strict(),Bo=z$2.object({hash:z$2.string().regex(/^sha256:[0-9a-f]{64}$/,"muss die Form sha256:<64 hex> haben"),destination:z$2.string().min(1),label:z$2.string().max(200).optional(),policy:Lo.optional(),createdAt:z$2.string().optional(),revoked:z$2.boolean().optional()}).strict(),Fo=z$2.object({version:z$2.literal(1),destinations:z$2.record(z$2.string(),z$2.unknown()),tokens:z$2.array(Bo).default([])}).strict(),Sr=/\$\{([A-Z_][A-Z0-9_]*)\}/g;function Sn(t,e){let n=[],r=s=>{if(typeof s=="string"){let i=[...s.matchAll(Sr)].map(a=>a[1]);if(i.length===0)return s;let o=i.filter(a=>e[a]===void 0);if(o.length>0){for(let a of o)n.includes(a)||n.push(a);return s}return s.replace(Sr,(a,d)=>e[d]??"")}return Array.isArray(s)?s.map(r):s!==null&&typeof s=="object"?Object.fromEntries(Object.entries(s).map(([i,o])=>[i,r(o)])):s};return {value:r(t),missing:n}}var Ho=Ae.options.map(t=>t.shape.authType.value);function br(t,e){return e.map(n=>{let r=n.path.join("."),s=r==="authType"?`fehlt oder ist unbekannt (erlaubt: ${Ho.join(", ")})`:n.message;return `${t}${r?`${r}: `:""}${s}`})}function ft(t,e){if(t===null||typeof t!="object"||Array.isArray(t))return {ok:false,errors:['Die Datei muss ein JSON-Objekt mit "version" und "destinations" sein.']};let n=Fo.safeParse(t);if(!n.success)return {ok:false,errors:br("",n.error.issues)};let r=[],s=new Map,i=Object.entries(n.data.destinations);i.length===0&&r.push('"destinations" enth\xE4lt keinen Eintrag.');for(let[a,d]of i){if(!yn.test(a)){r.push(`Destination "${a}": unzul\xE4ssiger Name \u2014 erlaubt sind Buchstaben, Ziffern, "_", "." und "-" (max. 64 Zeichen, kein Leerzeichen).`);continue}if(d===null||typeof d!="object"||Array.isArray(d)){r.push(`Destination "${a}": muss ein Objekt sein.`);continue}let l=Sn(d,e);if(l.missing.length>0){r.push(`Destination "${a}": Umgebungsvariable(n) nicht gesetzt: ${l.missing.join(", ")}.`);continue}let c={...l.value,name:a},u=Ae.safeParse(c);if(!u.success){r.push(...br(`Destination "${a}": `,u.error.issues));continue}s.set(a,u.data);}let o=n.data.tokens;return o.forEach((a,d)=>{Object.hasOwn(n.data.destinations,a.destination)||r.push(`tokens[${d}]${a.label?` ("${a.label}")`:""}: Destination "${a.destination}" existiert nicht.`);}),r.length>0?{ok:false,errors:r}:{ok:true,value:{destinations:s,tokens:o}}}function je(t,e){let n=createHash("sha256").update(t).digest(),r=createHash("sha256").update(e).digest();return timingSafeEqual(n,r)}var qo="gsm",wr=10,gt=6e4,Ko=1e4;function Ar(t){return `sha256:${createHash("sha256").update(t,"utf8").digest("hex")}`}function vr(t){let e=randomBytes(32).toString("base64url"),n=`${qo}_${t}_${e}`;return {token:n,hash:Ar(n)}}var ve=class{apiKey;tokens;now;failures=new Map;constructor(e){this.apiKey=e.apiKey,this.tokens=e.tokens,this.now=e.now??Date.now;}enforced(){return this.apiKey!==void 0||this.tokens().length>0}authenticate(e,n){if(!this.enforced())return {kind:"open"};let r=this.blockedFor(n);if(r!==void 0)return {kind:"rate-limited",retryAfterSeconds:r};let s=this.check(e);return s.kind==="rejected"?this.recordFailure(n):this.failures.delete(n),s}check(e){let n=zo(e),r=n??"",s=this.apiKey!==void 0&&je(r,this.apiKey),i=Buffer.from(Ar(r),"utf8"),o,a=false;for(let d of this.tokens()){let l=Buffer.from(d.hash,"utf8");l.length===i.length&&timingSafeEqual(l,i)&&(d.revoked?a=true:o||(o=d));}return o?{kind:"token",token:o}:s?{kind:"api-key"}:n===void 0?{kind:"rejected",reason:"Kein Bearer-Token im Authorization-Header."}:a?{kind:"rejected",reason:"Das Token wurde widerrufen."}:{kind:"rejected",reason:"Unbekanntes Token oder falscher API-Key."}}blockedFor(e){let n=this.failures.get(e);if(!n)return;let r=this.now()-n.windowStart;if(r>gt){this.failures.delete(e);return}if(n.count>=wr)return Math.max(1,Math.ceil((gt-r)/1e3))}recordFailure(e){let n=this.now();if(this.failures.size>=Ko)for(let[s,i]of this.failures)n-i.windowStart>gt&&this.failures.delete(s);let r=this.failures.get(e);if(!r||n-r.windowStart>gt){this.failures.set(e,{count:1,windowStart:n});return}r.count+=1,r.count===wr&&(r.windowStart=n);}};function zo(t){return typeof t!="string"?void 0:/^Bearer\s+(.+)$/i.exec(t.trim())?.[1]?.trim()||void 0}var Er=["core","odata","idoc","rfc"],P=class extends Error{constructor(n,r=400){super(n);this.status=r;this.name="AdminError";}},Ee=class{filePath;env;now;constructor(e){this.filePath=e.filePath,this.env=e.env,this.now=e.now??(()=>new Date);}listDestinations(){let e=this.read({mustExist:false});return Object.keys(e.destinations).length===0&&e.tokens.length===0?[]:(this.validate(e,true,422),Object.entries(e.destinations).map(([n,r])=>{let s=Cr(e,n);return {name:n,baseUrl:String(r.baseUrl??""),authType:String(r.authType??""),sapClient:r.sapClient===void 0?void 0:String(r.sapClient),tokens:s.length,activeTokens:s.filter(i=>i.revoked!==true).length}}))}addDestination(e,n,r={}){if(!yn.test(e))throw new P(`"${e}" is not a valid destination name (letters, digits, "_", ".", "-", max 64 characters).`,400);let s=this.read({mustExist:false}),i=s.destinations[e]!==void 0;if(i&&!r.replace)throw new P(`Destination "${e}" already exists. Use --replace to overwrite it.`,409);let o;if(r.fromEnv){let l;try{let{name:c,...u}=He(this.env);l=u;}catch(c){throw new P(c instanceof Error?c.message:String(c),400)}o=Rr(l);}else if(o=Rr(n),Object.keys(o).length===0)throw new P("Nothing to add: pass --from-env or --base-url/--auth-type and the auth fields.",400);let a={...s,destinations:{...s.destinations,[e]:o}},{warnings:d}=this.validate(a,!!r.allowMissingEnv,400);return this.write(a),{replaced:i,warnings:d}}removeDestination(e,n={}){let r=this.read({mustExist:true});if(!r.destinations[e])throw new P(`Destination "${e}" not found in ${this.filePath}.`,404);let s=Cr(r,e);if(s.length>0&&!n.force)throw new P(`Destination "${e}" still has ${s.length} token(s) (${s.map(d=>typeof d.label=="string"?d.label:de(d.hash)).join(", ")}). Revoke them first, or pass --force to remove them together.`,409);if(Object.keys(r.destinations).length===1)throw new P(`Destination "${e}" is the last one in ${this.filePath}; the server needs at least one. Add a replacement first, or delete the file.`,409);let{[e]:i,...o}=r.destinations,a={...r,destinations:o,tokens:r.tokens.filter(d=>d.destination!==e)};return this.validate(a,true,400),this.write(a),{removedTokens:s.length}}listTokens(){let e=this.read({mustExist:false});return Object.keys(e.destinations).length===0&&e.tokens.length===0?[]:(this.validate(e,true,422),e.tokens.map(n=>({label:typeof n.label=="string"?n.label:void 0,destination:String(n.destination),hash:de(n.hash),policy:n.policy,revoked:n.revoked===true,createdAt:typeof n.createdAt=="string"?n.createdAt:void 0})))}issueToken(e,n={}){let r=this.read({mustExist:true});if(!r.destinations[e])throw new P(`Destination "${e}" not found in ${this.filePath}. Known: ${Object.keys(r.destinations).join(", ")||"(none)"}.`,404);let s={};if(n.readOnly&&(s.readOnly=true),n.tiers!==void 0){let l=n.tiers.map(u=>u.trim()).filter(u=>u.length>0),c=l.filter(u=>!Er.includes(u));if(c.length>0||l.length===0)throw new P(`Unknown tier(s): ${c.join(", ")||"(empty)"}. Allowed: ${Er.join(", ")}.`,400);s.tiers=l;}if(n.label!==void 0&&n.label.length>200)throw new P("Label must not exceed 200 characters.",400);let{token:i,hash:o}=vr(e),a={hash:o,destination:e,...n.label?{label:n.label}:{},...Object.keys(s).length>0?{policy:s}:{},createdAt:this.now().toISOString()},d={...r,tokens:[...r.tokens,a]};return this.validate(d,true,400),this.write(d),{token:i,hash:o,entry:a}}revokeToken(e){let n=this.read({mustExist:true}),r=n.tokens.filter(c=>c.label===e),s=e.startsWith("sha256:")?e.slice(7):e,i=/^[0-9a-f]{8,64}$/i.test(s)?n.tokens.filter(c=>typeof c.hash=="string"&&c.hash.slice(7).startsWith(s.toLowerCase())):[],o=r.length>0?r:i;if(o.length===0)throw new P(`No token matches "${e}". Use the label or at least 8 hex characters of the hash (see: tokens list).`,404);if(o.length>1)throw new P(`"${e}" is ambiguous (${o.length} tokens). Use a longer hash prefix: ${o.map(c=>de(c.hash)).join(", ")}.`,409);let a=o[0],d=typeof a.label=="string"?a.label:void 0;if(a.revoked===true)return {hash:de(a.hash),label:d,alreadyRevoked:true};let l={...n,tokens:n.tokens.map(c=>c===a?{...c,revoked:true}:c)};return this.validate(l,true,400),this.write(l),{hash:de(a.hash),label:d,alreadyRevoked:false}}read({mustExist:e}){if(!existsSync(this.filePath)){if(e)throw new P(`${this.filePath}: file not found.`,404);return {version:1,destinations:{},tokens:[]}}let n;try{n=JSON.parse(readFileSync(this.filePath,"utf8"));}catch(s){throw new P(`${this.filePath}: not valid JSON (${s instanceof Error?s.message:String(s)}).`,422)}if(n===null||typeof n!="object"||Array.isArray(n))throw new P(`${this.filePath}: must be a JSON object with "version" and "destinations".`,422);let r=n;return {version:1,destinations:r.destinations??{},tokens:r.tokens??[],...r.version!==void 0&&r.version!==1?{version:r.version}:{}}}validate(e,n,r){let s=Sn(e.destinations,this.env),i=[],o=this.env;if(s.missing.length>0&&n){o={...this.env};for(let d of s.missing)o[d]="placeholder";i.push(`Environment variable(s) not set here: ${s.missing.join(", ")}. The server needs them at load time.`);}let a=ft(e,o);if(!a.ok)throw new P(`${r===400?"Refusing to write an invalid file":`${this.filePath} is invalid`}:
62
+ Set the required SAP_* environment variables.`)}return r.data}var Tn=/^[A-Za-z0-9][A-Za-z0-9_.-]{0,63}$/,Ko=z$2.enum(["core","odata","idoc","rfc"]),zo=z$2.object({readOnly:z$2.boolean().optional(),tiers:z$2.array(Ko).min(1).optional()}).strict(),Yo=z$2.object({hash:z$2.string().regex(/^sha256:[0-9a-f]{64}$/,"muss die Form sha256:<64 hex> haben"),destination:z$2.string().min(1),label:z$2.string().max(200).optional(),policy:zo.optional(),createdAt:z$2.string().optional(),revoked:z$2.boolean().optional()}).strict(),Xo=z$2.object({version:z$2.literal(1),destinations:z$2.record(z$2.string(),z$2.unknown()),tokens:z$2.array(Yo).default([])}).strict(),Ar=/\$\{([A-Z_][A-Z0-9_]*)\}/g;function vn(t,e){let n=[],r=s=>{if(typeof s=="string"){let i=[...s.matchAll(Ar)].map(a=>a[1]);if(i.length===0)return s;let o=i.filter(a=>e[a]===void 0);if(o.length>0){for(let a of o)n.includes(a)||n.push(a);return s}return s.replace(Ar,(a,d)=>e[d]??"")}return Array.isArray(s)?s.map(r):s!==null&&typeof s=="object"?Object.fromEntries(Object.entries(s).map(([i,o])=>[i,r(o)])):s};return {value:r(t),missing:n}}var Jo=Ee.options.map(t=>t.shape.authType.value);function Er(t,e){return e.map(n=>{let r=n.path.join("."),s=r==="authType"?`fehlt oder ist unbekannt (erlaubt: ${Jo.join(", ")})`:n.message;return `${t}${r?`${r}: `:""}${s}`})}function wt(t,e){if(t===null||typeof t!="object"||Array.isArray(t))return {ok:false,errors:['Die Datei muss ein JSON-Objekt mit "version" und "destinations" sein.']};let n=Xo.safeParse(t);if(!n.success)return {ok:false,errors:Er("",n.error.issues)};let r=[],s=new Map,i=Object.entries(n.data.destinations);i.length===0&&r.push('"destinations" enth\xE4lt keinen Eintrag.');for(let[a,d]of i){if(!Tn.test(a)){r.push(`Destination "${a}": unzul\xE4ssiger Name \u2014 erlaubt sind Buchstaben, Ziffern, "_", "." und "-" (max. 64 Zeichen, kein Leerzeichen).`);continue}if(d===null||typeof d!="object"||Array.isArray(d)){r.push(`Destination "${a}": muss ein Objekt sein.`);continue}let l=vn(d,e);if(l.missing.length>0){r.push(`Destination "${a}": Umgebungsvariable(n) nicht gesetzt: ${l.missing.join(", ")}.`);continue}let c={...l.value,name:a},u=Ee.safeParse(c);if(!u.success){r.push(...Er(`Destination "${a}": `,u.error.issues));continue}s.set(a,u.data);}let o=n.data.tokens;return o.forEach((a,d)=>{Object.hasOwn(n.data.destinations,a.destination)||r.push(`tokens[${d}]${a.label?` ("${a.label}")`:""}: Destination "${a.destination}" existiert nicht.`);}),r.length>0?{ok:false,errors:r}:{ok:true,value:{destinations:s,tokens:o}}}function Ge(t,e){let n=createHash("sha256").update(t).digest(),r=createHash("sha256").update(e).digest();return timingSafeEqual(n,r)}var na="gsm",Rr=10,Tt=6e4,ra=1e4;function Pr(t){return `sha256:${createHash("sha256").update(t,"utf8").digest("hex")}`}function kr(t){let e=randomBytes(32).toString("base64url"),n=`${na}_${t}_${e}`;return {token:n,hash:Pr(n)}}var Ce=class{apiKey;tokens;now;failures=new Map;constructor(e){this.apiKey=e.apiKey,this.tokens=e.tokens,this.now=e.now??Date.now;}enforced(){return this.apiKey!==void 0||this.tokens().length>0}authenticate(e,n){if(!this.enforced())return {kind:"open"};let r=this.blockedFor(n);if(r!==void 0)return {kind:"rate-limited",retryAfterSeconds:r};let s=this.check(e);return s.kind==="rejected"?this.recordFailure(n):this.failures.delete(n),s}check(e){let n=sa(e),r=n??"",s=this.apiKey!==void 0&&Ge(r,this.apiKey),i=Buffer.from(Pr(r),"utf8"),o,a=false;for(let d of this.tokens()){let l=Buffer.from(d.hash,"utf8");l.length===i.length&&timingSafeEqual(l,i)&&(d.revoked?a=true:o||(o=d));}return o?{kind:"token",token:o}:s?{kind:"api-key"}:n===void 0?{kind:"rejected",reason:"Kein Bearer-Token im Authorization-Header."}:a?{kind:"rejected",reason:"Das Token wurde widerrufen."}:{kind:"rejected",reason:"Unbekanntes Token oder falscher API-Key."}}blockedFor(e){let n=this.failures.get(e);if(!n)return;let r=this.now()-n.windowStart;if(r>Tt){this.failures.delete(e);return}if(n.count>=Rr)return Math.max(1,Math.ceil((Tt-r)/1e3))}recordFailure(e){let n=this.now();if(this.failures.size>=ra)for(let[s,i]of this.failures)n-i.windowStart>Tt&&this.failures.delete(s);let r=this.failures.get(e);if(!r||n-r.windowStart>Tt){this.failures.set(e,{count:1,windowStart:n});return}r.count+=1,r.count===Rr&&(r.windowStart=n);}};function sa(t){return typeof t!="string"?void 0:/^Bearer\s+(.+)$/i.exec(t.trim())?.[1]?.trim()||void 0}var _r=["core","odata","idoc","rfc"],P=class extends Error{constructor(n,r=400){super(n);this.status=r;this.name="AdminError";}},Re=class{filePath;env;now;constructor(e){this.filePath=e.filePath,this.env=e.env,this.now=e.now??(()=>new Date);}listDestinations(){let e=this.read({mustExist:false});return Object.keys(e.destinations).length===0&&e.tokens.length===0?[]:(this.validate(e,true,422),Object.entries(e.destinations).map(([n,r])=>{let s=Or(e,n);return {name:n,baseUrl:String(r.baseUrl??""),authType:String(r.authType??""),sapClient:r.sapClient===void 0?void 0:String(r.sapClient),tokens:s.length,activeTokens:s.filter(i=>i.revoked!==true).length}}))}addDestination(e,n,r={}){if(!Tn.test(e))throw new P(`"${e}" is not a valid destination name (letters, digits, "_", ".", "-", max 64 characters).`,400);let s=this.read({mustExist:false}),i=s.destinations[e]!==void 0;if(i&&!r.replace)throw new P(`Destination "${e}" already exists. Use --replace to overwrite it.`,409);let o;if(r.fromEnv){let l;try{let{name:c,...u}=We(this.env);l=u;}catch(c){throw new P(c instanceof Error?c.message:String(c),400)}o=Ir(l);}else if(o=Ir(n),Object.keys(o).length===0)throw new P("Nothing to add: pass --from-env or --base-url/--auth-type and the auth fields.",400);let a={...s,destinations:{...s.destinations,[e]:o}},{warnings:d}=this.validate(a,!!r.allowMissingEnv,400);return this.write(a),{replaced:i,warnings:d}}removeDestination(e,n={}){let r=this.read({mustExist:true});if(!r.destinations[e])throw new P(`Destination "${e}" not found in ${this.filePath}.`,404);let s=Or(r,e);if(s.length>0&&!n.force)throw new P(`Destination "${e}" still has ${s.length} token(s) (${s.map(d=>typeof d.label=="string"?d.label:pe(d.hash)).join(", ")}). Revoke them first, or pass --force to remove them together.`,409);if(Object.keys(r.destinations).length===1)throw new P(`Destination "${e}" is the last one in ${this.filePath}; the server needs at least one. Add a replacement first, or delete the file.`,409);let{[e]:i,...o}=r.destinations,a={...r,destinations:o,tokens:r.tokens.filter(d=>d.destination!==e)};return this.validate(a,true,400),this.write(a),{removedTokens:s.length}}listTokens(){let e=this.read({mustExist:false});return Object.keys(e.destinations).length===0&&e.tokens.length===0?[]:(this.validate(e,true,422),e.tokens.map(n=>({label:typeof n.label=="string"?n.label:void 0,destination:String(n.destination),hash:pe(n.hash),policy:n.policy,revoked:n.revoked===true,createdAt:typeof n.createdAt=="string"?n.createdAt:void 0})))}issueToken(e,n={}){let r=this.read({mustExist:true});if(!r.destinations[e])throw new P(`Destination "${e}" not found in ${this.filePath}. Known: ${Object.keys(r.destinations).join(", ")||"(none)"}.`,404);let s={};if(n.readOnly&&(s.readOnly=true),n.tiers!==void 0){let l=n.tiers.map(u=>u.trim()).filter(u=>u.length>0),c=l.filter(u=>!_r.includes(u));if(c.length>0||l.length===0)throw new P(`Unknown tier(s): ${c.join(", ")||"(empty)"}. Allowed: ${_r.join(", ")}.`,400);s.tiers=l;}if(n.label!==void 0&&n.label.length>200)throw new P("Label must not exceed 200 characters.",400);let{token:i,hash:o}=kr(e),a={hash:o,destination:e,...n.label?{label:n.label}:{},...Object.keys(s).length>0?{policy:s}:{},createdAt:this.now().toISOString()},d={...r,tokens:[...r.tokens,a]};return this.validate(d,true,400),this.write(d),{token:i,hash:o,entry:a}}revokeToken(e){let n=this.read({mustExist:true}),r=n.tokens.filter(c=>c.label===e),s=e.startsWith("sha256:")?e.slice(7):e,i=/^[0-9a-f]{8,64}$/i.test(s)?n.tokens.filter(c=>typeof c.hash=="string"&&c.hash.slice(7).startsWith(s.toLowerCase())):[],o=r.length>0?r:i;if(o.length===0)throw new P(`No token matches "${e}". Use the label or at least 8 hex characters of the hash (see: tokens list).`,404);if(o.length>1)throw new P(`"${e}" is ambiguous (${o.length} tokens). Use a longer hash prefix: ${o.map(c=>pe(c.hash)).join(", ")}.`,409);let a=o[0],d=typeof a.label=="string"?a.label:void 0;if(a.revoked===true)return {hash:pe(a.hash),label:d,alreadyRevoked:true};let l={...n,tokens:n.tokens.map(c=>c===a?{...c,revoked:true}:c)};return this.validate(l,true,400),this.write(l),{hash:pe(a.hash),label:d,alreadyRevoked:false}}read({mustExist:e}){if(!existsSync(this.filePath)){if(e)throw new P(`${this.filePath}: file not found.`,404);return {version:1,destinations:{},tokens:[]}}let n;try{n=JSON.parse(readFileSync(this.filePath,"utf8"));}catch(s){throw new P(`${this.filePath}: not valid JSON (${s instanceof Error?s.message:String(s)}).`,422)}if(n===null||typeof n!="object"||Array.isArray(n))throw new P(`${this.filePath}: must be a JSON object with "version" and "destinations".`,422);let r=n;return {version:1,destinations:r.destinations??{},tokens:r.tokens??[],...r.version!==void 0&&r.version!==1?{version:r.version}:{}}}validate(e,n,r){let s=vn(e.destinations,this.env),i=[],o=this.env;if(s.missing.length>0&&n){o={...this.env};for(let d of s.missing)o[d]="placeholder";i.push(`Environment variable(s) not set here: ${s.missing.join(", ")}. The server needs them at load time.`);}let a=wt(e,o);if(!a.ok)throw new P(`${r===400?"Refusing to write an invalid file":`${this.filePath} is invalid`}:
63
63
  ${a.errors.map(d=>` - ${d}`).join(`
64
64
  `)}`,r);return {warnings:i}}write(e){let n=dirname(this.filePath);mkdirSync(n,{recursive:true});let r=`${this.filePath}.${process.pid}.tmp`,s=`${JSON.stringify(e,null,2)}
65
- `;try{writeFileSync(r,s,{mode:384}),renameSync(r,this.filePath);}catch(i){try{unlinkSync(r);}catch{}throw i}}};function Cr(t,e){return t.tokens.filter(n=>n.destination===e)}function de(t){return typeof t=="string"?t.replace(/^sha256:/,"").slice(0,12):"?"}function Rr(t){return Object.fromEntries(Object.entries(t).filter(([,e])=>e!==void 0))}var Pr=new Set(["destinations","tokens"]),ht=`Usage:
65
+ `;try{writeFileSync(r,s,{mode:384}),renameSync(r,this.filePath);}catch(i){try{unlinkSync(r);}catch{}throw i}}};function Or(t,e){return t.tokens.filter(n=>n.destination===e)}function pe(t){return typeof t=="string"?t.replace(/^sha256:/,"").slice(0,12):"?"}function Ir(t){return Object.fromEntries(Object.entries(t).filter(([,e])=>e!==void 0))}var Nr=new Set(["destinations","tokens"]),vt=`Usage:
66
66
  guniweb-sap-mcp destinations list
67
67
  guniweb-sap-mcp destinations add <name> (--from-env | --base-url <url> --auth-type <type> [fields])
68
68
  [--sap-client <c>] [--set <field>=<value>]... [--replace]
@@ -87,26 +87,26 @@ Auth types: basic, user-basic (personal SAP login per request \u2014 the caller
87
87
 
88
88
  "tokens issue" prints the plain token ONCE on stdout; only its SHA-256 hash is stored.
89
89
  Put the token into an n8n Bearer Auth credential on the MCP Client node.
90
- `,V=class extends Error{constructor(n,r=1){super(n);this.exitCode=r;}};async function kr(t,e){let n=ia(t);try{if(n.flags.help)return e.stdout(ht),0;let[r,s,...i]=n.positional;if(r==="destinations")switch(s){case "list":return oa(n,e);case "add":return ca(i[0],n,e);case "remove":return da(i[0],n,e);default:throw new V(`Unknown command "destinations ${s??""}".
90
+ `,V=class extends Error{constructor(n,r=1){super(n);this.exitCode=r;}};async function Dr(t,e){let n=ga(t);try{if(n.flags.help)return e.stdout(vt),0;let[r,s,...i]=n.positional;if(r==="destinations")switch(s){case "list":return ha(n,e);case "add":return Sa(i[0],n,e);case "remove":return ba(i[0],n,e);default:throw new V(`Unknown command "destinations ${s??""}".
91
91
 
92
- ${ht}`,2)}if(r==="tokens")switch(s){case "list":return la(n,e);case "issue":return ua(i[0],n,e);case "revoke":return pa(i[0],n,e);default:throw new V(`Unknown command "tokens ${s??""}".
92
+ ${vt}`,2)}if(r==="tokens")switch(s){case "list":return wa(n,e);case "issue":return Ta(i[0],n,e);case "revoke":return va(i[0],n,e);default:throw new V(`Unknown command "tokens ${s??""}".
93
93
 
94
- ${ht}`,2)}throw new V(ht,2)}catch(r){return r instanceof V?(e.stderr(`${r.message}
94
+ ${vt}`,2)}throw new V(vt,2)}catch(r){return r instanceof V?(e.stderr(`${r.message}
95
95
  `),r.exitCode):r instanceof P?(e.stderr(`${r.message}
96
96
  `),1):(e.stderr(`Error: ${r instanceof Error?r.message:String(r)}
97
- `),1)}}var ra=new Set(["help","h","from-env","replace","force","read-only","allow-missing-env"]),sa=new Set(["set"]);function ia(t){let e=[],n={};for(let r=0;r<t.length;r++){let s=t[r];if(s==="-h"){n.help=true;continue}if(!s.startsWith("--")){e.push(s);continue}let i=s.indexOf("="),o=i===-1?s.slice(2):s.slice(2,i);if(ra.has(o)){n[o]=true;continue}let a=i===-1?t[++r]:s.slice(i+1);if(a===void 0)throw new V(`Missing value for --${o}.`,2);if(sa.has(o)){let d=n[o]??[];d.push(a),n[o]=d;}else n[o]=a;}return {positional:e,flags:n}}function yt(t,e){let n=t.flags[e];return typeof n=="string"?n:void 0}function Ce(t,e){let n=yt(t,"destinations")??e.env.SAP_MCP_DESTINATIONS;if(!n||n.trim().length===0)throw new V("No destinations file given. Pass --destinations <path> or set SAP_MCP_DESTINATIONS.",2);return new Ee({filePath:resolve(n.trim()),env:e.env,now:e.now})}function oa(t,e){let n=Ce(t,e).listDestinations();return e.stdout(`${_r(["NAME","BASE URL","AUTH","CLIENT","TOKENS"],n.map(r=>[r.name,r.baseUrl,r.authType,r.sapClient??"-",String(r.tokens)]))}
98
- `),0}var aa={"base-url":"baseUrl","auth-type":"authType","sap-client":"sapClient",username:"username",password:"password","api-key":"apiKey","client-id":"clientId","client-secret":"clientSecret","token-service-url":"tokenServiceUrl"};function ca(t,e,n){if(!t)throw new V("Usage: destinations add <name> ...",2);let r=Ce(e,n),s={};if(!e.flags["from-env"]){for(let[a,d]of Object.entries(aa)){let l=yt(e,a);l!==void 0&&(s[d]=l);}for(let a of e.flags.set??[]){let d=a.indexOf("=");if(d<=0)throw new V(`--set expects field=value, got "${a}".`,2);s[a.slice(0,d)]=a.slice(d+1);}}let{replaced:i,warnings:o}=r.addDestination(t,s,{replace:!!e.flags.replace,allowMissingEnv:!!e.flags["allow-missing-env"],fromEnv:!!e.flags["from-env"]});for(let a of o)n.stderr(`Warning: ${a}
97
+ `),1)}}var ma=new Set(["help","h","from-env","replace","force","read-only","allow-missing-env"]),fa=new Set(["set"]);function ga(t){let e=[],n={};for(let r=0;r<t.length;r++){let s=t[r];if(s==="-h"){n.help=true;continue}if(!s.startsWith("--")){e.push(s);continue}let i=s.indexOf("="),o=i===-1?s.slice(2):s.slice(2,i);if(ma.has(o)){n[o]=true;continue}let a=i===-1?t[++r]:s.slice(i+1);if(a===void 0)throw new V(`Missing value for --${o}.`,2);if(fa.has(o)){let d=n[o]??[];d.push(a),n[o]=d;}else n[o]=a;}return {positional:e,flags:n}}function At(t,e){let n=t.flags[e];return typeof n=="string"?n:void 0}function Pe(t,e){let n=At(t,"destinations")??e.env.SAP_MCP_DESTINATIONS;if(!n||n.trim().length===0)throw new V("No destinations file given. Pass --destinations <path> or set SAP_MCP_DESTINATIONS.",2);return new Re({filePath:resolve(n.trim()),env:e.env,now:e.now})}function ha(t,e){let n=Pe(t,e).listDestinations();return e.stdout(`${xr(["NAME","BASE URL","AUTH","CLIENT","TOKENS"],n.map(r=>[r.name,r.baseUrl,r.authType,r.sapClient??"-",String(r.tokens)]))}
98
+ `),0}var ya={"base-url":"baseUrl","auth-type":"authType","sap-client":"sapClient",username:"username",password:"password","api-key":"apiKey","client-id":"clientId","client-secret":"clientSecret","token-service-url":"tokenServiceUrl"};function Sa(t,e,n){if(!t)throw new V("Usage: destinations add <name> ...",2);let r=Pe(e,n),s={};if(!e.flags["from-env"]){for(let[a,d]of Object.entries(ya)){let l=At(e,a);l!==void 0&&(s[d]=l);}for(let a of e.flags.set??[]){let d=a.indexOf("=");if(d<=0)throw new V(`--set expects field=value, got "${a}".`,2);s[a.slice(0,d)]=a.slice(d+1);}}let{replaced:i,warnings:o}=r.addDestination(t,s,{replace:!!e.flags.replace,allowMissingEnv:!!e.flags["allow-missing-env"],fromEnv:!!e.flags["from-env"]});for(let a of o)n.stderr(`Warning: ${a}
99
99
  `);return n.stderr(`Destination "${t}" ${i?"replaced":"added"} in ${r.filePath}.
100
- `),0}function da(t,e,n){if(!t)throw new V("Usage: destinations remove <name> [--force]",2);let{removedTokens:r}=Ce(e,n).removeDestination(t,{force:!!e.flags.force});return n.stderr(`Destination "${t}" removed${r>0?` together with ${r} token(s)`:""}.
101
- `),0}function la(t,e){let n=Ce(t,e).listTokens().map(r=>{let s=[];return r.policy?.readOnly&&s.push("read-only"),r.policy?.tiers&&s.push(`tiers=${r.policy.tiers.join(",")}`),[r.label??"-",r.destination,r.hash,s.length>0?s.join(" "):"full",r.revoked?"revoked":"active",r.createdAt??"-"]});return e.stdout(`${_r(["LABEL","DESTINATION","HASH","POLICY","STATUS","CREATED"],n)}
102
- `),0}function ua(t,e,n){if(!t)throw new V("Usage: tokens issue <destination> [--label ...]",2);let r=Ce(e,n),s=yt(e,"tiers"),i=yt(e,"label"),{token:o,hash:a}=r.issueToken(t,{label:i,readOnly:!!e.flags["read-only"],tiers:s===void 0?void 0:s.split(",")});return n.stdout(`${o}
103
- `),n.stderr([`Token issued for destination "${t}"${i?` (${i})`:""} \u2014 hash ${de(a)}\u2026 stored in ${r.filePath}.`,"The plain token above is shown ONCE and cannot be recovered; put it into an n8n Bearer Auth credential","(Authorization: Bearer <token>) on the MCP Client node. Revoke with: tokens revoke <label|hash-prefix>.",""].join(`
104
- `)),0}function pa(t,e,n){if(!t)throw new V("Usage: tokens revoke <label | hash-prefix>",2);let{hash:r,label:s,alreadyRevoked:i}=Ce(e,n).revokeToken(t);return i?(n.stderr(`Token ${r} was already revoked.
100
+ `),0}function ba(t,e,n){if(!t)throw new V("Usage: destinations remove <name> [--force]",2);let{removedTokens:r}=Pe(e,n).removeDestination(t,{force:!!e.flags.force});return n.stderr(`Destination "${t}" removed${r>0?` together with ${r} token(s)`:""}.
101
+ `),0}function wa(t,e){let n=Pe(t,e).listTokens().map(r=>{let s=[];return r.policy?.readOnly&&s.push("read-only"),r.policy?.tiers&&s.push(`tiers=${r.policy.tiers.join(",")}`),[r.label??"-",r.destination,r.hash,s.length>0?s.join(" "):"full",r.revoked?"revoked":"active",r.createdAt??"-"]});return e.stdout(`${xr(["LABEL","DESTINATION","HASH","POLICY","STATUS","CREATED"],n)}
102
+ `),0}function Ta(t,e,n){if(!t)throw new V("Usage: tokens issue <destination> [--label ...]",2);let r=Pe(e,n),s=At(e,"tiers"),i=At(e,"label"),{token:o,hash:a}=r.issueToken(t,{label:i,readOnly:!!e.flags["read-only"],tiers:s===void 0?void 0:s.split(",")});return n.stdout(`${o}
103
+ `),n.stderr([`Token issued for destination "${t}"${i?` (${i})`:""} \u2014 hash ${pe(a)}\u2026 stored in ${r.filePath}.`,"The plain token above is shown ONCE and cannot be recovered; put it into an n8n Bearer Auth credential","(Authorization: Bearer <token>) on the MCP Client node. Revoke with: tokens revoke <label|hash-prefix>.",""].join(`
104
+ `)),0}function va(t,e,n){if(!t)throw new V("Usage: tokens revoke <label | hash-prefix>",2);let{hash:r,label:s,alreadyRevoked:i}=Pe(e,n).revokeToken(t);return i?(n.stderr(`Token ${r} was already revoked.
105
105
  `),0):(n.stderr(`Token ${r}${s?` (${s})`:""} revoked. A running server rejects it from the next request on.
106
- `),0)}function _r(t,e){let n=[t,...e],r=t.map((s,i)=>Math.max(...n.map(o=>(o[i]??"").length)));return n.map(s=>s.map((i,o)=>(i??"").padEnd(r[o])).join(" ").trimEnd()).join(`
107
- `)}var le="default",ba=250,Or=1e3,Re=class t{source;filePath;current;currentRaw;currentVersion=1;env;envDefault;warn;observeFile;warnedFileWins=false;watcher;polling=false;startupRecheck;sighupHandler;debounceTimer;reloadInFlight;reloadQueued=false;changeListeners=new Set;errorListeners=new Set;constructor(e){this.source=e.source,this.filePath=e.filePath,this.current=e.config,this.currentRaw=e.raw,this.env=e.env,this.envDefault=e.envDefault,this.warn=e.onWarn??(()=>{}),this.observeFile=e.watchFile??true;}static fromEnv(e=process.env){let n={...He(e),name:le};return new t({source:"env",config:{destinations:new Map([[le,n]]),tokens:[]},env:e})}static async fromFile(e,n={}){let r=n.env??process.env,s=resolve(e),i=r.SAP_BASE_URL?{...He(r),name:le}:void 0,o=new t({source:"file",filePath:s,config:{destinations:new Map,tokens:[]},env:r,envDefault:i,onWarn:n.onWarn,watchFile:n.watchFile}),a=await o.readAndParse();if(!a.ok){if(a.missing&&i)return o.warn(`${s} existiert (noch) nicht \u2014 der Server startet mit der SAP_*-Umgebung als Destination "default" und \xFCbernimmt die Datei, sobald sie angelegt wird.`),o.current={destinations:new Map([[le,i]]),tokens:[]},o;if(a.missing&&n.allowMissing)return o.warn(`${s} existiert (noch) nicht und es ist keine SAP_*-Umgebung gesetzt \u2014 der Server startet ohne Destination und \xFCbernimmt die Datei, sobald sie angelegt wird (z. B. \xFCber die Admin-API).`),o;throw new Error(`Ung\xFCltige Destinations-Datei ${s}:
106
+ `),0)}function xr(t,e){let n=[t,...e],r=t.map((s,i)=>Math.max(...n.map(o=>(o[i]??"").length)));return n.map(s=>s.map((i,o)=>(i??"").padEnd(r[o])).join(" ").trimEnd()).join(`
107
+ `)}var me="default",_a=250,Mr=1e3,ke=class t{source;filePath;current;currentRaw;currentVersion=1;env;envDefault;warn;observeFile;warnedFileWins=false;watcher;polling=false;startupRecheck;sighupHandler;debounceTimer;reloadInFlight;reloadQueued=false;changeListeners=new Set;errorListeners=new Set;constructor(e){this.source=e.source,this.filePath=e.filePath,this.current=e.config,this.currentRaw=e.raw,this.env=e.env,this.envDefault=e.envDefault,this.warn=e.onWarn??(()=>{}),this.observeFile=e.watchFile??true;}static fromEnv(e=process.env){let n={...We(e),name:me};return new t({source:"env",config:{destinations:new Map([[me,n]]),tokens:[]},env:e})}static async fromFile(e,n={}){let r=n.env??process.env,s=resolve(e),i=r.SAP_BASE_URL?{...We(r),name:me}:void 0,o=new t({source:"file",filePath:s,config:{destinations:new Map,tokens:[]},env:r,envDefault:i,onWarn:n.onWarn,watchFile:n.watchFile}),a=await o.readAndParse();if(!a.ok){if(a.missing&&i)return o.warn(`${s} existiert (noch) nicht \u2014 der Server startet mit der SAP_*-Umgebung als Destination "default" und \xFCbernimmt die Datei, sobald sie angelegt wird.`),o.current={destinations:new Map([[me,i]]),tokens:[]},o;if(a.missing&&n.allowMissing)return o.warn(`${s} existiert (noch) nicht und es ist keine SAP_*-Umgebung gesetzt \u2014 der Server startet ohne Destination und \xFCbernimmt die Datei, sobald sie angelegt wird (z. B. \xFCber die Admin-API).`),o;throw new Error(`Ung\xFCltige Destinations-Datei ${s}:
108
108
  ${a.errors.map(d=>` - ${d}`).join(`
109
- `)}`)}return o.current=a.value,o.currentRaw=a.raw,o}get version(){return this.currentVersion}get(e){return this.current.destinations.get(e)}names(){return [...this.current.destinations.keys()]}defaultDestination(){let e=this.current.destinations.get(le);if(e)return e;if(this.current.destinations.size===1)return this.current.destinations.values().next().value}tokens(){return this.current.tokens}onChange(e){return this.changeListeners.add(e),()=>this.changeListeners.delete(e)}onError(e){return this.errorListeners.add(e),()=>this.errorListeners.delete(e)}reload(){return this.source==="env"?Promise.resolve({ok:true,changed:false}):this.reloadInFlight?(this.reloadQueued=true,this.reloadInFlight):(this.reloadInFlight=this.doReload().finally(()=>{this.reloadInFlight=void 0,this.reloadQueued&&(this.reloadQueued=false,this.reload());}),this.reloadInFlight)}watch(){if(!(this.source==="env"||!this.filePath)&&(this.sighupHandler||(this.sighupHandler=()=>{this.reload();},process.on("SIGHUP",this.sighupHandler)),this.observeFile&&!this.polling&&(this.polling=true,watchFile(this.filePath,{persistent:false,interval:Or},(e,n)=>{(e.mtimeMs!==n.mtimeMs||e.size!==n.size)&&this.scheduleReload();}),this.startupRecheck=setTimeout(()=>{this.startupRecheck=void 0,this.scheduleReload();},Or+500),this.startupRecheck.unref()),this.observeFile&&!this.watcher))try{this.watcher=watch(dirname(this.filePath),{persistent:!1},()=>{this.scheduleReload();}),this.watcher.on("error",e=>{this.warn(`Dateibeobachtung f\xFCr ${this.filePath} ausgefallen (${e.message}); SIGHUP l\xE4dt weiterhin neu.`),this.watcher=void 0;});}catch(e){this.warn(`Dateibeobachtung f\xFCr ${this.filePath} nicht m\xF6glich (${e instanceof Error?e.message:String(e)}); SIGHUP l\xE4dt weiterhin neu.`);}}close(){this.debounceTimer&&(clearTimeout(this.debounceTimer),this.debounceTimer=void 0),this.startupRecheck&&(clearTimeout(this.startupRecheck),this.startupRecheck=void 0),this.watcher&&(this.watcher.close(),this.watcher=void 0),this.polling&&this.filePath&&(unwatchFile(this.filePath),this.polling=false),this.sighupHandler&&(process.off("SIGHUP",this.sighupHandler),this.sighupHandler=void 0),this.changeListeners.clear(),this.errorListeners.clear();}scheduleReload(){this.debounceTimer&&clearTimeout(this.debounceTimer),this.debounceTimer=setTimeout(()=>{this.debounceTimer=void 0,this.reload();},ba),this.debounceTimer.unref();}async doReload(){let e=await this.readAndParse();if(!e.ok){if(e.missing&&this.currentRaw===void 0)return {ok:true,changed:false};for(let r of this.errorListeners)r(e.errors);return {ok:false,errors:e.errors}}if(e.raw===this.currentRaw)return {ok:true,changed:false};this.current=e.value,this.currentRaw=e.raw,this.currentVersion+=1;let n={version:this.currentVersion,names:this.names(),tokenCount:this.current.tokens.length};for(let r of this.changeListeners)r(n);return {ok:true,changed:true}}async readAndParse(){if(!this.filePath)return {ok:false,errors:["Kein Dateipfad konfiguriert."]};let e;try{e=await readFile(this.filePath,"utf8");}catch(s){let i=s.code,o=i==="ENOENT"?"Datei nicht gefunden":s.message;return {ok:false,errors:[`${this.filePath}: ${o}`],missing:i==="ENOENT"}}let n;try{n=JSON.parse(e);}catch(s){return {ok:false,errors:[`${this.filePath}: kein g\xFCltiges JSON (${s instanceof Error?s.message:String(s)})`]}}let r=ft(n,this.env);return r.ok?(this.envDefault&&(r.value.destinations.has(le)?this.warnedFileWins||(this.warnedFileWins=true,this.warn(`Sowohl ${this.filePath} als auch die SAP_*-Umgebung definieren die Destination "default" \u2014 die Datei gilt, die Umgebung wird ignoriert.`)):r.value.destinations.set(le,this.envDefault)),{ok:true,value:r.value,raw:e}):r}};var Ir="@guniweb/sap-mcp-governance";function va(t){return isAbsolute(t)?t:createRequire(import.meta.url).resolve(t)}function Ea(t){let e=t?.code;return e==="MODULE_NOT_FOUND"||e==="ERR_MODULE_NOT_FOUND"}async function Dr(t,e={},n){let r=e.resolve??va,s=e.importer??(u=>import(u)),i=n?.trim()||t.env.SAP_MCP_GOVERNANCE_MODULE?.trim()||void 0,o=i??Ir,a;try{a=r(o);}catch(u){if(!i&&Ea(u))return {status:"not-installed"};throw new Error(`Governance-Modul "${o}" ist konfiguriert, aber nicht auffindbar: ${u.message}`)}let d;try{d=await s(pathToFileURL(a).href);}catch(u){throw new Error(`Governance-Modul "${o}" konnte nicht geladen werden: ${u.message}`)}let l=d.createGovernance??d.default;if(typeof l!="function")throw new Error(`Governance-Modul "${o}" exportiert keine Funktion createGovernance (oder default).`);let c=await l(t);if(c?.apiVersion!==1)throw new Error(`Governance-Modul "${o}" spricht apiVersion ${String(c?.apiVersion)}, dieser Server ${1}. Passende Versionen von Server und Modul verwenden.`);if(typeof c.onToolCall!="function")throw new Error(`Governance-Modul "${o}" hat keine Funktion onToolCall.`);return {status:"active",module:c,specifier:o}}var Pe=class{buffer=[];maxSize;constructor(e=100){this.maxSize=e;}add(e){this.buffer.length>=this.maxSize&&this.buffer.shift(),this.buffer.push(e);}get(e){return this.buffer.find(n=>n.docnum===e)}list(){return [...this.buffer]}get count(){return this.buffer.length}};var Ra=new XMLParser({ignoreAttributes:false,attributeNamePrefix:"@_",parseTagValue:false,processEntities:false,htmlEntities:false,isArray:t=>t==="IDOC"||t.startsWith("E1")||t.startsWith("E2")}),Ve=new Set(["@_SEGMENT","@_BEGIN"]);function bn(t,e){return !!(t.startsWith("E1")||t.startsWith("E2")||typeof e=="object"&&e!==null&&"@_SEGMENT"in e)}function Nr(t){let e=[];for(let[n,r]of Object.entries(t)){if(Ve.has(n)||!bn(n,r))continue;let s=Array.isArray(r)?r:[r];for(let i of s){if(typeof i!="object"||i===null)continue;let o={},a=[];for(let[d,l]of Object.entries(i))if(!Ve.has(d))if(bn(d,l)){let c=Array.isArray(l)?l:[l];for(let u of c){if(typeof u!="object"||u===null)continue;let p={},m=Nr(u);for(let[g,f]of Object.entries(u))Ve.has(g)||!bn(g,f)&&typeof f!="object"&&(p[g]=String(f));a.push({name:d,fields:p,...m.length>0?{children:m}:{}});}}else typeof l!="object"&&(o[d]=String(l));e.push({name:n,fields:o,...a.length>0?{children:a}:{}});}}return e}function xr(t){let e=Ra.parse(t),n=Object.keys(e).find(u=>u!=="?xml");if(!n)throw new Error("Invalid IDoc XML: no root element found");let r=n,i=e[n].IDOC;if(!i||!Array.isArray(i)||i.length===0)throw new Error("Invalid IDoc XML: no IDOC element found");let o=i[0],a=o.EDI_DC40,d={};if(a){let u=Array.isArray(a)?a[0]:a;for(let[p,m]of Object.entries(u))!Ve.has(p)&&typeof m!="object"&&(d[p]=String(m));}let l={};for(let[u,p]of Object.entries(o))u==="EDI_DC40"||Ve.has(u)||(l[u]=p);let c=Nr(l);return {idocType:r,controlRecord:d,segments:c}}var Pa=10*1024*1024,bt=class extends Error{};function ka(t,e){return new Promise((n,r)=>{let s=[],i=0,o=false;t.on("data",a=>{if(!o){if(i+=a.length,i>e){o=true,s.length=0,r(new bt(`Request body exceeds ${e} bytes`));return}s.push(a);}}),t.on("end",()=>{o||n(Buffer.concat(s).toString("utf-8"));}),t.on("error",a=>{o||r(a);});})}function _a(t,e){if(e.length===0||typeof t!="string")return false;if(t.startsWith("Bearer "))return je(t.slice(7),e);if(t.startsWith("Basic ")){let n=Buffer.from(t.slice(6),"base64").toString("utf-8"),r=n.indexOf(":");return r===-1?false:je(n.slice(r+1),e)}return false}function Oa(t){if(typeof t!="string")return true;let e=(t.split(";")[0]??"").trim().toLowerCase();return e.endsWith("xml")||e==="application/x-sap.idoc"}function Tt(t,e={}){let n=e.maxBodyBytes??Pa;return (r,s)=>{if(r.method!=="POST"){s.writeHead(405,{"Content-Type":"text/plain"}),s.end("Method Not Allowed");return}if(e.secret!==void 0&&!_a(r.headers.authorization,e.secret)){s.writeHead(401,{"Content-Type":"text/plain","WWW-Authenticate":'Basic realm="idoc-webhook"'}),s.end("Unauthorized"),r.destroy();return}if(!Oa(r.headers["content-type"])){s.writeHead(415,{"Content-Type":"text/plain"}),s.end("Unsupported Media Type: expected XML"),r.destroy();return}ka(r,n).then(i=>{let{idocType:o,controlRecord:a,segments:d}=xr(i),l={docnum:a.DOCNUM||`UNKNOWN_${Date.now()}`,idocType:o,mesType:a.MESTYP||"",receivedAt:new Date,rawXml:i,parsed:{controlRecord:a,segments:d}};t.add(l),s.writeHead(200,{"Content-Type":"text/plain"}),s.end("OK");}).catch(i=>{if(i instanceof bt){s.writeHead(413,{"Content-Type":"text/plain"}),s.end("Payload Too Large"),r.destroy();return}s.writeHead(400,{"Content-Type":"text/plain"}),s.end(`Parse error: ${i instanceof Error?i.message:String(i)}`);});}}function Mr(t,e,n={}){let r=Tt(e,n);return new Promise((s,i)=>{let o=createServer((d,l)=>{d.method==="POST"&&d.url==="/idoc"?r(d,l):(l.writeHead(404,{"Content-Type":"text/plain"}),l.end("Not Found"));}),a=()=>{let d=o.address(),l=typeof d=="object"&&d!==null?d.port:t;s({port:l,close:()=>new Promise((c,u)=>{o.close(p=>p?u(p):c());})});};n.host?o.listen(t,n.host,a):o.listen(t,a),o.on("error",i);})}var $r=1;function wt(t){if(!t.directory)return [];let e=join(t.directory,t.fileName),n;try{n=readFileSync(e,"utf-8");}catch{return []}try{let r=JSON.parse(n);if(r?.version!==$r||!Array.isArray(r.entries))return t.onWarn?.(`Cache-Datei ${e} hat ein unbekanntes Format und wird verworfen.`),[];let s=Date.now()-t.ttlMs;return r.entries.filter(i=>i&&typeof i.key=="string"&&typeof i.storedAt=="number"&&i.storedAt>s)}catch(r){return t.onWarn?.(`Cache-Datei ${e} ist unlesbar und wird verworfen. Der Cache wird aus SAP neu aufgebaut.`,r),[]}}function At(t,e){if(!e.directory)return;let n=join(e.directory,e.fileName),r=`${n}.tmp`;try{mkdirSync(dirname(n),{recursive:!0}),writeFileSync(r,JSON.stringify({version:$r,entries:t}),"utf-8"),renameSync(r,n);}catch(s){e.onWarn?.(`Cache konnte nicht nach ${n} geschrieben werden. Der Betrieb l\xE4uft weiter, nach einem Neustart ist der Cache aber leer.`,s);try{unlinkSync(r);}catch{}}}var La=30,Ba="catalog-cache.json",Lr="catalog",Q=class{cache=null;ttlMs;key;persistence;constructor(e={}){let n=typeof e=="number"?{ttlMinutes:e}:e;this.ttlMs=(n.ttlMinutes??La)*60*1e3;let r=(n.baseUrl??"").replace(/\/+$/,"").toLowerCase();if(this.key=r?`${r}|${Lr}`:Lr,n.persistDir){this.persistence={directory:n.persistDir,fileName:Ba,ttlMs:this.ttlMs,...n.onWarn?{onWarn:n.onWarn}:{}};let s=wt(this.persistence).find(i=>i.key===this.key);s&&(this.cache={entries:s.value,timestamp:s.storedAt});}}get(){return this.cache?Date.now()-this.cache.timestamp>this.ttlMs?(this.cache=null,null):this.cache.entries:null}set(e){this.cache={entries:e,timestamp:Date.now()},this.persist();}clear(){this.cache=null,this.persist();}persist(){this.persistence&&At(this.cache?[{key:this.key,value:this.cache.entries,storedAt:this.cache.timestamp}]:[],this.persistence);}};var Tn=0;function Br(t){let e=t.docnum??`${Date.now().toString().padStart(13,"0")}${String(Tn++).padStart(3,"0")}`;Tn>=1e3&&(Tn=0);let n=t.mesType??t.idocType.replace(/\d+$/,"");return {TABNAM:"EDI_DC40",DOCNUM:e,DIRECT:"2",IDOCTYP:t.idocType,MESTYP:n,SNDPOR:t.sndpor,SNDPRT:t.sndprt??"LS",SNDPRN:t.sndprn,RCVPOR:t.rcvpor,RCVPRT:t.rcvprt??"LS",RCVPRN:t.rcvprn,...t.extra}}function Fa(t,e,n){return e.required&&n===""?{segmentName:t,fieldName:e.name,expectedType:e.dataType,expectedLength:e.length,actualValue:n,violation:"Required field is empty"}:n===""?null:(e.dataType==="CHAR"||e.dataType==="NUMC")&&n.length>e.length?{segmentName:t,fieldName:e.name,expectedType:e.dataType,expectedLength:e.length,actualValue:n,violation:`Field value exceeds max length ${e.length} (actual: ${n.length})`}:e.dataType==="NUMC"&&!/^\d*$/.test(n)?{segmentName:t,fieldName:e.name,expectedType:e.dataType,expectedLength:e.length,actualValue:n,violation:"NUMC field must contain only digits"}:e.dataType==="DATS"&&!/^\d{8}$/.test(n)?{segmentName:t,fieldName:e.name,expectedType:e.dataType,expectedLength:e.length,actualValue:n,violation:"DATS field must be in YYYYMMDD format"}:e.dataType==="TIMS"&&!/^\d{6}$/.test(n)?{segmentName:t,fieldName:e.name,expectedType:e.dataType,expectedLength:e.length,actualValue:n,violation:"TIMS field must be in HHMMSS format"}:null}function Ha(t,e){return t.filter(n=>n.name===e).length}function Fr(t,e,n){let r=new Set;for(let s of t){if(r.has(s.name))continue;r.add(s.name);let i=e.get(s.name);if(!i)continue;let o=Ha(t,s.name);o>i.maxOccurrence&&n.push({segmentName:s.name,fieldName:"",expectedType:"",expectedLength:i.maxOccurrence,actualValue:String(o),violation:`Segment count ${o} exceeds maxOccurrence ${i.maxOccurrence}`});}for(let s of t){let i=e.get(s.name);if(!i){n.push({segmentName:s.name,fieldName:"",expectedType:"",expectedLength:0,actualValue:"",violation:`Unknown segment '${s.name}' not found in metadata`});continue}for(let o of i.fields){let a=s.fields[o.name]??"",d=Fa(s.name,o,a);d&&n.push(d);}s.children&&s.children.length>0&&Fr(s.children,e,n);}}function Hr(t,e){if(!e)return [];let n=new Map;for(let s of e.segments)n.set(s.name,s);let r=[];return Fr(t,n,r),r}var Va=new XMLBuilder({ignoreAttributes:false,attributeNamePrefix:"@_",format:true,suppressEmptyNode:false});function jr(t){let e={"@_SEGMENT":"1"};for(let[n,r]of Object.entries(t.fields))e[n]=r;if(t.children)for(let n of t.children){let r=jr(n),s=e[n.name];s?Array.isArray(s)?s.push(r):e[n.name]=[s,r]:e[n.name]=r;}return e}function Vr(t,e,n){let r={};for(let i of n){let o=jr(i),a=r[i.name];a?Array.isArray(a)?a.push(o):r[i.name]=[a,o]:r[i.name]=o;}let s={"?xml":{"@_version":"1.0","@_encoding":"UTF-8"},[t]:{IDOC:{"@_BEGIN":"1",EDI_DC40:{"@_SEGMENT":"1",...e},...r}}};return Va.build(s)}var vt=class{constructor(e,n,r){this.httpClient=e;this.sapClient=n;this.partnerDefaults=r;}async send(e){let n={...this.partnerDefaults,...e.partnerOverrides},r=Br({idocType:e.idocType,sndpor:n.sndpor??"",sndprn:n.sndprn??"",rcvpor:n.rcvpor??"",rcvprn:n.rcvprn??"",sndprt:n.sndprt,rcvprt:n.rcvprt,mesType:n.mesType,docnum:n.docnum,extra:n.extra});if(e.metadata){let u=Hr(e.segments,e.metadata);if(u.length>0)return {success:false,docnum:r.DOCNUM,message:"Validation failed",violations:u}}let s=Vr(e.idocType,r,e.segments),i="/sap/bc/idoc_xml";this.sapClient&&(i+=`?sap-client=${this.sapClient}`);let o=await this.httpClient.request({method:"post",url:i,data:s,headers:{"Content-Type":"text/xml"}}),a=typeof o.data=="string"?o.data:String(o.data);if(a.includes("<title>IDoc-XML-inbound ok</title>"))return {success:true,docnum:r.DOCNUM,message:"IDoc sent successfully"};let c=a.match(/<title>(.*?)<\/title>/)?.[1]??"IDoc send failed";return {success:false,docnum:r.DOCNUM,message:c}}};var Et={core:["test-connection","sap_list_services","sap_get_metadata","sap_discover_services","sap_nl_query"],odata:["sap_read","sap_query","sap_create","sap_update","sap_delete","sap_function","sap_batch","sap_media_upload","sap_media_download"],idoc:["sap_idoc_send","sap_idoc_status","sap_idoc_discover","sap_idoc_list_received"],rfc:["sap_rfc_call","sap_rfc_metadata","sap_bapi_call","sap_bapi_commit","sap_rfc_search_functions"]},We=new Set(["sap_create","sap_update","sap_delete","sap_batch","sap_media_upload","sap_idoc_send","sap_rfc_call","sap_bapi_call","sap_bapi_commit"]),wn=["core","odata"],Wr=new Map;for(let[t,e]of Object.entries(Et))for(let n of e)Wr.set(n,t);var Ct=class{handles=new Map;activeTiers;options;constructor(e){this.options=e,this.activeTiers=new Set(e.activeTiers);}registerHandle(e,n){this.handles.set(e,n);}applyInitialVisibility(){for(let[e,n]of this.handles)this.shouldToolBeVisible(e)||n.disable();}enableTier(e){if(this.options.allowedTiers&&!this.options.allowedTiers.includes(e))return {error:`Cannot enable ${e} tier: not permitted by the token policy of this connection (allowed: ${this.options.allowedTiers.join(", ")})`};if(e==="idoc"&&!this.options.hasIdocConfig)return {error:"Cannot enable IDoc tier: no IDoc partner configuration provided (--sndprn, --rcvprn required)"};if(e==="rfc"&&!this.options.hasRfcConfig)return {error:"Cannot enable RFC tier: no RFC connection configuration provided (SAP_RFC_ASHOST + SAP_RFC_SYSNR, or SAP_RFC_MSHOST + SAP_RFC_GROUP required)"};this.activeTiers.add(e);let n=Et[e],r=[];for(let s of n){if(this.options.readOnly&&We.has(s))continue;let i=this.handles.get(s);i&&(i.enable(),r.push(s));}return {enabled:r,activeTiers:this.getActiveTiers()}}getActiveTiers(){return Array.from(this.activeTiers)}getAllowedTiers(){return this.options.allowedTiers?[...this.options.allowedTiers]:void 0}getToolsByTier(e){return Et[e]}isReadOnlyMode(){return this.options.readOnly}shouldToolBeVisible(e){let n=Wr.get(e);return n?!(!this.activeTiers.has(n)||this.options.allowedTiers&&!this.options.allowedTiers.includes(n)||n==="idoc"&&!this.options.hasIdocConfig||n==="rfc"&&!this.options.hasRfcConfig||this.options.readOnly&&We.has(e)):true}};function Gr(t){let e=t.tiers??wn,n=[];for(let r of e)if(!(r==="idoc"&&!t.hasIdocConfig)&&!(r==="rfc"&&!t.hasRfcConfig))for(let s of Et[r])We.has(s)&&n.push(s);return n}var qr="0.0.0-unknown",Kr="guniweb-sap-mcp";function za(t){if(typeof t!="string"||t.length===0)return qr;let e=resolve(t);for(;;){try{let r=readFileSync(join(e,"package.json"),"utf-8"),s=JSON.parse(r);if(s.name===Kr&&typeof s.version=="string")return s.version}catch{}let n=dirname(e);if(n===e)return qr;e=n;}}var ke=za(import.meta.dirname),zr=Kr;var Ya=/^([0-9a-f]{2})-([0-9a-f]{32})-([0-9a-f]{16})-([0-9a-f]{2})(-.*)?$/,Yr=/^0+$/;function An(t){if(typeof t!="string")return;let e=t.trim();if(e.length>512)return;let n=Ya.exec(e);if(!n)return;let[,r,s,i,,o]=n;if(r!=="ff"&&!(r==="00"&&o!==void 0)&&!(Yr.test(s)||Yr.test(i)))return {traceId:s,parentId:i}}function Xr(t){if(!(!t||typeof t!="object")){for(let[e,n]of Object.entries(t))if(e.toLowerCase()==="traceparent")return Array.isArray(n)?void 0:An(n)}}var Rt=30,Xa={authKind:"stdio",personal:false};function Ja(t,e){return We.has(t)||(e.mutatingCalls?.count??0)>0?"write":t==="sap_function"&&e.sapCalls.count===0?"unknown":"read"}var Za=5e3;function Qa(t,e,n,r){let s=t?._meta?.progressToken,i=t?.sendNotification;if(s===void 0||typeof i!="function"||r.afterMs<=0)return ()=>{};let a=setInterval(()=>{let d=Date.now()-n;i({method:"notifications/progress",params:{progressToken:s,progress:Math.round(d/1e3),...r.budgetMs?{total:Math.round(r.budgetMs/1e3)}:{},message:`${e.toolName}: ${Math.round(d/1e3)} s, ${e.sapCalls.count} SAP-Aufruf(e)`}}).catch(()=>{});},r.afterMs);return a.unref?.(),()=>clearInterval(a)}var ec="SAP_TLS_VERIFY=false: Die Zertifikatspr\xFCfung ist abgeschaltet \u2014 die Verbindung zu SAP ist nicht gegen einen Angreifer in der Leitung gesch\xFCtzt. Richtiger Weg: Root-CA \xFCber SAP_CA_CERT (bzw. NODE_EXTRA_CA_CERTS) einbinden und SAP_TLS_VERIFY wieder entfernen.";function tc(t){return {...t,content:[...t.content,{type:"text",text:`\u26A0\uFE0F ${ec}`}]}}function nc(t,e,n,r,s){return {content:[{type:"text",text:JSON.stringify({truncated:true,reason:`Zeitbudget von ${Math.round(s/1e3)} s \xFCberschritten \u2014 der Aufruf wurde abgebrochen, damit die Verbindung nicht h\xE4ngen bleibt.`,hint:"Grenzen Sie die Anfrage ein (top/skip, filter, search) oder erh\xF6hen Sie --tool-timeout. Der Wert sollte unter der kleinsten Client-Grenze bleiben (Cloudflare 100 s, n8n-MCP-Transport 300 s).",tool:t,correlationId:e,elapsedMs:n,sapCalls:r},null,2)}],isError:true}}function rc(t,e){return {content:[{type:"text",text:JSON.stringify({aborted:true,reason:"Der Client hat die Verbindung verworfen; die Arbeit wurde eingestellt.",tool:t,correlationId:e})}],isError:true}}function Jr(t,e,n={}){let{toolTimeoutMs:r,logger:s,tlsVerifyDisabled:i,governance:o}=n,a=n.progressAfterMs??Za;return async(d,l)=>{let c=Kn(),{signal:u,deadline:p}=Jn(l?.signal,r),m=Xr(l?.requestInfo?.headers)??An(l?._meta?.traceparent),g={correlationId:c,...m?{traceId:m.traceId}:{},toolName:t,signal:u,deadline:p,sapCalls:{count:0},mutatingCalls:{count:0}},f=Date.now();return zn(g,async()=>{let h=Qa(l,g,f,{afterMs:a,...r?{budgetMs:r}:{}}),S="ok",y,E=(async()=>e(d,l))();E.catch(()=>{});try{y=await Promise.race([E,sc(u,t)]),y?.isError&&(S="error");}catch(v){if(v instanceof F)S=v.timedOut?"timeout":"aborted",y=v.timedOut?nc(t,c,Date.now()-f,g.sapCalls.count,r??0):rc(t,c);else {S="error";let M=v instanceof Error?v.message:String(v);y={content:[{type:"text",text:JSON.stringify({error:M,tool:t,correlationId:c})}],isError:true};}}S==="ok"&&u?.aborted&&(S=u.reason?.name==="TimeoutError"?"timeout":"aborted"),h();let b=i?tc(y):y;if(s?.info({correlationId:c,...m?{traceId:m.traceId,parentId:m.parentId}:{},tool:t,outcome:S,durationMs:Date.now()-f,sapCalls:g.sapCalls.count,resultBytes:ic(y),...r?{budgetMs:r}:{}},"MCP tool call"),o){let v={apiVersion:1,serverVersion:n.serverVersion??ke,correlationId:c,...m?{traceId:m.traceId,parentId:m.parentId}:{},tool:t,kind:Ja(t,g),outcome:S,startedAt:new Date(f).toISOString(),durationMs:Date.now()-f,sapCalls:g.sapCalls.count,...n.destination?{destination:n.destination}:{},identity:n.callerIdentity??Xa,args:d,result:y};try{o.onToolCall(v);}catch(M){s?.error({err:M,correlationId:c,tool:t,module:o.name},"Governance-Modul: Aufruf konnte nicht gemeldet werden");}}return b})}}function sc(t,e){return t?new Promise((n,r)=>{let s=()=>{let i=t.reason?.name==="TimeoutError";r(new F(i,e));};if(t.aborted){s();return}t.addEventListener("abort",s,{once:true});}):new Promise(()=>{})}function ic(t){if(!t?.content)return 0;let e=0;for(let n of t.content)typeof n?.text=="string"&&(e+=Buffer.byteLength(n.text,"utf-8"));return e}var oc=1440*60*1e3,ac="metadata-cache.json",I=class{cache=new Map;ttlMs;baseUrl;persistence;constructor(e={}){if(this.ttlMs=e.ttlMs??oc,this.baseUrl=cc(e.baseUrl),e.persistDir){this.persistence={directory:e.persistDir,fileName:ac,ttlMs:this.ttlMs,...e.onWarn?{onWarn:e.onWarn}:{}};for(let n of wt(this.persistence))this.cache.set(n.key,{value:n.value,storedAt:n.storedAt});}}get size(){return this.cache.size}get(e){let n=this.key(e),r=this.cache.get(n);if(r){if(Date.now()-r.storedAt>this.ttlMs){this.cache.delete(n);return}return r.value}}set(e,n){this.cache.set(this.key(e),{value:n,storedAt:Date.now()}),this.persist();}has(e){return this.get(e)!==void 0}clear(){this.cache.clear(),this.persist();}key(e){let n=e.replace(/\/+$/,"");return this.baseUrl?`${this.baseUrl}|${n}`:n}persist(){this.persistence&&At([...this.cache.entries()].map(([e,n])=>({key:e,value:n.value,storedAt:n.storedAt})),this.persistence);}};function cc(t){return t?t.replace(/\/+$/,"").toLowerCase():""}function Zr(t){t.registerPrompt("nl-to-odata-query",{title:"Natural Language to OData Query",description:"Convert a natural language question into a correct OData query against an SAP service. Reads entity schema for context, applies V2/V4 syntax rules, and enforces read-only by default.",argsSchema:{serviceUrl:z$2.string().describe("OData service URL, e.g., /sap/opu/odata/sap/API_BUSINESS_PARTNER"),entitySet:z$2.string().describe("Entity set to query, e.g., A_BusinessPartner"),question:z$2.string().describe('Natural language question, e.g., "show me all customers in Germany"'),allowWrite:z$2.boolean().optional().describe("Allow write operations (create/update/delete). Default: false (read-only)")}},async({serviceUrl:e,entitySet:n,question:r,allowWrite:s})=>{let i=s===true?"":`
109
+ `)}`)}return o.current=a.value,o.currentRaw=a.raw,o}get version(){return this.currentVersion}get(e){return this.current.destinations.get(e)}names(){return [...this.current.destinations.keys()]}defaultDestination(){let e=this.current.destinations.get(me);if(e)return e;if(this.current.destinations.size===1)return this.current.destinations.values().next().value}tokens(){return this.current.tokens}onChange(e){return this.changeListeners.add(e),()=>this.changeListeners.delete(e)}onError(e){return this.errorListeners.add(e),()=>this.errorListeners.delete(e)}reload(){return this.source==="env"?Promise.resolve({ok:true,changed:false}):this.reloadInFlight?(this.reloadQueued=true,this.reloadInFlight):(this.reloadInFlight=this.doReload().finally(()=>{this.reloadInFlight=void 0,this.reloadQueued&&(this.reloadQueued=false,this.reload());}),this.reloadInFlight)}watch(){if(!(this.source==="env"||!this.filePath)&&(this.sighupHandler||(this.sighupHandler=()=>{this.reload();},process.on("SIGHUP",this.sighupHandler)),this.observeFile&&!this.polling&&(this.polling=true,watchFile(this.filePath,{persistent:false,interval:Mr},(e,n)=>{(e.mtimeMs!==n.mtimeMs||e.size!==n.size)&&this.scheduleReload();}),this.startupRecheck=setTimeout(()=>{this.startupRecheck=void 0,this.scheduleReload();},Mr+500),this.startupRecheck.unref()),this.observeFile&&!this.watcher))try{this.watcher=watch(dirname(this.filePath),{persistent:!1},()=>{this.scheduleReload();}),this.watcher.on("error",e=>{this.warn(`Dateibeobachtung f\xFCr ${this.filePath} ausgefallen (${e.message}); SIGHUP l\xE4dt weiterhin neu.`),this.watcher=void 0;});}catch(e){this.warn(`Dateibeobachtung f\xFCr ${this.filePath} nicht m\xF6glich (${e instanceof Error?e.message:String(e)}); SIGHUP l\xE4dt weiterhin neu.`);}}close(){this.debounceTimer&&(clearTimeout(this.debounceTimer),this.debounceTimer=void 0),this.startupRecheck&&(clearTimeout(this.startupRecheck),this.startupRecheck=void 0),this.watcher&&(this.watcher.close(),this.watcher=void 0),this.polling&&this.filePath&&(unwatchFile(this.filePath),this.polling=false),this.sighupHandler&&(process.off("SIGHUP",this.sighupHandler),this.sighupHandler=void 0),this.changeListeners.clear(),this.errorListeners.clear();}scheduleReload(){this.debounceTimer&&clearTimeout(this.debounceTimer),this.debounceTimer=setTimeout(()=>{this.debounceTimer=void 0,this.reload();},_a),this.debounceTimer.unref();}async doReload(){let e=await this.readAndParse();if(!e.ok){if(e.missing&&this.currentRaw===void 0)return {ok:true,changed:false};for(let r of this.errorListeners)r(e.errors);return {ok:false,errors:e.errors}}if(e.raw===this.currentRaw)return {ok:true,changed:false};this.current=e.value,this.currentRaw=e.raw,this.currentVersion+=1;let n={version:this.currentVersion,names:this.names(),tokenCount:this.current.tokens.length};for(let r of this.changeListeners)r(n);return {ok:true,changed:true}}async readAndParse(){if(!this.filePath)return {ok:false,errors:["Kein Dateipfad konfiguriert."]};let e;try{e=await readFile(this.filePath,"utf8");}catch(s){let i=s.code,o=i==="ENOENT"?"Datei nicht gefunden":s.message;return {ok:false,errors:[`${this.filePath}: ${o}`],missing:i==="ENOENT"}}let n;try{n=JSON.parse(e);}catch(s){return {ok:false,errors:[`${this.filePath}: kein g\xFCltiges JSON (${s instanceof Error?s.message:String(s)})`]}}let r=wt(n,this.env);return r.ok?(this.envDefault&&(r.value.destinations.has(me)?this.warnedFileWins||(this.warnedFileWins=true,this.warn(`Sowohl ${this.filePath} als auch die SAP_*-Umgebung definieren die Destination "default" \u2014 die Datei gilt, die Umgebung wird ignoriert.`)):r.value.destinations.set(me,this.envDefault)),{ok:true,value:r.value,raw:e}):r}};function Ur(t){return createHash("sha256").update(JSON.stringify(t)??"undefined").digest("hex")}function An(t){return t.slice(7,19)}function $r(t,e){let n=new Map;for(let s of t)n.set(s.hash,{label:s.label??An(s.hash),destination:s.destination,revoked:s.revoked===true,policy:Ur(s.policy??null)});let r=new Map;for(let s of e){let i=new Map;for(let[o,a]of Object.entries(s))o!=="name"&&i.set(o,Ur(a));r.set(s.name??"default",i);}return {tokens:n,destinations:r}}function Lr(t,e){let n=[];for(let[r,s]of e.destinations){let i=t.destinations.get(r);if(!i){n.push({type:"destination-added",name:r});continue}let o=[...new Set([...s.keys(),...i.keys()])].filter(a=>s.get(a)!==i.get(a)).sort();o.length>0&&n.push({type:"destination-changed",name:r,fields:o});}for(let r of t.destinations.keys())e.destinations.has(r)||n.push({type:"destination-removed",name:r});for(let[r,s]of e.tokens){let i=t.tokens.get(r),o={tokenLabel:s.label,hashPrefix:An(r),destination:s.destination};if(!i){n.push({type:s.revoked?"token-added-revoked":"token-added",...o});continue}!i.revoked&&s.revoked?n.push({type:"token-revoked",...o}):i.revoked&&!s.revoked&&n.push({type:"token-reactivated",...o});let a=[...i.label!==s.label?["label"]:[],...i.destination!==s.destination?["destination"]:[],...i.policy!==s.policy?["policy"]:[]];a.length>0&&n.push({type:"token-changed",...o,fields:a});}for(let[r,s]of t.tokens)e.tokens.has(r)||n.push({type:"token-removed",tokenLabel:s.label,hashPrefix:An(r),destination:s.destination});return n}var Br="@guniweb/sap-mcp-governance";function xa(t){return isAbsolute(t)?t:createRequire(import.meta.url).resolve(t)}function Ma(t){let e=t?.code;return e==="MODULE_NOT_FOUND"||e==="ERR_MODULE_NOT_FOUND"}async function Fr(t,e={},n){let r=e.resolve??xa,s=e.importer??(u=>import(u)),i=n?.trim()||t.env.SAP_MCP_GOVERNANCE_MODULE?.trim()||void 0,o=i??Br,a;try{a=r(o);}catch(u){if(!i&&Ma(u))return {status:"not-installed"};throw new Error(`Governance-Modul "${o}" ist konfiguriert, aber nicht auffindbar: ${u.message}`)}let d;try{d=await s(pathToFileURL(a).href);}catch(u){throw new Error(`Governance-Modul "${o}" konnte nicht geladen werden: ${u.message}`)}let l=d.createGovernance??d.default;if(typeof l!="function")throw new Error(`Governance-Modul "${o}" exportiert keine Funktion createGovernance (oder default).`);let c=await l(t);if(c?.apiVersion!==1)throw new Error(`Governance-Modul "${o}" spricht apiVersion ${String(c?.apiVersion)}, dieser Server ${1}. Passende Versionen von Server und Modul verwenden.`);if(typeof c.onToolCall!="function")throw new Error(`Governance-Modul "${o}" hat keine Funktion onToolCall.`);return {status:"active",module:c,specifier:o}}var Ua=new Set(["off","false","0","no"]),Hr="https://guniweb.de/sap-mcp",jr="support@guniweb.de";function Vr(t){let e=t.SAP_MCP_GOVERNANCE_NOTICE?.trim().toLowerCase();if(!(e&&Ua.has(e)))return {msg:`Governance module not loaded \u2014 SAP access is logged for operations only. The GuniWeb Governance module adds a durable, queryable call journal for audits (who, which object, what result; no payload). More: ${Hr} \xB7 ${jr} (hide with SAP_MCP_GOVERNANCE_NOTICE=off)`,fields:{governance:"not-installed",learnMore:Hr,contact:jr}}}var _e=class{buffer=[];maxSize;constructor(e=100){this.maxSize=e;}add(e){this.buffer.length>=this.maxSize&&this.buffer.shift(),this.buffer.push(e);}get(e){return this.buffer.find(n=>n.docnum===e)}list(){return [...this.buffer]}get count(){return this.buffer.length}};var La=new XMLParser({ignoreAttributes:false,attributeNamePrefix:"@_",parseTagValue:false,processEntities:false,htmlEntities:false,isArray:t=>t==="IDOC"||t.startsWith("E1")||t.startsWith("E2")}),qe=new Set(["@_SEGMENT","@_BEGIN"]);function En(t,e){return !!(t.startsWith("E1")||t.startsWith("E2")||typeof e=="object"&&e!==null&&"@_SEGMENT"in e)}function Wr(t){let e=[];for(let[n,r]of Object.entries(t)){if(qe.has(n)||!En(n,r))continue;let s=Array.isArray(r)?r:[r];for(let i of s){if(typeof i!="object"||i===null)continue;let o={},a=[];for(let[d,l]of Object.entries(i))if(!qe.has(d))if(En(d,l)){let c=Array.isArray(l)?l:[l];for(let u of c){if(typeof u!="object"||u===null)continue;let p={},m=Wr(u);for(let[f,g]of Object.entries(u))qe.has(f)||!En(f,g)&&typeof g!="object"&&(p[f]=String(g));a.push({name:d,fields:p,...m.length>0?{children:m}:{}});}}else typeof l!="object"&&(o[d]=String(l));e.push({name:n,fields:o,...a.length>0?{children:a}:{}});}}return e}function Gr(t){let e=La.parse(t),n=Object.keys(e).find(u=>u!=="?xml");if(!n)throw new Error("Invalid IDoc XML: no root element found");let r=n,i=e[n].IDOC;if(!i||!Array.isArray(i)||i.length===0)throw new Error("Invalid IDoc XML: no IDOC element found");let o=i[0],a=o.EDI_DC40,d={};if(a){let u=Array.isArray(a)?a[0]:a;for(let[p,m]of Object.entries(u))!qe.has(p)&&typeof m!="object"&&(d[p]=String(m));}let l={};for(let[u,p]of Object.entries(o))u==="EDI_DC40"||qe.has(u)||(l[u]=p);let c=Wr(l);return {idocType:r,controlRecord:d,segments:c}}var Ba=10*1024*1024,Et=class extends Error{};function Fa(t,e){return new Promise((n,r)=>{let s=[],i=0,o=false;t.on("data",a=>{if(!o){if(i+=a.length,i>e){o=true,s.length=0,r(new Et(`Request body exceeds ${e} bytes`));return}s.push(a);}}),t.on("end",()=>{o||n(Buffer.concat(s).toString("utf-8"));}),t.on("error",a=>{o||r(a);});})}function Ha(t,e){if(e.length===0||typeof t!="string")return false;if(t.startsWith("Bearer "))return Ge(t.slice(7),e);if(t.startsWith("Basic ")){let n=Buffer.from(t.slice(6),"base64").toString("utf-8"),r=n.indexOf(":");return r===-1?false:Ge(n.slice(r+1),e)}return false}function ja(t){if(typeof t!="string")return true;let e=(t.split(";")[0]??"").trim().toLowerCase();return e.endsWith("xml")||e==="application/x-sap.idoc"}function Ct(t,e={}){let n=e.maxBodyBytes??Ba;return (r,s)=>{if(r.method!=="POST"){s.writeHead(405,{"Content-Type":"text/plain"}),s.end("Method Not Allowed");return}if(e.secret!==void 0&&!Ha(r.headers.authorization,e.secret)){s.writeHead(401,{"Content-Type":"text/plain","WWW-Authenticate":'Basic realm="idoc-webhook"'}),s.end("Unauthorized"),r.destroy();return}if(!ja(r.headers["content-type"])){s.writeHead(415,{"Content-Type":"text/plain"}),s.end("Unsupported Media Type: expected XML"),r.destroy();return}Fa(r,n).then(i=>{let{idocType:o,controlRecord:a,segments:d}=Gr(i),l={docnum:a.DOCNUM||`UNKNOWN_${Date.now()}`,idocType:o,mesType:a.MESTYP||"",receivedAt:new Date,rawXml:i,parsed:{controlRecord:a,segments:d}};t.add(l),s.writeHead(200,{"Content-Type":"text/plain"}),s.end("OK");}).catch(i=>{if(i instanceof Et){s.writeHead(413,{"Content-Type":"text/plain"}),s.end("Payload Too Large"),r.destroy();return}s.writeHead(400,{"Content-Type":"text/plain"}),s.end(`Parse error: ${i instanceof Error?i.message:String(i)}`);});}}function qr(t,e,n={}){let r=Ct(e,n);return new Promise((s,i)=>{let o=createServer((d,l)=>{d.method==="POST"&&d.url==="/idoc"?r(d,l):(l.writeHead(404,{"Content-Type":"text/plain"}),l.end("Not Found"));}),a=()=>{let d=o.address(),l=typeof d=="object"&&d!==null?d.port:t;s({port:l,close:()=>new Promise((c,u)=>{o.close(p=>p?u(p):c());})});};n.host?o.listen(t,n.host,a):o.listen(t,a),o.on("error",i);})}var zr=1;function Rt(t){if(!t.directory)return [];let e=join(t.directory,t.fileName),n;try{n=readFileSync(e,"utf-8");}catch{return []}try{let r=JSON.parse(n);if(r?.version!==zr||!Array.isArray(r.entries))return t.onWarn?.(`Cache-Datei ${e} hat ein unbekanntes Format und wird verworfen.`),[];let s=Date.now()-t.ttlMs;return r.entries.filter(i=>i&&typeof i.key=="string"&&typeof i.storedAt=="number"&&i.storedAt>s)}catch(r){return t.onWarn?.(`Cache-Datei ${e} ist unlesbar und wird verworfen. Der Cache wird aus SAP neu aufgebaut.`,r),[]}}function Pt(t,e){if(!e.directory)return;let n=join(e.directory,e.fileName),r=`${n}.tmp`;try{mkdirSync(dirname(n),{recursive:!0}),writeFileSync(r,JSON.stringify({version:zr,entries:t}),"utf-8"),renameSync(r,n);}catch(s){e.onWarn?.(`Cache konnte nicht nach ${n} geschrieben werden. Der Betrieb l\xE4uft weiter, nach einem Neustart ist der Cache aber leer.`,s);try{unlinkSync(r);}catch{}}}var Xa=30,Ja="catalog-cache.json",Yr="catalog",re=class{cache=null;ttlMs;key;persistence;constructor(e={}){let n=typeof e=="number"?{ttlMinutes:e}:e;this.ttlMs=(n.ttlMinutes??Xa)*60*1e3;let r=(n.baseUrl??"").replace(/\/+$/,"").toLowerCase();if(this.key=r?`${r}|${Yr}`:Yr,n.persistDir){this.persistence={directory:n.persistDir,fileName:Ja,ttlMs:this.ttlMs,...n.onWarn?{onWarn:n.onWarn}:{}};let s=Rt(this.persistence).find(i=>i.key===this.key);s&&(this.cache={entries:s.value,timestamp:s.storedAt});}}get(){return this.cache?Date.now()-this.cache.timestamp>this.ttlMs?(this.cache=null,null):this.cache.entries:null}set(e){this.cache={entries:e,timestamp:Date.now()},this.persist();}clear(){this.cache=null,this.persist();}persist(){this.persistence&&Pt(this.cache?[{key:this.key,value:this.cache.entries,storedAt:this.cache.timestamp}]:[],this.persistence);}};var Cn=0;function Xr(t){let e=t.docnum??`${Date.now().toString().padStart(13,"0")}${String(Cn++).padStart(3,"0")}`;Cn>=1e3&&(Cn=0);let n=t.mesType??t.idocType.replace(/\d+$/,"");return {TABNAM:"EDI_DC40",DOCNUM:e,DIRECT:"2",IDOCTYP:t.idocType,MESTYP:n,SNDPOR:t.sndpor,SNDPRT:t.sndprt??"LS",SNDPRN:t.sndprn,RCVPOR:t.rcvpor,RCVPRT:t.rcvprt??"LS",RCVPRN:t.rcvprn,...t.extra}}function Za(t,e,n){return e.required&&n===""?{segmentName:t,fieldName:e.name,expectedType:e.dataType,expectedLength:e.length,actualValue:n,violation:"Required field is empty"}:n===""?null:(e.dataType==="CHAR"||e.dataType==="NUMC")&&n.length>e.length?{segmentName:t,fieldName:e.name,expectedType:e.dataType,expectedLength:e.length,actualValue:n,violation:`Field value exceeds max length ${e.length} (actual: ${n.length})`}:e.dataType==="NUMC"&&!/^\d*$/.test(n)?{segmentName:t,fieldName:e.name,expectedType:e.dataType,expectedLength:e.length,actualValue:n,violation:"NUMC field must contain only digits"}:e.dataType==="DATS"&&!/^\d{8}$/.test(n)?{segmentName:t,fieldName:e.name,expectedType:e.dataType,expectedLength:e.length,actualValue:n,violation:"DATS field must be in YYYYMMDD format"}:e.dataType==="TIMS"&&!/^\d{6}$/.test(n)?{segmentName:t,fieldName:e.name,expectedType:e.dataType,expectedLength:e.length,actualValue:n,violation:"TIMS field must be in HHMMSS format"}:null}function Qa(t,e){return t.filter(n=>n.name===e).length}function Jr(t,e,n){let r=new Set;for(let s of t){if(r.has(s.name))continue;r.add(s.name);let i=e.get(s.name);if(!i)continue;let o=Qa(t,s.name);o>i.maxOccurrence&&n.push({segmentName:s.name,fieldName:"",expectedType:"",expectedLength:i.maxOccurrence,actualValue:String(o),violation:`Segment count ${o} exceeds maxOccurrence ${i.maxOccurrence}`});}for(let s of t){let i=e.get(s.name);if(!i){n.push({segmentName:s.name,fieldName:"",expectedType:"",expectedLength:0,actualValue:"",violation:`Unknown segment '${s.name}' not found in metadata`});continue}for(let o of i.fields){let a=s.fields[o.name]??"",d=Za(s.name,o,a);d&&n.push(d);}s.children&&s.children.length>0&&Jr(s.children,e,n);}}function Zr(t,e){if(!e)return [];let n=new Map;for(let s of e.segments)n.set(s.name,s);let r=[];return Jr(t,n,r),r}var tc=new XMLBuilder({ignoreAttributes:false,attributeNamePrefix:"@_",format:true,suppressEmptyNode:false});function Qr(t){let e={"@_SEGMENT":"1"};for(let[n,r]of Object.entries(t.fields))e[n]=r;if(t.children)for(let n of t.children){let r=Qr(n),s=e[n.name];s?Array.isArray(s)?s.push(r):e[n.name]=[s,r]:e[n.name]=r;}return e}function es(t,e,n){let r={};for(let i of n){let o=Qr(i),a=r[i.name];a?Array.isArray(a)?a.push(o):r[i.name]=[a,o]:r[i.name]=o;}let s={"?xml":{"@_version":"1.0","@_encoding":"UTF-8"},[t]:{IDOC:{"@_BEGIN":"1",EDI_DC40:{"@_SEGMENT":"1",...e},...r}}};return tc.build(s)}var kt=class{constructor(e,n,r){this.httpClient=e;this.sapClient=n;this.partnerDefaults=r;}async send(e){let n={...this.partnerDefaults,...e.partnerOverrides},r=Xr({idocType:e.idocType,sndpor:n.sndpor??"",sndprn:n.sndprn??"",rcvpor:n.rcvpor??"",rcvprn:n.rcvprn??"",sndprt:n.sndprt,rcvprt:n.rcvprt,mesType:n.mesType,docnum:n.docnum,extra:n.extra});if(e.metadata){let u=Zr(e.segments,e.metadata);if(u.length>0)return {success:false,docnum:r.DOCNUM,message:"Validation failed",violations:u}}let s=es(e.idocType,r,e.segments),i="/sap/bc/idoc_xml";this.sapClient&&(i+=`?sap-client=${this.sapClient}`);let o=await this.httpClient.request({method:"post",url:i,data:s,headers:{"Content-Type":"text/xml"}}),a=typeof o.data=="string"?o.data:String(o.data);if(a.includes("<title>IDoc-XML-inbound ok</title>"))return {success:true,docnum:r.DOCNUM,message:"IDoc sent successfully"};let c=a.match(/<title>(.*?)<\/title>/)?.[1]??"IDoc send failed";return {success:false,docnum:r.DOCNUM,message:c}}};var _t={core:["test-connection","sap_list_services","sap_get_metadata","sap_discover_services","sap_nl_query"],odata:["sap_read","sap_query","sap_create","sap_update","sap_delete","sap_function","sap_batch","sap_media_upload","sap_media_download"],idoc:["sap_idoc_send","sap_idoc_status","sap_idoc_discover","sap_idoc_list_received"],rfc:["sap_rfc_call","sap_rfc_metadata","sap_bapi_call","sap_bapi_commit","sap_rfc_search_functions"]},Ke=new Set(["sap_create","sap_update","sap_delete","sap_batch","sap_media_upload","sap_idoc_send","sap_rfc_call","sap_bapi_call","sap_bapi_commit"]),Rn=["core","odata"],ts=new Map;for(let[t,e]of Object.entries(_t))for(let n of e)ts.set(n,t);var Ot=class{handles=new Map;activeTiers;options;constructor(e){this.options=e,this.activeTiers=new Set(e.activeTiers);}registerHandle(e,n){this.handles.set(e,n);}applyInitialVisibility(){for(let[e,n]of this.handles)this.shouldToolBeVisible(e)||n.disable();}enableTier(e){if(this.options.allowedTiers&&!this.options.allowedTiers.includes(e))return {error:`Cannot enable ${e} tier: not permitted by the token policy of this connection (allowed: ${this.options.allowedTiers.join(", ")})`};if(e==="idoc"&&!this.options.hasIdocConfig)return {error:"Cannot enable IDoc tier: no IDoc partner configuration provided (--sndprn, --rcvprn required)"};if(e==="rfc"&&!this.options.hasRfcConfig)return {error:"Cannot enable RFC tier: no RFC connection configuration provided (SAP_RFC_ASHOST + SAP_RFC_SYSNR, or SAP_RFC_MSHOST + SAP_RFC_GROUP required)"};this.activeTiers.add(e);let n=_t[e],r=[];for(let s of n){if(this.options.readOnly&&Ke.has(s))continue;let i=this.handles.get(s);i&&(i.enable(),r.push(s));}return {enabled:r,activeTiers:this.getActiveTiers()}}getActiveTiers(){return Array.from(this.activeTiers)}getAllowedTiers(){return this.options.allowedTiers?[...this.options.allowedTiers]:void 0}getToolsByTier(e){return _t[e]}isReadOnlyMode(){return this.options.readOnly}shouldToolBeVisible(e){let n=ts.get(e);return n?!(!this.activeTiers.has(n)||this.options.allowedTiers&&!this.options.allowedTiers.includes(n)||n==="idoc"&&!this.options.hasIdocConfig||n==="rfc"&&!this.options.hasRfcConfig||this.options.readOnly&&Ke.has(e)):true}};function ns(t){let e=t.tiers??Rn,n=[];for(let r of e)if(!(r==="idoc"&&!t.hasIdocConfig)&&!(r==="rfc"&&!t.hasRfcConfig))for(let s of _t[r])Ke.has(s)&&n.push(s);return n}var rs="0.0.0-unknown",ss="guniweb-sap-mcp";function oc(t){if(typeof t!="string"||t.length===0)return rs;let e=resolve(t);for(;;){try{let r=readFileSync(join(e,"package.json"),"utf-8"),s=JSON.parse(r);if(s.name===ss&&typeof s.version=="string")return s.version}catch{}let n=dirname(e);if(n===e)return rs;e=n;}}var X=oc(import.meta.dirname),is=ss;var ac=/^([0-9a-f]{2})-([0-9a-f]{32})-([0-9a-f]{16})-([0-9a-f]{2})(-.*)?$/,os=/^0+$/;function Pn(t){if(typeof t!="string")return;let e=t.trim();if(e.length>512)return;let n=ac.exec(e);if(!n)return;let[,r,s,i,,o]=n;if(r!=="ff"&&!(r==="00"&&o!==void 0)&&!(os.test(s)||os.test(i)))return {traceId:s,parentId:i}}function as(t){if(!(!t||typeof t!="object")){for(let[e,n]of Object.entries(t))if(e.toLowerCase()==="traceparent")return Array.isArray(n)?void 0:Pn(n)}}var It=30,cc={authKind:"stdio",personal:false};function dc(t,e){return Ke.has(t)||(e.mutatingCalls?.count??0)>0?"write":t==="sap_function"&&e.sapCalls.count===0?"unknown":"read"}var lc=5e3;function uc(t,e,n,r){let s=t?._meta?.progressToken,i=t?.sendNotification;if(s===void 0||typeof i!="function"||r.afterMs<=0)return ()=>{};let a=setInterval(()=>{let d=Date.now()-n;i({method:"notifications/progress",params:{progressToken:s,progress:Math.round(d/1e3),...r.budgetMs?{total:Math.round(r.budgetMs/1e3)}:{},message:`${e.toolName}: ${Math.round(d/1e3)} s, ${e.sapCalls.count} SAP-Aufruf(e)`}}).catch(()=>{});},r.afterMs);return a.unref?.(),()=>clearInterval(a)}var pc="SAP_TLS_VERIFY=false: Die Zertifikatspr\xFCfung ist abgeschaltet \u2014 die Verbindung zu SAP ist nicht gegen einen Angreifer in der Leitung gesch\xFCtzt. Richtiger Weg: Root-CA \xFCber SAP_CA_CERT (bzw. NODE_EXTRA_CA_CERTS) einbinden und SAP_TLS_VERIFY wieder entfernen.";function mc(t){return {...t,content:[...t.content,{type:"text",text:`\u26A0\uFE0F ${pc}`}]}}function fc(t,e,n,r,s){return {content:[{type:"text",text:JSON.stringify({truncated:true,reason:`Zeitbudget von ${Math.round(s/1e3)} s \xFCberschritten \u2014 der Aufruf wurde abgebrochen, damit die Verbindung nicht h\xE4ngen bleibt.`,hint:"Grenzen Sie die Anfrage ein (top/skip, filter, search) oder erh\xF6hen Sie --tool-timeout. Der Wert sollte unter der kleinsten Client-Grenze bleiben (Cloudflare 100 s, n8n-MCP-Transport 300 s).",tool:t,correlationId:e,elapsedMs:n,sapCalls:r},null,2)}],isError:true}}function gc(t,e){return {content:[{type:"text",text:JSON.stringify({aborted:true,reason:"Der Client hat die Verbindung verworfen; die Arbeit wurde eingestellt.",tool:t,correlationId:e})}],isError:true}}function cs(t,e,n={}){let{toolTimeoutMs:r,logger:s,tlsVerifyDisabled:i,governance:o}=n,a=n.progressAfterMs??lc;return async(d,l)=>{let c=Zn(),{signal:u,deadline:p}=nr(l?.signal,r),m=as(l?.requestInfo?.headers)??Pn(l?._meta?.traceparent),f={correlationId:c,...m?{traceId:m.traceId}:{},toolName:t,signal:u,deadline:p,sapCalls:{count:0},mutatingCalls:{count:0},created:{}},g=Date.now();return Qn(f,async()=>{let h=uc(l,f,g,{afterMs:a,...r?{budgetMs:r}:{}}),b="ok",y,E=(async()=>e(d,l))();E.catch(()=>{});try{y=await Promise.race([E,hc(u,t)]),y?.isError&&(b="error");}catch(v){if(v instanceof F)b=v.timedOut?"timeout":"aborted",y=v.timedOut?fc(t,c,Date.now()-g,f.sapCalls.count,r??0):gc(t,c);else {b="error";let x=v instanceof Error?v.message:String(v);y={content:[{type:"text",text:JSON.stringify({error:x,tool:t,correlationId:c})}],isError:true};}}b==="ok"&&u?.aborted&&(b=u.reason?.name==="TimeoutError"?"timeout":"aborted"),h();let S=i?mc(y):y;if(s?.info({correlationId:c,...m?{traceId:m.traceId,parentId:m.parentId}:{},tool:t,outcome:b,durationMs:Date.now()-g,sapCalls:f.sapCalls.count,resultBytes:yc(y),...r?{budgetMs:r}:{}},"MCP tool call"),o){let v={apiVersion:1,serverVersion:n.serverVersion??X,correlationId:c,...m?{traceId:m.traceId,parentId:m.parentId}:{},tool:t,kind:dc(t,f),outcome:b,startedAt:new Date(g).toISOString(),durationMs:Date.now()-g,sapCalls:f.sapCalls.count,...n.destination?{destination:n.destination}:{},...b==="ok"&&f.created?.entity?{createdEntity:f.created.entity}:{},identity:n.callerIdentity??cc,args:d,result:y};try{o.onToolCall(v);}catch(x){s?.error({err:x,correlationId:c,tool:t,module:o.name},"Governance-Modul: Aufruf konnte nicht gemeldet werden");}}return S})}}function hc(t,e){return t?new Promise((n,r)=>{let s=()=>{let i=t.reason?.name==="TimeoutError";r(new F(i,e));};if(t.aborted){s();return}t.addEventListener("abort",s,{once:true});}):new Promise(()=>{})}function yc(t){if(!t?.content)return 0;let e=0;for(let n of t.content)typeof n?.text=="string"&&(e+=Buffer.byteLength(n.text,"utf-8"));return e}var Sc=1440*60*1e3,bc="metadata-cache.json",I=class{cache=new Map;ttlMs;baseUrl;persistence;constructor(e={}){if(this.ttlMs=e.ttlMs??Sc,this.baseUrl=wc(e.baseUrl),e.persistDir){this.persistence={directory:e.persistDir,fileName:bc,ttlMs:this.ttlMs,...e.onWarn?{onWarn:e.onWarn}:{}};for(let n of Rt(this.persistence))this.cache.set(n.key,{value:n.value,storedAt:n.storedAt});}}get size(){return this.cache.size}get(e){let n=this.key(e),r=this.cache.get(n);if(r){if(Date.now()-r.storedAt>this.ttlMs){this.cache.delete(n);return}return r.value}}set(e,n){this.cache.set(this.key(e),{value:n,storedAt:Date.now()}),this.persist();}has(e){return this.get(e)!==void 0}clear(){this.cache.clear(),this.persist();}key(e){let n=e.replace(/\/+$/,"");return this.baseUrl?`${this.baseUrl}|${n}`:n}persist(){this.persistence&&Pt([...this.cache.entries()].map(([e,n])=>({key:e,value:n.value,storedAt:n.storedAt})),this.persistence);}};function wc(t){return t?t.replace(/\/+$/,"").toLowerCase():""}function ds(t){t.registerPrompt("nl-to-odata-query",{title:"Natural Language to OData Query",description:"Convert a natural language question into a correct OData query against an SAP service. Reads entity schema for context, applies V2/V4 syntax rules, and enforces read-only by default.",argsSchema:{serviceUrl:z$2.string().describe("OData service URL, e.g., /sap/opu/odata/sap/API_BUSINESS_PARTNER"),entitySet:z$2.string().describe("Entity set to query, e.g., A_BusinessPartner"),question:z$2.string().describe('Natural language question, e.g., "show me all customers in Germany"'),allowWrite:z$2.boolean().optional().describe("Allow write operations (create/update/delete). Default: false (read-only)")}},async({serviceUrl:e,entitySet:n,question:r,allowWrite:s})=>{let i=s===true?"":`
110
110
 
111
111
  IMPORTANT \u2014 READ-ONLY MODE:
112
112
  You MUST only generate read queries (sap_query or sap_nl_query). Do NOT use sap_create, sap_update, or sap_delete.
@@ -167,7 +167,7 @@ Use the \`sap_nl_query\` tool with these parameters:
167
167
  - "orders over 1000 EUR" \u2192 \`{ field: "TotalAmount", operator: "gt", value: 1000 }\`
168
168
  - "products containing 'bolt'" \u2192 \`{ field: "ProductName", operator: "contains", value: "bolt" }\`
169
169
  - "invoices since January 2024" \u2192 \`{ field: "InvoiceDate", operator: "ge", value: "2024-01-01" }\`
170
- ${i}`}}]}});}function Qr(t){t.registerPrompt("explore-sales-orders",{title:"Explore Sales Orders",description:"Discover and query SAP Sales Order data step by step",argsSchema:{serviceUrl:z$2.string().optional().describe("OData service URL (leave empty to discover first)")}},async({serviceUrl:e})=>({messages:[{role:"user",content:{type:"text",text:`I want to explore SAP Sales Order data. Please help me step by step:
170
+ ${i}`}}]}});}function ls(t){t.registerPrompt("explore-sales-orders",{title:"Explore Sales Orders",description:"Discover and query SAP Sales Order data step by step",argsSchema:{serviceUrl:z$2.string().optional().describe("OData service URL (leave empty to discover first)")}},async({serviceUrl:e})=>({messages:[{role:"user",content:{type:"text",text:`I want to explore SAP Sales Order data. Please help me step by step:
171
171
 
172
172
  1. ${e?`Start by getting metadata for the service at: ${e}`:"Start by listing available services. A common Sales Order service URL is /sap/opu/odata/sap/API_SALES_ORDER_SRV"}
173
173
  2. Use sap_list_services to discover available entity sets
@@ -195,21 +195,21 @@ Use sap_query with appropriate filters to find the material data.`}}]})),t.regis
195
195
  1. ${r}
196
196
  2. Use sap_list_services to discover entity sets
197
197
  3. Use sap_get_metadata to understand the Business Partner data model
198
- ${s}`}}]}});}var _t=class{cache=new Map;buildKey(e,n){let s=Object.entries(n).sort(([i],[o])=>i.localeCompare(o)).map(([i,o])=>`${i}=${o}`).join(",");return `${e}|${s}`}set(e,n,r){this.cache.set(this.buildKey(e,n),r);}get(e,n){return this.cache.get(this.buildKey(e,n))}update(e,n,r){r?this.set(e,n,r):this.cache.delete(this.buildKey(e,n));}};function dc(t){let e=t.match(/HTTP\/1\.\d\s+(\d+)\s+/);if(!e)return null;let n=Number.parseInt(e[1],10),r=n>=200&&n<300,s=t.indexOf(e[0]),i=t.substring(s),o=i.indexOf(`
198
+ ${s}`}}]}});}var xt=class{cache=new Map;buildKey(e,n){let s=Object.entries(n).sort(([i],[o])=>i.localeCompare(o)).map(([i,o])=>`${i}=${o}`).join(",");return `${e}|${s}`}set(e,n,r){this.cache.set(this.buildKey(e,n),r);}get(e,n){return this.cache.get(this.buildKey(e,n))}update(e,n,r){r?this.set(e,n,r):this.cache.delete(this.buildKey(e,n));}};function Tc(t){let e=t.match(/HTTP\/1\.\d\s+(\d+)\s+/);if(!e)return null;let n=Number.parseInt(e[1],10),r=n>=200&&n<300,s=t.indexOf(e[0]),i=t.substring(s),o=i.indexOf(`
199
199
 
200
- `),a;o!==-1&&(a=i.substring(o+2).trim());let d={status:n,entitySet:""};if(a&&a.length>0)if(r)try{d.result=JSON.parse(a);}catch{}else d.error=a;return d}function es(t,e){let n=[],r=t.split(`--${e}`);for(let s of r){let i=s.trim();if(!i||i==="--")continue;let o=i.match(/Content-Type:\s*multipart\/mixed;\s*boundary=([^\s\r\n]+)/i);if(o){let d=o[1],l=i.indexOf(`
200
+ `),a;o!==-1&&(a=i.substring(o+2).trim());let d={status:n,entitySet:""};if(a&&a.length>0)if(r)try{d.result=JSON.parse(a);}catch{}else d.error=a;return d}function us(t,e){let n=[],r=t.split(`--${e}`);for(let s of r){let i=s.trim();if(!i||i==="--")continue;let o=i.match(/Content-Type:\s*multipart\/mixed;\s*boundary=([^\s\r\n]+)/i);if(o){let d=o[1],l=i.indexOf(`
201
201
 
202
- `);if(l!==-1){let c=i.substring(l+2);n.push(es(c,d).flat());}continue}let a=dc(i);a&&n.push(a);}return n}function ts(t,e){let n=e.match(/boundary=([^\s;]+)/);if(!n)return [];let r=n[1],s=t.replace(/\r\n/g,`
203
- `);return es(s,r)}function ue(t,e){let n=t?.entitySets.find(i=>i.name===e),r=n&&t?.entityTypes.find(i=>i.name===n.entityTypeName);if(!r)return;let s={};for(let i of [...r.properties,...r.keys])s[i.name]=i.type;return s}function vn(t,e){let n=t?.functionImports?.find(r=>r.name===e);if(n)return Object.fromEntries(n.parameters.map(r=>[r.name,r.type]))}function ns(t,e){let n=e.slice(e.lastIndexOf(".")+1),r=t?.actions?.find(s=>s.name.slice(s.name.lastIndexOf(".")+1)===n);if(r)return Object.fromEntries(r.parameters.map(s=>[s.name,s.type]))}var lc=/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i,uc=/^(guid|datetime|datetimeoffset|time|binary|X)'[^']*'$/i,pc=/^-?\d+(\.\d+)?([eE][+-]?\d+)?$/;function Ot(t,e){if(t==null)return "null";if(e){let r=mc(t,e);if(r!==void 0)return r}if(typeof t=="boolean"||typeof t=="number"||typeof t=="bigint")return String(t);if(t instanceof Date)return `datetime'${ss(t.toISOString())}'`;let n=String(t);return uc.test(n)?n:lc.test(n)?`guid'${n}'`:rs(n)}function mc(t,e){let n=t instanceof Date?t.toISOString():String(t);switch(e){case "Edm.String":return rs(n);case "Edm.Guid":return `guid'${Ge(n,"guid")}'`;case "Edm.Boolean":{let r=n.toLowerCase();return r==="true"||r==="false"?r:void 0}case "Edm.DateTime":return `datetime'${ss(Ge(n,"datetime"))}'`;case "Edm.DateTimeOffset":return `datetimeoffset'${Ge(n,"datetimeoffset")}'`;case "Edm.Time":return `time'${Ge(n,"time")}'`;case "Edm.Binary":return `binary'${Ge(n,"binary")}'`;case "Edm.Decimal":return qe(n,"M");case "Edm.Int64":return qe(n,"L");case "Edm.Double":return qe(n,"d");case "Edm.Single":return qe(n,"f");case "Edm.Byte":case "Edm.SByte":case "Edm.Int16":case "Edm.Int32":return qe(n,"");default:return}}function rs(t){return `'${t.replace(/'/g,"''")}'`}function Ge(t,e){let n=new RegExp(`^${e}'(.*)'$`,"is").exec(t);return n?n[1]:t}function qe(t,e){let n=t.replace(/[mMlLdDfF]$/,"");return pc.test(n)?`${n}${e}`:void 0}function ss(t){let e=/^\/Date\((-?\d+)(?:[+-]\d{4})?\)\/$/.exec(t),n=e?new Date(Number(e[1])).toISOString():t;return /^\d{4}-\d{2}-\d{2}$/.test(n)&&(n=`${n}T00:00:00`),n.replace(/(?:Z|[+-]00:?00)$/i,"").replace(/\.0+$/,"")}function is(t,e){return Ot(t,e)}function _e(t,e,n){let r=Object.entries(e);if(r.length===1){let[i,o]=r[0];return `${t}(${is(o,n?.[i])})`}let s=r.map(([i,o])=>`${i}=${is(o,n?.[i])}`);return `${t}(${s.join(",")})`}function En(t,e){let n={$format:"json"};return t.filter&&(n.$filter=t.filter),t.select&&t.select.length>0&&(n.$select=t.select.join(",")),t.expand&&t.expand.length>0&&(n.$expand=t.expand.join(",")),t.orderby&&(n.$orderby=t.orderby),t.top!==void 0&&(n.$top=String(t.top)),t.skip!==void 0&&(n.$skip=String(t.skip)),e&&(n.$inlinecount="allpages"),n}function fc(t,e){let n=[],r=new Map;for(let s of t){if(s.method==="get"){n.push({kind:"single",operations:[s]});continue}if(!s.changesetId){n.push({kind:"changeset",operations:[s]});continue}let i=r.get(s.changesetId);i||(i={kind:"changeset",operations:[]},r.set(s.changesetId,i),n.push(i)),i.operations.push(s);}for(let s of e??[])n.push({kind:"changeset",operations:s.operations});return n}function as(t,e){let n=t.key?_e(t.entitySet,t.key,e?.(t.entitySet)):t.entitySet,r=t.method==="patch"?"MERGE":t.method.toUpperCase(),{__etag:s,...i}=t.data??{},o=t.data!==void 0&&(r==="POST"||r==="MERGE")?JSON.stringify(i):void 0,a=["Content-Type: application/http","Content-Transfer-Encoding: binary","",`${r} ${n} HTTP/1.1`,"Accept: application/json"];return (r==="MERGE"||r==="DELETE")&&a.push(`If-Match: ${typeof s=="string"?s:"*"}`),o!==void 0&&a.push("Content-Type: application/json"),a.push("",o??""),a.join(`\r
204
- `)}function cs(t,e,n,r){let s=`batch_${randomUUID()}`,i=fc(e,n),o=[];for(let a of i){if(a.kind==="single"){o.push(`--${s}\r
205
- ${as(a.operations[0],r)}`);continue}let d=`changeset_${randomUUID()}`,l=[...a.operations.map(c=>`--${d}\r
206
- ${as(c,r)}`),`--${d}--`].join(`\r
202
+ `);if(l!==-1){let c=i.substring(l+2);n.push(us(c,d).flat());}continue}let a=Tc(i);a&&n.push(a);}return n}function ps(t,e){let n=e.match(/boundary=([^\s;]+)/);if(!n)return [];let r=n[1],s=t.replace(/\r\n/g,`
203
+ `);return us(s,r)}function fe(t,e){let n=t?.entitySets.find(i=>i.name===e),r=n&&t?.entityTypes.find(i=>i.name===n.entityTypeName);if(!r)return;let s={};for(let i of [...r.properties,...r.keys])s[i.name]=i.type;return s}function kn(t,e){let n=t?.functionImports?.find(r=>r.name===e);if(n)return Object.fromEntries(n.parameters.map(r=>[r.name,r.type]))}function ms(t,e){let n=e.slice(e.lastIndexOf(".")+1),r=t?.actions?.find(s=>s.name.slice(s.name.lastIndexOf(".")+1)===n);if(r)return Object.fromEntries(r.parameters.map(s=>[s.name,s.type]))}var vc=/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i,Ac=/^(guid|datetime|datetimeoffset|time|binary|X)'[^']*'$/i,Ec=/^-?\d+(\.\d+)?([eE][+-]?\d+)?$/;function Mt(t,e){if(t==null)return "null";if(e){let r=Cc(t,e);if(r!==void 0)return r}if(typeof t=="boolean"||typeof t=="number"||typeof t=="bigint")return String(t);if(t instanceof Date)return `datetime'${gs(t.toISOString())}'`;let n=String(t);return Ac.test(n)?n:vc.test(n)?`guid'${n}'`:fs(n)}function Cc(t,e){let n=t instanceof Date?t.toISOString():String(t);switch(e){case "Edm.String":return fs(n);case "Edm.Guid":return `guid'${ze(n,"guid")}'`;case "Edm.Boolean":{let r=n.toLowerCase();return r==="true"||r==="false"?r:void 0}case "Edm.DateTime":return `datetime'${gs(ze(n,"datetime"))}'`;case "Edm.DateTimeOffset":return `datetimeoffset'${ze(n,"datetimeoffset")}'`;case "Edm.Time":return `time'${ze(n,"time")}'`;case "Edm.Binary":return `binary'${ze(n,"binary")}'`;case "Edm.Decimal":return Ye(n,"M");case "Edm.Int64":return Ye(n,"L");case "Edm.Double":return Ye(n,"d");case "Edm.Single":return Ye(n,"f");case "Edm.Byte":case "Edm.SByte":case "Edm.Int16":case "Edm.Int32":return Ye(n,"");default:return}}function fs(t){return `'${t.replace(/'/g,"''")}'`}function ze(t,e){let n=new RegExp(`^${e}'(.*)'$`,"is").exec(t);return n?n[1]:t}function Ye(t,e){let n=t.replace(/[mMlLdDfF]$/,"");return Ec.test(n)?`${n}${e}`:void 0}function gs(t){let e=/^\/Date\((-?\d+)(?:[+-]\d{4})?\)\/$/.exec(t),n=e?new Date(Number(e[1])).toISOString():t;return /^\d{4}-\d{2}-\d{2}$/.test(n)&&(n=`${n}T00:00:00`),n.replace(/(?:Z|[+-]00:?00)$/i,"").replace(/\.0+$/,"")}function hs(t,e){return Mt(t,e)}function Oe(t,e,n){let r=Object.entries(e);if(r.length===1){let[i,o]=r[0];return `${t}(${hs(o,n?.[i])})`}let s=r.map(([i,o])=>`${i}=${hs(o,n?.[i])}`);return `${t}(${s.join(",")})`}function _n(t,e){let n={$format:"json"};return t.filter&&(n.$filter=t.filter),t.select&&t.select.length>0&&(n.$select=t.select.join(",")),t.expand&&t.expand.length>0&&(n.$expand=t.expand.join(",")),t.orderby&&(n.$orderby=t.orderby),t.top!==void 0&&(n.$top=String(t.top)),t.skip!==void 0&&(n.$skip=String(t.skip)),e&&(n.$inlinecount="allpages"),n}function Rc(t,e){let n=[],r=new Map;for(let s of t){if(s.method==="get"){n.push({kind:"single",operations:[s]});continue}if(!s.changesetId){n.push({kind:"changeset",operations:[s]});continue}let i=r.get(s.changesetId);i||(i={kind:"changeset",operations:[]},r.set(s.changesetId,i),n.push(i)),i.operations.push(s);}for(let s of e??[])n.push({kind:"changeset",operations:s.operations});return n}function Ss(t,e){let n=t.key?Oe(t.entitySet,t.key,e?.(t.entitySet)):t.entitySet,r=t.method==="patch"?"MERGE":t.method.toUpperCase(),{__etag:s,...i}=t.data??{},o=t.data!==void 0&&(r==="POST"||r==="MERGE")?JSON.stringify(i):void 0,a=["Content-Type: application/http","Content-Transfer-Encoding: binary","",`${r} ${n} HTTP/1.1`,"Accept: application/json"];return (r==="MERGE"||r==="DELETE")&&a.push(`If-Match: ${typeof s=="string"?s:"*"}`),o!==void 0&&a.push("Content-Type: application/json"),a.push("",o??""),a.join(`\r
204
+ `)}function bs(t,e,n,r){let s=`batch_${randomUUID()}`,i=Rc(e,n),o=[];for(let a of i){if(a.kind==="single"){o.push(`--${s}\r
205
+ ${Ss(a.operations[0],r)}`);continue}let d=`changeset_${randomUUID()}`,l=[...a.operations.map(c=>`--${d}\r
206
+ ${Ss(c,r)}`),`--${d}--`].join(`\r
207
207
  `);o.push(`--${s}\r
208
208
  Content-Type: multipart/mixed; boundary=${d}\r
209
209
  \r
210
210
  ${l}`);}return o.push(`--${s}--`),{body:`${o.join(`\r
211
211
  `)}\r
212
- `,contentType:`multipart/mixed; boundary=${s}`,parts:i}}var hc=new Set(["EntityType","Property","NavigationProperty","Association","EntitySet","AssociationSet","PropertyRef","End","FunctionImport","Parameter"]),yc=new XMLParser({ignoreAttributes:false,attributeNamePrefix:"@_",removeNSPrefix:true,processEntities:false,htmlEntities:false,isArray:t=>hc.has(t)});function Cn(t){return t===void 0?true:String(t).toLowerCase()!=="false"}function It(t,e){let r=yc.parse(t).Edmx.DataServices.Schema,s=Array.isArray(r)?r[0]:r,i=s.EntityType??[],o=s.Association??[],a=s.EntityContainer,d=a?.EntitySet??[],l=new Map;for(let f of o)l.set(f["@_Name"],f);let c=i.map(f=>{let h=Sc(f.Property??[]),S=(f.Key?.PropertyRef??[]).map(b=>b["@_Name"]),y=h.filter(b=>S.includes(b.name)),E=bc(f.NavigationProperty??[],l);return {name:f["@_Name"],keys:y,properties:h,navigationProperties:E}}),u=d.map(f=>({name:f["@_Name"],entityTypeName:Rn(f["@_EntityType"]),creatable:Cn(f["@_creatable"]),updatable:Cn(f["@_updatable"]),deletable:Cn(f["@_deletable"])})),p=a?.FunctionImport??[],m=Tc(Array.isArray(p)?p:[p]),g={version:"v2",serviceUrl:e,entityTypes:c,entitySets:u};return m.length>0&&(g.functionImports=m),g}function Sc(t){return t.map(e=>{let n={name:e["@_Name"],type:e["@_Type"],nullable:e["@_Nullable"]!=="false"};return e["@_MaxLength"]!==void 0&&(n.maxLength=Number.parseInt(e["@_MaxLength"],10)),e["@_Precision"]!==void 0&&(n.precision=Number.parseInt(e["@_Precision"],10)),e["@_Scale"]!==void 0&&(n.scale=Number.parseInt(e["@_Scale"],10)),n})}function bc(t,e){return t.map(n=>{let r=Rn(n["@_Relationship"]),s=e.get(r),i="Unknown",o=false;if(s){let a=s.End.find(d=>d["@_Role"]===n["@_ToRole"]);a&&(i=Rn(a["@_Type"]),o=a["@_Multiplicity"]==="*");}return {name:n["@_Name"],targetEntityType:i,isCollection:o}})}function Tc(t){return t.filter(e=>e["@_Name"]).map(e=>{let n=(e.Parameter??[]).map(s=>({name:s["@_Name"],type:s["@_Type"],...s["@_Nullable"]==="true"?{nullable:true}:{}})),r={name:e["@_Name"],httpMethod:e["@_HttpMethod"]??"POST",parameters:n};return e["@_ReturnType"]&&(r.returnType=e["@_ReturnType"]),r})}function Rn(t){let e=t.lastIndexOf(".");return e>=0?t.substring(e+1):t}var wc=/^\/Date\((-?\d+)([+-]\d{4})?\)\/$/;function ee(t){if(!t||typeof t!="object")return {results:[]};let e=t;if("d"in e&&e.d&&typeof e.d=="object"){let n=e.d;if("results"in n&&Array.isArray(n.results)){let s={results:n.results};return n.__count!==void 0&&(s.count=Number(n.__count)),typeof n.__next=="string"&&(s.nextLink=n.__next),s}return {results:[{...n}]}}return "results"in e&&Array.isArray(e.results)?{results:e.results}:{results:[e]}}function ds(t){let e=wc.exec(t);if(!e)return t;let n=Number(e[1]);return new Date(n).toISOString()}function q(t){if(t==null)return t;if(Array.isArray(t))return t.map(e=>q(e));if(typeof t=="object"){let e=t,n={};for(let[r,s]of Object.entries(e))r!=="__metadata"&&(s&&typeof s=="object"&&!Array.isArray(s)&&"__deferred"in s||(typeof s=="string"?n[r]=ds(s):n[r]=q(s)));return n}return typeof t=="string"?ds(t):t}var ls=10,Ke=class{constructor(e,n,r,s){this.httpClient=e;this.serviceUrl=n;this.etagCache=r;this.metadataProvider=s;}async metadataForLiterals(){if(this.metadataProvider)try{return await this.metadataProvider()}catch{return}}async keyUrl(e,n){let r=ue(await this.metadataForLiterals(),e);return `${this.serviceUrl}/${_e(e,n,r)}`}async read(e,n,r){let s=En(r??{});if(n){let i=await this.keyUrl(e,n),o=await this.httpClient.request({method:"get",url:i,headers:{Accept:"application/json"},params:s});o.headers.etag&&this.etagCache.set(e,n,o.headers.etag);let a=ee(o.data);return {...a,results:a.results.map(d=>q(d))}}return this.fetchWithPagination(`${this.serviceUrl}/${e}`,s,r?.maxPages??ls)}async query(e,n){let r=En(n,true),s=n.maxPages??ls;return this.fetchWithPagination(`${this.serviceUrl}/${e}`,r,s)}async create(e,n){let r=await this.httpClient.request({method:"post",url:`${this.serviceUrl}/${e}`,data:n,headers:{Accept:"application/json","Content-Type":"application/json"}}),s=ee(r.data);return s.results.length>0?q(s.results[0]):{}}async update(e,n,r){let s=await this.keyUrl(e,n),i=this.etagCache.get(e,n)??"*",o=await this.httpClient.request({method:"post",url:s,data:r,headers:{Accept:"application/json","Content-Type":"application/json","X-HTTP-Method":"MERGE","If-Match":i}});o.headers.etag&&this.etagCache.set(e,n,o.headers.etag);}async delete(e,n){let r=await this.keyUrl(e,n),s=this.etagCache.get(e,n)??"*";await this.httpClient.request({method:"delete",url:r,headers:{Accept:"application/json","If-Match":s}}),this.etagCache.update(e,n,void 0);}async functionImport(e,n,r){let s=await this.metadataForLiterals(),i=s?.functionImports?.find(g=>g.name===e),o=vn(s,e),a=(r??i?.httpMethod??"POST").toLowerCase(),d={$format:"json"};if(n)for(let[g,f]of Object.entries(n))d[g]=Ot(f,o?.[g]);let l=await this.httpClient.request({method:a,url:`${this.serviceUrl}/${e}`,headers:{Accept:"application/json"},params:d}),c=l.data?.d;if(i?.returnType?.startsWith("Collection(")||Array.isArray(c)||Array.isArray(c?.results)){let g=Array.isArray(c)?c:ee(l.data).results;return {results:q(g)}}let p=ee(l.data);if(p.results.length>0)return q(p.results[0]);let m=l.data;return m?.d&&typeof m.d=="object"?m.d:{}}async batch(e,n){let r=await this.metadataForLiterals(),{body:s,contentType:i,parts:o}=cs(this.serviceUrl,e,n,m=>ue(r,m)),a=await this.httpClient.request({method:"post",url:`${this.serviceUrl}/$batch`,data:s,headers:{"Content-Type":i,Accept:"multipart/mixed"}}),d=a.headers["content-type"]??i,l=ts(a.data,d),c=new Map;return o.forEach((m,g)=>{let f=l[g];m.operations.forEach((h,S)=>{let y=Array.isArray(f)?f[S]:f;c.set(h,y?{...y,entitySet:h.entitySet}:{status:0,entitySet:h.entitySet,error:"SAP returned no response for this operation"});});}),{results:[...e,...(n??[]).flatMap(m=>m.operations)].map(m=>c.get(m)).filter(m=>m!==void 0)}}async getMetadata(){let e=await this.httpClient.request({method:"get",url:`${this.serviceUrl}/$metadata`,headers:{Accept:"application/xml"}});return It(e.data,this.serviceUrl)}async fetchWithPagination(e,n,r){let s=[],i,o=e,a=n,d=0,l=false;for(;o&&d<r;){if(d>0&&rt()){l=true;break}let p=(await this.httpClient.request({method:"get",url:o,headers:{Accept:"application/json"},params:a})).data,m=ee(p),g=m.results.map(h=>q(h));s.push(...g),d===0&&m.count!==void 0&&(i=m.count),d++;let f=p?.d;f&&typeof f.__next=="string"?(o=f.__next,a=void 0):o=void 0;}let c={results:s};return i!==void 0&&(c.count=i),o&&(c.nextLink=o),l&&(c.truncated=true,c.truncationReason=`Nach ${d} Seite(n) abgebrochen: Zeitbudget des Tool-Aufrufs ersch\xF6pft oder Client hat die Verbindung verworfen. Mit skip=${s.length} weiterlesen.`),c}};function us(t){let n=(typeof t=="string"?JSON.parse(t):t).responses;return !n||!Array.isArray(n)?[]:n.map(r=>{let s=r.status,i=s>=200&&s<300,o={status:s,entitySet:""};return r.body!==void 0&&r.body!==null&&(i?o.result=r.body:o.error=JSON.stringify(r.body)),o})}var Ac=/^-?\d+(\.\d+)?([eE][+-]?\d+)?$/,vc=/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i,Ec=/(Z|[+-]\d{2}:?\d{2})$/i;function Nt(t,e){if(t==null)return "null";if(e){let n=Cc(t,e);if(n!==void 0)return n}return typeof t=="boolean"||typeof t=="number"||typeof t=="bigint"?String(t):t instanceof Date?t.toISOString():ms(String(t))}function Cc(t,e){let n=t instanceof Date?t.toISOString():String(t);switch(e){case "Edm.String":return ms(n);case "Edm.Guid":{let r=Dt(Dt(n,"guid"),"");return vc.test(r)?r:void 0}case "Edm.Boolean":{let r=n.toLowerCase();return r==="true"||r==="false"?r:void 0}case "Edm.Date":{let r=ps(n);return /^\d{4}-\d{2}-\d{2}/.test(r)?r.slice(0,10):void 0}case "Edm.DateTimeOffset":{let r=ps(n);return /^\d{4}-\d{2}-\d{2}$/.test(r)&&(r=`${r}T00:00:00`),/^\d{4}-\d{2}-\d{2}T/.test(r)?Ec.test(r)?r:`${r}Z`:void 0}case "Edm.TimeOfDay":return /^\d{2}:\d{2}(:\d{2}(\.\d+)?)?$/.test(n)?n:void 0;case "Edm.Duration":return `duration'${Dt(n,"duration")}'`;case "Edm.Binary":return `binary'${Dt(n,"binary")}'`;case "Edm.Decimal":case "Edm.Double":case "Edm.Single":case "Edm.Int64":case "Edm.Int32":case "Edm.Int16":case "Edm.Byte":case "Edm.SByte":{let r=n.replace(/[mMlLdDfF]$/,"");return Ac.test(r)?r:void 0}default:return}}function ms(t){return `'${t.replace(/'/g,"''")}'`}function Dt(t,e){let n=new RegExp(`^${e}'(.*)'$`,"is").exec(t);return n?n[1]:t}function ps(t){let e=/^\/Date\((-?\d+)(?:[+-]\d{4})?\)\/$/.exec(t);return e?new Date(Number(e[1])).toISOString():t}function fs(t,e){return Nt(t,e)}function xt(t,e,n){let r=Object.entries(e);if(r.length===1){let[i,o]=r[0];return `${t}(${fs(o,n?.[i])})`}let s=r.map(([i,o])=>`${i}=${fs(o,n?.[i])}`).join(",");return `${t}(${s})`}function Mt(t,e){let n={};return t.filter&&(n.$filter=t.filter),t.select?.length&&(n.$select=t.select.join(",")),t.expand?.length&&(n.$expand=t.expand.join(",")),t.orderby&&(n.$orderby=t.orderby),t.top!==void 0&&(n.$top=String(t.top)),t.skip!==void 0&&(n.$skip=String(t.skip)),e&&(n.$count="true"),n}function gs(t,e,n){let r=[];for(let i=0;i<e.length;i++){let o=e[i],a=o.key?xt(o.entitySet,o.key,n?.(o.entitySet)):o.entitySet,d={id:String(i+1),method:o.method.toUpperCase(),url:a};o.changesetId&&(d.atomicityGroup=o.changesetId),o.data&&(o.method==="post"||o.method==="patch"||o.method==="delete")&&(d.headers={"Content-Type":"application/json"},d.body=o.data),r.push(d);}return {body:JSON.stringify({requests:r}),contentType:"application/json"}}function hs(t){let e=t.split(".");return e[e.length-1]}function Rc(t,e){return {name:t,type:e.$Type??"Edm.String",nullable:e.$Nullable??false,maxLength:e.$MaxLength,precision:e.$Precision,scale:e.$Scale}}function ys(t,e){let n=JSON.parse(t),r=[],s=[],i=[];for(let[a,d]of Object.entries(n)){if(a.startsWith("$"))continue;let l=d;for(let[c,u]of Object.entries(l)){let p=u;if(p.$Kind==="Action"||p.$Kind==="Function"){let m=p.$IsBound??false,g=p.$Parameter??[],f=m&&g.length>0?g[0].$Name:void 0,h=(m?g.slice(1):g).map(y=>({name:y.$Name,type:y.$Type??"Edm.String",...y.$Nullable===true?{nullable:true}:{}})),S=p.$ReturnType?p.$ReturnType.$Type:void 0;i.push({name:c,isBound:m,kind:p.$Kind,...f?{bindingParameter:f}:{},parameters:h,...S?{returnType:S}:{}});}else if(p.$Kind==="EntityType"){let m=[],g=[];for(let[S,y]of Object.entries(p)){if(S.startsWith("$"))continue;let E=y;E.$Kind==="NavigationProperty"?g.push({name:S,targetEntityType:hs(E.$Type),isCollection:E.$Collection??false}):m.push(Rc(S,E));}let h=(p.$Key??[]).map(S=>{let y=m.find(E=>E.name===S);return y||{name:S,type:"Edm.String",nullable:false}});r.push({name:c,keys:h,properties:m,navigationProperties:g});}else if(p.$Kind==="EntityContainer")for(let[m,g]of Object.entries(p)){if(m.startsWith("$"))continue;let f=g;f.$Collection&&f.$Type&&s.push({name:m,entityTypeName:hs(f.$Type),creatable:Pn(f,"InsertRestrictions","Insertable"),updatable:Pn(f,"UpdateRestrictions","Updatable"),deletable:Pn(f,"DeleteRestrictions","Deletable")});}}}let o={version:"v4",serviceUrl:e,entityTypes:r,entitySets:s};return i.length>0&&(o.actions=i),o}function Pn(t,e,n){for(let[r,s]of Object.entries(t)){if(!r.startsWith("@")||!r.endsWith(e))continue;let i=s?.[n];if(typeof i=="boolean")return i}return true}var kc=new Set(["Schema","EntityType","Property","NavigationProperty","PropertyRef","EntityContainer","EntitySet","Action","Function","Parameter","Annotations","Annotation","PropertyValue"]),_c=new XMLParser({ignoreAttributes:false,attributeNamePrefix:"@_",removeNSPrefix:true,processEntities:false,htmlEntities:false,isArray:t=>kc.has(t)});function H(t){return Array.isArray(t)?t:[]}function D(t,e){let n=t?.[`@_${e}`];return n===void 0?void 0:String(n)}function kn(t,e){let n=D(t,e);return n===void 0||n==="max"?void 0:Number.parseInt(n,10)}function bs(t){let e=/^Collection\((.*)\)$/.exec(t)?.[1]??t;return e.slice(e.lastIndexOf(".")+1)}function Oc(t){let e={name:D(t,"Name"),type:D(t,"Type")??"Edm.String",nullable:D(t,"Nullable")!=="false"},n=kn(t,"MaxLength"),r=kn(t,"Precision"),s=kn(t,"Scale");return n!==void 0&&(e.maxLength=n),r!==void 0&&(e.precision=r),s!==void 0&&(e.scale=s),e}function Ic(t){let e=H(t.Property).map(Oc),r=H(t.Key?.PropertyRef).map(i=>D(i,"Name")).map(i=>e.find(o=>o.name===i)??{name:i??"",type:"Edm.String",nullable:false}),s=H(t.NavigationProperty).map(i=>{let o=D(i,"Type")??"";return {name:D(i,"Name"),targetEntityType:bs(o),isCollection:o.startsWith("Collection(")}});return {name:D(t,"Name"),keys:r,properties:e,navigationProperties:s}}function Ss(t,e){let n=D(t,"IsBound")==="true",r=H(t.Parameter),s=n?D(r[0],"Name"):void 0,i=(n?r.slice(1):r).map(a=>({name:D(a,"Name"),type:D(a,"Type")??"Edm.String",...D(a,"Nullable")!=="false"?{nullable:true}:{}})),o=D(t.ReturnType,"Type");return {name:D(t,"Name"),isBound:n,kind:e,...s?{bindingParameter:s}:{},parameters:i,...o?{returnType:o}:{}}}function _n(t,e,n){for(let r of t){if(!D(r,"Term")?.endsWith(e))continue;let i=H(r.Record?.PropertyValue).find(a=>D(a,"Property")===n),o=D(i,"Bool")??(i?.Bool!==void 0?String(i.Bool):void 0);if(o!==void 0)return o==="true"}}function Ts(t,e){let r=_c.parse(t).Edmx?.DataServices;if(!r)throw new Error("V4 metadata: <edmx:DataServices> fehlt \u2014 kein g\xFCltiges EDMX-Dokument");let s=H(r.Schema),i=[],o=[],a=[],d=new Map;for(let u of s){i.push(...H(u.EntityType).map(Ic)),o.push(...H(u.Action).map(p=>Ss(p,"Action"))),o.push(...H(u.Function).map(p=>Ss(p,"Function")));for(let p of H(u.EntityContainer))a.push(...H(p.EntitySet));for(let p of H(u.Annotations)){let m=D(p,"Target")??"",g=m.lastIndexOf("/");if(g===-1)continue;let f=m.slice(g+1);d.set(f,[...d.get(f)??[],...H(p.Annotation)]);}}let l=a.map(u=>{let p=D(u,"Name"),m=[...H(u.Annotation),...d.get(p)??[]];return {name:p,entityTypeName:bs(D(u,"EntityType")??""),creatable:_n(m,"InsertRestrictions","Insertable")??true,updatable:_n(m,"UpdateRestrictions","Updatable")??true,deletable:_n(m,"DeleteRestrictions","Deletable")??true}}),c={version:"v4",serviceUrl:e,entityTypes:i,entitySets:l};return o.length>0&&(c.actions=o),c}var Dc=10,Ut=class{constructor(e,n,r,s){this.httpClient=e;this.serviceUrl=n;this.etagCache=r;this.metadataProvider=s;}async metadataForLiterals(){if(this.metadataProvider)try{return await this.metadataProvider()}catch{return}}async keyUrl(e,n){let r=ue(await this.metadataForLiterals(),e);return `${this.serviceUrl}/${xt(e,n,r)}`}async read(e,n,r){if(n){let l=await this.keyUrl(e,n),c=r?Mt(r):void 0,u=await this.httpClient.request({method:"get",url:l,params:c}),p=u.data,m=u.headers.etag??u.headers.ETag;return m&&this.etagCache.set(e,n,m),{results:[p]}}let s=r?Mt(r):void 0,o=(await this.httpClient.request({method:"get",url:`${this.serviceUrl}/${e}`,params:s})).data,a=o.value??[],d=o["@odata.count"];return {results:a,count:d}}async query(e,n){let r=n.maxPages??Dc,s=Mt(n,true),o=(await this.httpClient.request({method:"get",url:`${this.serviceUrl}/${e}`,params:s})).data,a=[...o.value??[]],d=o["@odata.count"],l=o["@odata.nextLink"],c=1,u=false;for(;l&&c<r;){if(rt()){u=true;break}let m=this.resolveNextLink(l),f=(await this.httpClient.request({method:"get",url:m})).data,h=f.value??[];a.push(...h),l=f["@odata.nextLink"],c++;}let p={results:a,count:d};return l&&(p.nextLink=l),u&&(p.truncated=true,p.truncationReason=`Nach ${c} Seite(n) abgebrochen: Zeitbudget des Tool-Aufrufs ersch\xF6pft oder Client hat die Verbindung verworfen. Mit skip=${a.length} weiterlesen.`),p}async create(e,n){return (await this.httpClient.request({method:"post",url:`${this.serviceUrl}/${e}`,data:n,headers:{"Content-Type":"application/json"}})).data}async update(e,n,r){let s=await this.keyUrl(e,n),i=this.etagCache.get(e,n)??"*",o=await this.httpClient.request({method:"patch",url:s,data:r,headers:{"Content-Type":"application/json","If-Match":i}}),a=o.headers.etag??o.headers.ETag;a&&this.etagCache.update(e,n,a);}async delete(e,n){let r=await this.keyUrl(e,n),s=this.etagCache.get(e,n)??"*";await this.httpClient.request({method:"delete",url:r,headers:{"If-Match":s}});}async batch(e){let n=await this.metadataForLiterals(),{body:r,contentType:s}=gs(this.serviceUrl,e,a=>ue(n,a)),i=await this.httpClient.request({method:"post",url:`${this.serviceUrl}/$batch`,data:r,headers:{"Content-Type":s,Accept:"application/json"}}),o=us(i.data);for(let a=0;a<o.length&&a<e.length;a++)o[a].entitySet=e[a].entitySet;return {results:o}}async callAction(e,n,r,s){let i;return r&&s?i=`${await this.keyUrl(r,s)}/${e}`:i=`${this.serviceUrl}/${e}`,(await this.httpClient.request({method:"post",url:i,data:n??{},headers:{"Content-Type":"application/json"}})).data??{}}async callFunction(e,n,r,s){let i=ns(await this.metadataForLiterals(),e),o=this.buildFunctionParams(n,i),a;return r&&s?a=`${await this.keyUrl(r,s)}/${e}(${o})`:a=`${this.serviceUrl}/${e}(${o})`,(await this.httpClient.request({method:"get",url:a})).data??{}}buildFunctionParams(e,n){return !e||Object.keys(e).length===0?"":Object.entries(e).map(([r,s])=>`${r}=${Nt(s,n?.[r])}`).join(",")}async getMetadata(){let e=await this.httpClient.request({method:"get",url:`${this.serviceUrl}/$metadata`,headers:{Accept:"application/xml"}}),n=typeof e.data=="string"?e.data:JSON.stringify(e.data);return On(n,this.serviceUrl)}resolveNextLink(e){return e.startsWith("http://")||e.startsWith("https://")?e:`${this.serviceUrl}/${e}`}};function On(t,e){return t.trimStart().startsWith("{")?ys(t,e):Ts(t,e)}function In(t,e){let n=t.trim();if(n.startsWith("{"))try{if("$Version"in JSON.parse(n))return "v4"}catch{}if(n.startsWith("<?xml")||n.startsWith("<edmx:Edmx")||n.startsWith("<Edmx"))return /<(?:edmx:)?Edmx\b[^>]*\bVersion\s*=\s*["']([^"']+)["']/i.exec(n)?.[1]?.startsWith("4")?"v4":"v2";if(e){if(e.includes("/odata4/"))return "v4";if(e.includes("/odata/"))return "v2"}return "v2"}var $=class{constructor(e,n,r){this.httpClient=e;this.serviceUrl=n;this.metadataCache=r??new I;}protocolClient=null;version=null;initPromise=null;etagCache=new _t;metadataCache;metadataUnavailable=false;async ensureInitialized(){if(!this.protocolClient)return this.initPromise?this.initPromise:(this.initPromise=this.initialize(),this.initPromise)}async initialize(){let e=this.metadataCache.get(this.serviceUrl);if(e){this.version=e.version,this.protocolClient=this.createProtocolClient(e.version);return}let n="",r=false;try{let s=await this.httpClient.request({method:"get",url:`${this.serviceUrl}/$metadata`,headers:{Accept:"application/xml, application/json"}});n=typeof s.data=="string"?s.data:JSON.stringify(s.data),this.version=In(n,this.serviceUrl),r=!0;}catch{this.version=In("",this.serviceUrl),this.metadataUnavailable=true;}if(this.protocolClient=this.createProtocolClient(this.version),r&&n)try{let s=this.version==="v4"?On(n,this.serviceUrl):It(n,this.serviceUrl);this.metadataCache.set(this.serviceUrl,s);}catch{this.metadataUnavailable=true;}}async metadataForLiterals(){if(!this.metadataUnavailable)try{return await this.getMetadata()}catch{this.metadataUnavailable=true;return}}createProtocolClient(e){return e==="v4"?new Ut(this.httpClient,this.serviceUrl,this.etagCache,()=>this.metadataForLiterals()):new Ke(this.httpClient,this.serviceUrl,this.etagCache,()=>this.metadataForLiterals())}async getClient(){if(await this.ensureInitialized(),!this.protocolClient)throw new Error("ODataClient initialization failed: protocol client not created");return this.protocolClient}async read(e,n,r){return (await this.getClient()).read(e,n,r)}async query(e,n){return (await this.getClient()).query(e,n)}async create(e,n){return (await this.getClient()).create(e,n)}async update(e,n,r){return (await this.getClient()).update(e,n,r)}async delete(e,n){return (await this.getClient()).delete(e,n)}async batch(e,n){let r=await this.getClient();return this.version==="v4"?r.batch(e):r.batch(e,n)}async functionImport(e,n,r){let s=await this.getClient();if(s instanceof Ke)return s.functionImport(e,n,r?.httpMethod);let i=s;return r?.isFunction?i.callFunction(e,n,r?.entitySet,r?.key):i.callAction(e,n,r?.entitySet,r?.key)}async getMetadata(){let e=this.metadataCache.get(this.serviceUrl);if(e)return e;let n=await this.getClient();if(e=this.metadataCache.get(this.serviceUrl),e)return e;let r=await n.getMetadata();return this.metadataCache.set(this.serviceUrl,r),r}getVersion(){return this.version}};function ws(t,e,n){let r=n??new I,s=new ResourceTemplate("sap://schema/{serviceUrl}/{entitySet}",{list:void 0});t.registerResource("sap-entity-schema",s,{title:"SAP Entity Schema for Query Building",description:"Property names, types, and keys for an entity set \u2014 optimized context for building OData queries. Includes a sample filter in the correct V2/V4 syntax.",mimeType:"application/json"},async(i,o)=>{let a=decodeURIComponent(o.serviceUrl),d=decodeURIComponent(o.entitySet),c=await new $(e,a,r).getMetadata(),u=c.entitySets.find(h=>h.name===d);if(!u)return {contents:[{uri:i.toString(),mimeType:"application/json",text:JSON.stringify({error:`Entity set '${d}' not found in service ${a}`,availableEntitySets:c.entitySets.map(h=>h.name)},null,2)}]};let p=c.entityTypes.find(h=>h.name===u.entityTypeName);if(!p)return {contents:[{uri:i.toString(),mimeType:"application/json",text:JSON.stringify({error:`Entity type '${u.entityTypeName}' not found in metadata`},null,2)}]};let m=new Set(p.keys.map(h=>h.name)),g=p.properties.map(h=>({name:h.name,type:h.type,isKey:m.has(h.name)})),f=xc(p.properties,c.version);return {contents:[{uri:i.toString(),mimeType:"application/json",text:JSON.stringify({entitySet:d,version:c.version,properties:g,sampleFilter:f},null,2)}]}});}function xc(t,e){let n=t.find(r=>r.type==="Edm.String");return n?e==="v2"?`${n.name} eq 'example' or substringof('example',${n.name})`:`${n.name} eq 'example' or contains(${n.name},'example')`:"PropertyName eq 'value'"}function As(t,e){let n=new ResourceTemplate("idoc://received/{docnum}",{list:void 0});t.registerResource("idoc-received",n,{title:"Received IDoc",description:"Received IDoc data from webhook",mimeType:"application/json"},async(r,s)=>{let i=s.docnum,o=e.get(i);return o?{contents:[{uri:r.toString(),mimeType:"application/json",text:JSON.stringify({docnum:o.docnum,idocType:o.idocType,mesType:o.mesType,receivedAt:o.receivedAt.toISOString(),parsed:o.parsed},null,2)}]}:{contents:[{uri:r.toString(),mimeType:"application/json",text:JSON.stringify({error:`IDoc with docnum '${i}' not found`},null,2)}]}});}function vs(t,e,n){let r=n??new I,s=new ResourceTemplate("sap://metadata/{serviceUrl}",{list:void 0});t.registerResource("sap-metadata",s,{title:"SAP Service Metadata",description:"Entity types, properties, keys, and navigation properties for an SAP OData service",mimeType:"application/json"},async(i,o)=>{let a=decodeURIComponent(o.serviceUrl),l=await new $(e,a,r).getMetadata();return {contents:[{uri:i.toString(),mimeType:"application/json",text:JSON.stringify({version:l.version,serviceUrl:l.serviceUrl,entityTypes:l.entityTypes,entitySets:l.entitySets},null,2)}]}});}var Dn={"business-partner":{domain:"business-partner",description:"Customer, supplier, and business partner master data",services:[{name:"API_BUSINESS_PARTNER",path:"/sap/opu/odata/sap/API_BUSINESS_PARTNER",version:"v2",keyEntitySets:["A_BusinessPartner","A_BusinessPartnerAddress","A_Customer","A_Supplier"]}],queryTemplates:[{name:"find-customer-by-name",description:"Find customers by name (substring search)",entitySet:"A_Customer",filters:[{field:"CustomerName",operator:"contains",value:""}],select:["Customer","CustomerName","CustomerFullName","Country"],top:20},{name:"find-supplier-by-country",description:"Find suppliers in a specific country",entitySet:"A_Supplier",filters:[{field:"Country",operator:"eq",value:""}],select:["Supplier","SupplierName","Country","Region"],top:50}],suggestedTool:"sap_nl_query",commonQueries:["Find customers by name","List suppliers in a country","Get business partner addresses"]},sales:{domain:"sales",description:"Sales orders, billing documents, and revenue tracking",services:[{name:"API_SALES_ORDER_SRV",path:"/sap/opu/odata/sap/API_SALES_ORDER_SRV",version:"v2",keyEntitySets:["A_SalesOrder","A_SalesOrderItem"]},{name:"API_BILLING_DOCUMENT_SRV",path:"/sap/opu/odata/sap/API_BILLING_DOCUMENT_SRV",version:"v2",keyEntitySets:["A_BillingDocument"]}],queryTemplates:[{name:"recent-sales-orders",description:"Sales orders created this month",entitySet:"A_SalesOrder",filters:[{field:"CreationDate",operator:"ge",value:"$MONTH_START"}],select:["SalesOrder","SalesOrderType","SoldToParty","TotalNetAmount","CreationDate"],orderby:"CreationDate desc",top:50},{name:"overdue-invoices",description:"Billing documents past due date",entitySet:"A_BillingDocument",filters:[{field:"BillingDocumentDate",operator:"lt",value:"$TODAY"}],select:["BillingDocument","BillingDocumentType","SoldToParty","TotalNetAmount","BillingDocumentDate"],orderby:"BillingDocumentDate asc",top:50}],suggestedTool:"sap_nl_query",commonQueries:["Recent sales orders","Overdue invoices","Sales by customer"]},finance:{domain:"finance",description:"Journal entries, accounting documents, and financial postings",services:[{name:"API_JOURNALENTRY_SRV",path:"/sap/opu/odata/sap/API_JOURNALENTRY_SRV",version:"v2",keyEntitySets:["A_JournalEntry"]},{name:"API_OPLACCTG_SRV",path:"/sap/opu/odata/sap/API_OPLACCTG_SRV",version:"v2",keyEntitySets:["A_OperationalAcctgDocItem"]}],queryTemplates:[{name:"recent-journal-entries",description:"Journal entries posted this month",entitySet:"A_JournalEntry",filters:[{field:"DocumentDate",operator:"ge",value:"$MONTH_START"}],select:["AccountingDocument","CompanyCode","DocumentDate","PostingDate","DocumentType"],orderby:"DocumentDate desc",top:50},{name:"open-items-by-account",description:"Open accounting items for a G/L account",entitySet:"A_OperationalAcctgDocItem",filters:[{field:"GLAccount",operator:"eq",value:""}],select:["AccountingDocument","CompanyCode","GLAccount","AmountInCompanyCodeCurrency","PostingDate"],top:100}],suggestedTool:"sap_nl_query",commonQueries:["Recent journal entries","Open items by account","Accounting documents this month"]},procurement:{domain:"procurement",description:"Purchase orders, purchase requisitions, and supplier management",services:[{name:"API_PURCHASEORDER_PROCESS_SRV",path:"/sap/opu/odata/sap/API_PURCHASEORDER_PROCESS_SRV",version:"v2",keyEntitySets:["A_PurchaseOrder","A_PurchaseOrderItem"]},{name:"API_PURCHASEREQ_PROCESS_SRV",path:"/sap/opu/odata/sap/API_PURCHASEREQ_PROCESS_SRV",version:"v2",keyEntitySets:["A_PurchaseRequisition"]}],queryTemplates:[{name:"open-purchase-orders",description:"Purchase orders not yet fully delivered",entitySet:"A_PurchaseOrder",filters:[],select:["PurchaseOrder","PurchaseOrderType","Supplier","PurchasingOrganization","CreationDate"],orderby:"CreationDate desc",top:50},{name:"recent-purchase-requisitions",description:"Purchase requisitions created this month",entitySet:"A_PurchaseRequisition",filters:[{field:"CreationDate",operator:"ge",value:"$MONTH_START"}],select:["PurchaseRequisition","PurchaseRequisitionType","CreationDate"],orderby:"CreationDate desc",top:50}],suggestedTool:"sap_nl_query",commonQueries:["Open purchase orders","Recent purchase requisitions","Purchase orders by supplier"]},material:{domain:"material",description:"Material master data and material document movements",services:[{name:"API_PRODUCT_SRV",path:"/sap/opu/odata/sap/API_PRODUCT_SRV",version:"v2",keyEntitySets:["A_Product"]},{name:"API_MATERIAL_DOCUMENT_SRV",path:"/sap/opu/odata/sap/API_MATERIAL_DOCUMENT_SRV",version:"v2",keyEntitySets:["A_MaterialDocumentHeader"]}],queryTemplates:[{name:"find-material-by-description",description:"Search materials by description text",entitySet:"A_Product",filters:[{field:"ProductDescription",operator:"contains",value:""}],select:["Product","ProductType","ProductDescription","BaseUnit"],top:20},{name:"recent-material-movements",description:"Material documents created this month",entitySet:"A_MaterialDocumentHeader",filters:[{field:"DocumentDate",operator:"ge",value:"$MONTH_START"}],select:["MaterialDocument","MaterialDocumentYear","DocumentDate","PostingDate"],orderby:"DocumentDate desc",top:50}],suggestedTool:"sap_nl_query",commonQueries:["Find material by description","Recent material movements","Material stock levels"]},logistics:{domain:"logistics",description:"Inbound and outbound deliveries, shipping, and transportation",services:[{name:"API_INBOUND_DELIVERY_SRV",path:"/sap/opu/odata/sap/API_INBOUND_DELIVERY_SRV",version:"v2",keyEntitySets:["A_InbDeliveryHeader"]},{name:"API_OUTBOUND_DELIVERY_SRV",path:"/sap/opu/odata/sap/API_OUTBOUND_DELIVERY_SRV",version:"v2",keyEntitySets:["A_OutbDeliveryHeader"]}],queryTemplates:[{name:"pending-inbound-deliveries",description:"Inbound deliveries not yet received",entitySet:"A_InbDeliveryHeader",filters:[],select:["DeliveryDocument","Supplier","DeliveryDate","ReceivingPlant"],orderby:"DeliveryDate asc",top:50},{name:"recent-outbound-deliveries",description:"Outbound deliveries created this month",entitySet:"A_OutbDeliveryHeader",filters:[{field:"CreationDate",operator:"ge",value:"$MONTH_START"}],select:["DeliveryDocument","SoldToParty","CreationDate","DeliveryDate"],orderby:"CreationDate desc",top:50}],suggestedTool:"sap_nl_query",commonQueries:["Pending inbound deliveries","Recent outbound deliveries","Deliveries by ship-to party"]},hr:{domain:"hr",description:"Employee master data and organizational assignments",services:[{name:"API_BUSINESS_PARTNER",path:"/sap/opu/odata/sap/API_BUSINESS_PARTNER",version:"v2",keyEntitySets:["A_BusinessPartner"]}],queryTemplates:[{name:"find-employee-by-name",description:"Search employees by name (BP category 2 = Person)",entitySet:"A_BusinessPartner",filters:[{field:"BusinessPartnerCategory",operator:"eq",value:"2"},{field:"BusinessPartnerFullName",operator:"contains",value:""}],select:["BusinessPartner","BusinessPartnerFullName","BusinessPartnerCategory","OrganizationBPName1"],top:20},{name:"employees-by-department",description:"List employees assigned to a department/organization",entitySet:"A_BusinessPartner",filters:[{field:"BusinessPartnerCategory",operator:"eq",value:"2"},{field:"OrganizationBPName1",operator:"contains",value:""}],select:["BusinessPartner","BusinessPartnerFullName","OrganizationBPName1"],top:50}],suggestedTool:"sap_nl_query",commonQueries:["Find employee by name","Employees by department"]},production:{domain:"production",description:"Production orders, planned orders, and manufacturing execution",services:[{name:"API_PLANNED_ORDER",path:"/sap/opu/odata/sap/API_PLANNED_ORDER",version:"v2",keyEntitySets:["PlannedOrder"]},{name:"API_PRODUCTION_ORDER",path:"/sap/opu/odata/sap/API_PRODUCTION_ORDER",version:"v2",keyEntitySets:["A_ProductionOrder"]}],queryTemplates:[{name:"open-production-orders",description:"Production orders not yet completed",entitySet:"A_ProductionOrder",filters:[],select:["ManufacturingOrder","ManufacturingOrderType","Material","ProductionPlant","MfgOrderPlannedStartDate"],orderby:"MfgOrderPlannedStartDate asc",top:50},{name:"planned-orders-this-month",description:"Planned orders created this month",entitySet:"PlannedOrder",filters:[{field:"PlannedOrderCreationDate",operator:"ge",value:"$MONTH_START"}],select:["PlannedOrder","Material","ProductionPlant","PlannedOrderCreationDate"],orderby:"PlannedOrderCreationDate desc",top:50}],suggestedTool:"sap_nl_query",commonQueries:["Open production orders","Planned orders this month","Production orders by material"]},quality:{domain:"quality",description:"Quality inspections, inspection lots, and quality management",services:[{name:"API_QUALITYINSPECTION",path:"/sap/opu/odata/sap/API_QUALITYINSPECTION",version:"v2",keyEntitySets:["QualityInspection"]}],queryTemplates:[{name:"open-inspections",description:"Quality inspections not yet completed",entitySet:"QualityInspection",filters:[],select:["InspectionLot","Material","Plant","InspectionLotStartDate"],orderby:"InspectionLotStartDate asc",top:50},{name:"inspections-this-month",description:"Quality inspections started this month",entitySet:"QualityInspection",filters:[{field:"InspectionLotStartDate",operator:"ge",value:"$MONTH_START"}],select:["InspectionLot","Material","Plant","InspectionLotStartDate"],orderby:"InspectionLotStartDate desc",top:50}],suggestedTool:"sap_nl_query",commonQueries:["Open quality inspections","Inspections this month"]},"plant-maintenance":{domain:"plant-maintenance",description:"Maintenance notifications, orders, and equipment management",services:[{name:"API_MAINTNOTIFICATION",path:"/sap/opu/odata/sap/API_MAINTNOTIFICATION",version:"v2",keyEntitySets:["MaintenanceNotification"]},{name:"API_MAINTENANCEORDER",path:"/sap/opu/odata/sap/API_MAINTENANCEORDER",version:"v2",keyEntitySets:["MaintenanceOrder"]}],queryTemplates:[{name:"open-maintenance-notifications",description:"Maintenance notifications not yet completed",entitySet:"MaintenanceNotification",filters:[],select:["MaintenanceNotification","NotificationType","FunctionalLocation","ReportedByUser","CreationDate"],orderby:"CreationDate desc",top:50},{name:"maintenance-orders-this-month",description:"Maintenance orders created this month",entitySet:"MaintenanceOrder",filters:[{field:"CreationDate",operator:"ge",value:"$MONTH_START"}],select:["MaintenanceOrder","MaintenanceOrderType","FunctionalLocation","CreationDate"],orderby:"CreationDate desc",top:50}],suggestedTool:"sap_nl_query",commonQueries:["Open maintenance notifications","Maintenance orders this month","Notifications by functional location"]},project:{domain:"project",description:"Project systems, WBS elements, and project planning",services:[{name:"API_PROJECT",path:"/sap/opu/odata/sap/API_PROJECT",version:"v2",keyEntitySets:["A_Project","A_ProjectElement"]}],queryTemplates:[{name:"active-projects",description:"List active projects",entitySet:"A_Project",filters:[],select:["Project","ProjectDescription","ResponsiblePerson","PlannedStartDate"],orderby:"PlannedStartDate desc",top:50},{name:"project-elements-by-project",description:"WBS elements for a specific project",entitySet:"A_ProjectElement",filters:[{field:"Project",operator:"eq",value:""}],select:["ProjectElement","ProjectElementDescription","PlannedStartDate","PlannedEndDate"],top:100}],suggestedTool:"sap_nl_query",commonQueries:["Active projects","WBS elements for a project"]},warehouse:{domain:"warehouse",description:"Warehouse resources, tasks, and storage management",services:[{name:"API_WAREHOUSE_RESOURCE",path:"/sap/opu/odata/sap/API_WAREHOUSE_RESOURCE",version:"v2",keyEntitySets:["WarehouseResource","WarehouseTask"]}],queryTemplates:[{name:"open-warehouse-tasks",description:"Warehouse tasks not yet completed",entitySet:"WarehouseTask",filters:[],select:["WarehouseTask","WarehouseTaskType","Warehouse","WarehouseStorageBin"],top:50},{name:"warehouse-resources-by-plant",description:"Warehouse resources for a specific plant",entitySet:"WarehouseResource",filters:[{field:"Plant",operator:"eq",value:""}],select:["WarehouseResource","Warehouse","Plant"],top:50}],suggestedTool:"sap_nl_query",commonQueries:["Open warehouse tasks","Warehouse resources by plant"]},analytics:{domain:"analytics",description:"Financial analytics, expense tracking, and revenue analysis",services:[{name:"API_OPLACCTG_SRV",path:"/sap/opu/odata/sap/API_OPLACCTG_SRV",version:"v2",keyEntitySets:["A_OperationalAcctgDocItem"]}],queryTemplates:[{name:"expenses-this-year",description:"Expense postings since start of current year",entitySet:"A_OperationalAcctgDocItem",filters:[{field:"PostingDate",operator:"ge",value:"$YEAR_START"}],select:["AccountingDocument","CompanyCode","GLAccount","AmountInCompanyCodeCurrency","PostingDate"],orderby:"PostingDate desc",top:100},{name:"monthly-revenue",description:"Revenue postings this month",entitySet:"A_OperationalAcctgDocItem",filters:[{field:"PostingDate",operator:"ge",value:"$MONTH_START"}],select:["AccountingDocument","CompanyCode","GLAccount","AmountInCompanyCodeCurrency","PostingDate"],orderby:"PostingDate desc",top:100}],suggestedTool:"sap_nl_query",commonQueries:["Expenses this year","Monthly revenue","Postings by G/L account"]},"master-data":{domain:"master-data",description:"Cross-domain master data: business partners, materials, cost centers",services:[{name:"API_BUSINESS_PARTNER",path:"/sap/opu/odata/sap/API_BUSINESS_PARTNER",version:"v2",keyEntitySets:["A_BusinessPartner"]},{name:"API_PRODUCT_SRV",path:"/sap/opu/odata/sap/API_PRODUCT_SRV",version:"v2",keyEntitySets:["A_Product"]},{name:"API_COSTCENTER_SRV",path:"/sap/opu/odata/sap/API_COSTCENTER_SRV",version:"v2",keyEntitySets:["A_CostCenter"]}],queryTemplates:[{name:"search-master-data-by-name",description:"Search business partners, materials, or cost centers by name",entitySet:"A_BusinessPartner",filters:[{field:"BusinessPartnerFullName",operator:"contains",value:""}],select:["BusinessPartner","BusinessPartnerFullName","BusinessPartnerCategory"],top:20},{name:"cost-centers-by-company",description:"List cost centers for a company code",entitySet:"A_CostCenter",filters:[{field:"CompanyCode",operator:"eq",value:""}],select:["CostCenter","CostCenterDescription","CompanyCode","ValidityStartDate"],top:100}],suggestedTool:"sap_nl_query",commonQueries:["Search master data by name","Cost centers by company code","Materials by type"]},"cross-application":{domain:"cross-application",description:"Attachments, change documents, and cross-module services",services:[{name:"API_ATTACHMENT_SRV",path:"/sap/opu/odata/sap/API_ATTACHMENT_SRV",version:"v2",keyEntitySets:["A_DocumentInfoRecord"]},{name:"API_BUSINESS_OBJECT_PAGE",path:"/sap/opu/odata/sap/API_BUSINESS_OBJECT_PAGE",version:"v2",keyEntitySets:["A_BusinessObjectPage"]}],queryTemplates:[{name:"attachments-for-object",description:"Find attachments linked to a business object",entitySet:"A_DocumentInfoRecord",filters:[{field:"LinkedSAPObjectKey",operator:"eq",value:""}],select:["DocumentInfoRecordDocNumber","DocumentInfoRecordDocType","LinkedSAPObjectKey"],top:50},{name:"recent-change-documents",description:"Change documents from the last month",entitySet:"A_BusinessObjectPage",filters:[{field:"LastChangeDate",operator:"ge",value:"$MONTH_AGO"}],select:["BusinessObjectType","LastChangeDate","LastChangedByUser"],orderby:"LastChangeDate desc",top:50}],suggestedTool:"sap_nl_query",commonQueries:["Attachments for a business object","Recent change documents"]},unknown:{domain:"unknown",description:"Unknown or unclassified domain. Use service discovery to find available services.",services:[],queryTemplates:[{name:"discover-services",description:"No specific domain matched. Use sap_discover_services to explore available SAP services on this system.",entitySet:"",filters:[]},{name:"browse-domains",description:"Browse available routing domains with sap://routing/{domain} to find the right service for your query.",entitySet:"",filters:[]}],suggestedTool:"sap_discover_services",commonQueries:["Use sap_discover_services to find available services","Check sap://routing/{domain} with a specific domain"]}};var $c={$TODAY:()=>Nn(new Date),$YESTERDAY:()=>{let t=new Date;return t.setDate(t.getDate()-1),Nn(t)},$MONTH_START:()=>{let t=new Date;return `${t.getFullYear()}-${xn(t.getMonth()+1)}-01`},$YEAR_START:()=>`${new Date().getFullYear()}-01-01`,$MONTH_AGO:()=>{let t=new Date;return t.setMonth(t.getMonth()-1),Nn(t)}};function Nn(t){return `${t.getFullYear()}-${xn(t.getMonth()+1)}-${xn(t.getDate())}`}function xn(t){return t.toString().padStart(2,"0")}function Lc(t){if(typeof t!="string")return t;let e=$c[t];return e?e():t}function Es(t){return {...t,queryTemplates:t.queryTemplates.map(e=>({...e,filters:e.filters.map(n=>({...n,value:Lc(n.value)}))}))}}function Cs(t){let e=new ResourceTemplate("sap://routing/{domain}",{list:void 0});t.registerResource("sap-routing",e,{title:"SAP Domain Routing",description:"Service mappings and query templates for a business domain. Returns the relevant SAP services, entity sets, and pre-built query examples for a domain like business-partner, sales, or finance. Use this before building OData queries to know which service and entity set to target.",mimeType:"application/json"},async(n,r)=>{let s=r.domain,i=Dn[s];if(!i)return {contents:[{uri:n.toString(),mimeType:"application/json",text:JSON.stringify({error:`Unknown domain '${s}'`,availableDomains:Object.keys(Dn)},null,2)}]};let o=Es(i);return {contents:[{uri:n.toString(),mimeType:"application/json",text:JSON.stringify({...o,note:"Service paths are typical defaults. Use sap_discover_services to verify actual paths on your system."},null,2)}]}});}var Rs="/sap/opu/odata/sap",Fc=/^[A-Z0-9_/]+$/i,pe=class extends Error{guidance;constructor(e){super(`serviceUrl ist weder ein Pfad noch ein technischer Servicename: "${e}"`),this.name="InvalidServiceUrlError",this.guidance=`Erwartet wird ein Pfad wie ${Rs}/API_BUSINESS_PARTNER oder der technische Name (API_BUSINESS_PARTNER), den sap_discover_services als technicalName liefert.`;}};function j(t){let e=t.trim();if(e.length===0)throw new pe(t);if(e.startsWith("/"))return e.replace(/\/+$/,"")||"/";if(e.startsWith("http://")||e.startsWith("https://"))try{return new URL(e).pathname.replace(/\/+$/,"")}catch{throw new pe(t)}if(Fc.test(e))return `${Rs}/${e.replace(/^\/+|\/+$/g,"")}`;throw new pe(t)}var ze=class extends Error{guidance;extra;constructor(e,n,r={}){super(e),this.name="ToolInputError",this.guidance=n,this.extra=r;}};function _(t,e){if(t instanceof pe)return Mn({code:"INVALID_INPUT",error:t.message,guidance:t.guidance,...e?.hint?{hint:e.hint}:{}});if(t instanceof ze)return Mn({code:"INVALID_INPUT",error:t.message,...t.guidance?{guidance:t.guidance}:{},...t.extra,...e?.hint?{hint:e.hint}:{}});let n=ye(t,{serviceUrl:e?.serviceUrl});return Mn({code:n.code,error:n.message,...n.httpStatus!==void 0?{httpStatus:n.httpStatus}:{},...n.sapCode?{sapCode:n.sapCode}:{},...n.guidance?{guidance:n.guidance}:{},...e?.hint?{hint:e.hint}:{}})}function Mn(t){let e=ge()?.correlationId;return {content:[{type:"text",text:JSON.stringify({...t,...e?{correlationId:e}:{}},null,2)}],isError:true}}function Ps(t,e,n){let r=n??new I,s=new Map;function i(a){let d=j(a),l=s.get(d);return l||(l=new $(e,d,r),s.set(d,l)),l}function o(a,d){return _(a,{serviceUrl:d})}t.registerTool("sap_batch",{title:"Execute SAP Batch Request",description:"Execute multiple OData operations in a single batch request. Supports V2 (multipart/mixed) and V4 (JSON) batch formats automatically. Write operations sharing a changesetId run as one transaction (all succeed or all fail); in V2 a write without changesetId gets a changeset of its own. Returns per-operation status in the order of the operations -- individual failures are always reported, never hidden behind the batch HTTP 200.",inputSchema:z$2.object({serviceUrl:z$2.string().describe("OData service URL"),operations:z$2.array(z$2.object({method:z$2.enum(["get","post","patch","delete"]).describe("HTTP method"),entitySet:z$2.string().describe("Entity set name"),key:z$2.record(z$2.string(),z$2.unknown()).optional().describe("Entity key for read/update/delete"),data:z$2.record(z$2.string(),z$2.unknown()).optional().describe("Request body for create/update"),changesetId:z$2.string().optional().describe("Changeset group ID for transactional grouping")})).describe("Array of operations to execute in batch")}),annotations:{readOnlyHint:false,destructiveHint:true,idempotentHint:false,openWorldHint:true}},async({serviceUrl:a,operations:d})=>{try{let l=i(a),c=d,u=await l.batch(c);return {content:[{type:"text",text:JSON.stringify(u,null,2)}]}}catch(l){return o(l)}});}async function ks(t,e,n=5){if(t.length===0)return [];let r=Math.max(1,Math.min(Math.floor(n)||1,t.length)),s=new Array(t.length),i=0;async function o(){for(;;){let a=i++;if(a>=t.length)return;s[a]=await e(t[a],a);}}return await Promise.all(Array.from({length:r},()=>o())),s}var Hc=[".integrationsuite.","integrationsuite-trial.",".it-cpi.",".hci.",".prod.apimanagement.","-api.s4hana.ondemand.com"];function _s(t){let e=t.toLowerCase();return Hc.some(n=>e.includes(n))}var Y=class extends Error{constructor(n,r,s,i){super(n);this.httpStatus=r;this.sapGuidance=s;this.isBtpDetected=i;this.name="CatalogError";}},jc=new Set(["ECONNREFUSED","ETIMEDOUT","ENOTFOUND"]);function Vc(t,e=false){switch(t){case 403:return "Catalog access denied. Check transaction PFCG for role assignment and SU53 for authorization trace. Required authorization object: S_SERVICE with SRV_NAME = IWFND_CATALOGSERVICE.";case 404:return e?"V4 catalog not available. Publish service group via /IWFND/V4_ADMIN.":"Catalog service not found. Activate it via transaction /IWFND/MAINT_SERVICE.";case 500:return "SAP system error. Check transaction ST22 for ABAP dumps and SM21 for system log.";default:return "Could not connect to SAP system. Verify the hostname, port, and network connectivity."}}function Wc(t){switch(t){case "ECONNREFUSED":return "Connection refused. Verify that the SAP system is running and the port is correct.";case "ETIMEDOUT":return "Connection timeout. Check network connectivity and firewall rules.";case "ENOTFOUND":return "Hostname not found. Verify the SAP system hostname in your configuration.";default:return "Could not connect to SAP system. Verify the hostname, port, and network connectivity."}}function Os(t){return typeof t=="object"&&t!==null&&"response"in t&&typeof t.response=="object"&&t.response!==null&&typeof t.response.status=="number"}function Gc(t){return typeof t=="object"&&t!==null&&"code"in t&&typeof t.code=="string"&&jc.has(t.code)}function Ye(t,e,n=false){let r=_s(e);if(Os(t)){let i=t.response.status,o=Vc(i,n),a="message"in t&&typeof t.message=="string"?t.message:`HTTP ${i}`;return new Y(a,i,o,r)}if(Gc(t)){let i=Wc(t.code),o="message"in t&&typeof t.message=="string"?t.message:t.code;return new Y(o,void 0,i,r)}let s=t instanceof Error?t.message:String(t);return new Y(s,void 0,void 0,r)}function Is(t){return Os(t)&&t.response.status===404?"V4 catalog not available. Publish service group via /IWFND/V4_ADMIN.":t instanceof Error?t.message:String(t)}var qc=["/sap/opu/odata/IWFND/CATALOGSERVICE;v=2/ServiceCollection","/sap/opu/odata/iwfnd/CATALOGSERVICE;v=2/ServiceCollection","/sap/opu/odata/IWFND/CATALOGSERVICE/ServiceCollection"];function Kc(t){if(typeof t=="object"&&t!==null&&"response"in t)return t.response?.status}async function Ds(t,e,n){let r;for(let s of qc)try{return await t.request({method:"get",url:s,params:{$format:"json",$top:"1"},expectedStatuses:[404]}),n?.onMatch?.(s),s}catch(i){if(i instanceof F)throw i;if(Kc(i)===404){r=i;continue}throw Ye(i,e,false)}throw Ye(r??new Error("All V2 catalog paths returned 404"),e,false)}function Ns(t){try{return new URL(t).pathname}catch{return t}}function Yc(t){let e=t.toLowerCase().replace(/'/g,"''");return [`substringof('${e}',tolower(TechnicalServiceName))`,`substringof('${e}',tolower(Title))`,`substringof('${e}',tolower(Description))`].join(" or ")}var $t=class t{constructor(e,n,r={}){this.httpClient=e;this.cache=n;this.options=r;}static DEFAULT_V4_URL="/sap/opu/odata4/iwfnd/config/default/iwfnd/catalog/0002/ServiceGroups";resolvedV2Path;serverSideFilterUnsupported=false;async discoverServices(e){let n=this.cache.get();if(n)return {services:n,warnings:[]};if(e&&!this.serverSideFilterUnsupported){let l=await this.tryFilteredFetch(e);if(l)return l}let r=[],[s,i]=await ks(["v4","v2"],async l=>l==="v4"?await this.fetchV4Catalog().then(c=>({ok:true,services:c}),c=>({ok:false,error:c})):await this.fetchV2Catalog().then(c=>({ok:true,services:c}),c=>({ok:false,error:c})),this.options.concurrency??5),o=[];if(s?.ok)o=s.services;else if(s){if(s.error instanceof F)throw s.error;r.push(`V4 catalog fetch failed: ${Is(s.error)}`);}if(!i?.ok){let l=i?.error;throw l instanceof Y?l:Ye(l,this.options.baseUrl??"",false)}let a=i.services,d=this.mergeAndDeduplicate(o,a);return this.cache.set(d),{services:d,warnings:r}}async tryFilteredFetch(e){try{return {services:await this.fetchV2Catalog(Yc(e)),warnings:[],filtered:!0}}catch(n){if(n instanceof F)throw n;let r=n?.response?.status;(r===400||r===501)&&(this.serverSideFilterUnsupported=true);return}}async fetchV2Catalog(e){let n=this.options.catalogV2Url??this.resolvedV2Path;return n||(n=await Ds(this.httpClient,this.options.baseUrl??"",{onMatch:this.options.onDiscoveryMatch}),this.resolvedV2Path=n),((await this.httpClient.request({method:"get",url:n,params:{$format:"json",...e?{$filter:e}:{}},...e?{expectedStatuses:[400,501]}:{}})).data?.d?.results??[]).map(o=>({technicalName:o.TechnicalServiceName,title:o.Title,serviceUrl:Ns(o.ServiceUrl),description:o.Description,version:"v2",serviceVersion:o.TechnicalServiceVersion}))}async fetchV4Catalog(){let e=this.options.catalogV4Url??t.DEFAULT_V4_URL,s=(await this.httpClient.request({method:"get",url:e,params:{$expand:"DefaultSystem($expand=Services)"},headers:{Accept:"application/json"},expectedStatuses:[404]})).data?.value??[],i=[];for(let o of s){let a=o.DefaultSystem?.Services??[];for(let d of a)i.push({technicalName:d.ServiceId??d.ServiceName??"",title:d.ServiceTitle??d.Title??"",serviceUrl:Ns(d.ServiceUrl),version:"v4",serviceVersion:d.ServiceVersion});}return i}mergeAndDeduplicate(e,n){let r=new Map;for(let s of e)r.set(s.technicalName,s);for(let s of n)r.has(s.technicalName)||r.set(s.technicalName,s);return [...r.values()]}};var Xc=[[/BUSINESS_?PARTNER|BUPA/i,"business-partner"],[/SALES_ORDER|BILLING|CREDIT_MEMO|DEBIT_MEMO|SALES_CONTRACT|SALES_QUOT/i,"sales"],[/PURCHASEORDER|PURCHASE_ORDER|PURCHASE_REQ|SUPPLIER|PURG/i,"procurement"],[/JOURNALENTRY|JOURNAL_ENTRY|OPLACCTG|COST_CENTER|PROFIT_CENTER|GL_ACCOUNT|FINANCIAL/i,"finance"],[/MATERIAL_DOC|MATERIAL_STOCK|MATERIAL_SRV|PRODUCT\b/i,"material"],[/OUTBOUND_DELIV|INBOUND_DELIV|SHIPPING|TRANSPORTATION/i,"logistics"],[/PRODUCTION_ORDER|PLANNED_ORDER|ROUTING|BOM\b/i,"production"],[/EMPLOYEE|WORKFORCE|PERSONNEL|PAYROLL/i,"hr"],[/INSPECTION|QUALITY/i,"quality"],[/MAINTENANCE|EQUIPMENT|FUNCTIONAL_LOC/i,"plant-maintenance"],[/PROJECT|WBS\b/i,"project"],[/WAREHOUSE|STORAGE_BIN/i,"warehouse"],[/ANALYTIC|CUBE/i,"analytics"]],Jc=[[/^[ZY]?MM[_]/i,"procurement"],[/^[ZY]?SD[_]/i,"sales"],[/^[ZY]?FI[_]|^[ZY]?CO[_]/i,"finance"],[/^[ZY]?PP[_]/i,"production"],[/^[ZY]?HR[_]|^[ZY]?PA[_]|^[ZY]?PT[_]/i,"hr"],[/^[ZY]?WM[_]/i,"warehouse"],[/^[ZY]?PM[_]/i,"plant-maintenance"],[/^[ZY]?LE[_]/i,"logistics"]];function Zc(t){for(let[e,n]of Xc)if(e.test(t.technicalName))return {...t,category:n,categoryConfidence:"high"};for(let[e,n]of Jc)if(e.test(t.technicalName))return {...t,category:n,categoryConfidence:"high"};return {...t,category:"unknown",categoryConfidence:"low"}}function xs(t){return t.map(Zc)}function Oe(t,e){let n=Number.isFinite(t)&&t>0?Math.floor(t):50,r=Number.isFinite(e)&&e>0?Math.floor(e):0;return {top:Math.min(n,1e3),skip:r}}function Ie(t){let{returned:e,totalCount:n,paging:r,hasMoreHint:s}=t,i=s??(n!==void 0?r.skip+e<n:e>=r.top),o={returned:e,hasMore:i,top:r.top,skip:r.skip};return n!==void 0&&(o.totalCount=n),i&&(o.nextSkip=r.skip+e),o}function Ms(t,e,n,r){let s=r??new Q,i=new $t(e,s,n);t.registerTool("sap_discover_services",{title:"Discover SAP OData Services",description:`Discover all available OData services on the connected SAP system. Returns categorized services with search, category filtering, and pagination. Use this as the first step to explore what APIs are available before using sap_list_services or sap_get_metadata.
212
+ `,contentType:`multipart/mixed; boundary=${s}`,parts:i}}var kc=new Set(["EntityType","Property","NavigationProperty","Association","EntitySet","AssociationSet","PropertyRef","End","FunctionImport","Parameter"]),_c=new XMLParser({ignoreAttributes:false,attributeNamePrefix:"@_",removeNSPrefix:true,processEntities:false,htmlEntities:false,isArray:t=>kc.has(t)});function On(t){return t===void 0?true:String(t).toLowerCase()!=="false"}function Ut(t,e){let r=_c.parse(t).Edmx.DataServices.Schema,s=Array.isArray(r)?r[0]:r,i=s.EntityType??[],o=s.Association??[],a=s.EntityContainer,d=a?.EntitySet??[],l=new Map;for(let g of o)l.set(g["@_Name"],g);let c=i.map(g=>{let h=Oc(g.Property??[]),b=(g.Key?.PropertyRef??[]).map(S=>S["@_Name"]),y=h.filter(S=>b.includes(S.name)),E=Ic(g.NavigationProperty??[],l);return {name:g["@_Name"],keys:y,properties:h,navigationProperties:E}}),u=d.map(g=>({name:g["@_Name"],entityTypeName:In(g["@_EntityType"]),creatable:On(g["@_creatable"]),updatable:On(g["@_updatable"]),deletable:On(g["@_deletable"])})),p=a?.FunctionImport??[],m=Nc(Array.isArray(p)?p:[p]),f={version:"v2",serviceUrl:e,entityTypes:c,entitySets:u};return m.length>0&&(f.functionImports=m),f}function Oc(t){return t.map(e=>{let n={name:e["@_Name"],type:e["@_Type"],nullable:e["@_Nullable"]!=="false"};return e["@_MaxLength"]!==void 0&&(n.maxLength=Number.parseInt(e["@_MaxLength"],10)),e["@_Precision"]!==void 0&&(n.precision=Number.parseInt(e["@_Precision"],10)),e["@_Scale"]!==void 0&&(n.scale=Number.parseInt(e["@_Scale"],10)),n})}function Ic(t,e){return t.map(n=>{let r=In(n["@_Relationship"]),s=e.get(r),i="Unknown",o=false;if(s){let a=s.End.find(d=>d["@_Role"]===n["@_ToRole"]);a&&(i=In(a["@_Type"]),o=a["@_Multiplicity"]==="*");}return {name:n["@_Name"],targetEntityType:i,isCollection:o}})}function Nc(t){return t.filter(e=>e["@_Name"]).map(e=>{let n=(e.Parameter??[]).map(s=>({name:s["@_Name"],type:s["@_Type"],...s["@_Nullable"]==="true"?{nullable:true}:{}})),r={name:e["@_Name"],httpMethod:e["@_HttpMethod"]??"POST",parameters:n};return e["@_ReturnType"]&&(r.returnType=e["@_ReturnType"]),r})}function In(t){let e=t.lastIndexOf(".");return e>=0?t.substring(e+1):t}var Dc=/^\/Date\((-?\d+)([+-]\d{4})?\)\/$/;function se(t){if(!t||typeof t!="object")return {results:[]};let e=t;if("d"in e&&e.d&&typeof e.d=="object"){let n=e.d;if("results"in n&&Array.isArray(n.results)){let s={results:n.results};return n.__count!==void 0&&(s.count=Number(n.__count)),typeof n.__next=="string"&&(s.nextLink=n.__next),s}return {results:[{...n}]}}return "results"in e&&Array.isArray(e.results)?{results:e.results}:{results:[e]}}function ws(t){let e=Dc.exec(t);if(!e)return t;let n=Number(e[1]);return new Date(n).toISOString()}function K(t){if(t==null)return t;if(Array.isArray(t))return t.map(e=>K(e));if(typeof t=="object"){let e=t,n={};for(let[r,s]of Object.entries(e))r!=="__metadata"&&(s&&typeof s=="object"&&!Array.isArray(s)&&"__deferred"in s||(typeof s=="string"?n[r]=ws(s):n[r]=K(s)));return n}return typeof t=="string"?ws(t):t}var Ts=10,Xe=class{constructor(e,n,r,s){this.httpClient=e;this.serviceUrl=n;this.etagCache=r;this.metadataProvider=s;}async metadataForLiterals(){if(this.metadataProvider)try{return await this.metadataProvider()}catch{return}}async keyUrl(e,n){let r=fe(await this.metadataForLiterals(),e);return `${this.serviceUrl}/${Oe(e,n,r)}`}async read(e,n,r){let s=_n(r??{});if(n){let i=await this.keyUrl(e,n),o=await this.httpClient.request({method:"get",url:i,headers:{Accept:"application/json"},params:s});o.headers.etag&&this.etagCache.set(e,n,o.headers.etag);let a=se(o.data);return {...a,results:a.results.map(d=>K(d))}}return this.fetchWithPagination(`${this.serviceUrl}/${e}`,s,r?.maxPages??Ts)}async query(e,n){let r=_n(n,true),s=n.maxPages??Ts;return this.fetchWithPagination(`${this.serviceUrl}/${e}`,r,s)}async create(e,n){let r=await this.httpClient.request({method:"post",url:`${this.serviceUrl}/${e}`,data:n,headers:{Accept:"application/json","Content-Type":"application/json"}}),s=r.data?.d;ct(s?.__metadata?.uri??Le(r.headers,"location"));let i=se(r.data);return i.results.length>0?K(i.results[0]):{}}async update(e,n,r){let s=await this.keyUrl(e,n),i=this.etagCache.get(e,n)??"*",o=await this.httpClient.request({method:"post",url:s,data:r,headers:{Accept:"application/json","Content-Type":"application/json","X-HTTP-Method":"MERGE","If-Match":i}});o.headers.etag&&this.etagCache.set(e,n,o.headers.etag);}async delete(e,n){let r=await this.keyUrl(e,n),s=this.etagCache.get(e,n)??"*";await this.httpClient.request({method:"delete",url:r,headers:{Accept:"application/json","If-Match":s}}),this.etagCache.update(e,n,void 0);}async functionImport(e,n,r){let s=await this.metadataForLiterals(),i=s?.functionImports?.find(f=>f.name===e),o=kn(s,e),a=(r??i?.httpMethod??"POST").toLowerCase(),d={$format:"json"};if(n)for(let[f,g]of Object.entries(n))d[f]=Mt(g,o?.[f]);let l=await this.httpClient.request({method:a,url:`${this.serviceUrl}/${e}`,headers:{Accept:"application/json"},params:d}),c=l.data?.d;if(i?.returnType?.startsWith("Collection(")||Array.isArray(c)||Array.isArray(c?.results)){let f=Array.isArray(c)?c:se(l.data).results;return {results:K(f)}}let p=se(l.data);if(p.results.length>0)return K(p.results[0]);let m=l.data;return m?.d&&typeof m.d=="object"?m.d:{}}async batch(e,n){let r=await this.metadataForLiterals(),{body:s,contentType:i,parts:o}=bs(this.serviceUrl,e,n,m=>fe(r,m)),a=await this.httpClient.request({method:"post",url:`${this.serviceUrl}/$batch`,data:s,headers:{"Content-Type":i,Accept:"multipart/mixed"}}),d=a.headers["content-type"]??i,l=ps(a.data,d),c=new Map;return o.forEach((m,f)=>{let g=l[f];m.operations.forEach((h,b)=>{let y=Array.isArray(g)?g[b]:g;c.set(h,y?{...y,entitySet:h.entitySet}:{status:0,entitySet:h.entitySet,error:"SAP returned no response for this operation"});});}),{results:[...e,...(n??[]).flatMap(m=>m.operations)].map(m=>c.get(m)).filter(m=>m!==void 0)}}async getMetadata(){let e=await this.httpClient.request({method:"get",url:`${this.serviceUrl}/$metadata`,headers:{Accept:"application/xml"}});return Ut(e.data,this.serviceUrl)}async fetchWithPagination(e,n,r){let s=[],i,o=e,a=n,d=0,l=false;for(;o&&d<r;){if(d>0&&dt()){l=true;break}let p=(await this.httpClient.request({method:"get",url:o,headers:{Accept:"application/json"},params:a})).data,m=se(p),f=m.results.map(h=>K(h));s.push(...f),d===0&&m.count!==void 0&&(i=m.count),d++;let g=p?.d;g&&typeof g.__next=="string"?(o=g.__next,a=void 0):o=void 0;}let c={results:s};return i!==void 0&&(c.count=i),o&&(c.nextLink=o),l&&(c.truncated=true,c.truncationReason=`Nach ${d} Seite(n) abgebrochen: Zeitbudget des Tool-Aufrufs ersch\xF6pft oder Client hat die Verbindung verworfen. Mit skip=${s.length} weiterlesen.`),c}};function vs(t){let n=(typeof t=="string"?JSON.parse(t):t).responses;return !n||!Array.isArray(n)?[]:n.map(r=>{let s=r.status,i=s>=200&&s<300,o={status:s,entitySet:""};return r.body!==void 0&&r.body!==null&&(i?o.result=r.body:o.error=JSON.stringify(r.body)),o})}var xc=/^-?\d+(\.\d+)?([eE][+-]?\d+)?$/,Mc=/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i,Uc=/(Z|[+-]\d{2}:?\d{2})$/i;function Lt(t,e){if(t==null)return "null";if(e){let n=$c(t,e);if(n!==void 0)return n}return typeof t=="boolean"||typeof t=="number"||typeof t=="bigint"?String(t):t instanceof Date?t.toISOString():Es(String(t))}function $c(t,e){let n=t instanceof Date?t.toISOString():String(t);switch(e){case "Edm.String":return Es(n);case "Edm.Guid":{let r=$t($t(n,"guid"),"");return Mc.test(r)?r:void 0}case "Edm.Boolean":{let r=n.toLowerCase();return r==="true"||r==="false"?r:void 0}case "Edm.Date":{let r=As(n);return /^\d{4}-\d{2}-\d{2}/.test(r)?r.slice(0,10):void 0}case "Edm.DateTimeOffset":{let r=As(n);return /^\d{4}-\d{2}-\d{2}$/.test(r)&&(r=`${r}T00:00:00`),/^\d{4}-\d{2}-\d{2}T/.test(r)?Uc.test(r)?r:`${r}Z`:void 0}case "Edm.TimeOfDay":return /^\d{2}:\d{2}(:\d{2}(\.\d+)?)?$/.test(n)?n:void 0;case "Edm.Duration":return `duration'${$t(n,"duration")}'`;case "Edm.Binary":return `binary'${$t(n,"binary")}'`;case "Edm.Decimal":case "Edm.Double":case "Edm.Single":case "Edm.Int64":case "Edm.Int32":case "Edm.Int16":case "Edm.Byte":case "Edm.SByte":{let r=n.replace(/[mMlLdDfF]$/,"");return xc.test(r)?r:void 0}default:return}}function Es(t){return `'${t.replace(/'/g,"''")}'`}function $t(t,e){let n=new RegExp(`^${e}'(.*)'$`,"is").exec(t);return n?n[1]:t}function As(t){let e=/^\/Date\((-?\d+)(?:[+-]\d{4})?\)\/$/.exec(t);return e?new Date(Number(e[1])).toISOString():t}function Cs(t,e){return Lt(t,e)}function Bt(t,e,n){let r=Object.entries(e);if(r.length===1){let[i,o]=r[0];return `${t}(${Cs(o,n?.[i])})`}let s=r.map(([i,o])=>`${i}=${Cs(o,n?.[i])}`).join(",");return `${t}(${s})`}function Ft(t,e){let n={};return t.filter&&(n.$filter=t.filter),t.select?.length&&(n.$select=t.select.join(",")),t.expand?.length&&(n.$expand=t.expand.join(",")),t.orderby&&(n.$orderby=t.orderby),t.top!==void 0&&(n.$top=String(t.top)),t.skip!==void 0&&(n.$skip=String(t.skip)),e&&(n.$count="true"),n}function Rs(t,e,n){let r=[];for(let i=0;i<e.length;i++){let o=e[i],a=o.key?Bt(o.entitySet,o.key,n?.(o.entitySet)):o.entitySet,d={id:String(i+1),method:o.method.toUpperCase(),url:a};o.changesetId&&(d.atomicityGroup=o.changesetId),o.data&&(o.method==="post"||o.method==="patch"||o.method==="delete")&&(d.headers={"Content-Type":"application/json"},d.body=o.data),r.push(d);}return {body:JSON.stringify({requests:r}),contentType:"application/json"}}function Ps(t){let e=t.split(".");return e[e.length-1]}function Lc(t,e){return {name:t,type:e.$Type??"Edm.String",nullable:e.$Nullable??false,maxLength:e.$MaxLength,precision:e.$Precision,scale:e.$Scale}}function ks(t,e){let n=JSON.parse(t),r=[],s=[],i=[];for(let[a,d]of Object.entries(n)){if(a.startsWith("$"))continue;let l=d;for(let[c,u]of Object.entries(l)){let p=u;if(p.$Kind==="Action"||p.$Kind==="Function"){let m=p.$IsBound??false,f=p.$Parameter??[],g=m&&f.length>0?f[0].$Name:void 0,h=(m?f.slice(1):f).map(y=>({name:y.$Name,type:y.$Type??"Edm.String",...y.$Nullable===true?{nullable:true}:{}})),b=p.$ReturnType?p.$ReturnType.$Type:void 0;i.push({name:c,isBound:m,kind:p.$Kind,...g?{bindingParameter:g}:{},parameters:h,...b?{returnType:b}:{}});}else if(p.$Kind==="EntityType"){let m=[],f=[];for(let[b,y]of Object.entries(p)){if(b.startsWith("$"))continue;let E=y;E.$Kind==="NavigationProperty"?f.push({name:b,targetEntityType:Ps(E.$Type),isCollection:E.$Collection??false}):m.push(Lc(b,E));}let h=(p.$Key??[]).map(b=>{let y=m.find(E=>E.name===b);return y||{name:b,type:"Edm.String",nullable:false}});r.push({name:c,keys:h,properties:m,navigationProperties:f});}else if(p.$Kind==="EntityContainer")for(let[m,f]of Object.entries(p)){if(m.startsWith("$"))continue;let g=f;g.$Collection&&g.$Type&&s.push({name:m,entityTypeName:Ps(g.$Type),creatable:Nn(g,"InsertRestrictions","Insertable"),updatable:Nn(g,"UpdateRestrictions","Updatable"),deletable:Nn(g,"DeleteRestrictions","Deletable")});}}}let o={version:"v4",serviceUrl:e,entityTypes:r,entitySets:s};return i.length>0&&(o.actions=i),o}function Nn(t,e,n){for(let[r,s]of Object.entries(t)){if(!r.startsWith("@")||!r.endsWith(e))continue;let i=s?.[n];if(typeof i=="boolean")return i}return true}var Fc=new Set(["Schema","EntityType","Property","NavigationProperty","PropertyRef","EntityContainer","EntitySet","Action","Function","Parameter","Annotations","Annotation","PropertyValue"]),Hc=new XMLParser({ignoreAttributes:false,attributeNamePrefix:"@_",removeNSPrefix:true,processEntities:false,htmlEntities:false,isArray:t=>Fc.has(t)});function H(t){return Array.isArray(t)?t:[]}function N(t,e){let n=t?.[`@_${e}`];return n===void 0?void 0:String(n)}function Dn(t,e){let n=N(t,e);return n===void 0||n==="max"?void 0:Number.parseInt(n,10)}function Os(t){let e=/^Collection\((.*)\)$/.exec(t)?.[1]??t;return e.slice(e.lastIndexOf(".")+1)}function jc(t){let e={name:N(t,"Name"),type:N(t,"Type")??"Edm.String",nullable:N(t,"Nullable")!=="false"},n=Dn(t,"MaxLength"),r=Dn(t,"Precision"),s=Dn(t,"Scale");return n!==void 0&&(e.maxLength=n),r!==void 0&&(e.precision=r),s!==void 0&&(e.scale=s),e}function Vc(t){let e=H(t.Property).map(jc),r=H(t.Key?.PropertyRef).map(i=>N(i,"Name")).map(i=>e.find(o=>o.name===i)??{name:i??"",type:"Edm.String",nullable:false}),s=H(t.NavigationProperty).map(i=>{let o=N(i,"Type")??"";return {name:N(i,"Name"),targetEntityType:Os(o),isCollection:o.startsWith("Collection(")}});return {name:N(t,"Name"),keys:r,properties:e,navigationProperties:s}}function _s(t,e){let n=N(t,"IsBound")==="true",r=H(t.Parameter),s=n?N(r[0],"Name"):void 0,i=(n?r.slice(1):r).map(a=>({name:N(a,"Name"),type:N(a,"Type")??"Edm.String",...N(a,"Nullable")!=="false"?{nullable:true}:{}})),o=N(t.ReturnType,"Type");return {name:N(t,"Name"),isBound:n,kind:e,...s?{bindingParameter:s}:{},parameters:i,...o?{returnType:o}:{}}}function xn(t,e,n){for(let r of t){if(!N(r,"Term")?.endsWith(e))continue;let i=H(r.Record?.PropertyValue).find(a=>N(a,"Property")===n),o=N(i,"Bool")??(i?.Bool!==void 0?String(i.Bool):void 0);if(o!==void 0)return o==="true"}}function Is(t,e){let r=Hc.parse(t).Edmx?.DataServices;if(!r)throw new Error("V4 metadata: <edmx:DataServices> fehlt \u2014 kein g\xFCltiges EDMX-Dokument");let s=H(r.Schema),i=[],o=[],a=[],d=new Map;for(let u of s){i.push(...H(u.EntityType).map(Vc)),o.push(...H(u.Action).map(p=>_s(p,"Action"))),o.push(...H(u.Function).map(p=>_s(p,"Function")));for(let p of H(u.EntityContainer))a.push(...H(p.EntitySet));for(let p of H(u.Annotations)){let m=N(p,"Target")??"",f=m.lastIndexOf("/");if(f===-1)continue;let g=m.slice(f+1);d.set(g,[...d.get(g)??[],...H(p.Annotation)]);}}let l=a.map(u=>{let p=N(u,"Name"),m=[...H(u.Annotation),...d.get(p)??[]];return {name:p,entityTypeName:Os(N(u,"EntityType")??""),creatable:xn(m,"InsertRestrictions","Insertable")??true,updatable:xn(m,"UpdateRestrictions","Updatable")??true,deletable:xn(m,"DeleteRestrictions","Deletable")??true}}),c={version:"v4",serviceUrl:e,entityTypes:i,entitySets:l};return o.length>0&&(c.actions=o),c}var Wc=10,Ht=class{constructor(e,n,r,s){this.httpClient=e;this.serviceUrl=n;this.etagCache=r;this.metadataProvider=s;}async metadataForLiterals(){if(this.metadataProvider)try{return await this.metadataProvider()}catch{return}}async keyUrl(e,n){let r=fe(await this.metadataForLiterals(),e);return `${this.serviceUrl}/${Bt(e,n,r)}`}async read(e,n,r){if(n){let l=await this.keyUrl(e,n),c=r?Ft(r):void 0,u=await this.httpClient.request({method:"get",url:l,params:c}),p=u.data,m=u.headers.etag??u.headers.ETag;return m&&this.etagCache.set(e,n,m),{results:[p]}}let s=r?Ft(r):void 0,o=(await this.httpClient.request({method:"get",url:`${this.serviceUrl}/${e}`,params:s})).data,a=o.value??[],d=o["@odata.count"];return {results:a,count:d}}async query(e,n){let r=n.maxPages??Wc,s=Ft(n,true),o=(await this.httpClient.request({method:"get",url:`${this.serviceUrl}/${e}`,params:s})).data,a=[...o.value??[]],d=o["@odata.count"],l=o["@odata.nextLink"],c=1,u=false;for(;l&&c<r;){if(dt()){u=true;break}let m=this.resolveNextLink(l),g=(await this.httpClient.request({method:"get",url:m})).data,h=g.value??[];a.push(...h),l=g["@odata.nextLink"],c++;}let p={results:a,count:d};return l&&(p.nextLink=l),u&&(p.truncated=true,p.truncationReason=`Nach ${c} Seite(n) abgebrochen: Zeitbudget des Tool-Aufrufs ersch\xF6pft oder Client hat die Verbindung verworfen. Mit skip=${a.length} weiterlesen.`),p}async create(e,n){let r=await this.httpClient.request({method:"post",url:`${this.serviceUrl}/${e}`,data:n,headers:{"Content-Type":"application/json"}});return ct(Le(r.headers,"location")??Le(r.headers,"odata-entityid")??r.data?.["@odata.id"]),r.data}async update(e,n,r){let s=await this.keyUrl(e,n),i=this.etagCache.get(e,n)??"*",o=await this.httpClient.request({method:"patch",url:s,data:r,headers:{"Content-Type":"application/json","If-Match":i}}),a=o.headers.etag??o.headers.ETag;a&&this.etagCache.update(e,n,a);}async delete(e,n){let r=await this.keyUrl(e,n),s=this.etagCache.get(e,n)??"*";await this.httpClient.request({method:"delete",url:r,headers:{"If-Match":s}});}async batch(e){let n=await this.metadataForLiterals(),{body:r,contentType:s}=Rs(this.serviceUrl,e,a=>fe(n,a)),i=await this.httpClient.request({method:"post",url:`${this.serviceUrl}/$batch`,data:r,headers:{"Content-Type":s,Accept:"application/json"}}),o=vs(i.data);for(let a=0;a<o.length&&a<e.length;a++)o[a].entitySet=e[a].entitySet;return {results:o}}async callAction(e,n,r,s){let i;return r&&s?i=`${await this.keyUrl(r,s)}/${e}`:i=`${this.serviceUrl}/${e}`,(await this.httpClient.request({method:"post",url:i,data:n??{},headers:{"Content-Type":"application/json"}})).data??{}}async callFunction(e,n,r,s){let i=ms(await this.metadataForLiterals(),e),o=this.buildFunctionParams(n,i),a;return r&&s?a=`${await this.keyUrl(r,s)}/${e}(${o})`:a=`${this.serviceUrl}/${e}(${o})`,(await this.httpClient.request({method:"get",url:a})).data??{}}buildFunctionParams(e,n){return !e||Object.keys(e).length===0?"":Object.entries(e).map(([r,s])=>`${r}=${Lt(s,n?.[r])}`).join(",")}async getMetadata(){let e=await this.httpClient.request({method:"get",url:`${this.serviceUrl}/$metadata`,headers:{Accept:"application/xml"}}),n=typeof e.data=="string"?e.data:JSON.stringify(e.data);return Mn(n,this.serviceUrl)}resolveNextLink(e){return e.startsWith("http://")||e.startsWith("https://")?e:`${this.serviceUrl}/${e}`}};function Mn(t,e){return t.trimStart().startsWith("{")?ks(t,e):Is(t,e)}function Un(t,e){let n=t.trim();if(n.startsWith("{"))try{if("$Version"in JSON.parse(n))return "v4"}catch{}if(n.startsWith("<?xml")||n.startsWith("<edmx:Edmx")||n.startsWith("<Edmx"))return /<(?:edmx:)?Edmx\b[^>]*\bVersion\s*=\s*["']([^"']+)["']/i.exec(n)?.[1]?.startsWith("4")?"v4":"v2";if(e){if(e.includes("/odata4/"))return "v4";if(e.includes("/odata/"))return "v2"}return "v2"}var $=class{constructor(e,n,r){this.httpClient=e;this.serviceUrl=n;this.metadataCache=r??new I;}protocolClient=null;version=null;initPromise=null;etagCache=new xt;metadataCache;metadataUnavailable=false;async ensureInitialized(){if(!this.protocolClient)return this.initPromise?this.initPromise:(this.initPromise=this.initialize(),this.initPromise)}async initialize(){let e=this.metadataCache.get(this.serviceUrl);if(e){this.version=e.version,this.protocolClient=this.createProtocolClient(e.version);return}let n="",r=false;try{let s=await this.httpClient.request({method:"get",url:`${this.serviceUrl}/$metadata`,headers:{Accept:"application/xml, application/json"}});n=typeof s.data=="string"?s.data:JSON.stringify(s.data),this.version=Un(n,this.serviceUrl),r=!0;}catch{this.version=Un("",this.serviceUrl),this.metadataUnavailable=true;}if(this.protocolClient=this.createProtocolClient(this.version),r&&n)try{let s=this.version==="v4"?Mn(n,this.serviceUrl):Ut(n,this.serviceUrl);this.metadataCache.set(this.serviceUrl,s);}catch{this.metadataUnavailable=true;}}async metadataForLiterals(){if(!this.metadataUnavailable)try{return await this.getMetadata()}catch{this.metadataUnavailable=true;return}}createProtocolClient(e){return e==="v4"?new Ht(this.httpClient,this.serviceUrl,this.etagCache,()=>this.metadataForLiterals()):new Xe(this.httpClient,this.serviceUrl,this.etagCache,()=>this.metadataForLiterals())}async getClient(){if(await this.ensureInitialized(),!this.protocolClient)throw new Error("ODataClient initialization failed: protocol client not created");return this.protocolClient}async read(e,n,r){return (await this.getClient()).read(e,n,r)}async query(e,n){return (await this.getClient()).query(e,n)}async create(e,n){return (await this.getClient()).create(e,n)}async update(e,n,r){return (await this.getClient()).update(e,n,r)}async delete(e,n){return (await this.getClient()).delete(e,n)}async batch(e,n){let r=await this.getClient();return this.version==="v4"?r.batch(e):r.batch(e,n)}async functionImport(e,n,r){let s=await this.getClient();if(s instanceof Xe)return s.functionImport(e,n,r?.httpMethod);let i=s;return r?.isFunction?i.callFunction(e,n,r?.entitySet,r?.key):i.callAction(e,n,r?.entitySet,r?.key)}async getMetadata(){let e=this.metadataCache.get(this.serviceUrl);if(e)return e;let n=await this.getClient();if(e=this.metadataCache.get(this.serviceUrl),e)return e;let r=await n.getMetadata();return this.metadataCache.set(this.serviceUrl,r),r}getVersion(){return this.version}};function Ns(t,e,n){let r=n??new I,s=new ResourceTemplate("sap://schema/{serviceUrl}/{entitySet}",{list:void 0});t.registerResource("sap-entity-schema",s,{title:"SAP Entity Schema for Query Building",description:"Property names, types, and keys for an entity set \u2014 optimized context for building OData queries. Includes a sample filter in the correct V2/V4 syntax.",mimeType:"application/json"},async(i,o)=>{let a=decodeURIComponent(o.serviceUrl),d=decodeURIComponent(o.entitySet),c=await new $(e,a,r).getMetadata(),u=c.entitySets.find(h=>h.name===d);if(!u)return {contents:[{uri:i.toString(),mimeType:"application/json",text:JSON.stringify({error:`Entity set '${d}' not found in service ${a}`,availableEntitySets:c.entitySets.map(h=>h.name)},null,2)}]};let p=c.entityTypes.find(h=>h.name===u.entityTypeName);if(!p)return {contents:[{uri:i.toString(),mimeType:"application/json",text:JSON.stringify({error:`Entity type '${u.entityTypeName}' not found in metadata`},null,2)}]};let m=new Set(p.keys.map(h=>h.name)),f=p.properties.map(h=>({name:h.name,type:h.type,isKey:m.has(h.name)})),g=qc(p.properties,c.version);return {contents:[{uri:i.toString(),mimeType:"application/json",text:JSON.stringify({entitySet:d,version:c.version,properties:f,sampleFilter:g},null,2)}]}});}function qc(t,e){let n=t.find(r=>r.type==="Edm.String");return n?e==="v2"?`${n.name} eq 'example' or substringof('example',${n.name})`:`${n.name} eq 'example' or contains(${n.name},'example')`:"PropertyName eq 'value'"}function Ds(t,e){let n=new ResourceTemplate("idoc://received/{docnum}",{list:void 0});t.registerResource("idoc-received",n,{title:"Received IDoc",description:"Received IDoc data from webhook",mimeType:"application/json"},async(r,s)=>{let i=s.docnum,o=e.get(i);return o?{contents:[{uri:r.toString(),mimeType:"application/json",text:JSON.stringify({docnum:o.docnum,idocType:o.idocType,mesType:o.mesType,receivedAt:o.receivedAt.toISOString(),parsed:o.parsed},null,2)}]}:{contents:[{uri:r.toString(),mimeType:"application/json",text:JSON.stringify({error:`IDoc with docnum '${i}' not found`},null,2)}]}});}function xs(t,e,n){let r=n??new I,s=new ResourceTemplate("sap://metadata/{serviceUrl}",{list:void 0});t.registerResource("sap-metadata",s,{title:"SAP Service Metadata",description:"Entity types, properties, keys, and navigation properties for an SAP OData service",mimeType:"application/json"},async(i,o)=>{let a=decodeURIComponent(o.serviceUrl),l=await new $(e,a,r).getMetadata();return {contents:[{uri:i.toString(),mimeType:"application/json",text:JSON.stringify({version:l.version,serviceUrl:l.serviceUrl,entityTypes:l.entityTypes,entitySets:l.entitySets},null,2)}]}});}var $n={"business-partner":{domain:"business-partner",description:"Customer, supplier, and business partner master data",services:[{name:"API_BUSINESS_PARTNER",path:"/sap/opu/odata/sap/API_BUSINESS_PARTNER",version:"v2",keyEntitySets:["A_BusinessPartner","A_BusinessPartnerAddress","A_Customer","A_Supplier"]}],queryTemplates:[{name:"find-customer-by-name",description:"Find customers by name (substring search)",entitySet:"A_Customer",filters:[{field:"CustomerName",operator:"contains",value:""}],select:["Customer","CustomerName","CustomerFullName","Country"],top:20},{name:"find-supplier-by-country",description:"Find suppliers in a specific country",entitySet:"A_Supplier",filters:[{field:"Country",operator:"eq",value:""}],select:["Supplier","SupplierName","Country","Region"],top:50}],suggestedTool:"sap_nl_query",commonQueries:["Find customers by name","List suppliers in a country","Get business partner addresses"]},sales:{domain:"sales",description:"Sales orders, billing documents, and revenue tracking",services:[{name:"API_SALES_ORDER_SRV",path:"/sap/opu/odata/sap/API_SALES_ORDER_SRV",version:"v2",keyEntitySets:["A_SalesOrder","A_SalesOrderItem"]},{name:"API_BILLING_DOCUMENT_SRV",path:"/sap/opu/odata/sap/API_BILLING_DOCUMENT_SRV",version:"v2",keyEntitySets:["A_BillingDocument"]}],queryTemplates:[{name:"recent-sales-orders",description:"Sales orders created this month",entitySet:"A_SalesOrder",filters:[{field:"CreationDate",operator:"ge",value:"$MONTH_START"}],select:["SalesOrder","SalesOrderType","SoldToParty","TotalNetAmount","CreationDate"],orderby:"CreationDate desc",top:50},{name:"overdue-invoices",description:"Billing documents past due date",entitySet:"A_BillingDocument",filters:[{field:"BillingDocumentDate",operator:"lt",value:"$TODAY"}],select:["BillingDocument","BillingDocumentType","SoldToParty","TotalNetAmount","BillingDocumentDate"],orderby:"BillingDocumentDate asc",top:50}],suggestedTool:"sap_nl_query",commonQueries:["Recent sales orders","Overdue invoices","Sales by customer"]},finance:{domain:"finance",description:"Journal entries, accounting documents, and financial postings",services:[{name:"API_JOURNALENTRY_SRV",path:"/sap/opu/odata/sap/API_JOURNALENTRY_SRV",version:"v2",keyEntitySets:["A_JournalEntry"]},{name:"API_OPLACCTG_SRV",path:"/sap/opu/odata/sap/API_OPLACCTG_SRV",version:"v2",keyEntitySets:["A_OperationalAcctgDocItem"]}],queryTemplates:[{name:"recent-journal-entries",description:"Journal entries posted this month",entitySet:"A_JournalEntry",filters:[{field:"DocumentDate",operator:"ge",value:"$MONTH_START"}],select:["AccountingDocument","CompanyCode","DocumentDate","PostingDate","DocumentType"],orderby:"DocumentDate desc",top:50},{name:"open-items-by-account",description:"Open accounting items for a G/L account",entitySet:"A_OperationalAcctgDocItem",filters:[{field:"GLAccount",operator:"eq",value:""}],select:["AccountingDocument","CompanyCode","GLAccount","AmountInCompanyCodeCurrency","PostingDate"],top:100}],suggestedTool:"sap_nl_query",commonQueries:["Recent journal entries","Open items by account","Accounting documents this month"]},procurement:{domain:"procurement",description:"Purchase orders, purchase requisitions, and supplier management",services:[{name:"API_PURCHASEORDER_PROCESS_SRV",path:"/sap/opu/odata/sap/API_PURCHASEORDER_PROCESS_SRV",version:"v2",keyEntitySets:["A_PurchaseOrder","A_PurchaseOrderItem"]},{name:"API_PURCHASEREQ_PROCESS_SRV",path:"/sap/opu/odata/sap/API_PURCHASEREQ_PROCESS_SRV",version:"v2",keyEntitySets:["A_PurchaseRequisition"]}],queryTemplates:[{name:"open-purchase-orders",description:"Purchase orders not yet fully delivered",entitySet:"A_PurchaseOrder",filters:[],select:["PurchaseOrder","PurchaseOrderType","Supplier","PurchasingOrganization","CreationDate"],orderby:"CreationDate desc",top:50},{name:"recent-purchase-requisitions",description:"Purchase requisitions created this month",entitySet:"A_PurchaseRequisition",filters:[{field:"CreationDate",operator:"ge",value:"$MONTH_START"}],select:["PurchaseRequisition","PurchaseRequisitionType","CreationDate"],orderby:"CreationDate desc",top:50}],suggestedTool:"sap_nl_query",commonQueries:["Open purchase orders","Recent purchase requisitions","Purchase orders by supplier"]},material:{domain:"material",description:"Material master data and material document movements",services:[{name:"API_PRODUCT_SRV",path:"/sap/opu/odata/sap/API_PRODUCT_SRV",version:"v2",keyEntitySets:["A_Product"]},{name:"API_MATERIAL_DOCUMENT_SRV",path:"/sap/opu/odata/sap/API_MATERIAL_DOCUMENT_SRV",version:"v2",keyEntitySets:["A_MaterialDocumentHeader"]}],queryTemplates:[{name:"find-material-by-description",description:"Search materials by description text",entitySet:"A_Product",filters:[{field:"ProductDescription",operator:"contains",value:""}],select:["Product","ProductType","ProductDescription","BaseUnit"],top:20},{name:"recent-material-movements",description:"Material documents created this month",entitySet:"A_MaterialDocumentHeader",filters:[{field:"DocumentDate",operator:"ge",value:"$MONTH_START"}],select:["MaterialDocument","MaterialDocumentYear","DocumentDate","PostingDate"],orderby:"DocumentDate desc",top:50}],suggestedTool:"sap_nl_query",commonQueries:["Find material by description","Recent material movements","Material stock levels"]},logistics:{domain:"logistics",description:"Inbound and outbound deliveries, shipping, and transportation",services:[{name:"API_INBOUND_DELIVERY_SRV",path:"/sap/opu/odata/sap/API_INBOUND_DELIVERY_SRV",version:"v2",keyEntitySets:["A_InbDeliveryHeader"]},{name:"API_OUTBOUND_DELIVERY_SRV",path:"/sap/opu/odata/sap/API_OUTBOUND_DELIVERY_SRV",version:"v2",keyEntitySets:["A_OutbDeliveryHeader"]}],queryTemplates:[{name:"pending-inbound-deliveries",description:"Inbound deliveries not yet received",entitySet:"A_InbDeliveryHeader",filters:[],select:["DeliveryDocument","Supplier","DeliveryDate","ReceivingPlant"],orderby:"DeliveryDate asc",top:50},{name:"recent-outbound-deliveries",description:"Outbound deliveries created this month",entitySet:"A_OutbDeliveryHeader",filters:[{field:"CreationDate",operator:"ge",value:"$MONTH_START"}],select:["DeliveryDocument","SoldToParty","CreationDate","DeliveryDate"],orderby:"CreationDate desc",top:50}],suggestedTool:"sap_nl_query",commonQueries:["Pending inbound deliveries","Recent outbound deliveries","Deliveries by ship-to party"]},hr:{domain:"hr",description:"Employee master data and organizational assignments",services:[{name:"API_BUSINESS_PARTNER",path:"/sap/opu/odata/sap/API_BUSINESS_PARTNER",version:"v2",keyEntitySets:["A_BusinessPartner"]}],queryTemplates:[{name:"find-employee-by-name",description:"Search employees by name (BP category 2 = Person)",entitySet:"A_BusinessPartner",filters:[{field:"BusinessPartnerCategory",operator:"eq",value:"2"},{field:"BusinessPartnerFullName",operator:"contains",value:""}],select:["BusinessPartner","BusinessPartnerFullName","BusinessPartnerCategory","OrganizationBPName1"],top:20},{name:"employees-by-department",description:"List employees assigned to a department/organization",entitySet:"A_BusinessPartner",filters:[{field:"BusinessPartnerCategory",operator:"eq",value:"2"},{field:"OrganizationBPName1",operator:"contains",value:""}],select:["BusinessPartner","BusinessPartnerFullName","OrganizationBPName1"],top:50}],suggestedTool:"sap_nl_query",commonQueries:["Find employee by name","Employees by department"]},production:{domain:"production",description:"Production orders, planned orders, and manufacturing execution",services:[{name:"API_PLANNED_ORDER",path:"/sap/opu/odata/sap/API_PLANNED_ORDER",version:"v2",keyEntitySets:["PlannedOrder"]},{name:"API_PRODUCTION_ORDER",path:"/sap/opu/odata/sap/API_PRODUCTION_ORDER",version:"v2",keyEntitySets:["A_ProductionOrder"]}],queryTemplates:[{name:"open-production-orders",description:"Production orders not yet completed",entitySet:"A_ProductionOrder",filters:[],select:["ManufacturingOrder","ManufacturingOrderType","Material","ProductionPlant","MfgOrderPlannedStartDate"],orderby:"MfgOrderPlannedStartDate asc",top:50},{name:"planned-orders-this-month",description:"Planned orders created this month",entitySet:"PlannedOrder",filters:[{field:"PlannedOrderCreationDate",operator:"ge",value:"$MONTH_START"}],select:["PlannedOrder","Material","ProductionPlant","PlannedOrderCreationDate"],orderby:"PlannedOrderCreationDate desc",top:50}],suggestedTool:"sap_nl_query",commonQueries:["Open production orders","Planned orders this month","Production orders by material"]},quality:{domain:"quality",description:"Quality inspections, inspection lots, and quality management",services:[{name:"API_QUALITYINSPECTION",path:"/sap/opu/odata/sap/API_QUALITYINSPECTION",version:"v2",keyEntitySets:["QualityInspection"]}],queryTemplates:[{name:"open-inspections",description:"Quality inspections not yet completed",entitySet:"QualityInspection",filters:[],select:["InspectionLot","Material","Plant","InspectionLotStartDate"],orderby:"InspectionLotStartDate asc",top:50},{name:"inspections-this-month",description:"Quality inspections started this month",entitySet:"QualityInspection",filters:[{field:"InspectionLotStartDate",operator:"ge",value:"$MONTH_START"}],select:["InspectionLot","Material","Plant","InspectionLotStartDate"],orderby:"InspectionLotStartDate desc",top:50}],suggestedTool:"sap_nl_query",commonQueries:["Open quality inspections","Inspections this month"]},"plant-maintenance":{domain:"plant-maintenance",description:"Maintenance notifications, orders, and equipment management",services:[{name:"API_MAINTNOTIFICATION",path:"/sap/opu/odata/sap/API_MAINTNOTIFICATION",version:"v2",keyEntitySets:["MaintenanceNotification"]},{name:"API_MAINTENANCEORDER",path:"/sap/opu/odata/sap/API_MAINTENANCEORDER",version:"v2",keyEntitySets:["MaintenanceOrder"]}],queryTemplates:[{name:"open-maintenance-notifications",description:"Maintenance notifications not yet completed",entitySet:"MaintenanceNotification",filters:[],select:["MaintenanceNotification","NotificationType","FunctionalLocation","ReportedByUser","CreationDate"],orderby:"CreationDate desc",top:50},{name:"maintenance-orders-this-month",description:"Maintenance orders created this month",entitySet:"MaintenanceOrder",filters:[{field:"CreationDate",operator:"ge",value:"$MONTH_START"}],select:["MaintenanceOrder","MaintenanceOrderType","FunctionalLocation","CreationDate"],orderby:"CreationDate desc",top:50}],suggestedTool:"sap_nl_query",commonQueries:["Open maintenance notifications","Maintenance orders this month","Notifications by functional location"]},project:{domain:"project",description:"Project systems, WBS elements, and project planning",services:[{name:"API_PROJECT",path:"/sap/opu/odata/sap/API_PROJECT",version:"v2",keyEntitySets:["A_Project","A_ProjectElement"]}],queryTemplates:[{name:"active-projects",description:"List active projects",entitySet:"A_Project",filters:[],select:["Project","ProjectDescription","ResponsiblePerson","PlannedStartDate"],orderby:"PlannedStartDate desc",top:50},{name:"project-elements-by-project",description:"WBS elements for a specific project",entitySet:"A_ProjectElement",filters:[{field:"Project",operator:"eq",value:""}],select:["ProjectElement","ProjectElementDescription","PlannedStartDate","PlannedEndDate"],top:100}],suggestedTool:"sap_nl_query",commonQueries:["Active projects","WBS elements for a project"]},warehouse:{domain:"warehouse",description:"Warehouse resources, tasks, and storage management",services:[{name:"API_WAREHOUSE_RESOURCE",path:"/sap/opu/odata/sap/API_WAREHOUSE_RESOURCE",version:"v2",keyEntitySets:["WarehouseResource","WarehouseTask"]}],queryTemplates:[{name:"open-warehouse-tasks",description:"Warehouse tasks not yet completed",entitySet:"WarehouseTask",filters:[],select:["WarehouseTask","WarehouseTaskType","Warehouse","WarehouseStorageBin"],top:50},{name:"warehouse-resources-by-plant",description:"Warehouse resources for a specific plant",entitySet:"WarehouseResource",filters:[{field:"Plant",operator:"eq",value:""}],select:["WarehouseResource","Warehouse","Plant"],top:50}],suggestedTool:"sap_nl_query",commonQueries:["Open warehouse tasks","Warehouse resources by plant"]},analytics:{domain:"analytics",description:"Financial analytics, expense tracking, and revenue analysis",services:[{name:"API_OPLACCTG_SRV",path:"/sap/opu/odata/sap/API_OPLACCTG_SRV",version:"v2",keyEntitySets:["A_OperationalAcctgDocItem"]}],queryTemplates:[{name:"expenses-this-year",description:"Expense postings since start of current year",entitySet:"A_OperationalAcctgDocItem",filters:[{field:"PostingDate",operator:"ge",value:"$YEAR_START"}],select:["AccountingDocument","CompanyCode","GLAccount","AmountInCompanyCodeCurrency","PostingDate"],orderby:"PostingDate desc",top:100},{name:"monthly-revenue",description:"Revenue postings this month",entitySet:"A_OperationalAcctgDocItem",filters:[{field:"PostingDate",operator:"ge",value:"$MONTH_START"}],select:["AccountingDocument","CompanyCode","GLAccount","AmountInCompanyCodeCurrency","PostingDate"],orderby:"PostingDate desc",top:100}],suggestedTool:"sap_nl_query",commonQueries:["Expenses this year","Monthly revenue","Postings by G/L account"]},"master-data":{domain:"master-data",description:"Cross-domain master data: business partners, materials, cost centers",services:[{name:"API_BUSINESS_PARTNER",path:"/sap/opu/odata/sap/API_BUSINESS_PARTNER",version:"v2",keyEntitySets:["A_BusinessPartner"]},{name:"API_PRODUCT_SRV",path:"/sap/opu/odata/sap/API_PRODUCT_SRV",version:"v2",keyEntitySets:["A_Product"]},{name:"API_COSTCENTER_SRV",path:"/sap/opu/odata/sap/API_COSTCENTER_SRV",version:"v2",keyEntitySets:["A_CostCenter"]}],queryTemplates:[{name:"search-master-data-by-name",description:"Search business partners, materials, or cost centers by name",entitySet:"A_BusinessPartner",filters:[{field:"BusinessPartnerFullName",operator:"contains",value:""}],select:["BusinessPartner","BusinessPartnerFullName","BusinessPartnerCategory"],top:20},{name:"cost-centers-by-company",description:"List cost centers for a company code",entitySet:"A_CostCenter",filters:[{field:"CompanyCode",operator:"eq",value:""}],select:["CostCenter","CostCenterDescription","CompanyCode","ValidityStartDate"],top:100}],suggestedTool:"sap_nl_query",commonQueries:["Search master data by name","Cost centers by company code","Materials by type"]},"cross-application":{domain:"cross-application",description:"Attachments, change documents, and cross-module services",services:[{name:"API_ATTACHMENT_SRV",path:"/sap/opu/odata/sap/API_ATTACHMENT_SRV",version:"v2",keyEntitySets:["A_DocumentInfoRecord"]},{name:"API_BUSINESS_OBJECT_PAGE",path:"/sap/opu/odata/sap/API_BUSINESS_OBJECT_PAGE",version:"v2",keyEntitySets:["A_BusinessObjectPage"]}],queryTemplates:[{name:"attachments-for-object",description:"Find attachments linked to a business object",entitySet:"A_DocumentInfoRecord",filters:[{field:"LinkedSAPObjectKey",operator:"eq",value:""}],select:["DocumentInfoRecordDocNumber","DocumentInfoRecordDocType","LinkedSAPObjectKey"],top:50},{name:"recent-change-documents",description:"Change documents from the last month",entitySet:"A_BusinessObjectPage",filters:[{field:"LastChangeDate",operator:"ge",value:"$MONTH_AGO"}],select:["BusinessObjectType","LastChangeDate","LastChangedByUser"],orderby:"LastChangeDate desc",top:50}],suggestedTool:"sap_nl_query",commonQueries:["Attachments for a business object","Recent change documents"]},unknown:{domain:"unknown",description:"Unknown or unclassified domain. Use service discovery to find available services.",services:[],queryTemplates:[{name:"discover-services",description:"No specific domain matched. Use sap_discover_services to explore available SAP services on this system.",entitySet:"",filters:[]},{name:"browse-domains",description:"Browse available routing domains with sap://routing/{domain} to find the right service for your query.",entitySet:"",filters:[]}],suggestedTool:"sap_discover_services",commonQueries:["Use sap_discover_services to find available services","Check sap://routing/{domain} with a specific domain"]}};var Yc={$TODAY:()=>Ln(new Date),$YESTERDAY:()=>{let t=new Date;return t.setDate(t.getDate()-1),Ln(t)},$MONTH_START:()=>{let t=new Date;return `${t.getFullYear()}-${Bn(t.getMonth()+1)}-01`},$YEAR_START:()=>`${new Date().getFullYear()}-01-01`,$MONTH_AGO:()=>{let t=new Date;return t.setMonth(t.getMonth()-1),Ln(t)}};function Ln(t){return `${t.getFullYear()}-${Bn(t.getMonth()+1)}-${Bn(t.getDate())}`}function Bn(t){return t.toString().padStart(2,"0")}function Xc(t){if(typeof t!="string")return t;let e=Yc[t];return e?e():t}function Ms(t){return {...t,queryTemplates:t.queryTemplates.map(e=>({...e,filters:e.filters.map(n=>({...n,value:Xc(n.value)}))}))}}function Us(t){let e=new ResourceTemplate("sap://routing/{domain}",{list:void 0});t.registerResource("sap-routing",e,{title:"SAP Domain Routing",description:"Service mappings and query templates for a business domain. Returns the relevant SAP services, entity sets, and pre-built query examples for a domain like business-partner, sales, or finance. Use this before building OData queries to know which service and entity set to target.",mimeType:"application/json"},async(n,r)=>{let s=r.domain,i=$n[s];if(!i)return {contents:[{uri:n.toString(),mimeType:"application/json",text:JSON.stringify({error:`Unknown domain '${s}'`,availableDomains:Object.keys($n)},null,2)}]};let o=Ms(i);return {contents:[{uri:n.toString(),mimeType:"application/json",text:JSON.stringify({...o,note:"Service paths are typical defaults. Use sap_discover_services to verify actual paths on your system."},null,2)}]}});}var $s="/sap/opu/odata/sap",Zc=/^[A-Z0-9_/]+$/i,ge=class extends Error{guidance;constructor(e){super(`serviceUrl ist weder ein Pfad noch ein technischer Servicename: "${e}"`),this.name="InvalidServiceUrlError",this.guidance=`Erwartet wird ein Pfad wie ${$s}/API_BUSINESS_PARTNER oder der technische Name (API_BUSINESS_PARTNER), den sap_discover_services als technicalName liefert.`;}};function j(t){let e=t.trim();if(e.length===0)throw new ge(t);if(e.startsWith("/"))return e.replace(/\/+$/,"")||"/";if(e.startsWith("http://")||e.startsWith("https://"))try{return new URL(e).pathname.replace(/\/+$/,"")}catch{throw new ge(t)}if(Zc.test(e))return `${$s}/${e.replace(/^\/+|\/+$/g,"")}`;throw new ge(t)}var Je=class extends Error{guidance;extra;constructor(e,n,r={}){super(e),this.name="ToolInputError",this.guidance=n,this.extra=r;}};function _(t,e){if(t instanceof ge)return Fn({code:"INVALID_INPUT",error:t.message,guidance:t.guidance,...e?.hint?{hint:e.hint}:{}});if(t instanceof Je)return Fn({code:"INVALID_INPUT",error:t.message,...t.guidance?{guidance:t.guidance}:{},...t.extra,...e?.hint?{hint:e.hint}:{}});let n=be(t,{serviceUrl:e?.serviceUrl});return Fn({code:n.code,error:n.message,...n.httpStatus!==void 0?{httpStatus:n.httpStatus}:{},...n.sapCode?{sapCode:n.sapCode}:{},...n.guidance?{guidance:n.guidance}:{},...e?.hint?{hint:e.hint}:{}})}function Fn(t){let e=ye()?.correlationId;return {content:[{type:"text",text:JSON.stringify({...t,...e?{correlationId:e}:{}},null,2)}],isError:true}}function Ls(t,e,n){let r=n??new I,s=new Map;function i(a){let d=j(a),l=s.get(d);return l||(l=new $(e,d,r),s.set(d,l)),l}function o(a,d){return _(a,{serviceUrl:d})}t.registerTool("sap_batch",{title:"Execute SAP Batch Request",description:"Execute multiple OData operations in a single batch request. Supports V2 (multipart/mixed) and V4 (JSON) batch formats automatically. Write operations sharing a changesetId run as one transaction (all succeed or all fail); in V2 a write without changesetId gets a changeset of its own. Returns per-operation status in the order of the operations -- individual failures are always reported, never hidden behind the batch HTTP 200.",inputSchema:z$2.object({serviceUrl:z$2.string().describe("OData service URL"),operations:z$2.array(z$2.object({method:z$2.enum(["get","post","patch","delete"]).describe("HTTP method"),entitySet:z$2.string().describe("Entity set name"),key:z$2.record(z$2.string(),z$2.unknown()).optional().describe("Entity key for read/update/delete"),data:z$2.record(z$2.string(),z$2.unknown()).optional().describe("Request body for create/update"),changesetId:z$2.string().optional().describe("Changeset group ID for transactional grouping")})).describe("Array of operations to execute in batch")}),annotations:{readOnlyHint:false,destructiveHint:true,idempotentHint:false,openWorldHint:true}},async({serviceUrl:a,operations:d})=>{try{let l=i(a),c=d,u=await l.batch(c);return {content:[{type:"text",text:JSON.stringify(u,null,2)}]}}catch(l){return o(l)}});}async function Bs(t,e,n=5){if(t.length===0)return [];let r=Math.max(1,Math.min(Math.floor(n)||1,t.length)),s=new Array(t.length),i=0;async function o(){for(;;){let a=i++;if(a>=t.length)return;s[a]=await e(t[a],a);}}return await Promise.all(Array.from({length:r},()=>o())),s}var Qc=[".integrationsuite.","integrationsuite-trial.",".it-cpi.",".hci.",".prod.apimanagement.","-api.s4hana.ondemand.com"];function Fs(t){let e=t.toLowerCase();return Qc.some(n=>e.includes(n))}var J=class extends Error{constructor(n,r,s,i){super(n);this.httpStatus=r;this.sapGuidance=s;this.isBtpDetected=i;this.name="CatalogError";}},ed=new Set(["ECONNREFUSED","ETIMEDOUT","ENOTFOUND"]);function td(t,e=false){switch(t){case 403:return "Catalog access denied. Check transaction PFCG for role assignment and SU53 for authorization trace. Required authorization object: S_SERVICE with SRV_NAME = IWFND_CATALOGSERVICE.";case 404:return e?"V4 catalog not available. Publish service group via /IWFND/V4_ADMIN.":"Catalog service not found. Activate it via transaction /IWFND/MAINT_SERVICE.";case 500:return "SAP system error. Check transaction ST22 for ABAP dumps and SM21 for system log.";default:return "Could not connect to SAP system. Verify the hostname, port, and network connectivity."}}function nd(t){switch(t){case "ECONNREFUSED":return "Connection refused. Verify that the SAP system is running and the port is correct.";case "ETIMEDOUT":return "Connection timeout. Check network connectivity and firewall rules.";case "ENOTFOUND":return "Hostname not found. Verify the SAP system hostname in your configuration.";default:return "Could not connect to SAP system. Verify the hostname, port, and network connectivity."}}function Hs(t){return typeof t=="object"&&t!==null&&"response"in t&&typeof t.response=="object"&&t.response!==null&&typeof t.response.status=="number"}function rd(t){return typeof t=="object"&&t!==null&&"code"in t&&typeof t.code=="string"&&ed.has(t.code)}function Ze(t,e,n=false){let r=Fs(e);if(Hs(t)){let i=t.response.status,o=td(i,n),a="message"in t&&typeof t.message=="string"?t.message:`HTTP ${i}`;return new J(a,i,o,r)}if(rd(t)){let i=nd(t.code),o="message"in t&&typeof t.message=="string"?t.message:t.code;return new J(o,void 0,i,r)}let s=t instanceof Error?t.message:String(t);return new J(s,void 0,void 0,r)}function js(t){return Hs(t)&&t.response.status===404?"V4 catalog not available. Publish service group via /IWFND/V4_ADMIN.":t instanceof Error?t.message:String(t)}var sd=["/sap/opu/odata/IWFND/CATALOGSERVICE;v=2/ServiceCollection","/sap/opu/odata/iwfnd/CATALOGSERVICE;v=2/ServiceCollection","/sap/opu/odata/IWFND/CATALOGSERVICE/ServiceCollection"];function id(t){if(typeof t=="object"&&t!==null&&"response"in t)return t.response?.status}async function Vs(t,e,n){let r;for(let s of sd)try{return await t.request({method:"get",url:s,params:{$format:"json",$top:"1"},expectedStatuses:[404]}),n?.onMatch?.(s),s}catch(i){if(i instanceof F)throw i;if(id(i)===404){r=i;continue}throw Ze(i,e,false)}throw Ze(r??new Error("All V2 catalog paths returned 404"),e,false)}function Ws(t){try{return new URL(t).pathname}catch{return t}}function ad(t){let e=t.toLowerCase().replace(/'/g,"''");return [`substringof('${e}',tolower(TechnicalServiceName))`,`substringof('${e}',tolower(Title))`,`substringof('${e}',tolower(Description))`].join(" or ")}var jt=class t{constructor(e,n,r={}){this.httpClient=e;this.cache=n;this.options=r;}static DEFAULT_V4_URL="/sap/opu/odata4/iwfnd/config/default/iwfnd/catalog/0002/ServiceGroups";resolvedV2Path;serverSideFilterUnsupported=false;async discoverServices(e){let n=this.cache.get();if(n)return {services:n,warnings:[]};if(e&&!this.serverSideFilterUnsupported){let l=await this.tryFilteredFetch(e);if(l)return l}let r=[],[s,i]=await Bs(["v4","v2"],async l=>l==="v4"?await this.fetchV4Catalog().then(c=>({ok:true,services:c}),c=>({ok:false,error:c})):await this.fetchV2Catalog().then(c=>({ok:true,services:c}),c=>({ok:false,error:c})),this.options.concurrency??5),o=[];if(s?.ok)o=s.services;else if(s){if(s.error instanceof F)throw s.error;r.push(`V4 catalog fetch failed: ${js(s.error)}`);}if(!i?.ok){let l=i?.error;throw l instanceof J?l:Ze(l,this.options.baseUrl??"",false)}let a=i.services,d=this.mergeAndDeduplicate(o,a);return this.cache.set(d),{services:d,warnings:r}}async tryFilteredFetch(e){try{return {services:await this.fetchV2Catalog(ad(e)),warnings:[],filtered:!0}}catch(n){if(n instanceof F)throw n;let r=n?.response?.status;(r===400||r===501)&&(this.serverSideFilterUnsupported=true);return}}async fetchV2Catalog(e){let n=this.options.catalogV2Url??this.resolvedV2Path;return n||(n=await Vs(this.httpClient,this.options.baseUrl??"",{onMatch:this.options.onDiscoveryMatch}),this.resolvedV2Path=n),((await this.httpClient.request({method:"get",url:n,params:{$format:"json",...e?{$filter:e}:{}},...e?{expectedStatuses:[400,501]}:{}})).data?.d?.results??[]).map(o=>({technicalName:o.TechnicalServiceName,title:o.Title,serviceUrl:Ws(o.ServiceUrl),description:o.Description,version:"v2",serviceVersion:o.TechnicalServiceVersion}))}async fetchV4Catalog(){let e=this.options.catalogV4Url??t.DEFAULT_V4_URL,s=(await this.httpClient.request({method:"get",url:e,params:{$expand:"DefaultSystem($expand=Services)"},headers:{Accept:"application/json"},expectedStatuses:[404]})).data?.value??[],i=[];for(let o of s){let a=o.DefaultSystem?.Services??[];for(let d of a)i.push({technicalName:d.ServiceId??d.ServiceName??"",title:d.ServiceTitle??d.Title??"",serviceUrl:Ws(d.ServiceUrl),version:"v4",serviceVersion:d.ServiceVersion});}return i}mergeAndDeduplicate(e,n){let r=new Map;for(let s of e)r.set(s.technicalName,s);for(let s of n)r.has(s.technicalName)||r.set(s.technicalName,s);return [...r.values()]}};var cd=[[/BUSINESS_?PARTNER|BUPA/i,"business-partner"],[/SALES_ORDER|BILLING|CREDIT_MEMO|DEBIT_MEMO|SALES_CONTRACT|SALES_QUOT/i,"sales"],[/PURCHASEORDER|PURCHASE_ORDER|PURCHASE_REQ|SUPPLIER|PURG/i,"procurement"],[/JOURNALENTRY|JOURNAL_ENTRY|OPLACCTG|COST_CENTER|PROFIT_CENTER|GL_ACCOUNT|FINANCIAL/i,"finance"],[/MATERIAL_DOC|MATERIAL_STOCK|MATERIAL_SRV|PRODUCT\b/i,"material"],[/OUTBOUND_DELIV|INBOUND_DELIV|SHIPPING|TRANSPORTATION/i,"logistics"],[/PRODUCTION_ORDER|PLANNED_ORDER|ROUTING|BOM\b/i,"production"],[/EMPLOYEE|WORKFORCE|PERSONNEL|PAYROLL/i,"hr"],[/INSPECTION|QUALITY/i,"quality"],[/MAINTENANCE|EQUIPMENT|FUNCTIONAL_LOC/i,"plant-maintenance"],[/PROJECT|WBS\b/i,"project"],[/WAREHOUSE|STORAGE_BIN/i,"warehouse"],[/ANALYTIC|CUBE/i,"analytics"]],dd=[[/^[ZY]?MM[_]/i,"procurement"],[/^[ZY]?SD[_]/i,"sales"],[/^[ZY]?FI[_]|^[ZY]?CO[_]/i,"finance"],[/^[ZY]?PP[_]/i,"production"],[/^[ZY]?HR[_]|^[ZY]?PA[_]|^[ZY]?PT[_]/i,"hr"],[/^[ZY]?WM[_]/i,"warehouse"],[/^[ZY]?PM[_]/i,"plant-maintenance"],[/^[ZY]?LE[_]/i,"logistics"]];function ld(t){for(let[e,n]of cd)if(e.test(t.technicalName))return {...t,category:n,categoryConfidence:"high"};for(let[e,n]of dd)if(e.test(t.technicalName))return {...t,category:n,categoryConfidence:"high"};return {...t,category:"unknown",categoryConfidence:"low"}}function Gs(t){return t.map(ld)}function Ie(t,e){let n=Number.isFinite(t)&&t>0?Math.floor(t):50,r=Number.isFinite(e)&&e>0?Math.floor(e):0;return {top:Math.min(n,1e3),skip:r}}function Ne(t){let{returned:e,totalCount:n,paging:r,hasMoreHint:s}=t,i=s??(n!==void 0?r.skip+e<n:e>=r.top),o={returned:e,hasMore:i,top:r.top,skip:r.skip};return n!==void 0&&(o.totalCount=n),i&&(o.nextSkip=r.skip+e),o}function qs(t,e,n,r){let s=r??new re,i=new jt(e,s,n);t.registerTool("sap_discover_services",{title:"Discover SAP OData Services",description:`Discover all available OData services on the connected SAP system. Returns categorized services with search, category filtering, and pagination. Use this as the first step to explore what APIs are available before using sap_list_services or sap_get_metadata.
213
213
 
214
214
  **When to use:**
215
215
  - You need to find which SAP services are available on this system
@@ -218,7 +218,7 @@ ${l}`);}return o.push(`--${s}--`),{body:`${o.join(`\r
218
218
 
219
219
  **When NOT to use:**
220
220
  - You already know the service URL (proceed to sap_query or sap_nl_query)
221
- - You need entity-level metadata (use sap_get_metadata after discovering the service)`,inputSchema:z$2.object({search:z$2.string().optional().describe("Free-text search across service name, title, and description (case-insensitive)"),category:z$2.enum(["business-partner","sales","finance","procurement","hr","logistics","production","quality","plant-maintenance","project","material","warehouse","analytics","master-data","cross-application","unknown"]).optional().describe("Filter by business domain category"),limit:z$2.number().optional().default(50).describe(`Maximum number of services to return (default ${50}, hard cap ${1e3})`),offset:z$2.number().optional().default(0).describe("Number of services to skip for pagination (default 0)")}),annotations:{readOnlyHint:true,destructiveHint:false,idempotentHint:true,openWorldHint:true}},async({search:o,category:a,limit:d,offset:l})=>{try{let c=await i.discoverServices(o),u=xs(c.services);if(a&&(u=u.filter(y=>y.category===a)),o&&!c.filtered){let y=o.toLowerCase();u=u.filter(E=>E.technicalName.toLowerCase().includes(y)||E.title.toLowerCase().includes(y)||(E.description?.toLowerCase().includes(y)??!1));}let p=u.length,m={};for(let y of u)m[y.category]=(m[y.category]??0)+1;let g=Oe(d,l),f=u.slice(g.skip,g.skip+g.top),h=Ie({returned:f.length,totalCount:p,paging:g}),S={services:f.map(y=>({technicalName:y.technicalName,title:y.title,category:y.category,serviceUrl:y.serviceUrl,version:y.version})),...h,summary:{total:p,returned:f.length,offset:g.skip,byCategory:m},...c.warnings.length>0?{warnings:c.warnings}:{},...o?{filterApplied:c.filtered?"server":"client"}:{}};return {content:[{type:"text",text:JSON.stringify(S,null,2)}]}}catch(c){if(c instanceof Y){let u={error:c.message};return c.sapGuidance&&(u.guidance=c.sapGuidance),c.isBtpDetected&&(u.btpWarning="BTP Integration Suite detected. Catalog discovery requires direct S/4HANA access. The Integration Suite proxies individual OData services but does not expose the system catalog. Use sap_list_services with a known service URL instead."),{content:[{type:"text",text:JSON.stringify(u,null,2)}],isError:true}}return _(c)}});}function Us(t,e,n){let r=new I;t.registerTool("sap_list_services",{title:"List SAP Entity Sets",description:`Discover available entity sets in a specific SAP OData service. Requires a full OData service path \u2014 NOT a base URL. Common SAP OData services: /sap/opu/odata/sap/API_BUSINESS_PARTNER, /sap/opu/odata/sap/API_MATERIAL_DOCUMENT_SRV, /sap/opu/odata/sap/API_SALES_ORDER_SRV. Use test-connection first to verify SAP connectivity.
221
+ - You need entity-level metadata (use sap_get_metadata after discovering the service)`,inputSchema:z$2.object({search:z$2.string().optional().describe("Free-text search across service name, title, and description (case-insensitive)"),category:z$2.enum(["business-partner","sales","finance","procurement","hr","logistics","production","quality","plant-maintenance","project","material","warehouse","analytics","master-data","cross-application","unknown"]).optional().describe("Filter by business domain category"),limit:z$2.number().optional().default(50).describe(`Maximum number of services to return (default ${50}, hard cap ${1e3})`),offset:z$2.number().optional().default(0).describe("Number of services to skip for pagination (default 0)")}),annotations:{readOnlyHint:true,destructiveHint:false,idempotentHint:true,openWorldHint:true}},async({search:o,category:a,limit:d,offset:l})=>{try{let c=await i.discoverServices(o),u=Gs(c.services);if(a&&(u=u.filter(y=>y.category===a)),o&&!c.filtered){let y=o.toLowerCase();u=u.filter(E=>E.technicalName.toLowerCase().includes(y)||E.title.toLowerCase().includes(y)||(E.description?.toLowerCase().includes(y)??!1));}let p=u.length,m={};for(let y of u)m[y.category]=(m[y.category]??0)+1;let f=Ie(d,l),g=u.slice(f.skip,f.skip+f.top),h=Ne({returned:g.length,totalCount:p,paging:f}),b={services:g.map(y=>({technicalName:y.technicalName,title:y.title,category:y.category,serviceUrl:y.serviceUrl,version:y.version})),...h,summary:{total:p,returned:g.length,offset:f.skip,byCategory:m},...c.warnings.length>0?{warnings:c.warnings}:{},...o?{filterApplied:c.filtered?"server":"client"}:{}};return {content:[{type:"text",text:JSON.stringify(b,null,2)}]}}catch(c){if(c instanceof J){let u={error:c.message};return c.sapGuidance&&(u.guidance=c.sapGuidance),c.isBtpDetected&&(u.btpWarning="BTP Integration Suite detected. Catalog discovery requires direct S/4HANA access. The Integration Suite proxies individual OData services but does not expose the system catalog. Use sap_list_services with a known service URL instead."),{content:[{type:"text",text:JSON.stringify(u,null,2)}],isError:true}}return _(c)}});}function Ks(t,e,n){let r=new I;t.registerTool("sap_list_services",{title:"List SAP Entity Sets",description:`Discover available entity sets in a specific SAP OData service. Requires a full OData service path \u2014 NOT a base URL. Common SAP OData services: /sap/opu/odata/sap/API_BUSINESS_PARTNER, /sap/opu/odata/sap/API_MATERIAL_DOCUMENT_SRV, /sap/opu/odata/sap/API_SALES_ORDER_SRV. Use test-connection first to verify SAP connectivity.
222
222
 
223
223
  **When to use:**
224
224
  - You need the raw list of OData services at a base URL
@@ -226,7 +226,7 @@ ${l}`);}return o.push(`--${s}--`),{body:`${o.join(`\r
226
226
 
227
227
  **When NOT to use:**
228
228
  - Use sap_discover_services instead for categorized, searchable results
229
- - You already know the service URL`,inputSchema:z$2.object({serviceUrl:z$2.string().describe('Full OData service path starting with /sap/opu/odata/sap/. Example: /sap/opu/odata/sap/API_BUSINESS_PARTNER. Do NOT pass "/" or a base URL.'),top:z$2.number().optional().describe(`Maximum number of entity sets to return (default ${50}, hard cap ${1e3}).`),skip:z$2.number().optional().describe("Number of entity sets to skip for paging")}),annotations:{readOnlyHint:true,destructiveHint:false,idempotentHint:true,openWorldHint:true}},async({serviceUrl:s,top:i,skip:o})=>{try{let a=j(s),l=(await e.request({method:"get",url:a,headers:{Accept:"application/json"},params:{$format:"json"}})).data,c=[],u=l.d;u&&"EntitySets"in u&&Array.isArray(u.EntitySets)?c=u.EntitySets:"value"in l&&Array.isArray(l.value)&&(c=l.value.map(h=>h.name)),c=c.filter(h=>K(h,n));let p=Oe(i,o),m=c.length,g=c.slice(p.skip,p.skip+p.top),f=Ie({returned:g.length,totalCount:m,paging:p});return {content:[{type:"text",text:JSON.stringify({serviceUrl:a,entitySets:g,count:m,...f},null,2)}]}}catch(a){return _(a,{serviceUrl:s})}}),t.registerTool("sap_get_metadata",{title:"Get SAP Service Metadata",description:`Inspect entity types, properties, keys, and navigation properties for an SAP OData service. Second step: after listing services, use this to understand the data model before executing operations.
229
+ - You already know the service URL`,inputSchema:z$2.object({serviceUrl:z$2.string().describe('Full OData service path starting with /sap/opu/odata/sap/. Example: /sap/opu/odata/sap/API_BUSINESS_PARTNER. Do NOT pass "/" or a base URL.'),top:z$2.number().optional().describe(`Maximum number of entity sets to return (default ${50}, hard cap ${1e3}).`),skip:z$2.number().optional().describe("Number of entity sets to skip for paging")}),annotations:{readOnlyHint:true,destructiveHint:false,idempotentHint:true,openWorldHint:true}},async({serviceUrl:s,top:i,skip:o})=>{try{let a=j(s),l=(await e.request({method:"get",url:a,headers:{Accept:"application/json"},params:{$format:"json"}})).data,c=[],u=l.d;u&&"EntitySets"in u&&Array.isArray(u.EntitySets)?c=u.EntitySets:"value"in l&&Array.isArray(l.value)&&(c=l.value.map(h=>h.name)),c=c.filter(h=>z(h,n));let p=Ie(i,o),m=c.length,f=c.slice(p.skip,p.skip+p.top),g=Ne({returned:f.length,totalCount:m,paging:p});return {content:[{type:"text",text:JSON.stringify({serviceUrl:a,entitySets:f,count:m,...g},null,2)}]}}catch(a){return _(a,{serviceUrl:s})}}),t.registerTool("sap_get_metadata",{title:"Get SAP Service Metadata",description:`Inspect entity types, properties, keys, and navigation properties for an SAP OData service. Second step: after listing services, use this to understand the data model before executing operations.
230
230
 
231
231
  Each entity set carries what SAP allows on it \u2014 \`creatable\`, \`updatable\`, \`deletable\` \u2014 plus a \`capabilities\` summary listing the entity sets you can create in. Use it to answer questions like 'which service can create sales orders?' without reading raw $metadata XML.
232
232
 
@@ -237,24 +237,24 @@ Each entity set carries what SAP allows on it \u2014 \`creatable\`, \`updatable\
237
237
  - Use 'search' to filter large services by name pattern
238
238
 
239
239
  **When NOT to use:**
240
- - You don't know which service to query (use sap_discover_services first)`,inputSchema:z$2.object({serviceUrl:z$2.string().describe("OData service URL"),entityType:z$2.string().optional().describe("Filter to a specific entity type name for full property details"),search:z$2.string().optional().describe("Filter entity types/sets by name pattern (case-insensitive). Use this for large services to narrow results.")}),annotations:{readOnlyHint:true,destructiveHint:false,idempotentHint:true,openWorldHint:true}},async({serviceUrl:s,entityType:i,search:o})=>{try{let d=await new $(e,j(s),r).getMetadata(),l;if(i){let c=d.entityTypes.find(u=>u.name===i);if(!c){let u=i.toLowerCase();c=d.entityTypes.find(p=>p.name.toLowerCase()===u);}if(!c){let u=i.toLowerCase(),p=d.entityTypes.filter(m=>m.name.toLowerCase().includes(u)).map(m=>m.name).slice(0,20);return _(new ze(`Entity type '${i}' existiert in diesem Service nicht.`,"Mit dem Parameter 'search' nach passenden Typen suchen, oder entityType weglassen, um alle Entity Sets zu sehen.",p.length>0?{closestMatches:p}:{}),{serviceUrl:s})}l={version:d.version,entityType:c};}else {let c=d.entitySets.filter(g=>K(g.name,n)),u=d.entityTypes;if(o){let g=o.toLowerCase();c=c.filter(f=>f.name.toLowerCase().includes(g)),u=u.filter(f=>f.name.toLowerCase().includes(g));}let p={creatable:c.filter(g=>g.creatable).map(g=>g.name),updatable:c.filter(g=>g.updatable).length,deletable:c.filter(g=>g.deletable).length};u.length>50&&!o?l={version:d.version,entitySets:c,capabilities:p,entityTypeCount:u.length,hint:`Service has ${u.length} entity types. Use the 'search' parameter (e.g. search='BusinessPartner') or 'entityType' parameter to get details for specific types. Entity sets listed above are queryable.`}:l={version:d.version,entityTypes:u.map(g=>({name:g.name,keys:g.keys.map(f=>f.name),propertyCount:g.properties.length,navigationProperties:g.navigationProperties.map(f=>f.name)})),entitySets:c,capabilities:p};}return {content:[{type:"text",text:JSON.stringify(l,null,2)}]}}catch(a){return _(a,{serviceUrl:s})}});}function Ls(t,e){if(!t)return "unknown";let n=$s(e).toLowerCase(),r=t.functionImports?.find(i=>i.name.toLowerCase()===n);if(r)return r.httpMethod==="GET"?"read":"write";let s=t.actions?.find(i=>$s(i.name).toLowerCase()===n);return s?.kind==="Function"?"read":s?.kind==="Action"?"write":"unknown"}function $s(t){let e=t.lastIndexOf(".");return e===-1?t:t.slice(e+1)}function Bs(t,e,n,r=false){let s=n??new I,i=new Map;function o(l){let c=j(l),u=i.get(c);return u||(u=new $(e,c,s),i.set(c,u)),u}function a(l,c){return _(l,{serviceUrl:c})}async function d(l,c){if(!r)return null;let u;try{u=await o(l).getMetadata();}catch{}let p=Ls(u,c);if(p==="read")return null;let m=p==="write"?`"${c}" schreibt laut den Metadaten des Dienstes (POST).`:`"${c}" ist in den Metadaten des Dienstes nicht als lesend nachweisbar.`;return _(new Error(`${m} Dieser Zugang ist lesend. Lesende Funktionsimporte (V2 HttpMethod=GET, V4 Function) sind erlaubt; f\xFCr schreibende braucht es einen Zugang ohne Read-only-Policy bzw. einen Server mit --allow-write.`),{serviceUrl:l})}t.registerTool("sap_function",{title:"Call SAP Function Import or Action",description:`Invoke an OData V2 Function Import or V4 Action/Function. For V2: calls function imports with parameters; values are typed from $metadata (Edm.Guid \u2192 guid'\u2026', Edm.Boolean \u2192 true/false), so pass plain values. For V4: supports bound actions (on a specific entity) and unbound actions/functions; keys and function parameters are typed from $metadata too (Edm.Guid and Edm.Date bare, strings quoted). Set isFunction=true for V4 Functions (GET), leave false for V4 Actions (POST). For bound operations, provide entitySet and key.
240
+ - You don't know which service to query (use sap_discover_services first)`,inputSchema:z$2.object({serviceUrl:z$2.string().describe("OData service URL"),entityType:z$2.string().optional().describe("Filter to a specific entity type name for full property details"),search:z$2.string().optional().describe("Filter entity types/sets by name pattern (case-insensitive). Use this for large services to narrow results.")}),annotations:{readOnlyHint:true,destructiveHint:false,idempotentHint:true,openWorldHint:true}},async({serviceUrl:s,entityType:i,search:o})=>{try{let d=await new $(e,j(s),r).getMetadata(),l;if(i){let c=d.entityTypes.find(u=>u.name===i);if(!c){let u=i.toLowerCase();c=d.entityTypes.find(p=>p.name.toLowerCase()===u);}if(!c){let u=i.toLowerCase(),p=d.entityTypes.filter(m=>m.name.toLowerCase().includes(u)).map(m=>m.name).slice(0,20);return _(new Je(`Entity type '${i}' existiert in diesem Service nicht.`,"Mit dem Parameter 'search' nach passenden Typen suchen, oder entityType weglassen, um alle Entity Sets zu sehen.",p.length>0?{closestMatches:p}:{}),{serviceUrl:s})}l={version:d.version,entityType:c};}else {let c=d.entitySets.filter(f=>z(f.name,n)),u=d.entityTypes;if(o){let f=o.toLowerCase();c=c.filter(g=>g.name.toLowerCase().includes(f)),u=u.filter(g=>g.name.toLowerCase().includes(f));}let p={creatable:c.filter(f=>f.creatable).map(f=>f.name),updatable:c.filter(f=>f.updatable).length,deletable:c.filter(f=>f.deletable).length};u.length>50&&!o?l={version:d.version,entitySets:c,capabilities:p,entityTypeCount:u.length,hint:`Service has ${u.length} entity types. Use the 'search' parameter (e.g. search='BusinessPartner') or 'entityType' parameter to get details for specific types. Entity sets listed above are queryable.`}:l={version:d.version,entityTypes:u.map(f=>({name:f.name,keys:f.keys.map(g=>g.name),propertyCount:f.properties.length,navigationProperties:f.navigationProperties.map(g=>g.name)})),entitySets:c,capabilities:p};}return {content:[{type:"text",text:JSON.stringify(l,null,2)}]}}catch(a){return _(a,{serviceUrl:s})}});}function Ys(t,e){if(!t)return "unknown";let n=zs(e).toLowerCase(),r=t.functionImports?.find(i=>i.name.toLowerCase()===n);if(r)return r.httpMethod==="GET"?"read":"write";let s=t.actions?.find(i=>zs(i.name).toLowerCase()===n);return s?.kind==="Function"?"read":s?.kind==="Action"?"write":"unknown"}function zs(t){let e=t.lastIndexOf(".");return e===-1?t:t.slice(e+1)}function Xs(t,e,n,r=false){let s=n??new I,i=new Map;function o(l){let c=j(l),u=i.get(c);return u||(u=new $(e,c,s),i.set(c,u)),u}function a(l,c){return _(l,{serviceUrl:c})}async function d(l,c){if(!r)return null;let u;try{u=await o(l).getMetadata();}catch{}let p=Ys(u,c);if(p==="read")return null;let m=p==="write"?`"${c}" schreibt laut den Metadaten des Dienstes (POST).`:`"${c}" ist in den Metadaten des Dienstes nicht als lesend nachweisbar.`;return _(new Error(`${m} Dieser Zugang ist lesend. Lesende Funktionsimporte (V2 HttpMethod=GET, V4 Function) sind erlaubt; f\xFCr schreibende braucht es einen Zugang ohne Read-only-Policy bzw. einen Server mit --allow-write.`),{serviceUrl:l})}t.registerTool("sap_function",{title:"Call SAP Function Import or Action",description:`Invoke an OData V2 Function Import or V4 Action/Function. For V2: calls function imports with parameters; values are typed from $metadata (Edm.Guid \u2192 guid'\u2026', Edm.Boolean \u2192 true/false), so pass plain values. For V4: supports bound actions (on a specific entity) and unbound actions/functions; keys and function parameters are typed from $metadata too (Edm.Guid and Edm.Date bare, strings quoted). Set isFunction=true for V4 Functions (GET), leave false for V4 Actions (POST). For bound operations, provide entitySet and key.
241
241
 
242
- Fiori draft services (V2, e.g. purchase requisitions): activate a draft with the <EntitySet>Activation function import and start editing an active document with <EntitySet>Edit, passing the full key as parameters, e.g. { PurchaseRequisition: "", DraftUUID: "<uuid>", IsActiveEntity: false }. An active document has DraftUUID 00000000-0000-0000-0000-000000000000 and IsActiveEntity true. Draft items have a DraftUUID of their own: read their keys via the draft header's navigation (e.g. to_PurchaseReqnItem) before sap_update.`,inputSchema:z$2.object({serviceUrl:z$2.string().describe("OData service URL"),functionName:z$2.string().describe("Function import name (V2) or action/function name (V4). For V4 bound operations, include the full namespace e.g. com.sap.namespace.ActionName"),parameters:z$2.record(z$2.string(),z$2.unknown()).optional().describe("Function/action parameters as key-value pairs"),httpMethod:z$2.enum(["GET","POST"]).optional().describe("HTTP method override. V2: from metadata or default POST. V4: Actions=POST, Functions=GET"),entitySet:z$2.string().optional().describe("Entity set for V4 bound actions/functions"),key:z$2.record(z$2.string(),z$2.unknown()).optional().describe('Entity key for V4 bound actions/functions, e.g. { BusinessPartner: "1000001" }'),isFunction:z$2.boolean().optional().describe("Set true for V4 Functions (GET). Default false = Action (POST). Ignored for V2.")}),annotations:{readOnlyHint:false,destructiveHint:false,idempotentHint:false,openWorldHint:true}},async({serviceUrl:l,functionName:c,parameters:u,httpMethod:p,entitySet:m,key:g,isFunction:f})=>{try{let h=await d(l,c);if(h)return h;let y=await o(l).functionImport(c,u,{httpMethod:p,entitySet:m,key:g,isFunction:f??!1});return {content:[{type:"text",text:JSON.stringify(y,null,2)}]}}catch(h){return a(h)}});}function Fs(t,e,n){t.registerTool("test-connection",{title:"Test SAP Connection",description:`Diagnose the connection to the configured SAP system stage by stage: DNS \u2192 TLS (including certificate chain) \u2192 authentication \u2192 client (Mandant) \u2192 service catalog. Reports the FIRST failing stage with a concrete next step, so a 401 no longer leaves you guessing between certificate, user and client.
242
+ Fiori draft services (V2, e.g. purchase requisitions): activate a draft with the <EntitySet>Activation function import and start editing an active document with <EntitySet>Edit, passing the full key as parameters, e.g. { PurchaseRequisition: "", DraftUUID: "<uuid>", IsActiveEntity: false }. An active document has DraftUUID 00000000-0000-0000-0000-000000000000 and IsActiveEntity true. Draft items have a DraftUUID of their own: read their keys via the draft header's navigation (e.g. to_PurchaseReqnItem) before sap_update.`,inputSchema:z$2.object({serviceUrl:z$2.string().describe("OData service URL"),functionName:z$2.string().describe("Function import name (V2) or action/function name (V4). For V4 bound operations, include the full namespace e.g. com.sap.namespace.ActionName"),parameters:z$2.record(z$2.string(),z$2.unknown()).optional().describe("Function/action parameters as key-value pairs"),httpMethod:z$2.enum(["GET","POST"]).optional().describe("HTTP method override. V2: from metadata or default POST. V4: Actions=POST, Functions=GET"),entitySet:z$2.string().optional().describe("Entity set for V4 bound actions/functions"),key:z$2.record(z$2.string(),z$2.unknown()).optional().describe('Entity key for V4 bound actions/functions, e.g. { BusinessPartner: "1000001" }'),isFunction:z$2.boolean().optional().describe("Set true for V4 Functions (GET). Default false = Action (POST). Ignored for V2.")}),annotations:{readOnlyHint:false,destructiveHint:false,idempotentHint:false,openWorldHint:true}},async({serviceUrl:l,functionName:c,parameters:u,httpMethod:p,entitySet:m,key:f,isFunction:g})=>{try{let h=await d(l,c);if(h)return h;let y=await o(l).functionImport(c,u,{httpMethod:p,entitySet:m,key:f,isFunction:g??!1});return {content:[{type:"text",text:JSON.stringify(y,null,2)}]}}catch(h){return a(h)}});}function Js(t,e,n){t.registerTool("test-connection",{title:"Test SAP Connection",description:`Diagnose the connection to the configured SAP system stage by stage: DNS \u2192 TLS (including certificate chain) \u2192 authentication \u2192 client (Mandant) \u2192 service catalog. Reports the FIRST failing stage with a concrete next step, so a 401 no longer leaves you guessing between certificate, user and client.
243
243
 
244
244
  **When to use:**
245
245
  - Any SAP tool fails and you need to know which layer is at fault
246
246
  - After changing SAP_BASE_URL, credentials, SAP_CLIENT or the CA bundle
247
247
 
248
248
  **When NOT to use:**
249
- - You already know the connection works (proceed to sap_discover_services)`,inputSchema:z$2.object({}),annotations:{readOnlyHint:true,destructiveHint:false,idempotentHint:true,openWorldHint:true}},async()=>{try{let r=await ot(e,{baseUrl:n?.baseUrl??"",sapClient:n?.sapClient,tlsVerify:n?.tlsVerify});return {content:[{type:"text",text:JSON.stringify({...r,...r.status==="connected"?{hint:"N\xE4chster Schritt: sap_discover_services zeigt die verf\xFCgbaren OData-Services dieses Systems."}:{}},null,2)}],...r.status==="failed"?{isError:!0}:{}}}catch(r){return _(r,{hint:"Die Verbindungsdiagnose konnte nicht ausgef\xFChrt werden. Das ist ein Fehler des Servers, kein Befund \xFCber das SAP-System."})}});}function ed(t){return {name:t.FieldName,dataType:t.DataType,length:t.Length,decimals:t.Decimals??0,required:t.Required}}function td(t){return {name:t.SegmentName,parentSegment:t.ParentSegment??"",minOccurrence:t.MinOccurrence,maxOccurrence:t.MaxOccurrence,fields:t.Fields?.results?.map(ed)??[]}}function nd(t){return {idocType:t.IdocType,mesType:t.MesType,segments:t.Segments?.results?.map(td)??[]}}async function Un(t,e,n){try{if(n){let o=(await t.request({method:"get",url:`${e}/IdocTypes('${n}')?$expand=Segments($expand=Fields)`})).data;return nd(o.d)}return (await t.request({method:"get",url:`${e}/IdocTypes`})).data.d.results.map(i=>({idocType:i.IdocType,mesType:i.MesType}))}catch(r){let s=r instanceof Error?r.message:String(r);throw new Error(`Failed to fetch IDoc metadata: ${s}`)}}var Hs={50:{text:"IDoc added",category:"pending"},51:{text:"Application document not posted",category:"error"},52:{text:"Application document not fully posted",category:"error"},53:{text:"Application document posted",category:"success"},56:{text:"IDoc with errors added",category:"error"},62:{text:"IDoc passed to application",category:"pending"},64:{text:"IDoc ready to be transferred to application",category:"pending"},66:{text:"IDoc is waiting for predecessor IDoc (serialization)",category:"pending"},68:{text:"Error - no further processing",category:"error"},69:{text:"IDoc was edited",category:"pending"},73:{text:"IDoc passed to BTP Integration Suite",category:"pending"},1:{text:"IDoc generated",category:"pending"},3:{text:"IDoc data passed to port OK",category:"success"},5:{text:"IDoc translation error",category:"error"},12:{text:"Dispatch OK",category:"success"},18:{text:"Triggering EDI subsystem OK",category:"success"},30:{text:"IDoc ready to be dispatched",category:"pending"}};async function js(t,e,n){try{let i=(await t.request({method:"get",url:`${e}/IdocStatus('${n}')`})).data.d,o=i.Status,a=Hs[o];return {docnum:i.Docnum,status:o,statusText:a?.text??"Unknown status",category:a?.category??"pending",timestamp:i.Timestamp}}catch(r){let s=r instanceof Error?r.message:String(r);throw new Error(`Failed to query IDoc status: ${s}`)}}var $n={name:z$2.string().describe("Segment name, e.g. E1MARAM"),fields:z$2.record(z$2.string(),z$2.string()).describe("Segment field values")},rd=z$2.object({...$n}),sd=z$2.object({...$n,children:z$2.array(rd).optional().describe("Nested child segments (level 3)")}),id=z$2.object({...$n,children:z$2.array(sd).optional().describe("Nested child segments")});function Vs(t,e,n,r){function s(i,o){return _(i,{serviceUrl:o})}t.registerTool("sap_idoc_send",{title:"Send IDoc to SAP",description:"Send an IDoc to SAP via HTTP/XML. Auto-constructs EDI_DC40 control record. Validates against segment metadata before sending -- blocks on validation failure.",inputSchema:z$2.object({idocType:z$2.string().describe("IDoc type name, e.g. MATMAS05, ORDERS05"),segments:z$2.array(id).describe("IDoc data segments"),metadataServiceUrl:z$2.string().optional().describe("OData service URL for IDoc metadata validation. If provided, validates before sending."),mesType:z$2.string().optional().describe("Override auto-derived message type (MESTYP)"),sndpor:z$2.string().optional().describe("Override sender port"),sndprn:z$2.string().optional().describe("Override sender partner number"),rcvpor:z$2.string().optional().describe("Override receiver port"),rcvprn:z$2.string().optional().describe("Override receiver partner number")}),annotations:{readOnlyHint:false,destructiveHint:false,idempotentHint:false,openWorldHint:true}},async({idocType:i,segments:o,metadataServiceUrl:a,mesType:d,sndpor:l,sndprn:c,rcvpor:u,rcvprn:p})=>{try{let m;if(a){let f=await Un(e,a,i);Array.isArray(f)||(m=f);}let g=await n.send({idocType:i,segments:o,metadata:m,partnerOverrides:{mesType:d,sndpor:l,sndprn:c,rcvpor:u,rcvprn:p}});return {content:[{type:"text",text:JSON.stringify(g,null,2)}]}}catch(m){return s(m)}}),t.registerTool("sap_idoc_status",{title:"Query IDoc Status",description:"Query IDoc processing status in SAP. Returns status code with human-readable description (50=received, 53=processed, 51=error).",inputSchema:z$2.object({docnum:z$2.string().describe("IDoc document number"),statusServiceUrl:z$2.string().describe("OData service URL for IDoc status query")}),annotations:{readOnlyHint:true,destructiveHint:false,idempotentHint:true,openWorldHint:true}},async({docnum:i,statusServiceUrl:o})=>{try{let a=await js(e,o,i);return {content:[{type:"text",text:JSON.stringify(a,null,2)}]}}catch(a){return s(a)}}),t.registerTool("sap_idoc_discover",{title:"Discover IDoc Types",description:"Discover available IDoc types and segment structures from SAP. Returns IDoc type definitions with segment hierarchy and field metadata.",inputSchema:z$2.object({metadataServiceUrl:z$2.string().describe("OData service URL for IDoc metadata"),idocType:z$2.string().optional().describe("Specific IDoc type to get details for. Omit to list all types.")}),annotations:{readOnlyHint:true,destructiveHint:false,idempotentHint:true,openWorldHint:true}},async({metadataServiceUrl:i,idocType:o})=>{try{let a=await Un(e,i,o);return {content:[{type:"text",text:JSON.stringify(a,null,2)}]}}catch(a){return s(a)}}),t.registerTool("sap_idoc_list_received",{title:"List Received IDocs",description:"List IDocs received via webhook. Returns recently received IDocs from the in-memory store.",inputSchema:z$2.object({}),annotations:{readOnlyHint:true,destructiveHint:false,idempotentHint:true,openWorldHint:true}},async()=>{try{let i=r.list().map(o=>({docnum:o.docnum,idocType:o.idocType,mesType:o.mesType,receivedAt:o.receivedAt.toISOString()}));return {content:[{type:"text",text:JSON.stringify(i,null,2)}]}}catch(i){return s(i)}});}var od=/^[!#$%&'*+.^_`|~0-9A-Za-z-]+$/,ad=/[\u0000-\u001f\u007f]/;function Ln(t){let e={};if(!t)return e;for(let[n,r]of Object.entries(t)){if(r==null)continue;let s=typeof r=="string"?r.trim():String(r);if(s.length!==0){if(!od.test(n))throw new Error(`"${n}" ist kein zul\xE4ssiger Kopfzeilenname. Erlaubt sind Buchstaben, Ziffern und -_.~ ohne Leerzeichen.`);if(ad.test(s))throw new Error(`Der Wert der Kopfzeile "${n}" enth\xE4lt einen Zeilenumbruch oder ein Steuerzeichen. Das w\xE4re eine Kopfzeilen-Einschleusung und wird nicht gesendet.`);e[n]=s;}}return e}var cd=[[/ä/g,"ae"],[/ö/g,"oe"],[/ü/g,"ue"],[/Ä/g,"Ae"],[/Ö/g,"Oe"],[/Ü/g,"Ue"],[/ß/g,"ss"]],dd=[[/[\u2010-\u2015]/g,"-"],[/[\u2018\u2019\u201a\u201b]/g,"'"],[/[\u201c\u201d\u201e\u201f]/g,'"'],[/…/g,"..."],[/[\u00a0\u2007\u202f\u2009]/g," "]],ld=/[\u0300-\u036f]/g,ud=/[^\u0020-\u007e]/g;function Ws(t){let e=t.trim();if(e.length===0)throw new Error("Der Dateiname ist leer. SAP braucht ihn als Slug-Kopfzeile.");let n=e;for(let[r,s]of cd)n=n.replace(r,s);for(let[r,s]of dd)n=n.replace(r,s);if(n=n.normalize("NFKD").replace(ld,""),n=n.replace(ud,"").trim(),n.length===0)throw new Error(`Aus dem Dateinamen "${e}" bleibt nichts \xFCbrig, was durch eine HTTP-Kopfzeile passt. Gib einen Namen mit lateinischen Zeichen an.`);return {slug:n,changed:n!==e}}async function Gs(t,e,n){if(n.content.byteLength===0)throw new Error("Der Rumpf ist leer. Ein Anhang ohne Bytes legt in SAP ein leeres Dokument an, das sich nicht mehr \xE4ndern l\xE4sst (der Dienst kennt kein PATCH).");let{slug:r,changed:s}=Ws(n.fileName),i=n.contentType.trim();if(i.length===0)throw new Error("Es fehlt der Content-Type der Datei, z. B. application/pdf.");let o={...Ln(n.headers),...Ln({Slug:r,"Content-Type":i,Accept:"application/json"})},a=await t.request({method:"post",url:`${e}/${n.entitySet}`,data:n.content,headers:o}),d=ee(a.data),l=d.results.length>0?q(d.results[0]):{},c={status:a.status,slug:r,bytesSent:n.content.byteLength,entity:l};s&&(c.slugAdjustedFrom=n.fileName);let u=a.headers?.location;return u&&(c.location=u),c}async function qs(t,e,n){let r=_e(n.entitySet,n.key),s=`${e}/${r}${n.withoutValuePath?"":"/$value"}`,i=await t.request({method:"get",url:s,responseType:"arraybuffer"}),o={status:i.status,content:pd(i.data),contentType:String(i.headers?.["content-type"]??"application/octet-stream")},a=md(i.headers?.["content-disposition"]);return a&&(o.fileName=a),o}function pd(t){return Buffer.isBuffer(t)?t:t instanceof ArrayBuffer?Buffer.from(t):ArrayBuffer.isView(t)?Buffer.from(t.buffer,t.byteOffset,t.byteLength):typeof t=="string"?Buffer.from(t,"binary"):Buffer.alloc(0)}function md(t){if(typeof t!="string")return;let e=/filename\*=UTF-8''([^;]+)/i.exec(t);if(e?.[1])try{return decodeURIComponent(e[1].trim())}catch{}return /filename="?([^";]+)"?/i.exec(t)?.[1]?.trim()}function Ks(t,e,n){function r(s){return K(s,n)?null:_(new Error(`Entity set '${s}' is not exposed. Configure --expose to include it.`))}t.registerTool("sap_media_upload",{title:"Upload to a SAP Media Entity",description:`L\xE4dt eine Datei als Rohbytes in eine SAP-Media-Entity, z. B. einen Anhang in AttachmentContentSet (API_CV_ATTACHMENT_SRV). Der Dateiname geht als Slug-Kopfzeile hinaus, die Bytes in den Rumpf, die Antwort kommt als JSON.
249
+ - You already know the connection works (proceed to sap_discover_services)`,inputSchema:z$2.object({}),annotations:{readOnlyHint:true,destructiveHint:false,idempotentHint:true,openWorldHint:true}},async()=>{try{let r=await pt(e,{baseUrl:n?.baseUrl??"",sapClient:n?.sapClient,tlsVerify:n?.tlsVerify});return {content:[{type:"text",text:JSON.stringify({...r,...r.status==="connected"?{hint:"N\xE4chster Schritt: sap_discover_services zeigt die verf\xFCgbaren OData-Services dieses Systems."}:{}},null,2)}],...r.status==="failed"?{isError:!0}:{}}}catch(r){return _(r,{hint:"Die Verbindungsdiagnose konnte nicht ausgef\xFChrt werden. Das ist ein Fehler des Servers, kein Befund \xFCber das SAP-System."})}});}function pd(t){return {name:t.FieldName,dataType:t.DataType,length:t.Length,decimals:t.Decimals??0,required:t.Required}}function md(t){return {name:t.SegmentName,parentSegment:t.ParentSegment??"",minOccurrence:t.MinOccurrence,maxOccurrence:t.MaxOccurrence,fields:t.Fields?.results?.map(pd)??[]}}function fd(t){return {idocType:t.IdocType,mesType:t.MesType,segments:t.Segments?.results?.map(md)??[]}}async function Hn(t,e,n){try{if(n){let o=(await t.request({method:"get",url:`${e}/IdocTypes('${n}')?$expand=Segments($expand=Fields)`})).data;return fd(o.d)}return (await t.request({method:"get",url:`${e}/IdocTypes`})).data.d.results.map(i=>({idocType:i.IdocType,mesType:i.MesType}))}catch(r){let s=r instanceof Error?r.message:String(r);throw new Error(`Failed to fetch IDoc metadata: ${s}`)}}var Zs={50:{text:"IDoc added",category:"pending"},51:{text:"Application document not posted",category:"error"},52:{text:"Application document not fully posted",category:"error"},53:{text:"Application document posted",category:"success"},56:{text:"IDoc with errors added",category:"error"},62:{text:"IDoc passed to application",category:"pending"},64:{text:"IDoc ready to be transferred to application",category:"pending"},66:{text:"IDoc is waiting for predecessor IDoc (serialization)",category:"pending"},68:{text:"Error - no further processing",category:"error"},69:{text:"IDoc was edited",category:"pending"},73:{text:"IDoc passed to BTP Integration Suite",category:"pending"},1:{text:"IDoc generated",category:"pending"},3:{text:"IDoc data passed to port OK",category:"success"},5:{text:"IDoc translation error",category:"error"},12:{text:"Dispatch OK",category:"success"},18:{text:"Triggering EDI subsystem OK",category:"success"},30:{text:"IDoc ready to be dispatched",category:"pending"}};async function Qs(t,e,n){try{let i=(await t.request({method:"get",url:`${e}/IdocStatus('${n}')`})).data.d,o=i.Status,a=Zs[o];return {docnum:i.Docnum,status:o,statusText:a?.text??"Unknown status",category:a?.category??"pending",timestamp:i.Timestamp}}catch(r){let s=r instanceof Error?r.message:String(r);throw new Error(`Failed to query IDoc status: ${s}`)}}var jn={name:z$2.string().describe("Segment name, e.g. E1MARAM"),fields:z$2.record(z$2.string(),z$2.string()).describe("Segment field values")},gd=z$2.object({...jn}),hd=z$2.object({...jn,children:z$2.array(gd).optional().describe("Nested child segments (level 3)")}),yd=z$2.object({...jn,children:z$2.array(hd).optional().describe("Nested child segments")});function ei(t,e,n,r){function s(i,o){return _(i,{serviceUrl:o})}t.registerTool("sap_idoc_send",{title:"Send IDoc to SAP",description:"Send an IDoc to SAP via HTTP/XML. Auto-constructs EDI_DC40 control record. Validates against segment metadata before sending -- blocks on validation failure.",inputSchema:z$2.object({idocType:z$2.string().describe("IDoc type name, e.g. MATMAS05, ORDERS05"),segments:z$2.array(yd).describe("IDoc data segments"),metadataServiceUrl:z$2.string().optional().describe("OData service URL for IDoc metadata validation. If provided, validates before sending."),mesType:z$2.string().optional().describe("Override auto-derived message type (MESTYP)"),sndpor:z$2.string().optional().describe("Override sender port"),sndprn:z$2.string().optional().describe("Override sender partner number"),rcvpor:z$2.string().optional().describe("Override receiver port"),rcvprn:z$2.string().optional().describe("Override receiver partner number")}),annotations:{readOnlyHint:false,destructiveHint:false,idempotentHint:false,openWorldHint:true}},async({idocType:i,segments:o,metadataServiceUrl:a,mesType:d,sndpor:l,sndprn:c,rcvpor:u,rcvprn:p})=>{try{let m;if(a){let g=await Hn(e,a,i);Array.isArray(g)||(m=g);}let f=await n.send({idocType:i,segments:o,metadata:m,partnerOverrides:{mesType:d,sndpor:l,sndprn:c,rcvpor:u,rcvprn:p}});return {content:[{type:"text",text:JSON.stringify(f,null,2)}]}}catch(m){return s(m)}}),t.registerTool("sap_idoc_status",{title:"Query IDoc Status",description:"Query IDoc processing status in SAP. Returns status code with human-readable description (50=received, 53=processed, 51=error).",inputSchema:z$2.object({docnum:z$2.string().describe("IDoc document number"),statusServiceUrl:z$2.string().describe("OData service URL for IDoc status query")}),annotations:{readOnlyHint:true,destructiveHint:false,idempotentHint:true,openWorldHint:true}},async({docnum:i,statusServiceUrl:o})=>{try{let a=await Qs(e,o,i);return {content:[{type:"text",text:JSON.stringify(a,null,2)}]}}catch(a){return s(a)}}),t.registerTool("sap_idoc_discover",{title:"Discover IDoc Types",description:"Discover available IDoc types and segment structures from SAP. Returns IDoc type definitions with segment hierarchy and field metadata.",inputSchema:z$2.object({metadataServiceUrl:z$2.string().describe("OData service URL for IDoc metadata"),idocType:z$2.string().optional().describe("Specific IDoc type to get details for. Omit to list all types.")}),annotations:{readOnlyHint:true,destructiveHint:false,idempotentHint:true,openWorldHint:true}},async({metadataServiceUrl:i,idocType:o})=>{try{let a=await Hn(e,i,o);return {content:[{type:"text",text:JSON.stringify(a,null,2)}]}}catch(a){return s(a)}}),t.registerTool("sap_idoc_list_received",{title:"List Received IDocs",description:"List IDocs received via webhook. Returns recently received IDocs from the in-memory store.",inputSchema:z$2.object({}),annotations:{readOnlyHint:true,destructiveHint:false,idempotentHint:true,openWorldHint:true}},async()=>{try{let i=r.list().map(o=>({docnum:o.docnum,idocType:o.idocType,mesType:o.mesType,receivedAt:o.receivedAt.toISOString()}));return {content:[{type:"text",text:JSON.stringify(i,null,2)}]}}catch(i){return s(i)}});}var Sd=/^[!#$%&'*+.^_`|~0-9A-Za-z-]+$/,bd=/[\u0000-\u001f\u007f]/;function Vn(t){let e={};if(!t)return e;for(let[n,r]of Object.entries(t)){if(r==null)continue;let s=typeof r=="string"?r.trim():String(r);if(s.length!==0){if(!Sd.test(n))throw new Error(`"${n}" ist kein zul\xE4ssiger Kopfzeilenname. Erlaubt sind Buchstaben, Ziffern und -_.~ ohne Leerzeichen.`);if(bd.test(s))throw new Error(`Der Wert der Kopfzeile "${n}" enth\xE4lt einen Zeilenumbruch oder ein Steuerzeichen. Das w\xE4re eine Kopfzeilen-Einschleusung und wird nicht gesendet.`);e[n]=s;}}return e}var wd=[[/ä/g,"ae"],[/ö/g,"oe"],[/ü/g,"ue"],[/Ä/g,"Ae"],[/Ö/g,"Oe"],[/Ü/g,"Ue"],[/ß/g,"ss"]],Td=[[/[\u2010-\u2015]/g,"-"],[/[\u2018\u2019\u201a\u201b]/g,"'"],[/[\u201c\u201d\u201e\u201f]/g,'"'],[/…/g,"..."],[/[\u00a0\u2007\u202f\u2009]/g," "]],vd=/[\u0300-\u036f]/g,Ad=/[^\u0020-\u007e]/g;function ti(t){let e=t.trim();if(e.length===0)throw new Error("Der Dateiname ist leer. SAP braucht ihn als Slug-Kopfzeile.");let n=e;for(let[r,s]of wd)n=n.replace(r,s);for(let[r,s]of Td)n=n.replace(r,s);if(n=n.normalize("NFKD").replace(vd,""),n=n.replace(Ad,"").trim(),n.length===0)throw new Error(`Aus dem Dateinamen "${e}" bleibt nichts \xFCbrig, was durch eine HTTP-Kopfzeile passt. Gib einen Namen mit lateinischen Zeichen an.`);return {slug:n,changed:n!==e}}async function ni(t,e,n){if(n.content.byteLength===0)throw new Error("Der Rumpf ist leer. Ein Anhang ohne Bytes legt in SAP ein leeres Dokument an, das sich nicht mehr \xE4ndern l\xE4sst (der Dienst kennt kein PATCH).");let{slug:r,changed:s}=ti(n.fileName),i=n.contentType.trim();if(i.length===0)throw new Error("Es fehlt der Content-Type der Datei, z. B. application/pdf.");let o={...Vn(n.headers),...Vn({Slug:r,"Content-Type":i,Accept:"application/json"})},a=await t.request({method:"post",url:`${e}/${n.entitySet}`,data:n.content,headers:o}),d=se(a.data),l=d.results.length>0?K(d.results[0]):{},c={status:a.status,slug:r,bytesSent:n.content.byteLength,entity:l};s&&(c.slugAdjustedFrom=n.fileName);let u=a.headers?.location;return u&&(c.location=u),c}async function ri(t,e,n){let r=Oe(n.entitySet,n.key),s=`${e}/${r}${n.withoutValuePath?"":"/$value"}`,i=await t.request({method:"get",url:s,responseType:"arraybuffer"}),o={status:i.status,content:Ed(i.data),contentType:String(i.headers?.["content-type"]??"application/octet-stream")},a=Cd(i.headers?.["content-disposition"]);return a&&(o.fileName=a),o}function Ed(t){return Buffer.isBuffer(t)?t:t instanceof ArrayBuffer?Buffer.from(t):ArrayBuffer.isView(t)?Buffer.from(t.buffer,t.byteOffset,t.byteLength):typeof t=="string"?Buffer.from(t,"binary"):Buffer.alloc(0)}function Cd(t){if(typeof t!="string")return;let e=/filename\*=UTF-8''([^;]+)/i.exec(t);if(e?.[1])try{return decodeURIComponent(e[1].trim())}catch{}return /filename="?([^";]+)"?/i.exec(t)?.[1]?.trim()}function si(t,e,n){function r(s){return z(s,n)?null:_(new Error(`Entity set '${s}' is not exposed. Configure --expose to include it.`))}t.registerTool("sap_media_upload",{title:"Upload to a SAP Media Entity",description:`L\xE4dt eine Datei als Rohbytes in eine SAP-Media-Entity, z. B. einen Anhang in AttachmentContentSet (API_CV_ATTACHMENT_SRV). Der Dateiname geht als Slug-Kopfzeile hinaus, die Bytes in den Rumpf, die Antwort kommt als JSON.
250
250
 
251
251
  **Kopfzeilen:** objektbezogene Angaben wie BusinessObjectTypeName (Kundenauftrag: BUS2032), LinkedSAPObjectKey (zehnstellig mit f\xFChrenden Nullen) und DocumentInfoRecordDocType geh\xF6ren in \`headers\`. Leere Werte werden nicht gesendet.
252
252
 
253
253
  **Achtung:** Der Anhangdienst kennt kein PATCH \u2014 ein zweiter Upload ersetzt nichts, er h\xE4ngt ein zweites Dokument an dasselbe Objekt. Vorher nachsehen, ob schon eines da ist.
254
254
 
255
- **Wann nicht:** f\xFCr gew\xF6hnliche JSON-Entit\xE4ten sap_create verwenden.`,inputSchema:z$2.object({serviceUrl:z$2.string().describe("OData service URL"),entitySet:z$2.string().describe("Entity set name, e.g., AttachmentContentSet"),contentBase64:z$2.string().describe("Der Dateiinhalt base64-kodiert. Ein data:-Pr\xE4fix wird abgeschnitten."),fileName:z$2.string().describe("Dateiname, geht als Slug-Kopfzeile hinaus"),contentType:z$2.string().describe("Content-Type der Datei, z. B. application/pdf"),headers:z$2.record(z$2.string(),z$2.unknown()).optional().describe('Weitere Kopfzeilen, z. B. { "BusinessObjectTypeName": "BUS2032", "LinkedSAPObjectKey": "0000012345", "DocumentInfoRecordDocType": "PDF" }. Leere Werte werden nicht gesendet.')}),annotations:{readOnlyHint:false,destructiveHint:false,idempotentHint:false,openWorldHint:true}},async({serviceUrl:s,entitySet:i,contentBase64:o,fileName:a,contentType:d,headers:l})=>{let c=r(i);if(c)return c;let u;try{u=gd(o);}catch(p){return _(p,{serviceUrl:s})}try{let p=j(s),m=await Gs(e,p,{entitySet:i,content:u,fileName:a,contentType:d,...l?{headers:l}:{}});return {content:[{type:"text",text:JSON.stringify({uploaded:m},null,2)}]}}catch(p){return _(p,{serviceUrl:s})}}),t.registerTool("sap_media_download",{title:"Download from a SAP Media Entity",description:`Holt die Rohbytes einer SAP-Media-Entity \xFCber den $value-Pfad, z. B. den Inhalt eines Anhangs. Die Bytes kommen als resource/blob zur\xFCck, nicht als base64-Zeichenkette im JSON; dazu Dateiname, Content-Type und Gr\xF6\xDFe als Text.
255
+ **Wann nicht:** f\xFCr gew\xF6hnliche JSON-Entit\xE4ten sap_create verwenden.`,inputSchema:z$2.object({serviceUrl:z$2.string().describe("OData service URL"),entitySet:z$2.string().describe("Entity set name, e.g., AttachmentContentSet"),contentBase64:z$2.string().describe("Der Dateiinhalt base64-kodiert. Ein data:-Pr\xE4fix wird abgeschnitten."),fileName:z$2.string().describe("Dateiname, geht als Slug-Kopfzeile hinaus"),contentType:z$2.string().describe("Content-Type der Datei, z. B. application/pdf"),headers:z$2.record(z$2.string(),z$2.unknown()).optional().describe('Weitere Kopfzeilen, z. B. { "BusinessObjectTypeName": "BUS2032", "LinkedSAPObjectKey": "0000012345", "DocumentInfoRecordDocType": "PDF" }. Leere Werte werden nicht gesendet.')}),annotations:{readOnlyHint:false,destructiveHint:false,idempotentHint:false,openWorldHint:true}},async({serviceUrl:s,entitySet:i,contentBase64:o,fileName:a,contentType:d,headers:l})=>{let c=r(i);if(c)return c;let u;try{u=Pd(o);}catch(p){return _(p,{serviceUrl:s})}try{let p=j(s),m=await ni(e,p,{entitySet:i,content:u,fileName:a,contentType:d,...l?{headers:l}:{}});return {content:[{type:"text",text:JSON.stringify({uploaded:m},null,2)}]}}catch(p){return _(p,{serviceUrl:s})}}),t.registerTool("sap_media_download",{title:"Download from a SAP Media Entity",description:`Holt die Rohbytes einer SAP-Media-Entity \xFCber den $value-Pfad, z. B. den Inhalt eines Anhangs. Die Bytes kommen als resource/blob zur\xFCck, nicht als base64-Zeichenkette im JSON; dazu Dateiname, Content-Type und Gr\xF6\xDFe als Text.
256
256
 
257
- **Wann nicht:** f\xFCr die Metadaten eines Anhangs (Name, Gr\xF6\xDFe, Anleger) reicht sap_read auf dieselbe Entit\xE4t.`,inputSchema:z$2.object({serviceUrl:z$2.string().describe("OData service URL"),entitySet:z$2.string().describe("Entity set name, e.g., AttachmentContentSet"),key:z$2.record(z$2.string(),z$2.unknown()).describe('Entity key as object, e.g., { DocumentInfoRecordDocNumber: "10000042" }'),withoutValuePath:z$2.boolean().optional().describe("Ohne /$value anfragen. Nur n\xF6tig, wenn der Dienst die Bytes direkt unter dem Entit\xE4tspfad liefert.")}),annotations:{readOnlyHint:true,destructiveHint:false,idempotentHint:true,openWorldHint:true}},async({serviceUrl:s,entitySet:i,key:o,withoutValuePath:a})=>{let d=r(i);if(d)return d;try{let l=j(s),c=await qs(e,l,{entitySet:i,key:o,...a?{withoutValuePath:a}:{}}),u=`sap://${i}/${encodeURIComponent(c.fileName??"content")}`;return {content:[{type:"text",text:JSON.stringify({status:c.status,...c.fileName?{fileName:c.fileName}:{},contentType:c.contentType,bytes:c.content.byteLength},null,2)},{type:"resource",resource:{uri:u,mimeType:c.contentType,blob:c.content.toString("base64")}}]}}catch(l){return _(l,{serviceUrl:s})}});}var fd=/^[A-Za-z0-9+/\r\n=_-]+$/;function gd(t){let e=t.replace(/^data:[^;,]*;base64,/,"").trim();if(e.length===0)throw new Error("contentBase64 ist leer.");if(!fd.test(e))throw new Error("contentBase64 ist keine base64-Kodierung. Erwartet wird der Dateiinhalt base64-kodiert (im n8n-Knoten \xFCbernimmt das das Bin\xE4rfeld), nicht der Klartext oder ein Dateipfad.");let n=Buffer.from(e,"base64");if(n.byteLength===0)throw new Error("contentBase64 ergibt keine Bytes.");return n}var hd={core:"Core tools (connection, discovery, metadata, NL query)",odata:"OData CRUD tools (read, query, create, update, delete, function, batch)",idoc:"IDoc tools (send, status, discover, list received)",rfc:"RFC/BAPI tools (rfc_call, rfc_metadata, bapi_call, bapi_commit, rfc_search_functions). Requires SAP_RFC_ASHOST/SYSNR or load-balanced equivalent."};function Ys(t,e){if(e.isReadOnlyMode())return;let n=e.getActiveTiers(),r=["core","odata","idoc","rfc"],s=e.getAllowedTiers(),i=r.filter(a=>!n.includes(a)&&(!s||s.includes(a))),o=i.length>0?`Available tiers to activate: ${i.map(a=>`${a} (${hd[a]})`).join(", ")}.`:"All tiers are already active.";t.registerTool("sap_enable_tools",{title:"Enable Additional SAP Tools",description:`Activate additional tool tiers for this session. Currently active: ${n.join(", ")}. ${o}`,inputSchema:z$2.object({tier:z$2.enum(["core","odata","idoc","rfc"]).describe('Tier to activate. Use "idoc" for IDoc tools, "rfc" for RFC/BAPI tools.')}),annotations:{readOnlyHint:true,destructiveHint:false,idempotentHint:true,openWorldHint:false}},async({tier:a})=>{let d=e.enableTier(a);return "error"in d?{content:[{type:"text",text:JSON.stringify({status:"error",message:d.error})}],isError:true}:{content:[{type:"text",text:JSON.stringify({status:"success",tier_enabled:a,enabled_tools:d.enabled,active_tiers:d.activeTiers,note:"Tools enabled. If your client did not refresh the tool list automatically, you may need to reconnect."})}]}});}function Xs(t,e){return t.length===0?"":t.map(n=>yd(n,e)).join(" and ")}function yd(t,e){let{field:n,operator:r,value:s}=t;switch(r){case "contains":return Sd(n,String(s),e);case "startswith":return `startswith(${n},'${Lt(String(s))}')`;case "endswith":return `endswith(${n},'${Lt(String(s))}')`;default:return bd(n,r,s,e)}}function Sd(t,e,n){let r=Lt(e);return n==="v2"?`substringof('${r}',${t})`:`contains(${t},'${r}')`}function bd(t,e,n,r){let s=Td(n,r);return `${t} ${e} ${s}`}function Td(t,e){return typeof t=="number"||typeof t=="boolean"?String(t):wd(t)?Ad(t,e):`'${Lt(t)}'`}function wd(t){return /^\d{4}-\d{2}-\d{2}(T\d{2}:\d{2}(:\d{2})?)?/.test(t)}function Ad(t,e){return e==="v2"?`datetime'${t.includes("T")?t:`${t}T00:00:00`}'`:t}function Lt(t){return t.replace(/'/g,"''")}function Js(t,e,n,r){let s=r??new I,i=new Map;function o(d){let l=j(d),c=i.get(l);return c||(c=new $(e,l,s),i.set(l,c)),c}function a(d,l){return _(d,{serviceUrl:l})}t.registerTool("sap_nl_query",{title:"Execute NL-Generated OData Query",description:`Execute a structured OData query generated from natural language. Accepts structured filters (field/operator/value) and converts them to the correct OData V2 or V4 filter syntax automatically. Read-only: only performs queries, never creates, updates, or deletes data.
257
+ **Wann nicht:** f\xFCr die Metadaten eines Anhangs (Name, Gr\xF6\xDFe, Anleger) reicht sap_read auf dieselbe Entit\xE4t.`,inputSchema:z$2.object({serviceUrl:z$2.string().describe("OData service URL"),entitySet:z$2.string().describe("Entity set name, e.g., AttachmentContentSet"),key:z$2.record(z$2.string(),z$2.unknown()).describe('Entity key as object, e.g., { DocumentInfoRecordDocNumber: "10000042" }'),withoutValuePath:z$2.boolean().optional().describe("Ohne /$value anfragen. Nur n\xF6tig, wenn der Dienst die Bytes direkt unter dem Entit\xE4tspfad liefert.")}),annotations:{readOnlyHint:true,destructiveHint:false,idempotentHint:true,openWorldHint:true}},async({serviceUrl:s,entitySet:i,key:o,withoutValuePath:a})=>{let d=r(i);if(d)return d;try{let l=j(s),c=await ri(e,l,{entitySet:i,key:o,...a?{withoutValuePath:a}:{}}),u=`sap://${i}/${encodeURIComponent(c.fileName??"content")}`;return {content:[{type:"text",text:JSON.stringify({status:c.status,...c.fileName?{fileName:c.fileName}:{},contentType:c.contentType,bytes:c.content.byteLength},null,2)},{type:"resource",resource:{uri:u,mimeType:c.contentType,blob:c.content.toString("base64")}}]}}catch(l){return _(l,{serviceUrl:s})}});}var Rd=/^[A-Za-z0-9+/\r\n=_-]+$/;function Pd(t){let e=t.replace(/^data:[^;,]*;base64,/,"").trim();if(e.length===0)throw new Error("contentBase64 ist leer.");if(!Rd.test(e))throw new Error("contentBase64 ist keine base64-Kodierung. Erwartet wird der Dateiinhalt base64-kodiert (im n8n-Knoten \xFCbernimmt das das Bin\xE4rfeld), nicht der Klartext oder ein Dateipfad.");let n=Buffer.from(e,"base64");if(n.byteLength===0)throw new Error("contentBase64 ergibt keine Bytes.");return n}var kd={core:"Core tools (connection, discovery, metadata, NL query)",odata:"OData CRUD tools (read, query, create, update, delete, function, batch)",idoc:"IDoc tools (send, status, discover, list received)",rfc:"RFC/BAPI tools (rfc_call, rfc_metadata, bapi_call, bapi_commit, rfc_search_functions). Requires SAP_RFC_ASHOST/SYSNR or load-balanced equivalent."};function oi(t,e){if(e.isReadOnlyMode())return;let n=e.getActiveTiers(),r=["core","odata","idoc","rfc"],s=e.getAllowedTiers(),i=r.filter(a=>!n.includes(a)&&(!s||s.includes(a))),o=i.length>0?`Available tiers to activate: ${i.map(a=>`${a} (${kd[a]})`).join(", ")}.`:"All tiers are already active.";t.registerTool("sap_enable_tools",{title:"Enable Additional SAP Tools",description:`Activate additional tool tiers for this session. Currently active: ${n.join(", ")}. ${o}`,inputSchema:z$2.object({tier:z$2.enum(["core","odata","idoc","rfc"]).describe('Tier to activate. Use "idoc" for IDoc tools, "rfc" for RFC/BAPI tools.')}),annotations:{readOnlyHint:true,destructiveHint:false,idempotentHint:true,openWorldHint:false}},async({tier:a})=>{let d=e.enableTier(a);return "error"in d?{content:[{type:"text",text:JSON.stringify({status:"error",message:d.error})}],isError:true}:{content:[{type:"text",text:JSON.stringify({status:"success",tier_enabled:a,enabled_tools:d.enabled,active_tiers:d.activeTiers,note:"Tools enabled. If your client did not refresh the tool list automatically, you may need to reconnect."})}]}});}function ai(t,e){return t.length===0?"":t.map(n=>_d(n,e)).join(" and ")}function _d(t,e){let{field:n,operator:r,value:s}=t;switch(r){case "contains":return Od(n,String(s),e);case "startswith":return `startswith(${n},'${Vt(String(s))}')`;case "endswith":return `endswith(${n},'${Vt(String(s))}')`;default:return Id(n,r,s,e)}}function Od(t,e,n){let r=Vt(e);return n==="v2"?`substringof('${r}',${t})`:`contains(${t},'${r}')`}function Id(t,e,n,r){let s=Nd(n,r);return `${t} ${e} ${s}`}function Nd(t,e){return typeof t=="number"||typeof t=="boolean"?String(t):Dd(t)?xd(t,e):`'${Vt(t)}'`}function Dd(t){return /^\d{4}-\d{2}-\d{2}(T\d{2}:\d{2}(:\d{2})?)?/.test(t)}function xd(t,e){return e==="v2"?`datetime'${t.includes("T")?t:`${t}T00:00:00`}'`:t}function Vt(t){return t.replace(/'/g,"''")}function ci(t,e,n,r){let s=r??new I,i=new Map;function o(d){let l=j(d),c=i.get(l);return c||(c=new $(e,l,s),i.set(l,c)),c}function a(d,l){return _(d,{serviceUrl:l})}t.registerTool("sap_nl_query",{title:"Execute NL-Generated OData Query",description:`Execute a structured OData query generated from natural language. Accepts structured filters (field/operator/value) and converts them to the correct OData V2 or V4 filter syntax automatically. Read-only: only performs queries, never creates, updates, or deletes data.
258
258
 
259
259
  **When to use:**
260
260
  - You have a natural language question about SAP data
@@ -264,7 +264,7 @@ Fiori draft services (V2, e.g. purchase requisitions): activate a draft with the
264
264
  **When NOT to use:**
265
265
  - You need to create, update, or delete data (use sap_create/sap_update/sap_delete)
266
266
  - You already have an exact OData $filter string (use sap_query instead)
267
- - You don't know which service to query (use sap://routing/{domain} first)`,inputSchema:z$2.object({serviceUrl:z$2.string().describe("OData service URL"),entitySet:z$2.string().describe("Entity set to query"),filters:z$2.array(z$2.object({field:z$2.string().describe("Property name from entity schema"),operator:z$2.enum(["eq","ne","gt","ge","lt","le","contains","startswith","endswith"]).describe("Filter operator"),value:z$2.union([z$2.string(),z$2.number(),z$2.boolean()]).describe("Filter value")})).describe("Structured filters from NL interpretation"),select:z$2.array(z$2.string()).optional().describe("Properties to return"),orderby:z$2.string().optional().describe("Sort expression"),top:z$2.number().optional().describe("Maximum number of results"),skip:z$2.number().optional().describe("Number of results to skip")}),annotations:{readOnlyHint:true,destructiveHint:false,idempotentHint:true,openWorldHint:true}},async({serviceUrl:d,entitySet:l,filters:c,select:u,orderby:p,top:m,skip:g})=>{if(!K(l,n))return a(new Error(`Entity set '${l}' is not exposed. Configure --expose to include it.`));try{let f=o(d),S=(await f.getMetadata()).version,y=Xs(c,S),E=await f.query(l,{filter:y||void 0,select:u,orderby:p,top:m,skip:g});return {content:[{type:"text",text:JSON.stringify({version:S,generatedFilter:y||"(none)",results:E.results,count:E.count,nextLink:E.nextLink},null,2)}]}}catch(f){return a(f)}});}function Zs(t,e,n,r){let s=r??new I,i=new Map;function o(l){let c=j(l),u=i.get(c);return u||(u=new $(e,c,s),i.set(c,u)),u}function a(l,c){return _(l,{serviceUrl:c})}function d(l){return K(l,n)?null:a(new Error(`Entity set '${l}' is not exposed. Configure --expose to include it.`))}t.registerTool("sap_read",{title:"Read SAP Entity",description:`Read a single entity or entity collection from SAP. Use key parameter for single entity, omit for collection. Supports $select and $expand.
267
+ - You don't know which service to query (use sap://routing/{domain} first)`,inputSchema:z$2.object({serviceUrl:z$2.string().describe("OData service URL"),entitySet:z$2.string().describe("Entity set to query"),filters:z$2.array(z$2.object({field:z$2.string().describe("Property name from entity schema"),operator:z$2.enum(["eq","ne","gt","ge","lt","le","contains","startswith","endswith"]).describe("Filter operator"),value:z$2.union([z$2.string(),z$2.number(),z$2.boolean()]).describe("Filter value")})).describe("Structured filters from NL interpretation"),select:z$2.array(z$2.string()).optional().describe("Properties to return"),orderby:z$2.string().optional().describe("Sort expression"),top:z$2.number().optional().describe("Maximum number of results"),skip:z$2.number().optional().describe("Number of results to skip")}),annotations:{readOnlyHint:true,destructiveHint:false,idempotentHint:true,openWorldHint:true}},async({serviceUrl:d,entitySet:l,filters:c,select:u,orderby:p,top:m,skip:f})=>{if(!z(l,n))return a(new Error(`Entity set '${l}' is not exposed. Configure --expose to include it.`));try{let g=o(d),b=(await g.getMetadata()).version,y=ai(c,b),E=await g.query(l,{filter:y||void 0,select:u,orderby:p,top:m,skip:f});return {content:[{type:"text",text:JSON.stringify({version:b,generatedFilter:y||"(none)",results:E.results,count:E.count,nextLink:E.nextLink},null,2)}]}}catch(g){return a(g)}});}function di(t,e,n,r){let s=r??new I,i=new Map;function o(l){let c=j(l),u=i.get(c);return u||(u=new $(e,c,s),i.set(c,u)),u}function a(l,c){return _(l,{serviceUrl:c})}function d(l){return z(l,n)?null:a(new Error(`Entity set '${l}' is not exposed. Configure --expose to include it.`))}t.registerTool("sap_read",{title:"Read SAP Entity",description:`Read a single entity or entity collection from SAP. Use key parameter for single entity, omit for collection. Supports $select and $expand.
268
268
 
269
269
  **When to use:**
270
270
  - You have a specific entity key and want one record
@@ -272,7 +272,7 @@ Fiori draft services (V2, e.g. purchase requisitions): activate a draft with the
272
272
 
273
273
  **When NOT to use:**
274
274
  - You want to list/filter multiple entities (use sap_query)
275
- - You don't know the entity key (query first, then read)`,inputSchema:z$2.object({serviceUrl:z$2.string().describe("OData service URL"),entitySet:z$2.string().describe("Entity set name, e.g., A_BusinessPartner"),key:z$2.record(z$2.string(),z$2.unknown()).optional().describe('Entity key as object, e.g., { BusinessPartner: "1000001" }. Draft entities: { PurchaseRequisition: "10000001", DraftUUID: "<uuid>", IsActiveEntity: true }'),select:z$2.array(z$2.string()).optional().describe("Properties to return"),expand:z$2.array(z$2.string()).optional().describe("Navigation properties to expand")}),annotations:{readOnlyHint:true,destructiveHint:false,idempotentHint:true,openWorldHint:true}},async({serviceUrl:l,entitySet:c,key:u,select:p,expand:m})=>{let g=d(c);if(g)return g;try{let f=o(l),h={select:p,expand:m},S=await f.read(c,u,h);return {content:[{type:"text",text:JSON.stringify(S,null,2)}]}}catch(f){return a(f,l)}}),t.registerTool("sap_query",{title:"Query SAP Entities",description:`Query SAP entities with filter, sort, pagination. Returns matching entities with count. Per D-03: each query option is a separate typed parameter.
275
+ - You don't know the entity key (query first, then read)`,inputSchema:z$2.object({serviceUrl:z$2.string().describe("OData service URL"),entitySet:z$2.string().describe("Entity set name, e.g., A_BusinessPartner"),key:z$2.record(z$2.string(),z$2.unknown()).optional().describe('Entity key as object, e.g., { BusinessPartner: "1000001" }. Draft entities: { PurchaseRequisition: "10000001", DraftUUID: "<uuid>", IsActiveEntity: true }'),select:z$2.array(z$2.string()).optional().describe("Properties to return"),expand:z$2.array(z$2.string()).optional().describe("Navigation properties to expand")}),annotations:{readOnlyHint:true,destructiveHint:false,idempotentHint:true,openWorldHint:true}},async({serviceUrl:l,entitySet:c,key:u,select:p,expand:m})=>{let f=d(c);if(f)return f;try{let g=o(l),h={select:p,expand:m},b=await g.read(c,u,h);return {content:[{type:"text",text:JSON.stringify(b,null,2)}]}}catch(g){return a(g,l)}}),t.registerTool("sap_query",{title:"Query SAP Entities",description:`Query SAP entities with filter, sort, pagination. Returns matching entities with count. Per D-03: each query option is a separate typed parameter.
276
276
 
277
277
  **When to use:**
278
278
  - You have an exact OData $filter string ready
@@ -282,7 +282,7 @@ Fiori draft services (V2, e.g. purchase requisitions): activate a draft with the
282
282
  **When NOT to use:**
283
283
  - You have a natural language question (use sap_nl_query instead)
284
284
  - You don't know which service to query (use sap://routing/{domain} first, then sap_discover_services)
285
- - You need to create, update, or delete data (use sap_create/sap_update/sap_delete)`,inputSchema:z$2.object({serviceUrl:z$2.string().describe("OData service URL"),entitySet:z$2.string().describe("Entity set name"),filter:z$2.string().optional().describe(`OData $filter expression, e.g., "Country eq 'DE'"`),select:z$2.array(z$2.string()).optional().describe("Properties to return"),expand:z$2.array(z$2.string()).optional().describe("Navigation properties to expand"),orderby:z$2.string().optional().describe('Sort expression, e.g., "CreationDate desc"'),top:z$2.number().optional().describe(`Maximum number of results (default ${50}, hard cap ${1e3}). Omitting it does NOT mean "all" \u2014 use skip plus the nextSkip value from the response to page through.`),skip:z$2.number().optional().describe("Number of results to skip"),maxPages:z$2.number().optional().describe("Maximum pagination pages to follow (default: 10)")}),annotations:{readOnlyHint:true,destructiveHint:false,idempotentHint:true,openWorldHint:true}},async({serviceUrl:l,entitySet:c,filter:u,select:p,expand:m,orderby:g,top:f,skip:h,maxPages:S})=>{let y=d(c);if(y)return y;try{let E=o(l),b=Oe(f,h),v=await E.query(c,{filter:u,select:p,expand:m,orderby:g,top:b.top,skip:b.skip,maxPages:S}),M=Ie({returned:v.results.length,totalCount:v.count,paging:b,hasMoreHint:v.nextLink?!0:void 0});return {content:[{type:"text",text:JSON.stringify({...v,...M},null,2)}]}}catch(E){return a(E,l)}}),t.registerTool("sap_create",{title:"Create SAP Entity",description:"Create a new entity in SAP. Pass entity data as a JSON string in the data parameter. Use sap_get_metadata with entityType first to discover required fields.",inputSchema:z$2.object({serviceUrl:z$2.string().describe("OData service URL"),entitySet:z$2.string().describe("Entity set name"),data:z$2.string().describe(`Entity data as JSON string, e.g. '{"BusinessPartnerCategory": "2", "BusinessPartnerName": "Acme Corp", "Country": "DE"}'`)}),annotations:{readOnlyHint:false,destructiveHint:false,idempotentHint:false,openWorldHint:true}},async({serviceUrl:l,entitySet:c,data:u})=>{let p;try{p=JSON.parse(u);}catch{return {content:[{type:"text",text:JSON.stringify({error:"Invalid JSON in data parameter. Must be a valid JSON string.",example:'{"BusinessPartnerCategory": "2", "BusinessPartnerName": "Acme Corp"}'})}],isError:true}}let m=d(c);if(m)return m;try{let f=await o(l).create(c,p);return {content:[{type:"text",text:JSON.stringify({created:f},null,2)}]}}catch(g){return a(g,l)}}),t.registerTool("sap_update",{title:"Update SAP Entity",description:"Update an existing SAP entity. Provide the entity key and the fields to update as JSON strings. ETag handling is automatic.",inputSchema:z$2.object({serviceUrl:z$2.string().describe("OData service URL"),entitySet:z$2.string().describe("Entity set name"),key:z$2.string().describe(`Entity key as JSON string, e.g. '{"BusinessPartner": "1000001"}'. Draft entities include DraftUUID and IsActiveEntity (boolean).`),data:z$2.string().describe(`Fields to update as JSON string, e.g. '{"BusinessPartnerName": "New Name"}'`)}),annotations:{readOnlyHint:false,destructiveHint:false,idempotentHint:true,openWorldHint:true}},async({serviceUrl:l,entitySet:c,key:u,data:p})=>{let m,g;try{m=JSON.parse(u),g=JSON.parse(p);}catch{return a(new Error("Invalid JSON in key or data parameter"))}let f=d(c);if(f)return f;try{return await o(l).update(c,m,g),{content:[{type:"text",text:JSON.stringify({updated:!0,entitySet:c,key:u})}]}}catch(h){return a(h,l)}}),t.registerTool("sap_delete",{title:"Delete SAP Entity",description:"Delete an entity from SAP. Provide the entity key. ETag handling is automatic.",inputSchema:z$2.object({serviceUrl:z$2.string().describe("OData service URL"),entitySet:z$2.string().describe("Entity set name"),key:z$2.string().describe(`Entity key as JSON string, e.g. '{"BusinessPartner": "1000001"}'. Draft entities include DraftUUID and IsActiveEntity (boolean).`)}),annotations:{readOnlyHint:false,destructiveHint:true,idempotentHint:true,openWorldHint:true}},async({serviceUrl:l,entitySet:c,key:u})=>{let p;try{p=JSON.parse(u);}catch{return a(new Error("Invalid JSON in key parameter"))}let m=d(c);if(m)return m;try{return await o(l).delete(c,p),{content:[{type:"text",text:JSON.stringify({deleted:!0,entitySet:c,key:u})}]}}catch(g){return a(g,l)}});}function Ze(t){let e=t.RETURN??t.E_RETURN??null;if(e==null)return {messages:[],hasErrors:false,errorCount:0,warningCount:0};let r=(Array.isArray(e)?e:[e]).filter(a=>a!==null&&typeof a=="object").map(a=>vd(a)),s=r.filter(a=>a.type==="E"||a.type==="A").length,i=r.filter(a=>a.type==="W").length,o=s>0;return {messages:r,hasErrors:o,errorCount:s,warningCount:i}}function vd(t){let e=String(t.TYPE??"I");return {type:e==="S"||e==="I"||e==="W"||e==="E"||e==="A"?e:"I",id:String(t.ID??""),number:String(t.NUMBER??""),message:String(t.MESSAGE??""),messageV1:X(t.MESSAGE_V1),messageV2:X(t.MESSAGE_V2),messageV3:X(t.MESSAGE_V3),messageV4:X(t.MESSAGE_V4),parameter:X(t.PARAMETER),row:Ed(t.ROW),field:X(t.FIELD),system:X(t.SYSTEM),logNo:X(t.LOG_NO),logMsgNo:X(t.LOG_MSG_NO)}}function X(t){if(t==null)return;let e=String(t);return e===""?void 0:e}function Ed(t){if(t==null)return;let e=String(t);if(e==="")return;let n=Number.parseInt(e,10);return Number.isNaN(n)?void 0:n}function Qs(t){if(!(t instanceof Error))return {code:"UNKNOWN_RFC",message:typeof t=="string"?t:String(t),details:[],rawResponse:t};let e=t;switch(e.code){case "RFC_COMMUNICATION_FAILURE":case "RFC_LOGON_FAILURE":case "RFC_TIMEOUT":case "RFC_INVALID_HANDLE":case "RFC_CLOSED":case "RFC_AUTHORIZATION_FAILURE":case "RFC_AUTHENTICATION_FAILURE":case "RFC_CRYPTOLIB_FAILURE":case "RFC_IO_FAILURE":return {code:e.code,message:e.message,details:[],rawResponse:t};case "RFC_ABAP_MESSAGE":{let n={code:`${e.msgClass??"UNKNOWN"}-${e.msgNumber??"000"}`,message:e.message,severity:e.msgType==="E"||e.msgType==="A"||e.msgType==="X"?"error":e.msgType==="W"?"warning":"info"};return {code:`ABAP_MESSAGE:${e.msgClass??"UNKNOWN"}:${e.msgNumber??"000"}`,message:e.message,details:[n],rawResponse:t}}case "RFC_ABAP_EXCEPTION":return {code:`ABAP_CLASSIC:${e.key??"UNKNOWN"}`,message:e.message,details:[],rawResponse:t};case "RFC_ABAP_CLASS_EXCEPTION":return {code:`ABAP_CLASS:${e.classKey??"UNKNOWN"}`,message:e.message,details:[],rawResponse:t};case "RFC_EXTERNAL_FAILURE":case "RFC_ABAP_RUNTIME_FAILURE":return {code:"RFC_EXTERNAL_RUNTIME",message:e.message,details:[],rawResponse:t};default:return {code:"UNKNOWN_RFC",message:e.message,details:[],rawResponse:t}}}var Bt=null;async function ei(t){if(Bt)return true;try{return Bt=await import('node-rfc'),!0}catch(e){let n=e instanceof Error?e.message:String(e);return t.warn({err:n},"node-rfc not available \u2014 RFC/BAPI tools disabled"),t.warn("Install SAP NW RFC SDK 7.50+ from SAP Support Portal (https://support.sap.com/connectors)"),t.warn("Then run `npm install node-rfc` to enable RFC/BAPI tools"),false}}function ti(){if(!Bt)throw new Error("node-rfc not loaded \u2014 call tryLoadRfc() first");return Bt}var ni=6e4,Rd=5e3,Pd=2,kd=10,Ne=class extends Error{constructor(n){super(`Session ${n} expired or not found. Re-run sap_bapi_call to start a new session.`);this.sessionId=n;this.name="SessionNotFoundError";}},Ft=class{pool;sessions=new Map;logger;closed=false;constructor(e,n){let s=ti().Pool;this.pool=new s({connectionParameters:{...e},poolOptions:{low:Pd,high:kd}}),this.logger=n;}async callOnce(e,n){if(this.closed)throw new Error("RfcConnectionPool closed");let r=await this.pool.acquire();try{return await r.call(e,n)}finally{try{await this.pool.release(r);}catch(s){this.logger.warn({err:s},"rfc-pool: release after callOnce failed");}}}async callBapi(e,n,r){if(this.closed)throw new Error("RfcConnectionPool closed");let s;if(r){let o=this.sessions.get(r);if(!o)throw new Ne(r);this.refreshIdle(o),s=o;}else {let o=await this.pool.acquire();s=this.createSession(o);}return {result:await s.client.call(e,n),sessionId:s.id}}async commit(e,n){let r=this.sessions.get(e);if(!r)throw new Ne(e);clearTimeout(r.idleTimer);try{let s=n?{WAIT:"X"}:{},i=await r.client.call("BAPI_TRANSACTION_COMMIT",s),{hasErrors:o}=Ze(i);return {result:i,committed:!o,sessionId:e}}finally{this.sessions.delete(e);try{await this.pool.release(r.client);}catch(s){this.logger.warn({err:s},"rfc-pool: release after commit failed");}}}async closeAll(){if(this.closed)return;this.closed=true;let e=Date.now()+Rd;for(;this.sessions.size>0&&Date.now()<e;)await new Promise(n=>setTimeout(n,100));for(let n of this.sessions.values()){clearTimeout(n.idleTimer);try{await this.pool.release(n.client);}catch(r){this.logger.warn({err:r},"rfc-pool: force-release on closeAll failed");}}this.sessions.clear(),await this.pool.closeAll();}sessionCount(){return this.sessions.size}createSession(e){let n=randomUUID(),r={id:n,client:e,createdAt:new Date,idleTimer:setTimeout(()=>this.onIdle(n),ni)};return this.sessions.set(n,r),r}refreshIdle(e){clearTimeout(e.idleTimer),e.idleTimer=setTimeout(()=>this.onIdle(e.id),ni);}async onIdle(e){let n=this.sessions.get(e);if(n){this.sessions.delete(e);try{await this.pool.release(n.client);}catch(r){this.logger.warn({err:r,sessionId:e},"rfc-pool: release on idle-timeout failed");}}}};function Qe(t){if(t instanceof Ne)return {content:[{type:"text",text:JSON.stringify({code:"SESSION_NOT_FOUND",message:t.message,sessionId:t.sessionId})}],isError:true};let e=Qs(t);return {content:[{type:"text",text:JSON.stringify(e)}],isError:true}}var _d={I:"IMPORT",E:"EXPORT",C:"CHANGING",T:"TABLES",X:"EXCEPTION"};function ri(t,e,n){t.registerTool("sap_rfc_call",{title:"Call SAP RFC Function Module",description:`Invoke any RFC-enabled function module on the SAP backend.
285
+ - You need to create, update, or delete data (use sap_create/sap_update/sap_delete)`,inputSchema:z$2.object({serviceUrl:z$2.string().describe("OData service URL"),entitySet:z$2.string().describe("Entity set name"),filter:z$2.string().optional().describe(`OData $filter expression, e.g., "Country eq 'DE'"`),select:z$2.array(z$2.string()).optional().describe("Properties to return"),expand:z$2.array(z$2.string()).optional().describe("Navigation properties to expand"),orderby:z$2.string().optional().describe('Sort expression, e.g., "CreationDate desc"'),top:z$2.number().optional().describe(`Maximum number of results (default ${50}, hard cap ${1e3}). Omitting it does NOT mean "all" \u2014 use skip plus the nextSkip value from the response to page through.`),skip:z$2.number().optional().describe("Number of results to skip"),maxPages:z$2.number().optional().describe("Maximum pagination pages to follow (default: 10)")}),annotations:{readOnlyHint:true,destructiveHint:false,idempotentHint:true,openWorldHint:true}},async({serviceUrl:l,entitySet:c,filter:u,select:p,expand:m,orderby:f,top:g,skip:h,maxPages:b})=>{let y=d(c);if(y)return y;try{let E=o(l),S=Ie(g,h),v=await E.query(c,{filter:u,select:p,expand:m,orderby:f,top:S.top,skip:S.skip,maxPages:b}),x=Ne({returned:v.results.length,totalCount:v.count,paging:S,hasMoreHint:v.nextLink?!0:void 0});return {content:[{type:"text",text:JSON.stringify({...v,...x},null,2)}]}}catch(E){return a(E,l)}}),t.registerTool("sap_create",{title:"Create SAP Entity",description:"Create a new entity in SAP. Pass entity data as a JSON string in the data parameter. Use sap_get_metadata with entityType first to discover required fields.",inputSchema:z$2.object({serviceUrl:z$2.string().describe("OData service URL"),entitySet:z$2.string().describe("Entity set name"),data:z$2.string().describe(`Entity data as JSON string, e.g. '{"BusinessPartnerCategory": "2", "BusinessPartnerName": "Acme Corp", "Country": "DE"}'`)}),annotations:{readOnlyHint:false,destructiveHint:false,idempotentHint:false,openWorldHint:true}},async({serviceUrl:l,entitySet:c,data:u})=>{let p;try{p=JSON.parse(u);}catch{return {content:[{type:"text",text:JSON.stringify({error:"Invalid JSON in data parameter. Must be a valid JSON string.",example:'{"BusinessPartnerCategory": "2", "BusinessPartnerName": "Acme Corp"}'})}],isError:true}}let m=d(c);if(m)return m;try{let g=await o(l).create(c,p);return {content:[{type:"text",text:JSON.stringify({created:g},null,2)}]}}catch(f){return a(f,l)}}),t.registerTool("sap_update",{title:"Update SAP Entity",description:"Update an existing SAP entity. Provide the entity key and the fields to update as JSON strings. ETag handling is automatic.",inputSchema:z$2.object({serviceUrl:z$2.string().describe("OData service URL"),entitySet:z$2.string().describe("Entity set name"),key:z$2.string().describe(`Entity key as JSON string, e.g. '{"BusinessPartner": "1000001"}'. Draft entities include DraftUUID and IsActiveEntity (boolean).`),data:z$2.string().describe(`Fields to update as JSON string, e.g. '{"BusinessPartnerName": "New Name"}'`)}),annotations:{readOnlyHint:false,destructiveHint:false,idempotentHint:true,openWorldHint:true}},async({serviceUrl:l,entitySet:c,key:u,data:p})=>{let m,f;try{m=JSON.parse(u),f=JSON.parse(p);}catch{return a(new Error("Invalid JSON in key or data parameter"))}let g=d(c);if(g)return g;try{return await o(l).update(c,m,f),{content:[{type:"text",text:JSON.stringify({updated:!0,entitySet:c,key:u})}]}}catch(h){return a(h,l)}}),t.registerTool("sap_delete",{title:"Delete SAP Entity",description:"Delete an entity from SAP. Provide the entity key. ETag handling is automatic.",inputSchema:z$2.object({serviceUrl:z$2.string().describe("OData service URL"),entitySet:z$2.string().describe("Entity set name"),key:z$2.string().describe(`Entity key as JSON string, e.g. '{"BusinessPartner": "1000001"}'. Draft entities include DraftUUID and IsActiveEntity (boolean).`)}),annotations:{readOnlyHint:false,destructiveHint:true,idempotentHint:true,openWorldHint:true}},async({serviceUrl:l,entitySet:c,key:u})=>{let p;try{p=JSON.parse(u);}catch{return a(new Error("Invalid JSON in key parameter"))}let m=d(c);if(m)return m;try{return await o(l).delete(c,p),{content:[{type:"text",text:JSON.stringify({deleted:!0,entitySet:c,key:u})}]}}catch(f){return a(f,l)}});}function tt(t){let e=t.RETURN??t.E_RETURN??null;if(e==null)return {messages:[],hasErrors:false,errorCount:0,warningCount:0};let r=(Array.isArray(e)?e:[e]).filter(a=>a!==null&&typeof a=="object").map(a=>Md(a)),s=r.filter(a=>a.type==="E"||a.type==="A").length,i=r.filter(a=>a.type==="W").length,o=s>0;return {messages:r,hasErrors:o,errorCount:s,warningCount:i}}function Md(t){let e=String(t.TYPE??"I");return {type:e==="S"||e==="I"||e==="W"||e==="E"||e==="A"?e:"I",id:String(t.ID??""),number:String(t.NUMBER??""),message:String(t.MESSAGE??""),messageV1:Z(t.MESSAGE_V1),messageV2:Z(t.MESSAGE_V2),messageV3:Z(t.MESSAGE_V3),messageV4:Z(t.MESSAGE_V4),parameter:Z(t.PARAMETER),row:Ud(t.ROW),field:Z(t.FIELD),system:Z(t.SYSTEM),logNo:Z(t.LOG_NO),logMsgNo:Z(t.LOG_MSG_NO)}}function Z(t){if(t==null)return;let e=String(t);return e===""?void 0:e}function Ud(t){if(t==null)return;let e=String(t);if(e==="")return;let n=Number.parseInt(e,10);return Number.isNaN(n)?void 0:n}function li(t){if(!(t instanceof Error))return {code:"UNKNOWN_RFC",message:typeof t=="string"?t:String(t),details:[],rawResponse:t};let e=t;switch(e.code){case "RFC_COMMUNICATION_FAILURE":case "RFC_LOGON_FAILURE":case "RFC_TIMEOUT":case "RFC_INVALID_HANDLE":case "RFC_CLOSED":case "RFC_AUTHORIZATION_FAILURE":case "RFC_AUTHENTICATION_FAILURE":case "RFC_CRYPTOLIB_FAILURE":case "RFC_IO_FAILURE":return {code:e.code,message:e.message,details:[],rawResponse:t};case "RFC_ABAP_MESSAGE":{let n={code:`${e.msgClass??"UNKNOWN"}-${e.msgNumber??"000"}`,message:e.message,severity:e.msgType==="E"||e.msgType==="A"||e.msgType==="X"?"error":e.msgType==="W"?"warning":"info"};return {code:`ABAP_MESSAGE:${e.msgClass??"UNKNOWN"}:${e.msgNumber??"000"}`,message:e.message,details:[n],rawResponse:t}}case "RFC_ABAP_EXCEPTION":return {code:`ABAP_CLASSIC:${e.key??"UNKNOWN"}`,message:e.message,details:[],rawResponse:t};case "RFC_ABAP_CLASS_EXCEPTION":return {code:`ABAP_CLASS:${e.classKey??"UNKNOWN"}`,message:e.message,details:[],rawResponse:t};case "RFC_EXTERNAL_FAILURE":case "RFC_ABAP_RUNTIME_FAILURE":return {code:"RFC_EXTERNAL_RUNTIME",message:e.message,details:[],rawResponse:t};default:return {code:"UNKNOWN_RFC",message:e.message,details:[],rawResponse:t}}}var Wt=null;async function ui(t){if(Wt)return true;try{return Wt=await import('node-rfc'),!0}catch(e){let n=e instanceof Error?e.message:String(e);return t.warn({err:n},"node-rfc not available \u2014 RFC/BAPI tools disabled"),t.warn("Install SAP NW RFC SDK 7.50+ from SAP Support Portal (https://support.sap.com/connectors)"),t.warn("Then run `npm install node-rfc` to enable RFC/BAPI tools"),false}}function pi(){if(!Wt)throw new Error("node-rfc not loaded \u2014 call tryLoadRfc() first");return Wt}var mi=6e4,Ld=5e3,Bd=2,Fd=10,xe=class extends Error{constructor(n){super(`Session ${n} expired or not found. Re-run sap_bapi_call to start a new session.`);this.sessionId=n;this.name="SessionNotFoundError";}},Gt=class{pool;sessions=new Map;logger;closed=false;constructor(e,n){let s=pi().Pool;this.pool=new s({connectionParameters:{...e},poolOptions:{low:Bd,high:Fd}}),this.logger=n;}async callOnce(e,n){if(this.closed)throw new Error("RfcConnectionPool closed");let r=await this.pool.acquire();try{return await r.call(e,n)}finally{try{await this.pool.release(r);}catch(s){this.logger.warn({err:s},"rfc-pool: release after callOnce failed");}}}async callBapi(e,n,r){if(this.closed)throw new Error("RfcConnectionPool closed");let s;if(r){let o=this.sessions.get(r);if(!o)throw new xe(r);this.refreshIdle(o),s=o;}else {let o=await this.pool.acquire();s=this.createSession(o);}return {result:await s.client.call(e,n),sessionId:s.id}}async commit(e,n){let r=this.sessions.get(e);if(!r)throw new xe(e);clearTimeout(r.idleTimer);try{let s=n?{WAIT:"X"}:{},i=await r.client.call("BAPI_TRANSACTION_COMMIT",s),{hasErrors:o}=tt(i);return {result:i,committed:!o,sessionId:e}}finally{this.sessions.delete(e);try{await this.pool.release(r.client);}catch(s){this.logger.warn({err:s},"rfc-pool: release after commit failed");}}}async closeAll(){if(this.closed)return;this.closed=true;let e=Date.now()+Ld;for(;this.sessions.size>0&&Date.now()<e;)await new Promise(n=>setTimeout(n,100));for(let n of this.sessions.values()){clearTimeout(n.idleTimer);try{await this.pool.release(n.client);}catch(r){this.logger.warn({err:r},"rfc-pool: force-release on closeAll failed");}}this.sessions.clear(),await this.pool.closeAll();}sessionCount(){return this.sessions.size}createSession(e){let n=randomUUID(),r={id:n,client:e,createdAt:new Date,idleTimer:setTimeout(()=>this.onIdle(n),mi)};return this.sessions.set(n,r),r}refreshIdle(e){clearTimeout(e.idleTimer),e.idleTimer=setTimeout(()=>this.onIdle(e.id),mi);}async onIdle(e){let n=this.sessions.get(e);if(n){this.sessions.delete(e);try{await this.pool.release(n.client);}catch(r){this.logger.warn({err:r,sessionId:e},"rfc-pool: release on idle-timeout failed");}}}};function nt(t){if(t instanceof xe)return {content:[{type:"text",text:JSON.stringify({code:"SESSION_NOT_FOUND",message:t.message,sessionId:t.sessionId})}],isError:true};let e=li(t);return {content:[{type:"text",text:JSON.stringify(e)}],isError:true}}var Hd={I:"IMPORT",E:"EXPORT",C:"CHANGING",T:"TABLES",X:"EXCEPTION"};function fi(t,e,n){t.registerTool("sap_rfc_call",{title:"Call SAP RFC Function Module",description:`Invoke any RFC-enabled function module on the SAP backend.
286
286
 
287
287
  When to use:
288
288
  - Custom Z_* function modules (no BAPI commit needed)
@@ -292,7 +292,7 @@ When NOT to use:
292
292
  - For BAPIs that need transactional commit -> use sap_bapi_call + sap_bapi_commit instead
293
293
  - sap_rfc_call is STATELESS: it CANNOT participate in BAPI commit transactions. If you need BAPI_TRANSACTION_COMMIT after this call, the function module must be invoked via sap_bapi_call.
294
294
 
295
- The function module must be flagged Remote-Enabled in SE37. Returns the raw output parameters from node-rfc (UPPERCASE keys). SAP date/time/decimal types come as strings (e.g. '20260427', '143052', '1234.56') \u2014 see README for type-mapping notes.`,inputSchema:z$2.object({functionModule:z$2.string().min(1).describe("Function module name, e.g. RFC_PING, RFC_READ_TABLE, Z_CUSTOM_FM"),parameters:z$2.record(z$2.string(),z$2.unknown()).optional().describe('IMPORT/CHANGING/TABLES parameters as ABAP-uppercase keys, e.g. { QUERY_TABLE: "T001", DELIMITER: "|" }')}),annotations:{readOnlyHint:false,destructiveHint:false,idempotentHint:false,openWorldHint:true}},async({functionModule:r,parameters:s})=>{try{let i=await e.callOnce(r.toUpperCase(),s??{});return {content:[{type:"text",text:JSON.stringify(i,null,2)}]}}catch(i){return Qe(i)}}),t.registerTool("sap_rfc_metadata",{title:"Get SAP RFC Function Module Interface",description:`Retrieve the IMPORT/EXPORT/CHANGING/TABLES/EXCEPTIONS interface of an RFC-enabled function module (via RFC_GET_FUNCTION_INTERFACE).
295
+ The function module must be flagged Remote-Enabled in SE37. Returns the raw output parameters from node-rfc (UPPERCASE keys). SAP date/time/decimal types come as strings (e.g. '20260427', '143052', '1234.56') \u2014 see README for type-mapping notes.`,inputSchema:z$2.object({functionModule:z$2.string().min(1).describe("Function module name, e.g. RFC_PING, RFC_READ_TABLE, Z_CUSTOM_FM"),parameters:z$2.record(z$2.string(),z$2.unknown()).optional().describe('IMPORT/CHANGING/TABLES parameters as ABAP-uppercase keys, e.g. { QUERY_TABLE: "T001", DELIMITER: "|" }')}),annotations:{readOnlyHint:false,destructiveHint:false,idempotentHint:false,openWorldHint:true}},async({functionModule:r,parameters:s})=>{try{let i=await e.callOnce(r.toUpperCase(),s??{});return {content:[{type:"text",text:JSON.stringify(i,null,2)}]}}catch(i){return nt(i)}}),t.registerTool("sap_rfc_metadata",{title:"Get SAP RFC Function Module Interface",description:`Retrieve the IMPORT/EXPORT/CHANGING/TABLES/EXCEPTIONS interface of an RFC-enabled function module (via RFC_GET_FUNCTION_INTERFACE).
296
296
 
297
297
  When to use:
298
298
  - Before calling an unfamiliar RFC/BAPI to understand its parameters
@@ -301,7 +301,7 @@ When to use:
301
301
  When NOT to use:
302
302
  - To search for function modules by name pattern -> use sap_rfc_search_functions
303
303
 
304
- Returns a structured FunctionInterface object: name, remoteEnabled, updateTask, parameters[].`,inputSchema:z$2.object({functionModule:z$2.string().min(1).describe("Function module name, e.g. BAPI_USER_GET_DETAIL"),language:z$2.string().length(1).optional().describe("Single-character language key for parameter texts (default: server config)")}),annotations:{readOnlyHint:true,destructiveHint:false,idempotentHint:true,openWorldHint:true}},async({functionModule:r,language:s})=>{try{let i=r.toUpperCase(),o={FUNCNAME:i};s&&(o.LANGUAGE=s);let a=await e.callOnce("RFC_GET_FUNCTION_INTERFACE",o),l=(a.PARAMS??[]).map(u=>{let p=String(u.PARAMCLASS??"").trim(),m=_d[p]??"IMPORT",g=String(u.TABNAME??"").trim(),f=String(u.FIELDNAME??"").trim(),h=g&&f?`${g}-${f}`:g||f||void 0,S=String(u.DECIMALS??"").trim(),y=S===""?void 0:Number.parseInt(S,10),E=Number.isNaN(y)?void 0:y,b=String(u.INTLENGTH??"0").trim(),v=Number.parseInt(b===""?"0":b,10)||0,M=String(u.DEFAULT??"").trim(),fe=String(u.PARAMTEXT??"").trim();return {name:String(u.PARAMETER??"").trim(),direction:m,type:String(u.EXID??"").trim(),length:v,decimals:E,optional:String(u.OPTIONAL??"").trim()==="X",default:M===""?void 0:M,text:fe===""?void 0:fe,ddicReference:h}}),c={name:i,remoteEnabled:String(a.REMOTE_CALL??"")==="X",updateTask:String(a.UPDATE_TASK??"")==="X",parameters:l};return {content:[{type:"text",text:JSON.stringify(c,null,2)}]}}catch(i){return Qe(i)}}),t.registerTool("sap_bapi_call",{title:"Call SAP BAPI (stateful)",description:`Invoke a BAPI (Business API) on a stateful connection. Returns a sessionId for subsequent BAPI calls and the eventual sap_bapi_commit.
304
+ Returns a structured FunctionInterface object: name, remoteEnabled, updateTask, parameters[].`,inputSchema:z$2.object({functionModule:z$2.string().min(1).describe("Function module name, e.g. BAPI_USER_GET_DETAIL"),language:z$2.string().length(1).optional().describe("Single-character language key for parameter texts (default: server config)")}),annotations:{readOnlyHint:true,destructiveHint:false,idempotentHint:true,openWorldHint:true}},async({functionModule:r,language:s})=>{try{let i=r.toUpperCase(),o={FUNCNAME:i};s&&(o.LANGUAGE=s);let a=await e.callOnce("RFC_GET_FUNCTION_INTERFACE",o),l=(a.PARAMS??[]).map(u=>{let p=String(u.PARAMCLASS??"").trim(),m=Hd[p]??"IMPORT",f=String(u.TABNAME??"").trim(),g=String(u.FIELDNAME??"").trim(),h=f&&g?`${f}-${g}`:f||g||void 0,b=String(u.DECIMALS??"").trim(),y=b===""?void 0:Number.parseInt(b,10),E=Number.isNaN(y)?void 0:y,S=String(u.INTLENGTH??"0").trim(),v=Number.parseInt(S===""?"0":S,10)||0,x=String(u.DEFAULT??"").trim(),G=String(u.PARAMTEXT??"").trim();return {name:String(u.PARAMETER??"").trim(),direction:m,type:String(u.EXID??"").trim(),length:v,decimals:E,optional:String(u.OPTIONAL??"").trim()==="X",default:x===""?void 0:x,text:G===""?void 0:G,ddicReference:h}}),c={name:i,remoteEnabled:String(a.REMOTE_CALL??"")==="X",updateTask:String(a.UPDATE_TASK??"")==="X",parameters:l};return {content:[{type:"text",text:JSON.stringify(c,null,2)}]}}catch(i){return nt(i)}}),t.registerTool("sap_bapi_call",{title:"Call SAP BAPI (stateful)",description:`Invoke a BAPI (Business API) on a stateful connection. Returns a sessionId for subsequent BAPI calls and the eventual sap_bapi_commit.
305
305
 
306
306
  When to use:
307
307
  - BAPI_USER_CREATE1, BAPI_SALESORDER_CREATEFROMDAT2, BAPI_*_CHANGE, etc.
@@ -314,7 +314,7 @@ Critical behavior:
314
314
  - The output contains a parsed \`return\` array (BAPIRET2 messages, camelCase) plus \`hasErrors\`, \`errorCount\`, \`warningCount\`.
315
315
  - If hasErrors=true, do NOT call sap_bapi_commit. The session has not yet been committed; either call sap_bapi_call again with corrected params (sessionId reused) or let the session idle out (auto-rollback after 60s).
316
316
  - hasErrors=true is NOT isError=true at the MCP transport level (the call itself succeeded).
317
- - If sessionId is omitted, a fresh stateful connection is opened. Pass it back to chain BAPIs on the same connection before BAPI_TRANSACTION_COMMIT.`,inputSchema:z$2.object({bapi:z$2.string().min(1).describe("BAPI function module name, e.g. BAPI_USER_GET_DETAIL"),parameters:z$2.record(z$2.string(),z$2.unknown()).optional().describe("BAPI input parameters with ABAP-uppercase keys"),sessionId:z$2.string().uuid().optional().describe("Continue an existing session from a previous sap_bapi_call. Omit on first call.")}),annotations:{readOnlyHint:false,destructiveHint:false,idempotentHint:false,openWorldHint:true}},async({bapi:r,parameters:s,sessionId:i})=>{try{let{result:o,sessionId:a}=await e.callBapi(r.toUpperCase(),s??{},i),d=Ze(o),{RETURN:l,E_RETURN:c,...u}=o,p={},m={};for(let[g,f]of Object.entries(u))Array.isArray(f)?m[g]=f:p[g]=f;return {content:[{type:"text",text:JSON.stringify({sessionId:a,return:d.messages,hasErrors:d.hasErrors,errorCount:d.errorCount,warningCount:d.warningCount,exports:p,tables:m},null,2)}]}}catch(o){return Qe(o)}}),t.registerTool("sap_bapi_commit",{title:"Commit SAP BAPI Transaction",description:`Call BAPI_TRANSACTION_COMMIT on the SAME stateful connection used by a prior sap_bapi_call. Releases the session afterwards.
317
+ - If sessionId is omitted, a fresh stateful connection is opened. Pass it back to chain BAPIs on the same connection before BAPI_TRANSACTION_COMMIT.`,inputSchema:z$2.object({bapi:z$2.string().min(1).describe("BAPI function module name, e.g. BAPI_USER_GET_DETAIL"),parameters:z$2.record(z$2.string(),z$2.unknown()).optional().describe("BAPI input parameters with ABAP-uppercase keys"),sessionId:z$2.string().uuid().optional().describe("Continue an existing session from a previous sap_bapi_call. Omit on first call.")}),annotations:{readOnlyHint:false,destructiveHint:false,idempotentHint:false,openWorldHint:true}},async({bapi:r,parameters:s,sessionId:i})=>{try{let{result:o,sessionId:a}=await e.callBapi(r.toUpperCase(),s??{},i),d=tt(o),{RETURN:l,E_RETURN:c,...u}=o,p={},m={};for(let[f,g]of Object.entries(u))Array.isArray(g)?m[f]=g:p[f]=g;return {content:[{type:"text",text:JSON.stringify({sessionId:a,return:d.messages,hasErrors:d.hasErrors,errorCount:d.errorCount,warningCount:d.warningCount,exports:p,tables:m},null,2)}]}}catch(o){return nt(o)}}),t.registerTool("sap_bapi_commit",{title:"Commit SAP BAPI Transaction",description:`Call BAPI_TRANSACTION_COMMIT on the SAME stateful connection used by a prior sap_bapi_call. Releases the session afterwards.
318
318
 
319
319
  When to use:
320
320
  - After one or more sap_bapi_call invocations that returned hasErrors=false
@@ -323,7 +323,7 @@ When NOT to use:
323
323
  - If the prior sap_bapi_call returned hasErrors=true (commit would persist a faulty state \u2014 implicit rollback by letting the session idle is safer)
324
324
  - For non-BAPI RFC calls (sap_rfc_call cannot participate)
325
325
 
326
- Returns committed=true when BAPI_TRANSACTION_COMMIT returns no E/A messages.`,inputSchema:z$2.object({sessionId:z$2.string().uuid().describe("Session id from a prior sap_bapi_call"),wait:z$2.boolean().optional().default(true).describe("When true (default), waits for ABAP UPDATE-Task to complete (WAIT=X). When false, fire-and-forget (risky \u2014 failures only visible in SM58/SM37).")}),annotations:{readOnlyHint:false,destructiveHint:true,idempotentHint:false,openWorldHint:true}},async({sessionId:r,wait:s})=>{try{let{result:i,committed:o,sessionId:a}=await e.commit(r,s??!0),d=Ze(i);return {content:[{type:"text",text:JSON.stringify({sessionId:a,return:d.messages,committed:o},null,2)}]}}catch(i){return Qe(i)}}),t.registerTool("sap_rfc_search_functions",{title:"Search SAP RFC Function Modules",description:`Search for function modules by name pattern via RFC_FUNCTION_SEARCH.
326
+ Returns committed=true when BAPI_TRANSACTION_COMMIT returns no E/A messages.`,inputSchema:z$2.object({sessionId:z$2.string().uuid().describe("Session id from a prior sap_bapi_call"),wait:z$2.boolean().optional().default(true).describe("When true (default), waits for ABAP UPDATE-Task to complete (WAIT=X). When false, fire-and-forget (risky \u2014 failures only visible in SM58/SM37).")}),annotations:{readOnlyHint:false,destructiveHint:true,idempotentHint:false,openWorldHint:true}},async({sessionId:r,wait:s})=>{try{let{result:i,committed:o,sessionId:a}=await e.commit(r,s??!0),d=tt(i);return {content:[{type:"text",text:JSON.stringify({sessionId:a,return:d.messages,committed:o},null,2)}]}}catch(i){return nt(i)}}),t.registerTool("sap_rfc_search_functions",{title:"Search SAP RFC Function Modules",description:`Search for function modules by name pattern via RFC_FUNCTION_SEARCH.
327
327
 
328
328
  When to use:
329
329
  - Discover BAPIs/FMs by partial name (e.g. "BAPI_USER_*", "Z_*")
@@ -334,7 +334,7 @@ When NOT to use:
334
334
  Wildcards (SAP-native, NOT glob):
335
335
  - \`*\` matches any sequence of characters
336
336
  - \`+\` matches a single character
337
- Patterns are case-folded to uppercase. Default limit is 100; set higher to widen, but SAP returns unpaginated results \u2014 large patterns may stress the backend.`,inputSchema:z$2.object({pattern:z$2.string().min(1).describe('Name pattern with SAP wildcards (* and +). Examples: "BAPI_USER_*", "Z_*", "+MATERIAL+"'),groupName:z$2.string().optional().describe('Optional function group filter (RS38L_AREA, e.g. "SU05")'),limit:z$2.number().int().positive().optional().default(100).describe("Max number of hits to return (default 100). Excess is truncated.")}),annotations:{readOnlyHint:true,destructiveHint:false,idempotentHint:true,openWorldHint:true}},async({pattern:r,groupName:s,limit:i})=>{try{let o={FUNCNAME:r.toUpperCase()};s&&(o.GROUPNAME=s.toUpperCase());let d=(await e.callOnce("RFC_FUNCTION_SEARCH",o)).FUNCTIONS??[],l=d.length,c=i??100,u=l>c,g={functions:(u?d.slice(0,c):d).map(f=>{let h=String(f.TEXT??"").trim();return {name:String(f.FUNCNAME??"").trim(),groupName:String(f.GROUPNAME??"").trim(),shortText:h===""?void 0:h}}),total:l,...u?{truncated:!0}:{}};return {content:[{type:"text",text:JSON.stringify(g,null,2)}]}}catch(o){return Qe(o)}});}function Ht(t,e){let n=new McpServer({name:zr,version:ke},{capabilities:{logging:{},resources:{},prompts:{},tools:{listChanged:true}}}),r={readOnly:e?.readOnly??false,activeTiers:e?.tiers??wn,...e?.allowedTiers?{allowedTiers:e.allowedTiers}:{},hasIdocConfig:e?.hasIdocConfig??false,hasRfcConfig:e?.hasRfcConfig??false},s=new Ct(r),i=n.registerTool.bind(n),o=e?.toolTimeoutMs??Rt*1e3;n.registerTool=((h,...S)=>{let y=S.length-1,E=S[y];typeof E=="function"&&(S[y]=Jr(h,E,{toolTimeoutMs:o,logger:e?.logger,tlsVerifyDisabled:e?.httpOptions?.tlsVerify===false,...e?.governance?{governance:e.governance,destination:t.name,...e.callerIdentity?{callerIdentity:e.callerIdentity}:{}}:{}}));let b=i(h,...S);return s.registerHandle(h,b),b});let a={baseUrl:t.baseUrl,...e?.cacheDir?{persistDir:e.cacheDir}:{},...e?.logger?{onWarn:(h,S)=>e.logger?.warn({err:S},h)}:{}},d=e?.caches?.catalog??new Q(a),l=e?.caches?.metadata??new I(a),c=tt(t),u=new be(c,e?.httpOptions);e?.userContext&&(u.userContext=e.userContext);let p=e?.exposePatterns,m=e?.sapClient??t.sapClient;Qr(n),Zr(n),Fs(n,u,{baseUrl:t.baseUrl,sapClient:m,tlsVerify:e?.httpOptions?.tlsVerify}),Us(n,u,p),Ms(n,u,{catalogV2Url:e?.catalogV2Url,catalogV4Url:e?.catalogV4Url,baseUrl:t.baseUrl,onDiscoveryMatch:e?.onDiscoveryMatch,...e?.concurrency?{concurrency:e.concurrency}:{}},d),Zs(n,u,p,l),Bs(n,u,l,e?.readOnly??false),Ks(n,u,p),Ps(n,u,l),Js(n,u,p,l);let g=e?.idocStore??new Pe,f=new vt(u,m,e?.partnerDefaults);return Vs(n,u,f,g),As(n,g),e?.rfcAvailable&&e.rfcPool&&e.logger&&ri(n,e.rfcPool,e.logger),Ys(n,s),vs(n,u,l),ws(n,u,l),Cs(n),s.applyInitialVisibility(),{server:n,registry:s,httpClient:u}}var Id=z$1.object({snc_qop:z$1.enum(["1","2","3","8","9"]).optional(),snc_myname:z$1.string().min(1).optional(),snc_partnername:z$1.string().min(1).optional(),snc_lib:z$1.string().min(1).optional()}).superRefine((t,e)=>{let n=[t.snc_qop,t.snc_myname,t.snc_partnername,t.snc_lib].filter(r=>r!==void 0).length;if(n>0&&n<4){let r=[];t.snc_qop||r.push("SAP_SNC_QOP"),t.snc_myname||r.push("SAP_SNC_MYNAME"),t.snc_partnername||r.push("SAP_SNC_PARTNERNAME"),t.snc_lib||r.push("SAP_SNC_LIB"),e.addIssue({code:"custom",message:`SNC config incomplete: missing ${r.join(", ")} (D-12 all-or-none)`,path:["snc_qop"]});}});function Bn(t=process.env){let e=t.SAP_USERNAME,n=t.SAP_PASSWORD;if(!e||!n)return null;let r=!!(t.SAP_RFC_ASHOST&&t.SAP_RFC_SYSNR),s=!!(t.SAP_RFC_MSHOST&&t.SAP_RFC_GROUP);if(!r&&!s)return null;let i={user:e,passwd:n,client:t.SAP_CLIENT,lang:t.SAP_RFC_LANG??"EN"};r&&(i.ashost=t.SAP_RFC_ASHOST,i.sysnr=t.SAP_RFC_SYSNR),s&&(i.mshost=t.SAP_RFC_MSHOST,i.msserv=t.SAP_RFC_MSSERV,i.group=t.SAP_RFC_GROUP);let o=Id.safeParse({snc_qop:t.SAP_SNC_QOP,snc_myname:t.SAP_SNC_MYNAME,snc_partnername:t.SAP_SNC_PARTNERNAME,snc_lib:t.SAP_SNC_LIB});if(!o.success){let a=o.error.issues.map(d=>d.message).join("; ");throw new Error(`Invalid SNC configuration: ${a}`)}return o.data.snc_qop&&Object.assign(i,o.data),i}function Fn(t=process.env){try{return Bn(t)!==null}catch{return false}}var jt=class{constructor(e={}){this.options=e;this.discovery=e.discoveryClient??new oe;}discovery;jwks;jwksIssuer;get verifies(){return !!this.options.issuerUrl}async verify(e){let n=e.authorization??e.Authorization;if(typeof n!="string"||!n.startsWith("Bearer "))return {kind:"none"};let r=n.slice(7).trim();if(!r)return {kind:"none"};if(!this.options.issuerUrl)return this.withoutVerification(r);try{let s=await this.getKeySet(this.options.issuerUrl),{payload:i}=await jwtVerify(r,s,{issuer:void 0,...this.options.audience?{audience:this.options.audience}:{}});return typeof i.sub!="string"?{kind:"rejected",reason:"Token ohne sub-Claim"}:{kind:"user",context:{token:r,sub:i.sub,email:typeof i.email=="string"?i.email:void 0,name:typeof i.name=="string"?i.name:void 0,verified:!0}}}catch(s){return Md(r)?{kind:"rejected",reason:s instanceof Error?s.message:"Signaturpr\xFCfung fehlgeschlagen"}:{kind:"none"}}}withoutVerification(e){try{let n=decodeJwt(e);return typeof n.sub!="string"?{kind:"none"}:{kind:"user",context:{token:e,sub:n.sub,email:typeof n.email=="string"?n.email:void 0,name:typeof n.name=="string"?n.name:void 0,verified:!1}}}catch{return {kind:"none"}}}async getKeySet(e){if(this.jwks&&this.jwksIssuer===e)return this.jwks;let n=await this.discovery.discover(e);return this.jwks=createRemoteJWKSet(new URL(n.jwks_uri)),this.jwksIssuer=e,this.jwks}};function Md(t){let e=t.split(".");return e.length===3&&e.every(n=>n.length>0)}var Ud="x-sap-username",$d="x-sap-password",Ld="x-sap-authorization";function Hn(t,e){let n=t[e]??t[e.toLowerCase()],r=Array.isArray(n)?n[0]:n;return typeof r=="string"&&r.length>0?r:void 0}function Bd(t){let e=Hn(t,Ud),n=Hn(t,$d);if(e&&n)return {username:e,password:n};let r=Hn(t,Ld),s=r?/^Basic\s+(.+)$/i.exec(r.trim()):null;if(s?.[1]){let i=Buffer.from(s[1].trim(),"base64").toString("utf8"),o=i.indexOf(":");if(o>0&&o<i.length-1)return {username:i.slice(0,o),password:i.slice(o+1)}}}function si(t,e){let n=Bd(e);if(t.authType==="user-basic"){if(!n)return {kind:"missing",hint:`Destination "${t.name}" verlangt eine pers\xF6nliche SAP-Anmeldung: sende X-SAP-Username und X-SAP-Password (oder X-SAP-Authorization: Basic <base64 user:pass>) mit \u2014 im n8n-Node \u201EGuniWeb SAP" sind das die Felder SAP-Benutzer/SAP-Passwort des Credentials.`};let{name:r,baseUrl:s,sapClient:i}=t;return {kind:"ok",config:{name:r,baseUrl:s,authType:"basic",...i!==void 0?{sapClient:i}:{},username:n.username,password:n.password},username:n.username}}return n?{kind:"rejected",reason:`Destination "${t.name}" (authType ${t.authType}) nimmt keine pers\xF6nliche SAP-Anmeldung an \u2014 die Anfrage w\xFCrde unter dem konfigurierten technischen Zugang laufen. Lass X-SAP-Username/X-SAP-Password weg oder stelle die Destination auf authType user-basic um.`}:{kind:"ok",config:t}}var Fd=z$2.object({destination:z$2.string().min(1),label:z$2.string().max(200).optional(),readOnly:z$2.boolean().optional(),tiers:z$2.array(z$2.string()).optional()}).strict();function me(t,e,n){t.setHeader("Cache-Control","no-store"),t.status(e).json(n);}function ii(t){return t.ip??t.socket?.remoteAddress??"unknown"}function oi(t,e){let n=t?.[e];return n==="true"||n==="1"||n===""}function ai(t){t.use("/admin",(e,n)=>{me(n,404,{error:"Admin API not enabled",hint:"Start the server with --admin-token <secret> (or SAP_MCP_ADMIN_TOKEN) and --destinations <file>."});});}function ci(t,e){let{destinations:n,logger:r}=e,s=new ve({apiKey:e.adminToken,tokens:()=>[]});t.use("/admin",(d,l,c)=>{let u=d,p=l,m=ii(u),g=s.authenticate(u.headers.authorization,m);if(g.kind==="rate-limited"){r?.warn({clientAddress:m,path:u.originalUrl??u.path,retryAfterSeconds:g.retryAfterSeconds},"Admin-API: zu viele fehlgeschlagene Anmeldeversuche von dieser Adresse"),p.setHeader("Retry-After",String(g.retryAfterSeconds)),me(p,429,{error:"Too Many Requests",retryAfterSeconds:g.retryAfterSeconds});return}if(g.kind!=="api-key"){r?.warn({clientAddress:m,path:u.originalUrl??u.path},"Admin-API: Anfrage abgewiesen"),me(p,401,{error:"Unauthorized"});return}c();});let i=()=>{if(n.source!=="file"||!n.filePath)throw new P("Admin API requires a destinations file: start the server with --destinations <file>.",409);return new Ee({filePath:n.filePath,env:e.env})},o=(d,l)=>(c,u)=>{let p=c,m=u,g=ii(p);(async()=>{try{let{status:f,body:h,changed:S}=l(p);if(S){let y=await n.reload();h.reloaded=y.ok,y.ok||(h.reloadErrors=y.errors),r?.info({action:d,clientAddress:g,target:p.params?.name??p.params?.ref??p.body?.destination,reloaded:y.ok},"Admin-API: \xC4nderung ausgef\xFChrt");}me(m,f,h);}catch(f){if(f instanceof P){me(m,f.status,{error:f.message});return}r?.warn({action:d,clientAddress:g,err:f instanceof Error?f.message:String(f)},"Admin-API: unerwarteter Fehler"),me(m,500,{error:"Internal Server Error"});}})();},a=d=>{let l=d.body;if(l===null||typeof l!="object"||Array.isArray(l))throw new P("Request body must be a JSON object (Content-Type: application/json).",400);return l};t.get("/admin/destinations",o("destinations.list",()=>({status:200,body:{destinations:i().listDestinations()},changed:!1}))),t.put("/admin/destinations/:name",o("destinations.put",d=>{let l=d.params?.name??"",c=a(d),{replaced:u,warnings:p}=i().addDestination(l,c,{replace:!0,allowMissingEnv:oi(d.query,"allowMissingEnv")});return {status:u?200:201,body:{name:l,replaced:u,warnings:p},changed:!0}})),t.delete("/admin/destinations/:name",o("destinations.delete",d=>{let l=d.params?.name??"",{removedTokens:c}=i().removeDestination(l,{force:oi(d.query,"force")});return {status:200,body:{name:l,removedTokens:c},changed:!0}})),t.get("/admin/tokens",o("tokens.list",()=>({status:200,body:{tokens:i().listTokens()},changed:!1}))),t.post("/admin/tokens",o("tokens.issue",d=>{let l=Fd.safeParse(a(d));if(!l.success)throw new P(`Invalid body: ${l.error.issues.map(f=>`${f.path.join(".")||"(root)"}: ${f.message}`).join("; ")}`,400);let{destination:c,...u}=l.data,{token:p,hash:m,entry:g}=i().issueToken(c,u);return {status:201,body:{token:p,hash:m.replace(/^sha256:/,"").slice(0,12),destination:g.destination,label:g.label,policy:g.policy,createdAt:g.createdAt},changed:!0}})),t.delete("/admin/tokens/:ref",o("tokens.revoke",d=>{let l=d.params?.ref??"",c=i().revokeToken(l);return {status:200,body:{...c,revoked:!0},changed:!c.alreadyRevoked}})),t.use("/admin",(d,l)=>{me(l,404,{error:"Not Found"});});}var Vd=16*1024*1024;function Wd(t){let e=di();return e.use(di.json({limit:t})),e}function Gd(t,e){return e?.kind==="token"?t.destinations?.get(e.token.destination):t.destinations?t.destinations.defaultDestination():t.config}function qd(t,e){if(e?.kind!=="token"||!e.token.policy)return t;let n=e.token.policy;return {...t,readOnly:t.readOnly===true||n.readOnly===true,...n.tiers?{allowedTiers:[...n.tiers]}:{}}}function Kd(t,e){t.writeHead(503,{"Content-Type":"application/json"});let n=e?.names().length??0;t.end(JSON.stringify({error:"Keine Destination bestimmbar",hint:n===0?'Es ist noch keine Destination konfiguriert. Lege eine an \u2014 per Admin-API (PUT /admin/destinations/<name>) oder CLI (guniweb-sap-mcp destinations add) \u2014 und ein Token daf\xFCr, oder nenne sie "default".':'Es sind mehrere Destinations konfiguriert, aber keine hei\xDFt "default". Benenne eine Destination "default", lege Tokens an oder reduziere die Datei auf ein Ziel.'}));}var jn=class t{constructor(e){this.persistDir=e;}entries=new Map;static MAX_USER_SCOPES=100;for(e,n){let r=`${e.name}\0${e.baseUrl}\0${n??""}`,s=this.entries.get(r);if(!s){for(let o of this.entries.keys())o.startsWith(`${e.name}\0`)&&!o.startsWith(`${e.name}\0${e.baseUrl}\0`)&&this.entries.delete(o);n!==void 0&&this.evictOldestUserScopes(e);let i={baseUrl:e.baseUrl,...this.persistDir&&n===void 0?{persistDir:this.persistDir}:{}};s={catalog:new Q(i),metadata:new I(i)},this.entries.set(r,s);}return s}evictOldestUserScopes(e){let n=`${e.name}\0${e.baseUrl}\0`,r=[...this.entries.keys()].filter(s=>s.startsWith(n)&&s!==n);for(;r.length>=t.MAX_USER_SCOPES;)this.entries.delete(r.shift());}};function zd(t,e){if(e.kind==="missing"){t.writeHead(401,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"SAP login required",hint:e.hint}));return}t.writeHead(400,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:e.reason}));}function Yd(t,e,n){let r=t?.kind==="token"?"token":t?.kind==="api-key"?"api-key":"open",s=n?n.email??n.sub:void 0;return {authKind:r,...t?.kind==="token"?{tokenLabel:t.token.label??t.token.hash.slice(7,19)}:{},...e?{sapUser:e}:{},...s?{subject:s,subjectVerified:n?.verified===true}:{},personal:!!(e||s)}}function Xd(t,e){let n=t.logger;return !e||!n||typeof n.child!="function"?t:{...t,logger:n.child({sapUser:e})}}async function li(t){let e=new jt({...t.jwtIssuer?{issuerUrl:t.jwtIssuer}:{},...t.jwtAudience?{audience:t.jwtAudience}:{}}),n=t.maxRequestBytes??Vd,r=Wd(n),s=new ve({apiKey:t.apiKey,tokens:()=>t.destinations?.tokens()??[]}),i=t.serverOptions?.logger;r.use((d,l,c)=>{let u=d,p=l,m=c;if(u.path==="/healthz"){m();return}if(u.path==="/admin"||u.path.startsWith("/admin/")){m();return}if(t.webhookSecret&&u.path==="/idoc"){m();return}let g=u.ip??u.socket?.remoteAddress??"unknown",f=s.authenticate(u.headers.authorization,g);if(f.kind==="rate-limited"){i?.warn({clientAddress:g,path:u.path,retryAfterSeconds:f.retryAfterSeconds},"MCP-Anfrage abgewiesen: zu viele fehlgeschlagene Anmeldeversuche von dieser Adresse"),p.setHeader("Retry-After",String(f.retryAfterSeconds)),p.status(429).json({error:"Too Many Requests",retryAfterSeconds:f.retryAfterSeconds});return}if(f.kind==="rejected"){i?.warn({clientAddress:g,path:u.path,reason:f.reason},"MCP-Anfrage abgewiesen"),p.status(401).json({error:"Unauthorized"});return}u.sapAuth=f,m();}),r.get("/healthz",(d,l)=>{l.status(200).json({status:"ok",governance:t.governanceHealth?.()??{active:false}});}),t.adminToken&&t.destinations?ci(r,{adminToken:t.adminToken,destinations:t.destinations,env:t.env??process.env,logger:i}):ai(r),Jd(r,t,e);let o=Tt(t.idocStore,{secret:t.webhookSecret,maxBodyBytes:t.webhookMaxBodyBytes});r.post("/idoc",(d,l)=>{o(d,l);}),r.use((d,l,c,u)=>{let p=d,m=c;if(p?.type==="entity.parse.failed"&&!m.headersSent){m.status(400).json({error:`Invalid JSON body: ${p.message??"parse error"}`});return}if(p?.type==="entity.too.large"&&!m.headersSent){let g=(n/1024/1024).toFixed(1);m.status(413).json({error:`Anfrage zu gro\xDF: die Grenze liegt bei ${n} Bytes (${g} MiB). Bei einem base64-kodierten Anhang sind das rund ${(n*3/4/1024/1024).toFixed(1)} MiB Datei. Mit --max-request-bytes anheben.`});return}u(d);});let a=createServer(r);return new Promise(d=>{a.listen(t.port,()=>{let l=a.address(),c=typeof l=="object"&&l!==null?l.port:t.port;d({port:c,close:()=>new Promise((u,p)=>{a.close(m=>m?p(m):u());})});});})}function Jd(t,e,n){let r=new jn(e.serverOptions?.cacheDir),s=e.serverOptions?.logger;t.all("/mcp",(i,o)=>{let a=i,d=o,l=Gd(e,a.sapAuth);if(!l){Kd(d,e.destinations);return}let c=si(l,a.headers);if(c.kind!=="ok"){s?.warn({destination:l.name,clientAddress:a.socket?.remoteAddress,reason:c.kind},c.kind==="missing"?"MCP-Anfrage ohne pers\xF6nliche SAP-Anmeldung an eine user-basic-Destination abgewiesen":"MCP-Anfrage mit pers\xF6nlicher SAP-Anmeldung an eine Destination mit technischem Benutzer abgewiesen"),zd(d,c);return}let u=c.config,p=c.username,m=new StreamableHTTPServerTransport({sessionIdGenerator:void 0}),g=f=>{let{server:h}=Ht(u,{...qd(Xd(e.serverOptions,p),a.sapAuth),sapClient:u.sapClient,userContext:f,caches:r.for(u,p),callerIdentity:Yd(a.sapAuth,p,f)});h.connect(m).then(()=>m.handleRequest(a,d,a.body)).catch(()=>{d.headersSent||(d.writeHead(500),d.end("Internal Server Error"));});};n.verify(a.headers).then(f=>{if(f.kind==="rejected"){d.writeHead(401,{"Content-Type":"application/json"}),d.end(JSON.stringify({error:"Unauthorized",reason:f.reason,hint:"Das mitgeschickte Bearer-Token hat die Signaturpr\xFCfung gegen SAP_JWT_ISSUER nicht bestanden."}));return}let h=f.kind==="user"?f.context:null;g(h);});});}var tl=`Usage: guniweb-sap-mcp [options]
337
+ Patterns are case-folded to uppercase. Default limit is 100; set higher to widen, but SAP returns unpaginated results \u2014 large patterns may stress the backend.`,inputSchema:z$2.object({pattern:z$2.string().min(1).describe('Name pattern with SAP wildcards (* and +). Examples: "BAPI_USER_*", "Z_*", "+MATERIAL+"'),groupName:z$2.string().optional().describe('Optional function group filter (RS38L_AREA, e.g. "SU05")'),limit:z$2.number().int().positive().optional().default(100).describe("Max number of hits to return (default 100). Excess is truncated.")}),annotations:{readOnlyHint:true,destructiveHint:false,idempotentHint:true,openWorldHint:true}},async({pattern:r,groupName:s,limit:i})=>{try{let o={FUNCNAME:r.toUpperCase()};s&&(o.GROUPNAME=s.toUpperCase());let d=(await e.callOnce("RFC_FUNCTION_SEARCH",o)).FUNCTIONS??[],l=d.length,c=i??100,u=l>c,f={functions:(u?d.slice(0,c):d).map(g=>{let h=String(g.TEXT??"").trim();return {name:String(g.FUNCNAME??"").trim(),groupName:String(g.GROUPNAME??"").trim(),shortText:h===""?void 0:h}}),total:l,...u?{truncated:!0}:{}};return {content:[{type:"text",text:JSON.stringify(f,null,2)}]}}catch(o){return nt(o)}});}function qt(t,e){let n=new McpServer({name:is,version:X},{capabilities:{logging:{},resources:{},prompts:{},tools:{listChanged:true}}}),r={readOnly:e?.readOnly??false,activeTiers:e?.tiers??Rn,...e?.allowedTiers?{allowedTiers:e.allowedTiers}:{},hasIdocConfig:e?.hasIdocConfig??false,hasRfcConfig:e?.hasRfcConfig??false},s=new Ot(r),i=n.registerTool.bind(n),o=e?.toolTimeoutMs??It*1e3;n.registerTool=((h,...b)=>{let y=b.length-1,E=b[y];typeof E=="function"&&(b[y]=cs(h,E,{toolTimeoutMs:o,logger:e?.logger,tlsVerifyDisabled:e?.httpOptions?.tlsVerify===false,...e?.governance?{governance:e.governance,destination:t.name,...e.callerIdentity?{callerIdentity:e.callerIdentity}:{}}:{}}));let S=i(h,...b);return s.registerHandle(h,S),S});let a={baseUrl:t.baseUrl,...e?.cacheDir?{persistDir:e.cacheDir}:{},...e?.logger?{onWarn:(h,b)=>e.logger?.warn({err:b},h)}:{}},d=e?.caches?.catalog??new re(a),l=e?.caches?.metadata??new I(a),c=ot(t),u=new Te(c,e?.httpOptions);e?.userContext&&(u.userContext=e.userContext);let p=e?.exposePatterns,m=e?.sapClient??t.sapClient;ls(n),ds(n),Js(n,u,{baseUrl:t.baseUrl,sapClient:m,tlsVerify:e?.httpOptions?.tlsVerify}),Ks(n,u,p),qs(n,u,{catalogV2Url:e?.catalogV2Url,catalogV4Url:e?.catalogV4Url,baseUrl:t.baseUrl,onDiscoveryMatch:e?.onDiscoveryMatch,...e?.concurrency?{concurrency:e.concurrency}:{}},d),di(n,u,p,l),Xs(n,u,l,e?.readOnly??false),si(n,u,p),Ls(n,u,l),ci(n,u,p,l);let f=e?.idocStore??new _e,g=new kt(u,m,e?.partnerDefaults);return ei(n,u,g,f),Ds(n,f),e?.rfcAvailable&&e.rfcPool&&e.logger&&fi(n,e.rfcPool,e.logger),oi(n,s),xs(n,u,l),Ns(n,u,l),Us(n),s.applyInitialVisibility(),{server:n,registry:s,httpClient:u}}var Vd=z$1.object({snc_qop:z$1.enum(["1","2","3","8","9"]).optional(),snc_myname:z$1.string().min(1).optional(),snc_partnername:z$1.string().min(1).optional(),snc_lib:z$1.string().min(1).optional()}).superRefine((t,e)=>{let n=[t.snc_qop,t.snc_myname,t.snc_partnername,t.snc_lib].filter(r=>r!==void 0).length;if(n>0&&n<4){let r=[];t.snc_qop||r.push("SAP_SNC_QOP"),t.snc_myname||r.push("SAP_SNC_MYNAME"),t.snc_partnername||r.push("SAP_SNC_PARTNERNAME"),t.snc_lib||r.push("SAP_SNC_LIB"),e.addIssue({code:"custom",message:`SNC config incomplete: missing ${r.join(", ")} (D-12 all-or-none)`,path:["snc_qop"]});}});function Wn(t=process.env){let e=t.SAP_USERNAME,n=t.SAP_PASSWORD;if(!e||!n)return null;let r=!!(t.SAP_RFC_ASHOST&&t.SAP_RFC_SYSNR),s=!!(t.SAP_RFC_MSHOST&&t.SAP_RFC_GROUP);if(!r&&!s)return null;let i={user:e,passwd:n,client:t.SAP_CLIENT,lang:t.SAP_RFC_LANG??"EN"};r&&(i.ashost=t.SAP_RFC_ASHOST,i.sysnr=t.SAP_RFC_SYSNR),s&&(i.mshost=t.SAP_RFC_MSHOST,i.msserv=t.SAP_RFC_MSSERV,i.group=t.SAP_RFC_GROUP);let o=Vd.safeParse({snc_qop:t.SAP_SNC_QOP,snc_myname:t.SAP_SNC_MYNAME,snc_partnername:t.SAP_SNC_PARTNERNAME,snc_lib:t.SAP_SNC_LIB});if(!o.success){let a=o.error.issues.map(d=>d.message).join("; ");throw new Error(`Invalid SNC configuration: ${a}`)}return o.data.snc_qop&&Object.assign(i,o.data),i}function Gn(t=process.env){try{return Wn(t)!==null}catch{return false}}var Kt=class{constructor(e={}){this.options=e;this.discovery=e.discoveryClient??new de;}discovery;jwks;jwksIssuer;get verifies(){return !!this.options.issuerUrl}async verify(e){let n=e.authorization??e.Authorization;if(typeof n!="string"||!n.startsWith("Bearer "))return {kind:"none"};let r=n.slice(7).trim();if(!r)return {kind:"none"};if(!this.options.issuerUrl)return this.withoutVerification(r);try{let s=await this.getKeySet(this.options.issuerUrl),{payload:i}=await jwtVerify(r,s,{issuer:void 0,...this.options.audience?{audience:this.options.audience}:{}});return typeof i.sub!="string"?{kind:"rejected",reason:"Token ohne sub-Claim"}:{kind:"user",context:{token:r,sub:i.sub,email:typeof i.email=="string"?i.email:void 0,name:typeof i.name=="string"?i.name:void 0,verified:!0}}}catch(s){return Kd(r)?{kind:"rejected",reason:s instanceof Error?s.message:"Signaturpr\xFCfung fehlgeschlagen"}:{kind:"none"}}}withoutVerification(e){try{let n=decodeJwt(e);return typeof n.sub!="string"?{kind:"none"}:{kind:"user",context:{token:e,sub:n.sub,email:typeof n.email=="string"?n.email:void 0,name:typeof n.name=="string"?n.name:void 0,verified:!1}}}catch{return {kind:"none"}}}async getKeySet(e){if(this.jwks&&this.jwksIssuer===e)return this.jwks;let n=await this.discovery.discover(e);return this.jwks=createRemoteJWKSet(new URL(n.jwks_uri)),this.jwksIssuer=e,this.jwks}};function Kd(t){let e=t.split(".");return e.length===3&&e.every(n=>n.length>0)}var zd="x-sap-username",Yd="x-sap-password",Xd="x-sap-authorization";function qn(t,e){let n=t[e]??t[e.toLowerCase()],r=Array.isArray(n)?n[0]:n;return typeof r=="string"&&r.length>0?r:void 0}function Jd(t){let e=qn(t,zd),n=qn(t,Yd);if(e&&n)return {username:e,password:n};let r=qn(t,Xd),s=r?/^Basic\s+(.+)$/i.exec(r.trim()):null;if(s?.[1]){let i=Buffer.from(s[1].trim(),"base64").toString("utf8"),o=i.indexOf(":");if(o>0&&o<i.length-1)return {username:i.slice(0,o),password:i.slice(o+1)}}}function gi(t,e){let n=Jd(e);if(t.authType==="user-basic"){if(!n)return {kind:"missing",hint:`Destination "${t.name}" verlangt eine pers\xF6nliche SAP-Anmeldung: sende X-SAP-Username und X-SAP-Password (oder X-SAP-Authorization: Basic <base64 user:pass>) mit \u2014 im n8n-Node \u201EGuniWeb SAP" sind das die Felder SAP-Benutzer/SAP-Passwort des Credentials.`};let{name:r,baseUrl:s,sapClient:i}=t;return {kind:"ok",config:{name:r,baseUrl:s,authType:"basic",...i!==void 0?{sapClient:i}:{},username:n.username,password:n.password},username:n.username}}return n?{kind:"rejected",reason:`Destination "${t.name}" (authType ${t.authType}) nimmt keine pers\xF6nliche SAP-Anmeldung an \u2014 die Anfrage w\xFCrde unter dem konfigurierten technischen Zugang laufen. Lass X-SAP-Username/X-SAP-Password weg oder stelle die Destination auf authType user-basic um.`}:{kind:"ok",config:t}}var Zd=z$2.object({destination:z$2.string().min(1),label:z$2.string().max(200).optional(),readOnly:z$2.boolean().optional(),tiers:z$2.array(z$2.string()).optional()}).strict();function he(t,e,n){t.setHeader("Cache-Control","no-store"),t.status(e).json(n);}function hi(t){return t.ip??t.socket?.remoteAddress??"unknown"}function yi(t,e){let n=t?.[e];return n==="true"||n==="1"||n===""}function Si(t){t.use("/admin",(e,n)=>{he(n,404,{error:"Admin API not enabled",hint:"Start the server with --admin-token <secret> (or SAP_MCP_ADMIN_TOKEN) and --destinations <file>."});});}function bi(t,e){let{destinations:n,logger:r}=e,s=new Ce({apiKey:e.adminToken,tokens:()=>[]});t.use("/admin",(d,l,c)=>{let u=d,p=l,m=hi(u),f=s.authenticate(u.headers.authorization,m);if(f.kind==="rate-limited"){r?.warn({clientAddress:m,path:u.originalUrl??u.path,retryAfterSeconds:f.retryAfterSeconds},"Admin-API: zu viele fehlgeschlagene Anmeldeversuche von dieser Adresse"),p.setHeader("Retry-After",String(f.retryAfterSeconds)),he(p,429,{error:"Too Many Requests",retryAfterSeconds:f.retryAfterSeconds});return}if(f.kind!=="api-key"){r?.warn({clientAddress:m,path:u.originalUrl??u.path},"Admin-API: Anfrage abgewiesen"),he(p,401,{error:"Unauthorized"});return}c();});let i=()=>{if(n.source!=="file"||!n.filePath)throw new P("Admin API requires a destinations file: start the server with --destinations <file>.",409);return new Re({filePath:n.filePath,env:e.env})},o=(d,l)=>(c,u)=>{let p=c,m=u,f=hi(p);(async()=>{try{let{status:g,body:h,changed:b}=l(p);if(b){let y=await n.reload();h.reloaded=y.ok,y.ok||(h.reloadErrors=y.errors),r?.info({action:d,clientAddress:f,target:p.params?.name??p.params?.ref??p.body?.destination,reloaded:y.ok},"Admin-API: \xC4nderung ausgef\xFChrt");let E=p.params?.name??p.params?.ref??p.body?.destination;try{e.governance?.onAdminAction?.({apiVersion:1,serverVersion:X,at:new Date().toISOString(),action:d,...typeof E=="string"?{target:E}:{},...f?{clientAddress:f}:{},reloaded:y.ok});}catch(S){r?.warn({err:S,action:d},"Governance-Modul: Admin-Aktion konnte nicht gemeldet werden");}}he(m,g,h);}catch(g){if(g instanceof P){he(m,g.status,{error:g.message});return}r?.warn({action:d,clientAddress:f,err:g instanceof Error?g.message:String(g)},"Admin-API: unerwarteter Fehler"),he(m,500,{error:"Internal Server Error"});}})();},a=d=>{let l=d.body;if(l===null||typeof l!="object"||Array.isArray(l))throw new P("Request body must be a JSON object (Content-Type: application/json).",400);return l};t.get("/admin/destinations",o("destinations.list",()=>({status:200,body:{destinations:i().listDestinations()},changed:!1}))),t.put("/admin/destinations/:name",o("destinations.put",d=>{let l=d.params?.name??"",c=a(d),{replaced:u,warnings:p}=i().addDestination(l,c,{replace:!0,allowMissingEnv:yi(d.query,"allowMissingEnv")});return {status:u?200:201,body:{name:l,replaced:u,warnings:p},changed:!0}})),t.delete("/admin/destinations/:name",o("destinations.delete",d=>{let l=d.params?.name??"",{removedTokens:c}=i().removeDestination(l,{force:yi(d.query,"force")});return {status:200,body:{name:l,removedTokens:c},changed:!0}})),t.get("/admin/tokens",o("tokens.list",()=>({status:200,body:{tokens:i().listTokens()},changed:!1}))),t.post("/admin/tokens",o("tokens.issue",d=>{let l=Zd.safeParse(a(d));if(!l.success)throw new P(`Invalid body: ${l.error.issues.map(g=>`${g.path.join(".")||"(root)"}: ${g.message}`).join("; ")}`,400);let{destination:c,...u}=l.data,{token:p,hash:m,entry:f}=i().issueToken(c,u);return {status:201,body:{token:p,hash:m.replace(/^sha256:/,"").slice(0,12),destination:f.destination,label:f.label,policy:f.policy,createdAt:f.createdAt},changed:!0}})),t.delete("/admin/tokens/:ref",o("tokens.revoke",d=>{let l=d.params?.ref??"",c=i().revokeToken(l);return {status:200,body:{...c,revoked:!0},changed:!c.alreadyRevoked}})),t.use("/admin",(d,l)=>{he(l,404,{error:"Not Found"});});}var tl=16*1024*1024;function nl(t){let e=wi();return e.use(wi.json({limit:t})),e}function rl(t,e){return e?.kind==="token"?t.destinations?.get(e.token.destination):t.destinations?t.destinations.defaultDestination():t.config}function sl(t,e){if(e?.kind!=="token"||!e.token.policy)return t;let n=e.token.policy;return {...t,readOnly:t.readOnly===true||n.readOnly===true,...n.tiers?{allowedTiers:[...n.tiers]}:{}}}function il(t,e){t.writeHead(503,{"Content-Type":"application/json"});let n=e?.names().length??0;t.end(JSON.stringify({error:"Keine Destination bestimmbar",hint:n===0?'Es ist noch keine Destination konfiguriert. Lege eine an \u2014 per Admin-API (PUT /admin/destinations/<name>) oder CLI (guniweb-sap-mcp destinations add) \u2014 und ein Token daf\xFCr, oder nenne sie "default".':'Es sind mehrere Destinations konfiguriert, aber keine hei\xDFt "default". Benenne eine Destination "default", lege Tokens an oder reduziere die Datei auf ein Ziel.'}));}var Kn=class t{constructor(e){this.persistDir=e;}entries=new Map;static MAX_USER_SCOPES=100;for(e,n){let r=`${e.name}\0${e.baseUrl}\0${n??""}`,s=this.entries.get(r);if(!s){for(let o of this.entries.keys())o.startsWith(`${e.name}\0`)&&!o.startsWith(`${e.name}\0${e.baseUrl}\0`)&&this.entries.delete(o);n!==void 0&&this.evictOldestUserScopes(e);let i={baseUrl:e.baseUrl,...this.persistDir&&n===void 0?{persistDir:this.persistDir}:{}};s={catalog:new re(i),metadata:new I(i)},this.entries.set(r,s);}return s}evictOldestUserScopes(e){let n=`${e.name}\0${e.baseUrl}\0`,r=[...this.entries.keys()].filter(s=>s.startsWith(n)&&s!==n);for(;r.length>=t.MAX_USER_SCOPES;)this.entries.delete(r.shift());}};function ol(t,e){if(e.kind==="missing"){t.writeHead(401,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"SAP login required",hint:e.hint}));return}t.writeHead(400,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:e.reason}));}function al(t,e,n){let r=t?.kind==="token"?"token":t?.kind==="api-key"?"api-key":"open",s=n?n.email??n.sub:void 0;return {authKind:r,...t?.kind==="token"?{tokenLabel:t.token.label??t.token.hash.slice(7,19)}:{},...e?{sapUser:e}:{},...s?{subject:s,subjectVerified:n?.verified===true}:{},personal:!!(e||s)}}function cl(t,e){let n=t.logger;return !e||!n||typeof n.child!="function"?t:{...t,logger:n.child({sapUser:e})}}async function Ti(t){let e=new Kt({...t.jwtIssuer?{issuerUrl:t.jwtIssuer}:{},...t.jwtAudience?{audience:t.jwtAudience}:{}}),n=t.maxRequestBytes??tl,r=nl(n),s=new Ce({apiKey:t.apiKey,tokens:()=>t.destinations?.tokens()??[]}),i=t.serverOptions?.logger;r.use((d,l,c)=>{let u=d,p=l,m=c;if(u.path==="/healthz"){m();return}if(u.path==="/admin"||u.path.startsWith("/admin/")){m();return}if(t.webhookSecret&&u.path==="/idoc"){m();return}let f=u.ip??u.socket?.remoteAddress??"unknown",g=s.authenticate(u.headers.authorization,f);if(g.kind==="rate-limited"){i?.warn({clientAddress:f,path:u.path,retryAfterSeconds:g.retryAfterSeconds},"MCP-Anfrage abgewiesen: zu viele fehlgeschlagene Anmeldeversuche von dieser Adresse"),p.setHeader("Retry-After",String(g.retryAfterSeconds)),p.status(429).json({error:"Too Many Requests",retryAfterSeconds:g.retryAfterSeconds});return}if(g.kind==="rejected"){i?.warn({clientAddress:f,path:u.path,reason:g.reason},"MCP-Anfrage abgewiesen"),p.status(401).json({error:"Unauthorized"});return}u.sapAuth=g,m();}),r.get("/healthz",(d,l)=>{l.status(200).json({status:"ok",governance:t.governanceHealth?.()??{active:false}});}),t.adminToken&&t.destinations?bi(r,{adminToken:t.adminToken,destinations:t.destinations,env:t.env??process.env,logger:i,...t.serverOptions.governance?{governance:t.serverOptions.governance}:{}}):Si(r),dl(r,t,e);let o=Ct(t.idocStore,{secret:t.webhookSecret,maxBodyBytes:t.webhookMaxBodyBytes});r.post("/idoc",(d,l)=>{o(d,l);}),r.use((d,l,c,u)=>{let p=d,m=c;if(p?.type==="entity.parse.failed"&&!m.headersSent){m.status(400).json({error:`Invalid JSON body: ${p.message??"parse error"}`});return}if(p?.type==="entity.too.large"&&!m.headersSent){let f=(n/1024/1024).toFixed(1);m.status(413).json({error:`Anfrage zu gro\xDF: die Grenze liegt bei ${n} Bytes (${f} MiB). Bei einem base64-kodierten Anhang sind das rund ${(n*3/4/1024/1024).toFixed(1)} MiB Datei. Mit --max-request-bytes anheben.`});return}u(d);});let a=createServer(r);return new Promise(d=>{a.listen(t.port,()=>{let l=a.address(),c=typeof l=="object"&&l!==null?l.port:t.port;d({port:c,close:()=>new Promise((u,p)=>{a.close(m=>m?p(m):u());})});});})}function dl(t,e,n){let r=new Kn(e.serverOptions?.cacheDir),s=e.serverOptions?.logger;t.all("/mcp",(i,o)=>{let a=i,d=o,l=rl(e,a.sapAuth);if(!l){il(d,e.destinations);return}let c=gi(l,a.headers);if(c.kind!=="ok"){s?.warn({destination:l.name,clientAddress:a.socket?.remoteAddress,reason:c.kind},c.kind==="missing"?"MCP-Anfrage ohne pers\xF6nliche SAP-Anmeldung an eine user-basic-Destination abgewiesen":"MCP-Anfrage mit pers\xF6nlicher SAP-Anmeldung an eine Destination mit technischem Benutzer abgewiesen"),ol(d,c);return}let u=c.config,p=c.username,m=new StreamableHTTPServerTransport({sessionIdGenerator:void 0}),f=g=>{let{server:h}=qt(u,{...sl(cl(e.serverOptions,p),a.sapAuth),sapClient:u.sapClient,userContext:g,caches:r.for(u,p),callerIdentity:al(a.sapAuth,p,g)});h.connect(m).then(()=>m.handleRequest(a,d,a.body)).catch(()=>{d.headersSent||(d.writeHead(500),d.end("Internal Server Error"));});};n.verify(a.headers).then(g=>{if(g.kind==="rejected"){d.writeHead(401,{"Content-Type":"application/json"}),d.end(JSON.stringify({error:"Unauthorized",reason:g.reason,hint:"Das mitgeschickte Bearer-Token hat die Signaturpr\xFCfung gegen SAP_JWT_ISSUER nicht bestanden."}));return}let h=g.kind==="user"?g.context:null;f(h);});});}var ml=`Usage: guniweb-sap-mcp [options]
338
338
  guniweb-sap-mcp destinations list|add|remove ... (manage destinations.json)
339
339
  guniweb-sap-mcp tokens issue|revoke|list ... (see: guniweb-sap-mcp tokens --help)
340
340
 
@@ -406,5 +406,5 @@ Configuration via environment variables: SAP_BASE_URL, SAP_AUTH_TYPE
406
406
 
407
407
  Documentation, releases, issues: https://github.com/guniweb/guniweb-sap-mcp
408
408
  Support: support@guniweb.de \u2014 https://guniweb.de/sap-mcp
409
- `;async function nl(){let t=process.argv.slice(2);if(t[0]!==void 0&&Pr.has(t[0])){let b=await kr(t,{env:process.env,stdout:v=>process.stdout.write(v),stderr:v=>process.stderr.write(v)});process.exit(b);}let e=Wn();e.help&&(process.stdout.write(tl),process.exit(0)),Gn(e.transport);let n=e.transport??"stdio",r=!!e.adminToken;if(r&&!e.destinationsFile)throw new Error("--admin-token / SAP_MCP_ADMIN_TOKEN braucht --destinations <path> (bzw. SAP_MCP_DESTINATIONS): die Admin-API verwaltet diese Datei.");if(r&&n==="stdio")throw new Error("--admin-token / SAP_MCP_ADMIN_TOKEN wirkt nur im HTTP-Betrieb (--transport http): im stdio-Betrieb gibt es keinen /admin-Endpunkt.");let s;if(e.demo){let b=["SAP_BASE_URL","SAP_AUTH_TYPE"].filter(v=>process.env[v]);if(e.destinationsFile||b.length>0)throw new Error(`--demo und eine echte SAP-Konfiguration schlie\xDFen sich aus (gefunden: ${[...e.destinationsFile?["--destinations/SAP_MCP_DESTINATIONS"]:[],...b].join(", ")}). F\xFCr die Demo alle SAP_*-Variablen und --destinations weglassen.`);s=await yr();}let i=[],o=s?Re.fromEnv(rl(s.baseUrl)):e.destinationsFile?await Re.fromFile(e.destinationsFile,{env:process.env,onWarn:b=>i.push(b),allowMissing:r}):Re.fromEnv(process.env),a=o.defaultDestination(),d=o.tokens().length;if(!a&&(n==="stdio"||d===0)&&!r)throw new Error(`${o.filePath} definiert ${o.names().length} Destinations (${o.names().join(", ")}), aber keine hei\xDFt "default"${n==="stdio"?' \u2014 im stdio-Betrieb gibt es genau eine Verbindung, also muss eine Destination "default" hei\xDFen oder die Datei genau ein Ziel enthalten.':' und es sind keine Tokens konfiguriert, die eine Anfrage einem Ziel zuordnen k\xF6nnten. Benenne eine Destination "default" oder lege Tokens an.'}`);let l=Qt(process.env),c=eo({redact:dt,transport:{target:"pino/file",options:{destination:2}}});l.tlsVerify===false&&c.warn({tlsVerify:false},"SAP_TLS_VERIFY=false: TLS certificate validation disabled. ONLY use for development/test against self-signed certs. Production deployments MUST use SAP_TLS_VERIFY=true (or unset)."),l.clientCert&&c.info({hasCert:true,hasPassphrase:!!l.clientKeyPassphrase},"X.509 client certificate enabled for OData transport"),c.info(a?{baseUrl:a.baseUrl,authType:a.authType}:{destinations:o.names(),tokens:d},"SAP MCP server starting"),s&&c.warn({demo:true,mockSapUrl:s.baseUrl},`DEMO-MODUS: eingebautes Mock-SAP auf ${s.baseUrl} \u2014 Beispieldaten im Speicher (Gesch\xE4ftspartner, Kundenauftr\xE4ge, Produkte), keine echten SAP-Daten, keine Verbindung nach au\xDFen. \xC4nderungen gehen mit dem Prozess verloren.`);for(let b of i)c.warn(b);if(r&&!a&&d===0&&c.warn({file:o.filePath,destinations:o.names()},'Keine Standard-Destination und keine Tokens: /mcp antwortet 503, bis \xFCber die Admin-API (/admin) eine Destination "default" oder ein Token angelegt ist.'),o.source==="file"?(c.info({file:o.filePath,destinations:o.names(),defaultDestination:a?.name??null,tokens:d},"Destinations aus Datei geladen"),o.onChange(b=>{c.info({version:b.version,destinations:b.names,tokens:b.tokenCount},"Destinations neu geladen");}),o.onError(b=>{c.warn({errors:b},"Destinations-Datei ung\xFCltig \u2014 die letzte g\xFCltige Konfiguration bleibt in Kraft");})):c.info({destinations:o.names()},'Destination "default" aus SAP_*-Umgebung (keine destinations.json konfiguriert)'),e.allowWriteExplicit){let b=Gr({tiers:e.tiers,hasIdocConfig:Zt(e),hasRfcConfig:Fn(process.env)});c.warn({writeTools:b},`Schreibwerkzeuge sind aktiv (--allow-write): ${b.join(", ")} k\xF6nnen Daten im SAP-System ver\xE4ndern. sap_function ist nicht darunter: dort entscheiden die Metadaten des Dienstes je Aufruf, ob er lesend ist.`);}else c.info("Nur-Lese-Betrieb (Standard seit 1.0). Schreibwerkzeuge sind nicht registriert; mit --allow-write bzw. SAP_MCP_ALLOW_WRITE=true aktivieren.");for(let b of o.names())rr(o.names().length>1?c.child({destination:b}):c,o.get(b)?.sapClient);e.transport&&e.transport!=="stdio"&&(process.env.SAP_JWT_ISSUER?c.info({issuer:process.env.SAP_JWT_ISSUER},"Eingehende Benutzer-Token werden gegen die JWKS des Issuers gepr\xFCft"):c.warn("SAP_JWT_ISSUER ist nicht gesetzt: eingehende Bearer-Token werden nur dekodiert, nicht auf ihre Signatur gepr\xFCft. F\xFCr Principal Propagation an SAP ist das vertretbar (SAP pr\xFCft selbst); eine lokale Entscheidung darf sich auf die Identit\xE4t aber nicht st\xFCtzen.")),e.expose&&c.info({exposePatterns:e.expose},"Entity set filtering active");let u=await ei(c),p;if(u){let b=Bn(process.env);if(b){b.snc_lib&&!existsSync(b.snc_lib)&&c.warn({path:b.snc_lib},"SAP_SNC_LIB path does not exist on this host: SNC will fail at first RFC connect. Verify SAP NW RFC SDK + Cryptographic Library installation."),p=new Ft(b,c);let v=!!b.snc_qop;c.info({ashost:b.ashost,mshost:b.mshost,snc:v,...v?{qop:b.snc_qop,myname:b.snc_myname}:{}},v?"RFC pool ready (SNC-secured)":"RFC pool ready");}else c.info("node-rfc loaded but no SAP_RFC_* config \u2014 RFC tier requires sap_enable_tools rfc + env vars to activate");}let m=new Pe,g={exposePatterns:e.expose,idocStore:m,sapClient:a?.sapClient,partnerDefaults:{sndpor:e.sndpor,sndprt:e.sndprt,sndprn:e.sndprn,rcvpor:e.rcvpor,rcvprt:e.rcvprt,rcvprn:e.rcvprn},catalogV2Url:e.catalogV2Url,catalogV4Url:e.catalogV4Url,concurrency:e.concurrency,httpOptions:l,onDiscoveryMatch:b=>{c.info({path:b,attemptedPaths:3},"V2 catalog auto-discovery: matched path");}},f=e.toolTimeoutSeconds??Rt;f===0?c.warn("Zeitbudget je Tool-Aufruf abgeschaltet (--tool-timeout 0): ein Aufruf kann unbegrenzt laufen und die Client-Verbindung bis zu deren eigenem Timeout blockieren."):c.info({toolTimeoutSeconds:f},"Zeitbudget je Tool-Aufruf aktiv"),e.cacheDir?c.info({cacheDir:e.cacheDir},"Cache-Ablage aktiv (\xFCberlebt Neustarts)"):c.info("Kein Cache-Verzeichnis konfiguriert (--cache-dir / SAP_CACHE_DIR): Katalog und Metadaten werden nach jedem Neustart erneut aus SAP geholt.");let h=await Dr({serverVersion:ke,logger:c,env:process.env},{},e.governanceModule);h.module?c.info({module:h.module.name,version:h.module.version},"Governance-Modul aktiv: Werkzeugaufrufe werden dem Modul gemeldet (Aufrufjournal)."):c.info("Governance-Modul nicht installiert \u2014 kein Aufrufjournal. Das Betriebsprotokoll (pino) bleibt unver\xE4ndert.");let S={...h.module?{governance:h.module}:{},...g,toolTimeoutMs:f*1e3,cacheDir:e.cacheDir,readOnly:e.readOnly,tiers:e.tiers,hasIdocConfig:Zt(e),hasRfcConfig:Fn(process.env),rfcAvailable:u,rfcPool:p,logger:c},y;if(n==="stdio"){if(!a)throw new Error("stdio-Betrieb ohne Standard-Destination.");if(a.authType==="user-basic")throw new Error("authType user-basic (pers\xF6nliche SAP-Anmeldung je Anfrage) gibt es nur im HTTP-Betrieb: stdio hat keinen Header, \xFCber den SAP-Benutzer und -Passwort mitkommen k\xF6nnten. Starte mit --transport http oder verwende authType basic.");let{server:b}=Ht(a,S),v=new StdioServerTransport;if(await b.connect(v),c.info("SAP MCP server connected on stdio transport"),e.webhookPort){e.webhookSecret||c.warn({port:e.webhookPort},"IDoc webhook has NO authentication: anyone reaching this port can inject IDocs. Set --webhook-secret (or SAP_WEBHOOK_SECRET) for production.");let M=await Mr(e.webhookPort,m,{host:e.webhookHost,secret:e.webhookSecret,maxBodyBytes:e.webhookMaxBodyBytes});c.info({port:M.port,auth:e.webhookSecret?"secret":"open"},"IDoc webhook server listening");}}else {let b=e.port??8808,v=!!e.apiKey||d>0;!e.webhookSecret&&!v&&c.warn({port:b},"IDoc webhook (/idoc) and MCP endpoint have NO authentication. Set --api-key (or tokens in destinations.json) and --webhook-secret (or SAP_WEBHOOK_SECRET) for production."),o.watch(),y=await li({transport:n,port:b,apiKey:e.apiKey,adminToken:e.adminToken,env:process.env,destinations:o,serverOptions:S,governanceHealth:()=>h.module?{active:true,module:h.module.name,version:h.module.version,...h.module.health?.()??{}}:{active:false},jwtIssuer:process.env.SAP_JWT_ISSUER,jwtAudience:process.env.SAP_JWT_AUDIENCE,idocStore:m,webhookSecret:e.webhookSecret,webhookMaxBodyBytes:e.webhookMaxBodyBytes,maxRequestBytes:e.maxRequestBytes}),c.info({transport:n,port:y.port,auth:[...e.apiKey?["api-key"]:[],...d>0?[`tokens(${d})`]:[]].join("+")||"open",adminApi:e.adminToken?"/admin (admin-token)":"off"},"SAP MCP server listening on HTTP"),e.adminToken&&c.info({file:o.filePath},"Admin-API aktiv unter /admin: Destinations und Tokens per HTTP verwaltbar (nur mit dem Admin-Secret; n8n-Tokens gelten dort nicht).");}for(let b of o.names()){let v=o.get(b);if(!v)continue;let M=o.names().length>1?c.child({destination:b}):c;if(v.authType==="user-basic"){M.info({baseUrl:v.baseUrl,sapClient:v.sapClient??null},"Pers\xF6nliche SAP-Anmeldung je Anfrage (authType user-basic): Selbsttest ohne Benutzer nicht m\xF6glich \u2014 jede Anfrage bringt X-SAP-Username/X-SAP-Password mit, SAP pr\xFCft Passwort und Berechtigungen.");continue}sr(M,v,l);}let E=async b=>{c.info({signal:b},"Shutting down...");try{o.close(),p&&await p.closeAll(),y&&await y.close(),s&&await s.close(),h.module?.close&&await h.module.close();}catch(v){c.error({err:v},"Shutdown error (continuing)");}process.exit(0);};process.on("SIGTERM",()=>E("SIGTERM")),process.on("SIGINT",()=>E("SIGINT"));}function rl(t){let e=hr(t),n=e.authType==="basic"?e:void 0;return {...process.env,SAP_BASE_URL:e.baseUrl,SAP_AUTH_TYPE:e.authType,SAP_USERNAME:n?.username,SAP_PASSWORD:n?.password,SAP_CLIENT:e.sapClient,SAP_TLS_VERIFY:void 0,SAP_CLIENT_CERT:void 0,SAP_CLIENT_KEY:void 0}}nl().catch(t=>{process.stderr.write(`Fatal error: ${t instanceof Error?t.message:String(t)}
409
+ `;async function fl(){let t=process.argv.slice(2);if(t[0]!==void 0&&Nr.has(t[0])){let S=await Dr(t,{env:process.env,stdout:v=>process.stdout.write(v),stderr:v=>process.stderr.write(v)});process.exit(S);}let e=Yn();e.help&&(process.stdout.write(ml),process.exit(0)),Xn(e.transport);let n=e.transport??"stdio",r=!!e.adminToken;if(r&&!e.destinationsFile)throw new Error("--admin-token / SAP_MCP_ADMIN_TOKEN braucht --destinations <path> (bzw. SAP_MCP_DESTINATIONS): die Admin-API verwaltet diese Datei.");if(r&&n==="stdio")throw new Error("--admin-token / SAP_MCP_ADMIN_TOKEN wirkt nur im HTTP-Betrieb (--transport http): im stdio-Betrieb gibt es keinen /admin-Endpunkt.");let s;if(e.demo){let S=["SAP_BASE_URL","SAP_AUTH_TYPE"].filter(v=>process.env[v]);if(e.destinationsFile||S.length>0)throw new Error(`--demo und eine echte SAP-Konfiguration schlie\xDFen sich aus (gefunden: ${[...e.destinationsFile?["--destinations/SAP_MCP_DESTINATIONS"]:[],...S].join(", ")}). F\xFCr die Demo alle SAP_*-Variablen und --destinations weglassen.`);s=await vr();}let i=[],o=s?ke.fromEnv(gl(s.baseUrl)):e.destinationsFile?await ke.fromFile(e.destinationsFile,{env:process.env,onWarn:S=>i.push(S),allowMissing:r}):ke.fromEnv(process.env),a=o.defaultDestination(),d=o.tokens().length;if(!a&&(n==="stdio"||d===0)&&!r)throw new Error(`${o.filePath} definiert ${o.names().length} Destinations (${o.names().join(", ")}), aber keine hei\xDFt "default"${n==="stdio"?' \u2014 im stdio-Betrieb gibt es genau eine Verbindung, also muss eine Destination "default" hei\xDFen oder die Datei genau ein Ziel enthalten.':' und es sind keine Tokens konfiguriert, die eine Anfrage einem Ziel zuordnen k\xF6nnten. Benenne eine Destination "default" oder lege Tokens an.'}`);let l=rn(process.env),c=uo({redact:gt,transport:{target:"pino/file",options:{destination:2}}});l.tlsVerify===false&&c.warn({tlsVerify:false},"SAP_TLS_VERIFY=false: TLS certificate validation disabled. ONLY use for development/test against self-signed certs. Production deployments MUST use SAP_TLS_VERIFY=true (or unset)."),l.clientCert&&c.info({hasCert:true,hasPassphrase:!!l.clientKeyPassphrase},"X.509 client certificate enabled for OData transport"),c.info(a?{baseUrl:a.baseUrl,authType:a.authType}:{destinations:o.names(),tokens:d},"SAP MCP server starting"),s&&c.warn({demo:true,mockSapUrl:s.baseUrl},`DEMO-MODUS: eingebautes Mock-SAP auf ${s.baseUrl} \u2014 Beispieldaten im Speicher (Gesch\xE4ftspartner, Kundenauftr\xE4ge, Produkte), keine echten SAP-Daten, keine Verbindung nach au\xDFen. \xC4nderungen gehen mit dem Prozess verloren.`);for(let S of i)c.warn(S);if(r&&!a&&d===0&&c.warn({file:o.filePath,destinations:o.names()},'Keine Standard-Destination und keine Tokens: /mcp antwortet 503, bis \xFCber die Admin-API (/admin) eine Destination "default" oder ein Token angelegt ist.'),o.source==="file"?(c.info({file:o.filePath,destinations:o.names(),defaultDestination:a?.name??null,tokens:d},"Destinations aus Datei geladen"),o.onChange(S=>{c.info({version:S.version,destinations:S.names,tokens:S.tokenCount},"Destinations neu geladen");}),o.onError(S=>{c.warn({errors:S},"Destinations-Datei ung\xFCltig \u2014 die letzte g\xFCltige Konfiguration bleibt in Kraft");})):c.info({destinations:o.names()},'Destination "default" aus SAP_*-Umgebung (keine destinations.json konfiguriert)'),e.allowWriteExplicit){let S=ns({tiers:e.tiers,hasIdocConfig:nn(e),hasRfcConfig:Gn(process.env)});c.warn({writeTools:S},`Schreibwerkzeuge sind aktiv (--allow-write): ${S.join(", ")} k\xF6nnen Daten im SAP-System ver\xE4ndern. sap_function ist nicht darunter: dort entscheiden die Metadaten des Dienstes je Aufruf, ob er lesend ist.`);}else c.info("Nur-Lese-Betrieb (Standard seit 1.0). Schreibwerkzeuge sind nicht registriert; mit --allow-write bzw. SAP_MCP_ALLOW_WRITE=true aktivieren.");for(let S of o.names())cr(o.names().length>1?c.child({destination:S}):c,o.get(S)?.sapClient);e.transport&&e.transport!=="stdio"&&(process.env.SAP_JWT_ISSUER?c.info({issuer:process.env.SAP_JWT_ISSUER},"Eingehende Benutzer-Token werden gegen die JWKS des Issuers gepr\xFCft"):c.warn("SAP_JWT_ISSUER ist nicht gesetzt: eingehende Bearer-Token werden nur dekodiert, nicht auf ihre Signatur gepr\xFCft. F\xFCr Principal Propagation an SAP ist das vertretbar (SAP pr\xFCft selbst); eine lokale Entscheidung darf sich auf die Identit\xE4t aber nicht st\xFCtzen.")),e.expose&&c.info({exposePatterns:e.expose},"Entity set filtering active");let u=await ui(c),p;if(u){let S=Wn(process.env);if(S){S.snc_lib&&!existsSync(S.snc_lib)&&c.warn({path:S.snc_lib},"SAP_SNC_LIB path does not exist on this host: SNC will fail at first RFC connect. Verify SAP NW RFC SDK + Cryptographic Library installation."),p=new Gt(S,c);let v=!!S.snc_qop;c.info({ashost:S.ashost,mshost:S.mshost,snc:v,...v?{qop:S.snc_qop,myname:S.snc_myname}:{}},v?"RFC pool ready (SNC-secured)":"RFC pool ready");}else c.info("node-rfc loaded but no SAP_RFC_* config \u2014 RFC tier requires sap_enable_tools rfc + env vars to activate");}let m=new _e,f={exposePatterns:e.expose,idocStore:m,sapClient:a?.sapClient,partnerDefaults:{sndpor:e.sndpor,sndprt:e.sndprt,sndprn:e.sndprn,rcvpor:e.rcvpor,rcvprt:e.rcvprt,rcvprn:e.rcvprn},catalogV2Url:e.catalogV2Url,catalogV4Url:e.catalogV4Url,concurrency:e.concurrency,httpOptions:l,onDiscoveryMatch:S=>{c.info({path:S,attemptedPaths:3},"V2 catalog auto-discovery: matched path");}},g=e.toolTimeoutSeconds??It;g===0?c.warn("Zeitbudget je Tool-Aufruf abgeschaltet (--tool-timeout 0): ein Aufruf kann unbegrenzt laufen und die Client-Verbindung bis zu deren eigenem Timeout blockieren."):c.info({toolTimeoutSeconds:g},"Zeitbudget je Tool-Aufruf aktiv"),e.cacheDir?c.info({cacheDir:e.cacheDir},"Cache-Ablage aktiv (\xFCberlebt Neustarts)"):c.info("Kein Cache-Verzeichnis konfiguriert (--cache-dir / SAP_CACHE_DIR): Katalog und Metadaten werden nach jedem Neustart erneut aus SAP geholt.");let h=await Fr({serverVersion:X,logger:c,env:process.env},{},e.governanceModule);if(h.module){c.info({module:h.module.name,version:h.module.version},"Governance-Modul aktiv: Werkzeugaufrufe werden dem Modul gemeldet (Aufrufjournal).");let S=h.module;if(S.onConfigChange){let v=()=>$r(o.tokens(),o.names().map(G=>o.get(G)).filter(G=>G!==void 0)),x=v();o.onChange(G=>{let st=v(),it=Lr(x,st);if(x=st,it.length!==0)try{S.onConfigChange?.({apiVersion:1,serverVersion:X,at:new Date().toISOString(),version:G.version,changes:it});}catch(Ue){c.error({err:Ue},"Governance-Modul: Konfigurations\xE4nderung konnte nicht gemeldet werden");}});}}else {let S=Vr(process.env);S&&c.info(S.fields,S.msg);}let b={...h.module?{governance:h.module}:{},...f,toolTimeoutMs:g*1e3,cacheDir:e.cacheDir,readOnly:e.readOnly,tiers:e.tiers,hasIdocConfig:nn(e),hasRfcConfig:Gn(process.env),rfcAvailable:u,rfcPool:p,logger:c},y;if(n==="stdio"){if(!a)throw new Error("stdio-Betrieb ohne Standard-Destination.");if(a.authType==="user-basic")throw new Error("authType user-basic (pers\xF6nliche SAP-Anmeldung je Anfrage) gibt es nur im HTTP-Betrieb: stdio hat keinen Header, \xFCber den SAP-Benutzer und -Passwort mitkommen k\xF6nnten. Starte mit --transport http oder verwende authType basic.");let{server:S}=qt(a,b),v=new StdioServerTransport;if(await S.connect(v),c.info("SAP MCP server connected on stdio transport"),e.webhookPort){e.webhookSecret||c.warn({port:e.webhookPort},"IDoc webhook has NO authentication: anyone reaching this port can inject IDocs. Set --webhook-secret (or SAP_WEBHOOK_SECRET) for production.");let x=await qr(e.webhookPort,m,{host:e.webhookHost,secret:e.webhookSecret,maxBodyBytes:e.webhookMaxBodyBytes});c.info({port:x.port,auth:e.webhookSecret?"secret":"open"},"IDoc webhook server listening");}}else {let S=e.port??8808,v=!!e.apiKey||d>0;!e.webhookSecret&&!v&&c.warn({port:S},"IDoc webhook (/idoc) and MCP endpoint have NO authentication. Set --api-key (or tokens in destinations.json) and --webhook-secret (or SAP_WEBHOOK_SECRET) for production."),o.watch(),y=await Ti({transport:n,port:S,apiKey:e.apiKey,adminToken:e.adminToken,env:process.env,destinations:o,serverOptions:b,governanceHealth:()=>h.module?{active:true,module:h.module.name,version:h.module.version,...h.module.health?.()??{}}:{active:false},jwtIssuer:process.env.SAP_JWT_ISSUER,jwtAudience:process.env.SAP_JWT_AUDIENCE,idocStore:m,webhookSecret:e.webhookSecret,webhookMaxBodyBytes:e.webhookMaxBodyBytes,maxRequestBytes:e.maxRequestBytes}),c.info({transport:n,port:y.port,auth:[...e.apiKey?["api-key"]:[],...d>0?[`tokens(${d})`]:[]].join("+")||"open",adminApi:e.adminToken?"/admin (admin-token)":"off"},"SAP MCP server listening on HTTP"),e.adminToken&&c.info({file:o.filePath},"Admin-API aktiv unter /admin: Destinations und Tokens per HTTP verwaltbar (nur mit dem Admin-Secret; n8n-Tokens gelten dort nicht).");}for(let S of o.names()){let v=o.get(S);if(!v)continue;let x=o.names().length>1?c.child({destination:S}):c;if(v.authType==="user-basic"){x.info({baseUrl:v.baseUrl,sapClient:v.sapClient??null},"Pers\xF6nliche SAP-Anmeldung je Anfrage (authType user-basic): Selbsttest ohne Benutzer nicht m\xF6glich \u2014 jede Anfrage bringt X-SAP-Username/X-SAP-Password mit, SAP pr\xFCft Passwort und Berechtigungen.");continue}dr(x,v,l);}let E=async S=>{c.info({signal:S},"Shutting down...");try{o.close(),p&&await p.closeAll(),y&&await y.close(),s&&await s.close(),h.module?.close&&await h.module.close();}catch(v){c.error({err:v},"Shutdown error (continuing)");}process.exit(0);};process.on("SIGTERM",()=>E("SIGTERM")),process.on("SIGINT",()=>E("SIGINT"));}function gl(t){let e=Tr(t),n=e.authType==="basic"?e:void 0;return {...process.env,SAP_BASE_URL:e.baseUrl,SAP_AUTH_TYPE:e.authType,SAP_USERNAME:n?.username,SAP_PASSWORD:n?.password,SAP_CLIENT:e.sapClient,SAP_TLS_VERIFY:void 0,SAP_CLIENT_CERT:void 0,SAP_CLIENT_KEY:void 0}}fl().catch(t=>{process.stderr.write(`Fatal error: ${t instanceof Error?t.message:String(t)}
410
410
  `),process.exit(1);});