salesforce-metadata-mcp 2.0.0

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 (91) hide show
  1. package/AGENTFORCE.md +125 -0
  2. package/APEX_LWC.md +214 -0
  3. package/CHANGELOG.md +120 -0
  4. package/README.md +207 -0
  5. package/SETUP.md +208 -0
  6. package/TOOLS.md +193 -0
  7. package/dist/index.d.ts +2 -0
  8. package/dist/index.d.ts.map +1 -0
  9. package/dist/index.js +53 -0
  10. package/dist/index.js.map +1 -0
  11. package/dist/schemas/index.d.ts +3406 -0
  12. package/dist/schemas/index.d.ts.map +1 -0
  13. package/dist/schemas/index.js +992 -0
  14. package/dist/schemas/index.js.map +1 -0
  15. package/dist/services/deployment.d.ts +36 -0
  16. package/dist/services/deployment.d.ts.map +1 -0
  17. package/dist/services/deployment.js +215 -0
  18. package/dist/services/deployment.js.map +1 -0
  19. package/dist/services/mcpgen.d.ts +16 -0
  20. package/dist/services/mcpgen.d.ts.map +1 -0
  21. package/dist/services/mcpgen.js +229 -0
  22. package/dist/services/mcpgen.js.map +1 -0
  23. package/dist/services/salesforce.d.ts +598 -0
  24. package/dist/services/salesforce.d.ts.map +1 -0
  25. package/dist/services/salesforce.js +1317 -0
  26. package/dist/services/salesforce.js.map +1 -0
  27. package/dist/services/tooling.d.ts +23 -0
  28. package/dist/services/tooling.d.ts.map +1 -0
  29. package/dist/services/tooling.js +173 -0
  30. package/dist/services/tooling.js.map +1 -0
  31. package/dist/tools/agentforce.d.ts +3 -0
  32. package/dist/tools/agentforce.d.ts.map +1 -0
  33. package/dist/tools/agentforce.js +73 -0
  34. package/dist/tools/agentforce.js.map +1 -0
  35. package/dist/tools/apex.d.ts +3 -0
  36. package/dist/tools/apex.d.ts.map +1 -0
  37. package/dist/tools/apex.js +95 -0
  38. package/dist/tools/apex.js.map +1 -0
  39. package/dist/tools/automation.d.ts +3 -0
  40. package/dist/tools/automation.d.ts.map +1 -0
  41. package/dist/tools/automation.js +186 -0
  42. package/dist/tools/automation.js.map +1 -0
  43. package/dist/tools/deployment.d.ts +3 -0
  44. package/dist/tools/deployment.d.ts.map +1 -0
  45. package/dist/tools/deployment.js +89 -0
  46. package/dist/tools/deployment.js.map +1 -0
  47. package/dist/tools/experience.d.ts +3 -0
  48. package/dist/tools/experience.d.ts.map +1 -0
  49. package/dist/tools/experience.js +53 -0
  50. package/dist/tools/experience.js.map +1 -0
  51. package/dist/tools/index.d.ts +3 -0
  52. package/dist/tools/index.d.ts.map +1 -0
  53. package/dist/tools/index.js +27 -0
  54. package/dist/tools/index.js.map +1 -0
  55. package/dist/tools/integrations.d.ts +3 -0
  56. package/dist/tools/integrations.d.ts.map +1 -0
  57. package/dist/tools/integrations.js +96 -0
  58. package/dist/tools/integrations.js.map +1 -0
  59. package/dist/tools/lwc.d.ts +3 -0
  60. package/dist/tools/lwc.d.ts.map +1 -0
  61. package/dist/tools/lwc.js +73 -0
  62. package/dist/tools/lwc.js.map +1 -0
  63. package/dist/tools/mcp.d.ts +3 -0
  64. package/dist/tools/mcp.d.ts.map +1 -0
  65. package/dist/tools/mcp.js +44 -0
  66. package/dist/tools/mcp.js.map +1 -0
  67. package/dist/tools/metadata.d.ts +3 -0
  68. package/dist/tools/metadata.d.ts.map +1 -0
  69. package/dist/tools/metadata.js +168 -0
  70. package/dist/tools/metadata.js.map +1 -0
  71. package/dist/tools/objects.d.ts +3 -0
  72. package/dist/tools/objects.d.ts.map +1 -0
  73. package/dist/tools/objects.js +172 -0
  74. package/dist/tools/objects.js.map +1 -0
  75. package/dist/tools/security.d.ts +3 -0
  76. package/dist/tools/security.d.ts.map +1 -0
  77. package/dist/tools/security.js +82 -0
  78. package/dist/tools/security.js.map +1 -0
  79. package/dist/tools/ui.d.ts +3 -0
  80. package/dist/tools/ui.d.ts.map +1 -0
  81. package/dist/tools/ui.js +195 -0
  82. package/dist/tools/ui.js.map +1 -0
  83. package/dist/tools/utils.d.ts +15 -0
  84. package/dist/tools/utils.d.ts.map +1 -0
  85. package/dist/tools/utils.js +7 -0
  86. package/dist/tools/utils.js.map +1 -0
  87. package/dist/types.d.ts +85 -0
  88. package/dist/types.d.ts.map +1 -0
  89. package/dist/types.js +3 -0
  90. package/dist/types.js.map +1 -0
  91. package/package.json +46 -0
@@ -0,0 +1,1317 @@
1
+ import axios from "axios";
2
+ import { execSync } from "child_process";
3
+ export const API_VERSION = "62.0";
4
+ // ─── Token cache ──────────────────────────────────────────────────────────────
5
+ let cachedToken = null;
6
+ const TOKEN_TTL_MS = 55 * 60 * 1000;
7
+ function getFreshTokenFromCLI(alias) {
8
+ const result = execSync(`sf org display --target-org ${alias} --json`, {
9
+ encoding: "utf-8",
10
+ });
11
+ const parsed = JSON.parse(result);
12
+ const accessToken = parsed?.result?.accessToken;
13
+ if (!accessToken) {
14
+ throw new Error("No access token returned from SF CLI.");
15
+ }
16
+ return accessToken;
17
+ }
18
+ async function getFreshTokenFromOAuth(instanceUrl, clientId, clientSecret, refreshToken) {
19
+ const res = await axios.post(`${instanceUrl}/services/oauth2/token`, new URLSearchParams({
20
+ grant_type: "refresh_token",
21
+ client_id: clientId,
22
+ client_secret: clientSecret,
23
+ refresh_token: refreshToken,
24
+ }), { headers: { "Content-Type": "application/x-www-form-urlencoded" } });
25
+ const token = res.data.access_token;
26
+ if (!token)
27
+ throw new Error("No access_token in OAuth refresh response.");
28
+ return token;
29
+ }
30
+ export async function getAuth() {
31
+ const instanceUrl = process.env.SF_INSTANCE_URL;
32
+ if (!instanceUrl) {
33
+ throw new Error("Missing SF_INSTANCE_URL environment variable.");
34
+ }
35
+ const base = instanceUrl.replace(/\/$/, "");
36
+ const clientId = process.env.SF_CLIENT_ID;
37
+ const clientSecret = process.env.SF_CLIENT_SECRET;
38
+ const refreshToken = process.env.SF_REFRESH_TOKEN;
39
+ if (clientId && clientSecret && refreshToken) {
40
+ const now = Date.now();
41
+ if (cachedToken && now < cachedToken.expiresAt) {
42
+ return { instanceUrl: base, accessToken: cachedToken.accessToken };
43
+ }
44
+ try {
45
+ const accessToken = await getFreshTokenFromOAuth(base, clientId, clientSecret, refreshToken);
46
+ cachedToken = { accessToken, expiresAt: now + TOKEN_TTL_MS };
47
+ return { instanceUrl: base, accessToken };
48
+ }
49
+ catch (err) {
50
+ console.error("OAuth refresh failed, trying next strategy:", err instanceof Error ? err.message : err);
51
+ }
52
+ }
53
+ const alias = process.env.SF_ALIAS;
54
+ if (alias) {
55
+ try {
56
+ const accessToken = getFreshTokenFromCLI(alias);
57
+ return { instanceUrl: base, accessToken };
58
+ }
59
+ catch (err) {
60
+ console.error("SF CLI failed, trying static token:", err instanceof Error ? err.message : err);
61
+ }
62
+ }
63
+ const staticToken = process.env.SF_ACCESS_TOKEN;
64
+ if (staticToken) {
65
+ console.error("⚠️ Using static SF_ACCESS_TOKEN — expires in ~1 hour.");
66
+ return { instanceUrl: base, accessToken: staticToken };
67
+ }
68
+ throw new Error("No Salesforce credentials found. Set SF_CLIENT_ID+SF_CLIENT_SECRET+SF_REFRESH_TOKEN, or SF_ALIAS, or SF_ACCESS_TOKEN.");
69
+ }
70
+ export function createClient(auth) {
71
+ return axios.create({
72
+ baseURL: `${auth.instanceUrl}/services/data/v${API_VERSION}`,
73
+ headers: { Authorization: `Bearer ${auth.accessToken}`, "Content-Type": "application/json" },
74
+ timeout: 60_000,
75
+ });
76
+ }
77
+ export async function callMetadataSoap(auth, soapAction, bodyInner) {
78
+ const envelope = `<?xml version="1.0" encoding="utf-8"?>
79
+ <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:met="http://soap.sforce.com/2006/04/metadata">
80
+ <soapenv:Header>
81
+ <met:CallOptions><met:client>salesforce-metadata-mcp</met:client></met:CallOptions>
82
+ <met:SessionHeader><met:sessionId>${auth.accessToken}</met:sessionId></met:SessionHeader>
83
+ </soapenv:Header>
84
+ <soapenv:Body>${bodyInner}</soapenv:Body>
85
+ </soapenv:Envelope>`;
86
+ const response = await axios.post(`${auth.instanceUrl}/services/Soap/m/${API_VERSION}`, envelope, {
87
+ headers: { "Content-Type": "text/xml; charset=utf-8", SOAPAction: `"${soapAction}"` },
88
+ timeout: 60_000,
89
+ });
90
+ return response.data;
91
+ }
92
+ export function extractSoapError(xml) {
93
+ const faultMatch = xml.match(/<faultstring[^>]*>([\s\S]*?)<\/faultstring>/i);
94
+ if (faultMatch)
95
+ return faultMatch[1].trim();
96
+ const msgMatch = xml.match(/<message[^>]*>([\s\S]*?)<\/message>/i);
97
+ if (msgMatch)
98
+ return msgMatch[1].trim();
99
+ return null;
100
+ }
101
+ export function parseUpsertResult(xml) {
102
+ const results = [];
103
+ const resultBlocks = [...xml.matchAll(/<result>([\s\S]*?)<\/result>/gi)];
104
+ for (const block of resultBlocks) {
105
+ const inner = block[1];
106
+ const created = /<created>true<\/created>/i.test(inner);
107
+ const success = /<success>true<\/success>/i.test(inner);
108
+ const fullNameMatch = inner.match(/<fullName[^>]*>([\s\S]*?)<\/fullName>/i);
109
+ const fullName = fullNameMatch ? fullNameMatch[1].trim() : "";
110
+ const errors = [];
111
+ const errorBlocks = [...inner.matchAll(/<errors>([\s\S]*?)<\/errors>/gi)];
112
+ for (const eb of errorBlocks) {
113
+ const msgMatch = eb[1].match(/<message[^>]*>([\s\S]*?)<\/message>/i);
114
+ const codeMatch = eb[1].match(/<statusCode[^>]*>([\s\S]*?)<\/statusCode>/i);
115
+ errors.push({ message: msgMatch ? msgMatch[1].trim() : "Unknown error", statusCode: codeMatch ? codeMatch[1].trim() : "UNKNOWN" });
116
+ }
117
+ results.push({ created, success, fullName, ...(errors.length ? { errors } : {}) });
118
+ }
119
+ return results;
120
+ }
121
+ export function x(str) {
122
+ return str.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&apos;");
123
+ }
124
+ // ─── XML Builders ────────────────────────────────────────────────────────────
125
+ function buildCustomObjectXml(meta) {
126
+ const nameFieldXml = meta.nameField.type === "AutoNumber"
127
+ ? `<met:nameField><met:displayFormat>${x(meta.nameField.displayFormat ?? "REC-{0000}")}</met:displayFormat><met:label>${x(meta.nameField.label)}</met:label><met:type>AutoNumber</met:type></met:nameField>`
128
+ : `<met:nameField><met:label>${x(meta.nameField.label)}</met:label><met:type>Text</met:type></met:nameField>`;
129
+ return `<met:metadata xsi:type="met:CustomObject" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
130
+ <met:fullName>${x(meta.fullName)}</met:fullName>
131
+ <met:label>${x(meta.label)}</met:label>
132
+ <met:pluralLabel>${x(meta.pluralLabel)}</met:pluralLabel>
133
+ ${nameFieldXml}
134
+ <met:deploymentStatus>${meta.deploymentStatus}</met:deploymentStatus>
135
+ <met:sharingModel>${meta.sharingModel}</met:sharingModel>
136
+ ${meta.description ? `<met:description>${x(meta.description)}</met:description>` : ""}
137
+ ${meta.enableActivities !== undefined ? `<met:enableActivities>${meta.enableActivities}</met:enableActivities>` : ""}
138
+ ${meta.enableHistory !== undefined ? `<met:enableHistory>${meta.enableHistory}</met:enableHistory>` : ""}
139
+ ${meta.enableReports !== undefined ? `<met:enableReports>${meta.enableReports}</met:enableReports>` : ""}
140
+ ${meta.enableSearch !== undefined ? `<met:enableSearch>${meta.enableSearch}</met:enableSearch>` : ""}
141
+ </met:metadata>`;
142
+ }
143
+ function buildPicklistValuesXml(values) {
144
+ return values.map((v) => `<met:value>
145
+ <met:fullName>${x(v.fullName)}</met:fullName>
146
+ <met:label>${x(v.label)}</met:label>
147
+ <met:default>${v.default}</met:default>
148
+ ${v.isActive !== undefined ? `<met:isActive>${v.isActive}</met:isActive>` : ""}
149
+ ${v.color ? `<met:color>${x(v.color)}</met:color>` : ""}
150
+ ${v.description ? `<met:description>${x(v.description)}</met:description>` : ""}
151
+ </met:value>`).join("\n");
152
+ }
153
+ function buildCustomFieldXml(meta) {
154
+ const picklistXml = meta.valueSet
155
+ ? `<met:valueSet>
156
+ ${meta.valueSet.restricted !== undefined ? `<met:restricted>${meta.valueSet.restricted}</met:restricted>` : ""}
157
+ <met:valueSetDefinition>
158
+ <met:sorted>${meta.valueSet.valueSetDefinition.sorted}</met:sorted>
159
+ ${buildPicklistValuesXml(meta.valueSet.valueSetDefinition.value)}
160
+ </met:valueSetDefinition>
161
+ </met:valueSet>` : "";
162
+ const lookupXml = meta.referenceTo
163
+ ? `<met:referenceTo>${x(meta.referenceTo)}</met:referenceTo>
164
+ <met:relationshipLabel>${x(meta.relationshipLabel ?? meta.referenceTo)}</met:relationshipLabel>
165
+ <met:relationshipName>${x(meta.relationshipName ?? meta.referenceTo.replace(/__c$/i, ""))}</met:relationshipName>
166
+ ${meta.deleteConstraint ? `<met:deleteConstraint>${meta.deleteConstraint}</met:deleteConstraint>` : ""}` : "";
167
+ return `<met:metadata xsi:type="met:CustomField" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
168
+ <met:fullName>${x(meta.fullName)}</met:fullName>
169
+ <met:label>${x(meta.label)}</met:label>
170
+ <met:type>${meta.type}</met:type>
171
+ ${meta.description ? `<met:description>${x(meta.description)}</met:description>` : ""}
172
+ ${meta.required !== undefined ? `<met:required>${meta.required}</met:required>` : ""}
173
+ ${meta.unique !== undefined ? `<met:unique>${meta.unique}</met:unique>` : ""}
174
+ ${meta.externalId !== undefined ? `<met:externalId>${meta.externalId}</met:externalId>` : ""}
175
+ ${meta.length !== undefined ? `<met:length>${meta.length}</met:length>` : ""}
176
+ ${meta.visibleLines !== undefined ? `<met:visibleLines>${meta.visibleLines}</met:visibleLines>` : ""}
177
+ ${meta.precision !== undefined ? `<met:precision>${meta.precision}</met:precision>` : ""}
178
+ ${meta.scale !== undefined ? `<met:scale>${meta.scale}</met:scale>` : ""}
179
+ ${picklistXml}
180
+ ${lookupXml}
181
+ </met:metadata>`;
182
+ }
183
+ function buildSimpleFieldsXml(fields) {
184
+ return fields.map(f => {
185
+ const picklistXml = f.picklistValues && f.picklistValues.length > 0
186
+ ? `<met:valueSet><met:valueSetDefinition><met:sorted>false</met:sorted>
187
+ ${f.picklistValues.map(v => `<met:value><met:fullName>${x(v)}</met:fullName><met:label>${x(v)}</met:label><met:default>false</met:default></met:value>`).join("\n")}
188
+ </met:valueSetDefinition></met:valueSet>` : "";
189
+ return `<met:fields>
190
+ <met:fullName>${x(f.fullName)}</met:fullName>
191
+ <met:label>${x(f.label)}</met:label>
192
+ <met:type>${x(f.type)}</met:type>
193
+ ${f.required !== undefined ? `<met:required>${f.required}</met:required>` : ""}
194
+ ${f.length !== undefined ? `<met:length>${f.length}</met:length>` : ""}
195
+ ${f.precision !== undefined ? `<met:precision>${f.precision}</met:precision>` : ""}
196
+ ${f.scale !== undefined ? `<met:scale>${f.scale}</met:scale>` : ""}
197
+ ${f.defaultValue !== undefined ? `<met:defaultValue>${x(f.defaultValue)}</met:defaultValue>` : ""}
198
+ ${f.description ? `<met:description>${x(f.description)}</met:description>` : ""}
199
+ ${picklistXml}
200
+ </met:fields>`;
201
+ }).join("\n");
202
+ }
203
+ function buildFlowXml(params) {
204
+ const vars = (params.variables ?? []).map(v => `
205
+ <met:variables>
206
+ <met:name>${x(v.name)}</met:name>
207
+ <met:dataType>${v.dataType}</met:dataType>
208
+ ${v.objectType ? `<met:objectType>${x(v.objectType)}</met:objectType>` : ""}
209
+ <met:isCollection>${v.isCollection}</met:isCollection>
210
+ <met:isInput>${v.isInput}</met:isInput>
211
+ <met:isOutput>${v.isOutput}</met:isOutput>
212
+ </met:variables>`).join("\n");
213
+ const buildElements = (elements) => {
214
+ if (!elements || elements.length === 0)
215
+ return "";
216
+ return elements.map((el, idx) => {
217
+ const connector = el.nextElement
218
+ ? `<met:connector><met:targetReference>${x(el.nextElement)}</met:targetReference></met:connector>` : "";
219
+ switch (el.type) {
220
+ case "Decision": {
221
+ const outcomes = (el.conditions ?? []).map((c, i) => `
222
+ <met:rules>
223
+ <met:name>Outcome_${i + 1}</met:name>
224
+ <met:label>Outcome ${i + 1}</met:label>
225
+ <met:conditionLogic>and</met:conditionLogic>
226
+ <met:conditions>
227
+ <met:leftValueReference>${x(c.leftValueRef)}</met:leftValueReference>
228
+ <met:operator>${x(c.operator)}</met:operator>
229
+ <met:rightValue>${c.rightValueRef
230
+ ? `<met:elementReference>${x(c.rightValueRef)}</met:elementReference>`
231
+ : `<met:stringValue>${x(c.rightValue ?? "")}</met:stringValue>`}
232
+ </met:rightValue>
233
+ </met:conditions>
234
+ </met:rules>`).join("\n");
235
+ const defaultOut = el.defaultConnector
236
+ ? `<met:defaultConnector><met:targetReference>${x(el.defaultConnector)}</met:targetReference></met:defaultConnector>` : "";
237
+ return `<met:decisions>
238
+ <met:name>${x(el.name)}</met:name>
239
+ <met:label>${x(el.label)}</met:label>
240
+ <met:locationX>${50 + idx * 200}</met:locationX>
241
+ <met:locationY>180</met:locationY>
242
+ ${outcomes}
243
+ ${defaultOut}
244
+ </met:decisions>`;
245
+ }
246
+ case "GetRecords":
247
+ return `<met:recordLookups>
248
+ <met:name>${x(el.name)}</met:name>
249
+ <met:label>${x(el.label)}</met:label>
250
+ <met:locationX>${50 + idx * 200}</met:locationX>
251
+ <met:locationY>180</met:locationY>
252
+ <met:object>${x(el.objectApiName ?? "")}</met:object>
253
+ ${el.filterField ? `<met:filters>
254
+ <met:field>${x(el.filterField)}</met:field>
255
+ <met:operator>${x(el.filterOperator ?? "EqualTo")}</met:operator>
256
+ <met:value><met:elementReference>${x(el.filterValueRef ?? "")}</met:elementReference></met:value>
257
+ </met:filters>` : ""}
258
+ ${el.outputVariable ? `<met:outputReference>${x(el.outputVariable)}</met:outputReference>` : ""}
259
+ ${connector}
260
+ </met:recordLookups>`;
261
+ case "CreateRecords":
262
+ return `<met:recordCreates>
263
+ <met:name>${x(el.name)}</met:name>
264
+ <met:label>${x(el.label)}</met:label>
265
+ <met:locationX>${50 + idx * 200}</met:locationX>
266
+ <met:locationY>180</met:locationY>
267
+ <met:object>${x(el.objectApiName ?? "")}</met:object>
268
+ ${connector}
269
+ </met:recordCreates>`;
270
+ case "DeleteRecords":
271
+ return `<met:recordDeletes>
272
+ <met:name>${x(el.name)}</met:name>
273
+ <met:label>${x(el.label)}</met:label>
274
+ <met:locationX>${50 + idx * 200}</met:locationX>
275
+ <met:locationY>180</met:locationY>
276
+ ${connector}
277
+ </met:recordDeletes>`;
278
+ case "SendEmailAlert":
279
+ return `<met:actionCalls>
280
+ <met:name>${x(el.name)}</met:name>
281
+ <met:label>${x(el.label)}</met:label>
282
+ <met:locationX>${50 + idx * 200}</met:locationX>
283
+ <met:locationY>180</met:locationY>
284
+ <met:actionName>${x(el.emailAlertApiName ?? el.name)}</met:actionName>
285
+ <met:actionType>emailAlert</met:actionType>
286
+ ${connector}
287
+ </met:actionCalls>`;
288
+ case "ApexAction":
289
+ return `<met:actionCalls>
290
+ <met:name>${x(el.name)}</met:name>
291
+ <met:label>${x(el.label)}</met:label>
292
+ <met:locationX>${50 + idx * 200}</met:locationX>
293
+ <met:locationY>180</met:locationY>
294
+ <met:actionName>${x(el.apexClassName ?? "")}${el.apexMethodName ? `.${x(el.apexMethodName)}` : ""}</met:actionName>
295
+ <met:actionType>apex</met:actionType>
296
+ ${connector}
297
+ </met:actionCalls>`;
298
+ case "Subflow":
299
+ return `<met:subflows>
300
+ <met:name>${x(el.name)}</met:name>
301
+ <met:label>${x(el.label)}</met:label>
302
+ <met:locationX>${50 + idx * 200}</met:locationX>
303
+ <met:locationY>180</met:locationY>
304
+ <met:flowName>${x(el.subflowApiName ?? "")}</met:flowName>
305
+ ${connector}
306
+ </met:subflows>`;
307
+ case "Loop":
308
+ return `<met:loops>
309
+ <met:name>${x(el.name)}</met:name>
310
+ <met:label>${x(el.label)}</met:label>
311
+ <met:locationX>${50 + idx * 200}</met:locationX>
312
+ <met:locationY>180</met:locationY>
313
+ <met:collectionReference>${x(el.loopVariable ?? "")}</met:collectionReference>
314
+ <met:iterationOrder>Asc</met:iterationOrder>
315
+ ${el.loopIterationVariable ? `<met:iterationVariable>${x(el.loopIterationVariable)}</met:iterationVariable>` : ""}
316
+ ${connector}
317
+ </met:loops>`;
318
+ case "Assignment": {
319
+ const assignItems = (el.assignments ?? []).map(a => `
320
+ <met:assignmentItems>
321
+ <met:assignToReference>${x(a.assignToRef)}</met:assignToReference>
322
+ <met:operator>${x(a.operator)}</met:operator>
323
+ <met:value>${a.valueRef
324
+ ? `<met:elementReference>${x(a.valueRef)}</met:elementReference>`
325
+ : `<met:stringValue>${x(a.value ?? "")}</met:stringValue>`}
326
+ </met:value>
327
+ </met:assignmentItems>`).join("\n");
328
+ return `<met:assignments>
329
+ <met:name>${x(el.name)}</met:name>
330
+ <met:label>${x(el.label)}</met:label>
331
+ <met:locationX>${50 + idx * 200}</met:locationX>
332
+ <met:locationY>180</met:locationY>
333
+ ${assignItems}
334
+ ${connector}
335
+ </met:assignments>`;
336
+ }
337
+ case "Screen": {
338
+ const screenFieldsXml = (el.screenFields ?? []).map(sf => `
339
+ <met:fields>
340
+ <met:name>${x(sf.name)}</met:name>
341
+ <met:fieldType>${x(sf.fieldType)}</met:fieldType>
342
+ ${sf.label ? `<met:fieldText>${x(sf.label)}</met:fieldText>` : ""}
343
+ ${sf.dataType ? `<met:dataType>${x(sf.dataType)}</met:dataType>` : ""}
344
+ ${sf.defaultValueRef ? `<met:defaultValue><met:elementReference>${x(sf.defaultValueRef)}</met:elementReference></met:defaultValue>` : ""}
345
+ </met:fields>`).join("\n");
346
+ return `<met:screens>
347
+ <met:name>${x(el.name)}</met:name>
348
+ <met:label>${x(el.label)}</met:label>
349
+ <met:locationX>${50 + idx * 200}</met:locationX>
350
+ <met:locationY>180</met:locationY>
351
+ ${screenFieldsXml}
352
+ ${connector}
353
+ </met:screens>`;
354
+ }
355
+ default:
356
+ return `<!-- Unknown element type: ${el.type} -->`;
357
+ }
358
+ }).join("\n");
359
+ };
360
+ const hasFieldUpdates = params.fieldUpdates && params.fieldUpdates.length > 0;
361
+ const hasApprovalSubmit = !!params.submitForApprovalProcessName;
362
+ const hasElements = params.elements && params.elements.length > 0;
363
+ const firstTarget = hasElements && params.elements[0]
364
+ ? params.elements[0].name
365
+ : hasApprovalSubmit ? "Submit_For_Approval"
366
+ : hasFieldUpdates ? "Update_Record"
367
+ : null;
368
+ const startConnector = firstTarget
369
+ ? `<met:connector><met:targetReference>${firstTarget}</met:targetReference></met:connector>` : "";
370
+ const startElement = params.flowType === "RecordTriggeredFlow" && params.triggerObject ? `
371
+ <met:start>
372
+ <met:locationX>50</met:locationX><met:locationY>0</met:locationY>
373
+ <met:object>${x(params.triggerObject)}</met:object>
374
+ <met:recordTriggerType>CreateAndUpdate</met:recordTriggerType>
375
+ <met:triggerType>${x(params.triggerType ?? "RecordAfterSave")}</met:triggerType>
376
+ ${params.triggerFilterFormula ? `<met:filterFormula>${x(params.triggerFilterFormula)}</met:filterFormula>` : ""}
377
+ ${startConnector}
378
+ </met:start>` : `
379
+ <met:start>
380
+ <met:locationX>50</met:locationX><met:locationY>0</met:locationY>
381
+ ${startConnector}
382
+ </met:start>`;
383
+ const approvalSubmitElement = hasApprovalSubmit ? `
384
+ <met:actionCalls>
385
+ <met:name>Submit_For_Approval</met:name>
386
+ <met:label>Submit for Approval</met:label>
387
+ <met:locationX>50</met:locationX><met:locationY>180</met:locationY>
388
+ <met:actionName>submit</met:actionName>
389
+ <met:actionType>submit</met:actionType>
390
+ ${hasFieldUpdates ? `<met:connector><met:targetReference>Update_Record</met:targetReference></met:connector>` : ""}
391
+ <met:inputParameters>
392
+ <met:name>objectId</met:name>
393
+ <met:value><met:elementReference>$Record.Id</met:elementReference></met:value>
394
+ </met:inputParameters>
395
+ <met:inputParameters>
396
+ <met:name>processDefinitionNameOrId</met:name>
397
+ <met:value><met:stringValue>${x(params.submitForApprovalProcessName ?? "")}</met:stringValue></met:value>
398
+ </met:inputParameters>
399
+ <met:inputParameters>
400
+ <met:name>skipEntryCriteria</met:name>
401
+ <met:value><met:booleanValue>false</met:booleanValue></met:value>
402
+ </met:inputParameters>
403
+ </met:actionCalls>` : "";
404
+ const recordUpdateElement = hasFieldUpdates ? `
405
+ <met:recordUpdates>
406
+ <met:name>Update_Record</met:name>
407
+ <met:label>Update Record</met:label>
408
+ <met:locationX>50</met:locationX><met:locationY>300</met:locationY>
409
+ <met:inputReference>{!$Record}</met:inputReference>
410
+ ${(params.fieldUpdates ?? []).map(fu => `
411
+ <met:inputAssignments>
412
+ <met:field>${x(fu.field)}</met:field>
413
+ <met:value>${fu.formula
414
+ ? `<met:elementReference>${x(fu.formula)}</met:elementReference>`
415
+ : `<met:stringValue>${x(fu.value ?? "")}</met:stringValue>`}
416
+ </met:value>
417
+ </met:inputAssignments>`).join("\n")}
418
+ </met:recordUpdates>` : "";
419
+ return `<met:metadata xsi:type="met:Flow" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
420
+ <met:fullName>${x(params.apiName)}</met:fullName>
421
+ <met:label>${x(params.label)}</met:label>
422
+ <met:apiVersion>${API_VERSION}</met:apiVersion>
423
+ <met:status>${x(params.status)}</met:status>
424
+ <met:processType>${x(params.flowType)}</met:processType>
425
+ <met:environments>Default</met:environments>
426
+ ${params.description ? `<met:description>${x(params.description)}</met:description>` : ""}
427
+ ${vars}
428
+ ${startElement}
429
+ ${buildElements(params.elements)}
430
+ ${approvalSubmitElement}
431
+ ${recordUpdateElement}
432
+ </met:metadata>`;
433
+ }
434
+ function buildApprovalProcessXml(params) {
435
+ const submitters = params.allowedSubmitters.map(s => `
436
+ <met:allowedSubmitters>
437
+ <met:type>${x(s.type)}</met:type>
438
+ ${s.submitter ? `<met:submitter>${x(s.submitter)}</met:submitter>` : ""}
439
+ </met:allowedSubmitters>`).join("\n");
440
+ const steps = params.approvalSteps.map((step, i) => `
441
+ <met:approvalStep>
442
+ <met:name>${x(step.name)}</met:name>
443
+ <met:label>${x(step.label)}</met:label>
444
+ <met:allowDelegate>${step.allowDelegate}</met:allowDelegate>
445
+ <met:assignedApprover>
446
+ ${step.approvers.map(a => `<met:approver>
447
+ <met:type>${x(a.type)}</met:type>
448
+ ${a.name ? `<met:name>${x(a.name)}</met:name>` : ""}
449
+ </met:approver>`).join("\n")}
450
+ <met:whenMultipleApprovers>${x(step.whenMultiple)}</met:whenMultipleApprovers>
451
+ </met:assignedApprover>
452
+ ${step.entryFormula ? `<met:entryCriteria><met:formula>${x(step.entryFormula)}</met:formula></met:entryCriteria>
453
+ <met:ifCriteriaNotMet>${x(step.ifCriteriaNotMet)}</met:ifCriteriaNotMet>` : ""}
454
+ ${i > 0 && step.rejectBehavior ? `<met:rejectBehavior><met:type>${x(step.rejectBehavior)}</met:type></met:rejectBehavior>` : ""}
455
+ </met:approvalStep>`).join("\n");
456
+ let entryCriteriaXml = "";
457
+ if (params.entryFormula) {
458
+ entryCriteriaXml = `<met:entryCriteria><met:formula>${x(params.entryFormula)}</met:formula></met:entryCriteria>`;
459
+ }
460
+ else if (params.entryFilterCriteria?.length) {
461
+ const items = params.entryFilterCriteria.map(fc => `
462
+ <met:criteriaItems>
463
+ <met:field>${x(params.objectName)}.${x(fc.field)}</met:field>
464
+ <met:operation>${x(fc.operation)}</met:operation>
465
+ <met:value>${x(fc.value)}</met:value>
466
+ </met:criteriaItems>`).join("\n");
467
+ entryCriteriaXml = `<met:entryCriteria>${items}</met:entryCriteria>`;
468
+ }
469
+ return `<met:metadata xsi:type="met:ApprovalProcess" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
470
+ <met:fullName>${x(params.objectName)}.${x(params.processName)}</met:fullName>
471
+ <met:label>${x(params.label)}</met:label>
472
+ <met:active>${params.active}</met:active>
473
+ <met:allowRecall>${params.allowRecall}</met:allowRecall>
474
+ ${params.description ? `<met:description>${x(params.description)}</met:description>` : ""}
475
+ ${submitters}
476
+ <met:approvalPageFields><met:field>Name</met:field><met:field>Owner</met:field></met:approvalPageFields>
477
+ ${steps}
478
+ ${entryCriteriaXml}
479
+ ${params.emailTemplate ? `<met:emailTemplate>${x(params.emailTemplate)}</met:emailTemplate>` : ""}
480
+ <met:finalApprovalRecordLock>${params.finalApprovalLock}</met:finalApprovalRecordLock>
481
+ <met:finalRejectionRecordLock>${params.finalRejectionLock}</met:finalRejectionRecordLock>
482
+ <met:recordEditability>${x(params.recordEditability)}</met:recordEditability>
483
+ <met:showApprovalHistory>true</met:showApprovalHistory>
484
+ </met:metadata>`;
485
+ }
486
+ function buildValidationRuleXml(params) {
487
+ return `<met:metadata xsi:type="met:CustomObject" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
488
+ <met:fullName>${x(params.objectName)}</met:fullName>
489
+ <met:validationRules>
490
+ <met:fullName>${x(params.ruleName)}</met:fullName>
491
+ <met:active>${params.active}</met:active>
492
+ <met:errorConditionFormula>${x(params.errorConditionFormula)}</met:errorConditionFormula>
493
+ <met:errorMessage>${x(params.errorMessage)}</met:errorMessage>
494
+ ${params.errorDisplayField ? `<met:errorDisplayField>${x(params.errorDisplayField)}</met:errorDisplayField>` : ""}
495
+ ${params.description ? `<met:description>${x(params.description)}</met:description>` : ""}
496
+ </met:validationRules>
497
+ </met:metadata>`;
498
+ }
499
+ function buildWorkflowFieldUpdateXml(params) {
500
+ let operationXml = "";
501
+ if (params.nullValue) {
502
+ operationXml = `<met:operation>Null</met:operation>`;
503
+ }
504
+ else if (params.formula) {
505
+ operationXml = `<met:formula>${x(params.formula)}</met:formula><met:operation>Formula</met:operation>`;
506
+ }
507
+ else {
508
+ operationXml = `<met:literalValue>${x(params.literalValue ?? "")}</met:literalValue><met:operation>Literal</met:operation>`;
509
+ }
510
+ return `<met:metadata xsi:type="met:Workflow" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
511
+ <met:fullName>${x(params.objectName)}</met:fullName>
512
+ <met:fieldUpdates>
513
+ <met:name>${x(params.actionName)}</met:name>
514
+ <met:label>${x(params.label)}</met:label>
515
+ <met:field>${x(params.field)}</met:field>
516
+ ${operationXml}
517
+ <met:notifyAssignee>${params.notifyAssignee}</met:notifyAssignee>
518
+ <met:protected>false</met:protected>
519
+ </met:fieldUpdates>
520
+ </met:metadata>`;
521
+ }
522
+ // ─── New XML builders for expanded tools ─────────────────────────────────────
523
+ function buildCustomMetadataTypeXml(params) {
524
+ const fieldsXml = params.fields ? buildSimpleFieldsXml(params.fields) : "";
525
+ return `<met:metadata xsi:type="met:CustomObject" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
526
+ <met:fullName>${x(params.fullName)}</met:fullName>
527
+ <met:label>${x(params.label)}</met:label>
528
+ <met:pluralLabel>${x(params.pluralLabel)}</met:pluralLabel>
529
+ ${params.description ? `<met:description>${x(params.description)}</met:description>` : ""}
530
+ <met:deploymentStatus>Deployed</met:deploymentStatus>
531
+ ${fieldsXml}
532
+ </met:metadata>`;
533
+ }
534
+ function buildCustomMetadataRecordXml(params) {
535
+ const valuesXml = params.values.map(v => `
536
+ <met:values>
537
+ <met:field>${x(v.field)}</met:field>
538
+ <met:value xsi:type="xsd:string" xmlns:xsd="http://www.w3.org/2001/XMLSchema">${x(v.value)}</met:value>
539
+ </met:values>`).join("\n");
540
+ return `<met:metadata xsi:type="met:CustomMetadata" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
541
+ <met:fullName>${x(params.typeName)}.${x(params.recordName)}</met:fullName>
542
+ <met:label>${x(params.label)}</met:label>
543
+ ${valuesXml}
544
+ </met:metadata>`;
545
+ }
546
+ function buildCustomLabelXml(params) {
547
+ return `<met:metadata xsi:type="met:CustomLabels" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
548
+ <met:fullName>CustomLabels</met:fullName>
549
+ <met:labels>
550
+ <met:fullName>${x(params.fullName)}</met:fullName>
551
+ <met:value>${x(params.value)}</met:value>
552
+ <met:language>${x(params.language)}</met:language>
553
+ ${params.categories ? `<met:categories>${x(params.categories)}</met:categories>` : ""}
554
+ <met:protected>${params.protected}</met:protected>
555
+ ${params.shortDescription ? `<met:shortDescription>${x(params.shortDescription)}</met:shortDescription>` : ""}
556
+ </met:labels>
557
+ </met:metadata>`;
558
+ }
559
+ function buildCustomSettingXml(params) {
560
+ const fieldsXml = params.fields ? buildSimpleFieldsXml(params.fields) : "";
561
+ return `<met:metadata xsi:type="met:CustomObject" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
562
+ <met:fullName>${x(params.fullName)}</met:fullName>
563
+ <met:label>${x(params.label)}</met:label>
564
+ <met:customSettingsType>${x(params.settingType)}</met:customSettingsType>
565
+ <met:customSettingsVisibility>${x(params.visibility)}</met:customSettingsVisibility>
566
+ <met:deploymentStatus>Deployed</met:deploymentStatus>
567
+ ${params.description ? `<met:description>${x(params.description)}</met:description>` : ""}
568
+ ${fieldsXml}
569
+ </met:metadata>`;
570
+ }
571
+ function buildGlobalValueSetXml(params) {
572
+ const valuesXml = params.values.map(v => `
573
+ <met:customValue>
574
+ <met:fullName>${x(v.fullName)}</met:fullName>
575
+ <met:label>${x(v.label)}</met:label>
576
+ <met:default>${v.default}</met:default>
577
+ ${v.description ? `<met:description>${x(v.description)}</met:description>` : ""}
578
+ </met:customValue>`).join("\n");
579
+ return `<met:metadata xsi:type="met:GlobalValueSet" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
580
+ <met:fullName>${x(params.fullName)}</met:fullName>
581
+ <met:masterLabel>${x(params.masterLabel)}</met:masterLabel>
582
+ ${params.description ? `<met:description>${x(params.description)}</met:description>` : ""}
583
+ <met:sorted>${params.sorted}</met:sorted>
584
+ ${valuesXml}
585
+ </met:metadata>`;
586
+ }
587
+ function buildPlatformEventXml(params) {
588
+ const fieldsXml = params.fields ? buildSimpleFieldsXml(params.fields) : "";
589
+ return `<met:metadata xsi:type="met:CustomObject" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
590
+ <met:fullName>${x(params.fullName)}</met:fullName>
591
+ <met:label>${x(params.label)}</met:label>
592
+ <met:pluralLabel>${x(params.pluralLabel)}</met:pluralLabel>
593
+ <met:deploymentStatus>Deployed</met:deploymentStatus>
594
+ <met:publishBehavior>${x(params.publishBehavior)}</met:publishBehavior>
595
+ ${params.description ? `<met:description>${x(params.description)}</met:description>` : ""}
596
+ ${fieldsXml}
597
+ </met:metadata>`;
598
+ }
599
+ function buildEmailAlertXml(params) {
600
+ const recipientsXml = params.recipients.map(r => `
601
+ <met:recipients>
602
+ <met:type>${x(r.type)}</met:type>
603
+ ${r.recipient ? `<met:recipient>${x(r.recipient)}</met:recipient>` : ""}
604
+ </met:recipients>`).join("\n");
605
+ return `<met:metadata xsi:type="met:Workflow" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
606
+ <met:fullName>${x(params.objectName)}</met:fullName>
607
+ <met:alerts>
608
+ <met:fullName>${x(params.alertName)}</met:fullName>
609
+ <met:label>${x(params.label)}</met:label>
610
+ <met:template>${x(params.template)}</met:template>
611
+ <met:senderType>${x(params.senderType)}</met:senderType>
612
+ ${params.senderAddress ? `<met:senderAddress>${x(params.senderAddress)}</met:senderAddress>` : ""}
613
+ ${params.description ? `<met:description>${x(params.description)}</met:description>` : ""}
614
+ <met:protected>${params.protected}</met:protected>
615
+ ${recipientsXml}
616
+ </met:alerts>
617
+ </met:metadata>`;
618
+ }
619
+ function buildAssignmentRuleXml(params) {
620
+ const entriesXml = params.ruleEntries.map(e => {
621
+ const criteriaXml = (e.criteriaItems ?? []).map(c => `
622
+ <met:criteriaItems>
623
+ <met:field>${x(c.field)}</met:field>
624
+ <met:operation>${x(c.operation)}</met:operation>
625
+ <met:value>${x(c.value)}</met:value>
626
+ </met:criteriaItems>`).join("\n");
627
+ return `<met:ruleEntry>
628
+ <met:assignedTo>${x(e.assignedTo)}</met:assignedTo>
629
+ <met:assignedToType>${x(e.assignedToType)}</met:assignedToType>
630
+ ${criteriaXml}
631
+ ${e.formula ? `<met:formula>${x(e.formula)}</met:formula>` : ""}
632
+ ${e.booleanFilter ? `<met:booleanFilter>${x(e.booleanFilter)}</met:booleanFilter>` : ""}
633
+ ${e.template ? `<met:template>${x(e.template)}</met:template>` : ""}
634
+ </met:ruleEntry>`;
635
+ }).join("\n");
636
+ return `<met:metadata xsi:type="met:AssignmentRules" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
637
+ <met:fullName>${x(params.objectName)}</met:fullName>
638
+ <met:assignmentRule>
639
+ <met:fullName>${x(params.ruleName)}</met:fullName>
640
+ <met:active>${params.active}</met:active>
641
+ ${entriesXml}
642
+ </met:assignmentRule>
643
+ </met:metadata>`;
644
+ }
645
+ function buildPermissionSetXml(params) {
646
+ const objPermsXml = (params.objectPermissions ?? []).map(op => `
647
+ <met:objectPermissions>
648
+ <met:allowCreate>${op.allowCreate}</met:allowCreate>
649
+ <met:allowDelete>${op.allowDelete}</met:allowDelete>
650
+ <met:allowEdit>${op.allowEdit}</met:allowEdit>
651
+ <met:allowRead>${op.allowRead}</met:allowRead>
652
+ <met:modifyAllRecords>${op.modifyAllRecords}</met:modifyAllRecords>
653
+ <met:object>${x(op.object)}</met:object>
654
+ <met:viewAllRecords>${op.viewAllRecords}</met:viewAllRecords>
655
+ </met:objectPermissions>`).join("\n");
656
+ const fieldPermsXml = (params.fieldPermissions ?? []).map(fp => `
657
+ <met:fieldPermissions>
658
+ <met:editable>${fp.editable}</met:editable>
659
+ <met:field>${x(fp.field)}</met:field>
660
+ <met:readable>${fp.readable}</met:readable>
661
+ </met:fieldPermissions>`).join("\n");
662
+ const apexAccessXml = (params.apexClassAccesses ?? []).map(a => `
663
+ <met:classAccesses>
664
+ <met:apexClass>${x(a.apexClass)}</met:apexClass>
665
+ <met:enabled>${a.enabled}</met:enabled>
666
+ </met:classAccesses>`).join("\n");
667
+ const userPermsXml = (params.userPermissions ?? []).map(u => `
668
+ <met:userPermissions>
669
+ <met:enabled>${u.enabled}</met:enabled>
670
+ <met:name>${x(u.name)}</met:name>
671
+ </met:userPermissions>`).join("\n");
672
+ const tabXml = (params.tabSettings ?? []).map(t => `
673
+ <met:tabSettings>
674
+ <met:tab>${x(t.tab)}</met:tab>
675
+ <met:visibility>${x(t.visibility)}</met:visibility>
676
+ </met:tabSettings>`).join("\n");
677
+ return `<met:metadata xsi:type="met:PermissionSet" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
678
+ <met:fullName>${x(params.fullName)}</met:fullName>
679
+ <met:label>${x(params.label)}</met:label>
680
+ ${params.description ? `<met:description>${x(params.description)}</met:description>` : ""}
681
+ ${params.userLicense ? `<met:userLicense>${x(params.userLicense)}</met:userLicense>` : ""}
682
+ ${objPermsXml}
683
+ ${fieldPermsXml}
684
+ ${apexAccessXml}
685
+ ${userPermsXml}
686
+ ${tabXml}
687
+ </met:metadata>`;
688
+ }
689
+ function buildRoleXml(params) {
690
+ return `<met:metadata xsi:type="met:Role" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
691
+ <met:fullName>${x(params.fullName)}</met:fullName>
692
+ <met:name>${x(params.name)}</met:name>
693
+ ${params.description ? `<met:description>${x(params.description)}</met:description>` : ""}
694
+ ${params.parentRole ? `<met:parentRole>${x(params.parentRole)}</met:parentRole>` : ""}
695
+ <met:caseAccessLevel>${x(params.caseAccessLevel)}</met:caseAccessLevel>
696
+ <met:contactAccessLevel>${x(params.contactAccessLevel)}</met:contactAccessLevel>
697
+ <met:opportunityAccessLevel>${x(params.opportunityAccessLevel)}</met:opportunityAccessLevel>
698
+ <met:accountAccessLevel>${x(params.accountAccessLevel)}</met:accountAccessLevel>
699
+ <met:mayForecastManagerShare>${params.mayForecastManagerShare}</met:mayForecastManagerShare>
700
+ </met:metadata>`;
701
+ }
702
+ function buildQueueXml(params) {
703
+ const sobjectsXml = params.supportedObjects.map(o => `
704
+ <met:queueSobject><met:sobjectType>${x(o)}</met:sobjectType></met:queueSobject>`).join("\n");
705
+ const membersXml = params.queueMembers ? `
706
+ <met:queueMembers>
707
+ ${(params.queueMembers.users ?? []).map(u => `<met:users><met:user>${x(u)}</met:user></met:users>`).join("\n")}
708
+ ${(params.queueMembers.groups ?? []).map(g => `<met:groups><met:group>${x(g)}</met:group></met:groups>`).join("\n")}
709
+ ${(params.queueMembers.roles ?? []).map(r => `<met:roles><met:role>${x(r)}</met:role></met:roles>`).join("\n")}
710
+ </met:queueMembers>` : "";
711
+ return `<met:metadata xsi:type="met:Queue" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
712
+ <met:fullName>${x(params.fullName)}</met:fullName>
713
+ <met:name>${x(params.name)}</met:name>
714
+ ${params.email ? `<met:email>${x(params.email)}</met:email>` : ""}
715
+ <met:doesSendEmailToMembers>${params.doesSendEmailToMembers}</met:doesSendEmailToMembers>
716
+ ${sobjectsXml}
717
+ ${membersXml}
718
+ </met:metadata>`;
719
+ }
720
+ function buildNamedCredentialXml(params) {
721
+ return `<met:metadata xsi:type="met:NamedCredential" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
722
+ <met:fullName>${x(params.fullName)}</met:fullName>
723
+ <met:label>${x(params.label)}</met:label>
724
+ <met:endpoint>${x(params.endpoint)}</met:endpoint>
725
+ <met:principalType>${x(params.principalType)}</met:principalType>
726
+ <met:protocol>${x(params.protocol)}</met:protocol>
727
+ ${params.username ? `<met:username>${x(params.username)}</met:username>` : ""}
728
+ <met:allowMergeFieldsInBody>${params.allowFormula}</met:allowMergeFieldsInBody>
729
+ <met:allowMergeFieldsInHeader>${params.allowFormula}</met:allowMergeFieldsInHeader>
730
+ <met:generateAuthorizationHeader>${params.allowCallout}</met:generateAuthorizationHeader>
731
+ </met:metadata>`;
732
+ }
733
+ function buildLightningAppXml(params) {
734
+ const navItemsXml = (params.navItems ?? []).map(ni => `
735
+ <met:navItems>
736
+ <met:name>${x(ni.name)}</met:name>
737
+ <met:type>${x(ni.type)}</met:type>
738
+ ${ni.label ? `<met:label>${x(ni.label)}</met:label>` : ""}
739
+ <met:defaultItem>${ni.defaultItem}</met:defaultItem>
740
+ </met:navItems>`).join("\n");
741
+ const utilityXml = (params.utilityItems ?? []).map(u => `
742
+ <met:utilityBar>
743
+ <met:name>${x(u.name)}</met:name>
744
+ <met:type>${x(u.type)}</met:type>
745
+ ${u.label ? `<met:label>${x(u.label)}</met:label>` : ""}
746
+ ${u.iconName ? `<met:itemComponents><met:componentName>${x(u.iconName)}</met:componentName></met:itemComponents>` : ""}
747
+ </met:utilityBar>`).join("\n");
748
+ return `<met:metadata xsi:type="met:CustomApplication" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
749
+ <met:fullName>${x(params.fullName)}</met:fullName>
750
+ <met:label>${x(params.label)}</met:label>
751
+ ${params.description ? `<met:description>${x(params.description)}</met:description>` : ""}
752
+ <met:navType>${x(params.navType)}</met:navType>
753
+ <met:uiType>${x(params.uiType)}</met:uiType>
754
+ <met:setupExperience>${x(params.setupExperience)}</met:setupExperience>
755
+ <met:isNavAutoTempTabsDisabled>${params.isNavAutoTempTabsDisabled}</met:isNavAutoTempTabsDisabled>
756
+ <met:isNavPersonalizationDisabled>${params.isNavPersonalizationDisabled}</met:isNavPersonalizationDisabled>
757
+ ${navItemsXml}
758
+ ${utilityXml}
759
+ </met:metadata>`;
760
+ }
761
+ function buildTabXml(params) {
762
+ return `<met:metadata xsi:type="met:CustomTab" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
763
+ <met:fullName>${x(params.fullName)}</met:fullName>
764
+ <met:motif>${x(params.motif)}</met:motif>
765
+ <met:customObject>${params.customObject}</met:customObject>
766
+ ${params.sobjectName ? `<met:sobjectName>${x(params.sobjectName)}</met:sobjectName>` : ""}
767
+ ${params.label ? `<met:label>${x(params.label)}</met:label>` : ""}
768
+ ${params.url ? `<met:url>${x(params.url)}</met:url>` : ""}
769
+ ${params.page ? `<met:page>${x(params.page)}</met:page>` : ""}
770
+ ${params.description ? `<met:description>${x(params.description)}</met:description>` : ""}
771
+ </met:metadata>`;
772
+ }
773
+ function buildCompactLayoutXml(params) {
774
+ const fieldsXml = params.fields.map(f => `<met:fields>${x(f)}</met:fields>`).join("\n");
775
+ return `<met:metadata xsi:type="met:CustomObject" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
776
+ <met:fullName>${x(params.objectName)}</met:fullName>
777
+ <met:compactLayouts>
778
+ <met:fullName>${x(params.fullName)}</met:fullName>
779
+ <met:label>${x(params.label)}</met:label>
780
+ ${fieldsXml}
781
+ </met:compactLayouts>
782
+ </met:metadata>`;
783
+ }
784
+ function buildListViewXml(params) {
785
+ const colsXml = (params.columns ?? []).map(c => `<met:columns>${x(c)}</met:columns>`).join("\n");
786
+ const filtersXml = (params.filters ?? []).map(f => `
787
+ <met:filters>
788
+ <met:field>${x(f.field)}</met:field>
789
+ <met:operation>${x(f.operation)}</met:operation>
790
+ <met:value>${x(f.value)}</met:value>
791
+ </met:filters>`).join("\n");
792
+ const sharedToXml = params.sharedTo ? `
793
+ <met:sharedTo>
794
+ <met:${params.sharedTo.type}>${params.sharedTo.name ? x(params.sharedTo.name) : ""}</met:${params.sharedTo.type}>
795
+ </met:sharedTo>` : `<met:sharedTo><met:allUsers>true</met:allUsers></met:sharedTo>`;
796
+ return `<met:metadata xsi:type="met:CustomObject" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
797
+ <met:fullName>${x(params.objectName)}</met:fullName>
798
+ <met:listViews>
799
+ <met:fullName>${x(params.fullName)}</met:fullName>
800
+ <met:label>${x(params.label)}</met:label>
801
+ <met:filterScope>${x(params.filterScope)}</met:filterScope>
802
+ ${colsXml}
803
+ ${filtersXml}
804
+ ${params.booleanFilter ? `<met:booleanFilter>${x(params.booleanFilter)}</met:booleanFilter>` : ""}
805
+ ${sharedToXml}
806
+ </met:listViews>
807
+ </met:metadata>`;
808
+ }
809
+ function buildEmailTemplateXml(params) {
810
+ return `<met:metadata xsi:type="met:EmailTemplate" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
811
+ <met:fullName>${x(params.fullName)}</met:fullName>
812
+ <met:name>${x(params.name)}</met:name>
813
+ <met:available>${params.available}</met:available>
814
+ <met:encoding>${x(params.encoding)}</met:encoding>
815
+ <met:label>${x(params.label)}</met:label>
816
+ <met:style>none</met:style>
817
+ <met:subject>${x(params.subject)}</met:subject>
818
+ <met:textOnly>${x(params.body)}</met:textOnly>
819
+ ${params.htmlValue ? `<met:htmlValue>${x(params.htmlValue)}</met:htmlValue>` : ""}
820
+ <met:type>${x(params.type)}</met:type>
821
+ ${params.relatedEntityType ? `<met:relatedEntityType>${x(params.relatedEntityType)}</met:relatedEntityType>` : ""}
822
+ ${params.description ? `<met:description>${x(params.description)}</met:description>` : ""}
823
+ ${params.replyTo ? `<met:replyTo>${x(params.replyTo)}</met:replyTo>` : ""}
824
+ ${params.senderName ? `<met:senderName>${x(params.senderName)}</met:senderName>` : ""}
825
+ </met:metadata>`;
826
+ }
827
+ function buildCustomNotificationTypeXml(params) {
828
+ return `<met:metadata xsi:type="met:CustomNotificationType" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
829
+ <met:fullName>${x(params.fullName)}</met:fullName>
830
+ <met:customNotifTypeName>${x(params.customNotifTypeName)}</met:customNotifTypeName>
831
+ ${params.description ? `<met:description>${x(params.description)}</met:description>` : ""}
832
+ <met:desktop>${params.desktop}</met:desktop>
833
+ <met:mobile>${params.mobile}</met:mobile>
834
+ </met:metadata>`;
835
+ }
836
+ function buildReportTypeXml(params) {
837
+ const relXml = (params.relationships ?? []).map((r, i) => `
838
+ <met:sections>
839
+ <met:columns>
840
+ ${(r.columns ?? []).map(c => `<met:columns><met:field>${x(r.joinTable)}.${x(c)}</met:field><met:reverseJoinColumns><met:field/></met:reverseJoinColumns></met:columns>`).join("\n")}
841
+ </met:columns>
842
+ <met:masterLabel>${x(r.label ?? r.joinTable)}</met:masterLabel>
843
+ </met:sections>`).join("\n");
844
+ const joinXml = (params.relationships ?? []).map((r, i) => `
845
+ <met:relationships>
846
+ <met:join>
847
+ <met:outerJoin>${r.relationshipType === "Outer"}</met:outerJoin>
848
+ <met:relationship>${x(r.field ?? r.joinTable)}</met:relationship>
849
+ </met:join>
850
+ <met:preferredRelationship>${x(r.joinTable)}</met:preferredRelationship>
851
+ </met:relationships>`).join("\n");
852
+ return `<met:metadata xsi:type="met:ReportType" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
853
+ <met:fullName>${x(params.fullName)}</met:fullName>
854
+ <met:label>${x(params.label)}</met:label>
855
+ <met:baseObject>${x(params.baseObject)}</met:baseObject>
856
+ <met:category>${x(params.category)}</met:category>
857
+ <met:deployed>${params.deployed}</met:deployed>
858
+ ${params.description ? `<met:description>${x(params.description)}</met:description>` : ""}
859
+ ${relXml}
860
+ ${joinXml}
861
+ </met:metadata>`;
862
+ }
863
+ function buildConnectedAppXml(params) {
864
+ const callbacksXml = params.callbackUrls.map(u => `<met:callbackUrl>${x(u)}</met:callbackUrl>`).join("\n");
865
+ const scopesXml = params.scopes.map(s => `<met:scopes>${x(s)}</met:scopes>`).join("\n");
866
+ return `<met:metadata xsi:type="met:ConnectedApp" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
867
+ <met:fullName>${x(params.fullName)}</met:fullName>
868
+ <met:label>${x(params.label)}</met:label>
869
+ ${params.description ? `<met:description>${x(params.description)}</met:description>` : ""}
870
+ <met:contactEmail>${x(params.contactEmail)}</met:contactEmail>
871
+ <met:oauthConfig>
872
+ ${callbacksXml}
873
+ ${scopesXml}
874
+ ${params.consumerKey ? `<met:consumerKey>${x(params.consumerKey)}</met:consumerKey>` : ""}
875
+ ${params.startUrl ? `<met:startUrl>${x(params.startUrl)}</met:startUrl>` : ""}
876
+ </met:oauthConfig>
877
+ </met:metadata>`;
878
+ }
879
+ function buildExternalDataSourceXml(params) {
880
+ return `<met:metadata xsi:type="met:ExternalDataSource" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
881
+ <met:fullName>${x(params.fullName)}</met:fullName>
882
+ <met:label>${x(params.label)}</met:label>
883
+ <met:type>${x(params.type)}</met:type>
884
+ <met:endpoint>${x(params.endpoint)}</met:endpoint>
885
+ <met:principalType>${x(params.principalType)}</met:principalType>
886
+ <met:protocol>${x(params.protocol)}</met:protocol>
887
+ ${params.username ? `<met:username>${x(params.username)}</met:username>` : ""}
888
+ ${params.description ? `<met:description>${x(params.description)}</met:description>` : ""}
889
+ </met:metadata>`;
890
+ }
891
+ function buildExternalObjectXml(params) {
892
+ const fieldsXml = params.fields ? buildSimpleFieldsXml(params.fields) : "";
893
+ return `<met:metadata xsi:type="met:CustomObject" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
894
+ <met:fullName>${x(params.fullName)}</met:fullName>
895
+ <met:label>${x(params.label)}</met:label>
896
+ <met:pluralLabel>${x(params.pluralLabel)}</met:pluralLabel>
897
+ <met:externalDataSource>${x(params.externalDataSource)}</met:externalDataSource>
898
+ ${params.externalName ? `<met:externalName>${x(params.externalName)}</met:externalName>` : ""}
899
+ ${params.description ? `<met:description>${x(params.description)}</met:description>` : ""}
900
+ <met:deploymentStatus>Deployed</met:deploymentStatus>
901
+ ${fieldsXml}
902
+ </met:metadata>`;
903
+ }
904
+ function buildRemoteSiteSettingXml(params) {
905
+ return `<met:metadata xsi:type="met:RemoteSiteSetting" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
906
+ <met:fullName>${x(params.fullName)}</met:fullName>
907
+ <met:description>${x(params.description ?? params.name)}</met:description>
908
+ <met:disableProtocolSecurity>${params.disableProtocolSecurity}</met:disableProtocolSecurity>
909
+ <met:isActive>${params.isActive}</met:isActive>
910
+ <met:url>${x(params.url)}</met:url>
911
+ </met:metadata>`;
912
+ }
913
+ function buildCspTrustedSiteXml(params) {
914
+ const name = params.endpointUrl.replace(/[^A-Za-z0-9]/g, "_").slice(0, 40);
915
+ const directivesXml = params.cspDirectives.map(d => `<met:cspDirectives>${x(d)}</met:cspDirectives>`).join("\n");
916
+ return `<met:metadata xsi:type="met:CspTrustedSite" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
917
+ <met:fullName>${x(name)}</met:fullName>
918
+ <met:endpointUrl>${x(params.endpointUrl)}</met:endpointUrl>
919
+ ${params.description ? `<met:description>${x(params.description)}</met:description>` : ""}
920
+ <met:isActive>${params.isActive}</met:isActive>
921
+ ${directivesXml}
922
+ </met:metadata>`;
923
+ }
924
+ function buildSharingRuleXml(params) {
925
+ const criteriaXml = (params.criteriaItems ?? []).map(c => `
926
+ <met:criteriaItems>
927
+ <met:field>${x(params.objectName)}.${x(c.field)}</met:field>
928
+ <met:operation>${x(c.operation)}</met:operation>
929
+ <met:value>${x(c.value)}</met:value>
930
+ </met:criteriaItems>`).join("\n");
931
+ const sharedToXml = `<met:sharedTo><met:${x(params.sharedTo.type)}>${params.sharedTo.name ? x(params.sharedTo.name) : ""}</met:${x(params.sharedTo.type)}></met:sharedTo>`;
932
+ const sharedFromXml = params.sharedFrom
933
+ ? `<met:sharedFrom><met:${x(params.sharedFrom.type)}>${params.sharedFrom.name ? x(params.sharedFrom.name) : ""}</met:${x(params.sharedFrom.type)}></met:sharedFrom>` : "";
934
+ return `<met:metadata xsi:type="met:SharingRules" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
935
+ <met:fullName>${x(params.objectName)}</met:fullName>
936
+ <met:${params.ruleType === "criteria" ? "sharingCriteriaRules" : "sharingOwnerRules"}>
937
+ <met:fullName>${x(params.ruleName)}</met:fullName>
938
+ <met:label>${x(params.label)}</met:label>
939
+ <met:accessLevel>${x(params.accessLevel)}</met:accessLevel>
940
+ ${criteriaXml}
941
+ ${sharedFromXml}
942
+ ${sharedToXml}
943
+ </met:${params.ruleType === "criteria" ? "sharingCriteriaRules" : "sharingOwnerRules"}>
944
+ </met:metadata>`;
945
+ }
946
+ function buildRecordTypeXml(params) {
947
+ const plValues = (params.picklistValues ?? []).map(pv => `
948
+ <met:picklistValues>
949
+ <met:picklist>${x(pv.picklist)}</met:picklist>
950
+ ${pv.values.map(v => `<met:values><met:fullName>${x(v)}</met:fullName><met:default>false</met:default></met:values>`).join("\n")}
951
+ </met:picklistValues>`).join("\n");
952
+ return `<met:metadata xsi:type="met:CustomObject" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
953
+ <met:fullName>${x(params.objectName)}</met:fullName>
954
+ <met:recordTypes>
955
+ <met:fullName>${x(params.fullName)}</met:fullName>
956
+ <met:label>${x(params.label)}</met:label>
957
+ <met:active>${params.isActive}</met:active>
958
+ ${params.description ? `<met:description>${x(params.description)}</met:description>` : ""}
959
+ ${params.businessProcess ? `<met:businessProcess>${x(params.businessProcess)}</met:businessProcess>` : ""}
960
+ ${plValues}
961
+ </met:recordTypes>
962
+ </met:metadata>`;
963
+ }
964
+ function buildBusinessProcessXml(params) {
965
+ const valuesXml = params.values.map(v => `
966
+ <met:values>
967
+ <met:fullName>${x(v)}</met:fullName>
968
+ <met:default>false</met:default>
969
+ <met:closed>false</met:closed>
970
+ </met:values>`).join("\n");
971
+ return `<met:metadata xsi:type="met:BusinessProcess" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
972
+ <met:fullName>${x(params.objectName)}.${x(params.processName)}</met:fullName>
973
+ <met:isActive>${params.isActive}</met:isActive>
974
+ <met:description>${x(params.description ?? params.label)}</met:description>
975
+ ${valuesXml}
976
+ </met:metadata>`;
977
+ }
978
+ function buildPageLayoutXml(params) {
979
+ const sectionsXml = (params.sections ?? []).map(s => {
980
+ const columns = s.style === "OneColumn" ? 1 : 2;
981
+ const fieldItems = s.fields.map(f => `
982
+ <met:layoutItems>
983
+ <met:behavior>Edit</met:behavior>
984
+ <met:field>${x(f)}</met:field>
985
+ </met:layoutItems>`).join("\n");
986
+ return `<met:layoutSections>
987
+ <met:customLabel>true</met:customLabel>
988
+ <met:detailHeading>true</met:detailHeading>
989
+ <met:editHeading>true</met:editHeading>
990
+ <met:label>${x(s.label)}</met:label>
991
+ <met:layoutColumns>${fieldItems}</met:layoutColumns>
992
+ ${columns > 1 ? `<met:layoutColumns></met:layoutColumns>` : ""}
993
+ <met:style>${x(s.style)}</met:style>
994
+ </met:layoutSections>`;
995
+ }).join("\n");
996
+ const relatedListsXml = (params.relatedLists ?? []).map(rl => `
997
+ <met:relatedLists>
998
+ <met:relatedList>${x(rl)}</met:relatedList>
999
+ </met:relatedLists>`).join("\n");
1000
+ return `<met:metadata xsi:type="met:Layout" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
1001
+ <met:fullName>${x(params.objectName)}-${x(params.layoutName)}</met:fullName>
1002
+ ${sectionsXml}
1003
+ ${relatedListsXml}
1004
+ </met:metadata>`;
1005
+ }
1006
+ function buildFieldDependencyXml(params) {
1007
+ const settingsXml = params.valueSettings.map(vs => `
1008
+ <met:valueSettings>
1009
+ ${vs.controllingFieldValue.map(cfv => `<met:controllingFieldValue>${x(cfv)}</met:controllingFieldValue>`).join("\n")}
1010
+ <met:valueName>${x(vs.valueName)}</met:valueName>
1011
+ </met:valueSettings>`).join("\n");
1012
+ return `<met:metadata xsi:type="met:CustomField" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
1013
+ <met:fullName>${x(params.objectName)}.${x(params.dependentField)}</met:fullName>
1014
+ <met:fieldDependency>
1015
+ <met:controllingField>${x(params.controllingField)}</met:controllingField>
1016
+ ${settingsXml}
1017
+ </met:fieldDependency>
1018
+ </met:metadata>`;
1019
+ }
1020
+ function buildNetworkXml(params) {
1021
+ return `<met:metadata xsi:type="met:Network" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
1022
+ <met:fullName>${x(params.siteName)}</met:fullName>
1023
+ <met:label>${x(params.label)}</met:label>
1024
+ <met:urlPathPrefix>${x(params.urlPathPrefix)}</met:urlPathPrefix>
1025
+ <met:template><met:name>${x(params.template)}</met:name></met:template>
1026
+ <met:status>${x(params.status)}</met:status>
1027
+ ${params.description ? `<met:description>${x(params.description)}</met:description>` : ""}
1028
+ ${params.guestUserProfile ? `<met:guestProfile>${x(params.guestUserProfile)}</met:guestProfile>` : ""}
1029
+ <met:allowedExtensions>jpg,jpeg,png,gif,pdf,doc,docx</met:allowedExtensions>
1030
+ <met:enableGuestChatter>false</met:enableGuestChatter>
1031
+ <met:enableInvitation>false</met:enableInvitation>
1032
+ <met:enableKnowledgeable>false</met:enableKnowledgeable>
1033
+ <met:enableNicknameDisplay>false</met:enableNicknameDisplay>
1034
+ <met:enablePrivateMessages>false</met:enablePrivateMessages>
1035
+ <met:enableReputation>false</met:enableReputation>
1036
+ <met:enableShowAllNetworkSettings>false</met:enableShowAllNetworkSettings>
1037
+ <met:enableTalkingAboutStats>false</met:enableTalkingAboutStats>
1038
+ <met:gatherCustomerSentimentData>false</met:gatherCustomerSentimentData>
1039
+ <met:loginType>CommunitiesLogin</met:loginType>
1040
+ <met:networkMemberGroups></met:networkMemberGroups>
1041
+ <met:picassoSite>${x(params.siteName)}</met:picassoSite>
1042
+ <met:selfRegistration>false</met:selfRegistration>
1043
+ <met:sendWelcomeEmail>false</met:sendWelcomeEmail>
1044
+ <met:tabs></met:tabs>
1045
+ <met:verificationRequired>Relaxed</met:verificationRequired>
1046
+ </met:metadata>`;
1047
+ }
1048
+ function buildBotXml(params) {
1049
+ return `<met:metadata xsi:type="met:Bot" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
1050
+ <met:fullName>${x(params.agentName)}</met:fullName>
1051
+ <met:label>${x(params.label)}</met:label>
1052
+ ${params.description ? `<met:description>${x(params.description)}</met:description>` : ""}
1053
+ <met:type>${x(params.type)}</met:type>
1054
+ <met:status>Active</met:status>
1055
+ ${params.company ? `<met:company>${x(params.company)}</met:company>` : ""}
1056
+ ${params.persona ? `<met:persona>${x(params.persona)}</met:persona>` : ""}
1057
+ <met:tone>${x(params.tone)}</met:tone>
1058
+ ${params.instructions ? `<met:systemPrompt>${x(params.instructions)}</met:systemPrompt>` : ""}
1059
+ </met:metadata>`;
1060
+ }
1061
+ function buildBotVersionXml(params) {
1062
+ const actionsXml = (params.actions ?? []).map(a => `
1063
+ <met:botActions>
1064
+ <met:botActionName>${x(a)}</met:botActionName>
1065
+ </met:botActions>`).join("\n");
1066
+ return `<met:metadata xsi:type="met:BotVersion" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
1067
+ <met:fullName>${x(params.agentName)}.${x(params.topicName)}</met:fullName>
1068
+ <met:label>${x(params.label)}</met:label>
1069
+ <met:description>${x(params.description)}</met:description>
1070
+ <met:scope>${x(params.scope)}</met:scope>
1071
+ ${params.instructions ? `<met:instructions>${x(params.instructions)}</met:instructions>` : ""}
1072
+ ${actionsXml}
1073
+ </met:metadata>`;
1074
+ }
1075
+ function buildMatchingRuleXml(params) {
1076
+ const itemsXml = params.matchingRuleItems.map(item => `
1077
+ <met:matchingRuleItems>
1078
+ <met:blankValueBehavior>${x(item.blankValueBehavior)}</met:blankValueBehavior>
1079
+ <met:fieldName>${x(params.objectName)}.${x(item.fieldName)}</met:fieldName>
1080
+ <met:matchingMethod>${x(item.matchingMethod)}</met:matchingMethod>
1081
+ </met:matchingRuleItems>`).join("\n");
1082
+ return `<met:metadata xsi:type="met:MatchingRule" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
1083
+ <met:fullName>${x(params.objectName)}.${x(params.ruleName)}</met:fullName>
1084
+ <met:label>${x(params.label)}</met:label>
1085
+ ${params.description ? `<met:description>${x(params.description)}</met:description>` : ""}
1086
+ <met:matchingRuleStatus>Active</met:matchingRuleStatus>
1087
+ ${itemsXml}
1088
+ </met:metadata>`;
1089
+ }
1090
+ function buildDuplicateRuleXml(params) {
1091
+ const mrXml = params.matchingRules.map((mr, i) => `
1092
+ <met:duplicateRuleMatchRules>
1093
+ <met:duplicateRuleItemProperties></met:duplicateRuleItemProperties>
1094
+ <met:matchingRule>${x(params.objectName)}.${x(mr.matchingRule)}</met:matchingRule>
1095
+ <met:objectMapping>
1096
+ <met:inputObject>${x(params.objectName)}</met:inputObject>
1097
+ <met:outputObject>${x(params.objectName)}</met:outputObject>
1098
+ ${(mr.matchingRuleItems ?? []).map(item => `
1099
+ <met:mappingFields>
1100
+ <met:inputField>${x(item.fieldName)}</met:inputField>
1101
+ <met:outputField>${x(item.matchingField)}</met:outputField>
1102
+ </met:mappingFields>`).join("\n")}
1103
+ </met:objectMapping>
1104
+ </met:duplicateRuleMatchRules>`).join("\n");
1105
+ return `<met:metadata xsi:type="met:DuplicateRule" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
1106
+ <met:fullName>${x(params.objectName)}.${x(params.ruleName)}</met:fullName>
1107
+ <met:label>${x(params.label)}</met:label>
1108
+ <met:isActive>${params.isActive}</met:isActive>
1109
+ ${params.description ? `<met:description>${x(params.description)}</met:description>` : ""}
1110
+ <met:actionOnInsert>${x(params.actionOnInsert)}</met:actionOnInsert>
1111
+ <met:actionOnUpdate>${x(params.actionOnUpdate)}</met:actionOnUpdate>
1112
+ ${params.alertMessage ? `<met:alertText>${x(params.alertMessage)}</met:alertText>` : ""}
1113
+ ${mrXml}
1114
+ <met:operationsOnInsert>None</met:operationsOnInsert>
1115
+ <met:operationsOnUpdate>None</met:operationsOnUpdate>
1116
+ <met:securityOption>EnforcedWithWarning</met:securityOption>
1117
+ <met:sortOrder>1</met:sortOrder>
1118
+ </met:metadata>`;
1119
+ }
1120
+ function buildAutoResponseRuleXml(params) {
1121
+ const entriesXml = params.ruleEntries.map(e => {
1122
+ const criteriaXml = (e.criteriaItems ?? []).map(c => `
1123
+ <met:criteriaItems>
1124
+ <met:field>${x(c.field)}</met:field>
1125
+ <met:operation>${x(c.operation)}</met:operation>
1126
+ <met:value>${x(c.value)}</met:value>
1127
+ </met:criteriaItems>`).join("\n");
1128
+ return `<met:ruleEntry>
1129
+ <met:template>${x(e.template)}</met:template>
1130
+ ${e.senderName ? `<met:senderName>${x(e.senderName)}</met:senderName>` : ""}
1131
+ ${e.senderEmail ? `<met:senderEmail>${x(e.senderEmail)}</met:senderEmail>` : ""}
1132
+ ${criteriaXml}
1133
+ ${e.formula ? `<met:formula>${x(e.formula)}</met:formula>` : ""}
1134
+ </met:ruleEntry>`;
1135
+ }).join("\n");
1136
+ return `<met:metadata xsi:type="met:AutoResponseRules" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
1137
+ <met:fullName>${x(params.objectName)}</met:fullName>
1138
+ <met:autoResponseRule>
1139
+ <met:fullName>${x(params.ruleName)}</met:fullName>
1140
+ <met:active>${params.active}</met:active>
1141
+ ${entriesXml}
1142
+ </met:autoResponseRule>
1143
+ </met:metadata>`;
1144
+ }
1145
+ // ─── Core upsert ─────────────────────────────────────────────────────────────
1146
+ export async function upsertMetadata(auth, metadataXml) {
1147
+ const body = `<met:upsertMetadata>${metadataXml}</met:upsertMetadata>`;
1148
+ try {
1149
+ const xml = await callMetadataSoap(auth, "upsertMetadata", body);
1150
+ const error = extractSoapError(xml);
1151
+ if (error)
1152
+ return { success: false, message: error };
1153
+ const results = parseUpsertResult(xml);
1154
+ if (!results.length)
1155
+ return { success: false, message: "No result returned from Salesforce." };
1156
+ const r = results[0];
1157
+ if (!r.success) {
1158
+ const errMsg = r.errors?.map((e) => `[${e.statusCode}] ${e.message}`).join("; ") ?? "Unknown error";
1159
+ return { success: false, message: errMsg };
1160
+ }
1161
+ return { success: true, fullName: r.fullName, created: r.created, message: r.created ? `Successfully created '${r.fullName}'.` : `Successfully updated '${r.fullName}'.` };
1162
+ }
1163
+ catch (err) {
1164
+ const msg = err instanceof Error ? err.message : String(err);
1165
+ return { success: false, message: msg };
1166
+ }
1167
+ }
1168
+ // ─── Exported service functions ───────────────────────────────────────────────
1169
+ export async function createCustomObject(auth, meta) {
1170
+ return upsertMetadata(auth, buildCustomObjectXml(meta));
1171
+ }
1172
+ export async function createCustomField(auth, meta) {
1173
+ return upsertMetadata(auth, buildCustomFieldXml(meta));
1174
+ }
1175
+ export async function addPicklistValues(auth, objectFieldFullName, newValues) {
1176
+ const [objectName, fieldName] = objectFieldFullName.split(".");
1177
+ if (!objectName || !fieldName)
1178
+ return { success: false, message: "fullName must be in format 'ObjectName__c.FieldName__c'" };
1179
+ try {
1180
+ const client = createClient(auth);
1181
+ const query = `SELECT Id, Metadata FROM CustomField WHERE DeveloperName='${fieldName.replace(/__c$/i, "")}' AND TableEnumOrId='${objectName}'`;
1182
+ const resp = await client.get(`/tooling/query?q=${encodeURIComponent(query)}`);
1183
+ if (!resp.data.records.length)
1184
+ return { success: false, message: `Field '${objectFieldFullName}' not found in Tooling API.` };
1185
+ const record = resp.data.records[0];
1186
+ const existing = record.Metadata?.valueSet?.valueSetDefinition?.value ?? [];
1187
+ const existingNames = new Set(existing.map((v) => v.fullName));
1188
+ const merged = [...existing, ...newValues.filter((v) => !existingNames.has(v.fullName))];
1189
+ const fieldMeta = {
1190
+ fullName: objectFieldFullName, label: fieldName.replace(/__c$/i, "").replace(/_/g, " "), type: "Picklist",
1191
+ valueSet: { restricted: false, valueSetDefinition: { sorted: false, value: merged } },
1192
+ };
1193
+ return createCustomField(auth, fieldMeta);
1194
+ }
1195
+ catch (err) {
1196
+ const msg = err instanceof Error ? err.message : String(err);
1197
+ return { success: false, message: msg };
1198
+ }
1199
+ }
1200
+ export async function createFlow(auth, params) {
1201
+ return upsertMetadata(auth, buildFlowXml(params));
1202
+ }
1203
+ export async function createApprovalProcess(auth, params) {
1204
+ return upsertMetadata(auth, buildApprovalProcessXml(params));
1205
+ }
1206
+ export async function createValidationRule(auth, params) {
1207
+ return upsertMetadata(auth, buildValidationRuleXml(params));
1208
+ }
1209
+ export async function createWorkflowFieldUpdate(auth, params) {
1210
+ return upsertMetadata(auth, buildWorkflowFieldUpdateXml(params));
1211
+ }
1212
+ export async function createCustomMetadataType(auth, params) {
1213
+ return upsertMetadata(auth, buildCustomMetadataTypeXml(params));
1214
+ }
1215
+ export async function createCustomMetadataRecord(auth, params) {
1216
+ return upsertMetadata(auth, buildCustomMetadataRecordXml(params));
1217
+ }
1218
+ export async function createCustomLabel(auth, params) {
1219
+ return upsertMetadata(auth, buildCustomLabelXml(params));
1220
+ }
1221
+ export async function createCustomSetting(auth, params) {
1222
+ return upsertMetadata(auth, buildCustomSettingXml(params));
1223
+ }
1224
+ export async function createGlobalValueSet(auth, params) {
1225
+ return upsertMetadata(auth, buildGlobalValueSetXml(params));
1226
+ }
1227
+ export async function createPlatformEvent(auth, params) {
1228
+ return upsertMetadata(auth, buildPlatformEventXml(params));
1229
+ }
1230
+ export async function createEmailAlert(auth, params) {
1231
+ return upsertMetadata(auth, buildEmailAlertXml(params));
1232
+ }
1233
+ export async function createAssignmentRule(auth, params) {
1234
+ return upsertMetadata(auth, buildAssignmentRuleXml(params));
1235
+ }
1236
+ export async function createAutoResponseRule(auth, params) {
1237
+ return upsertMetadata(auth, buildAutoResponseRuleXml(params));
1238
+ }
1239
+ export async function createMatchingRule(auth, params) {
1240
+ return upsertMetadata(auth, buildMatchingRuleXml(params));
1241
+ }
1242
+ export async function createDuplicateRule(auth, params) {
1243
+ return upsertMetadata(auth, buildDuplicateRuleXml(params));
1244
+ }
1245
+ export async function createPermissionSet(auth, params) {
1246
+ return upsertMetadata(auth, buildPermissionSetXml(params));
1247
+ }
1248
+ export async function createRole(auth, params) {
1249
+ return upsertMetadata(auth, buildRoleXml(params));
1250
+ }
1251
+ export async function createQueue(auth, params) {
1252
+ return upsertMetadata(auth, buildQueueXml(params));
1253
+ }
1254
+ export async function createNamedCredential(auth, params) {
1255
+ return upsertMetadata(auth, buildNamedCredentialXml(params));
1256
+ }
1257
+ export async function createLightningApp(auth, params) {
1258
+ return upsertMetadata(auth, buildLightningAppXml(params));
1259
+ }
1260
+ export async function createTab(auth, params) {
1261
+ return upsertMetadata(auth, buildTabXml(params));
1262
+ }
1263
+ export async function createCompactLayout(auth, params) {
1264
+ return upsertMetadata(auth, buildCompactLayoutXml(params));
1265
+ }
1266
+ export async function createListView(auth, params) {
1267
+ return upsertMetadata(auth, buildListViewXml(params));
1268
+ }
1269
+ export async function createEmailTemplate(auth, params) {
1270
+ return upsertMetadata(auth, buildEmailTemplateXml(params));
1271
+ }
1272
+ export async function createCustomNotificationType(auth, params) {
1273
+ return upsertMetadata(auth, buildCustomNotificationTypeXml(params));
1274
+ }
1275
+ export async function createReportType(auth, params) {
1276
+ return upsertMetadata(auth, buildReportTypeXml(params));
1277
+ }
1278
+ export async function createConnectedApp(auth, params) {
1279
+ return upsertMetadata(auth, buildConnectedAppXml(params));
1280
+ }
1281
+ export async function createExternalDataSource(auth, params) {
1282
+ return upsertMetadata(auth, buildExternalDataSourceXml(params));
1283
+ }
1284
+ export async function createExternalObject(auth, params) {
1285
+ return upsertMetadata(auth, buildExternalObjectXml(params));
1286
+ }
1287
+ export async function createRemoteSiteSetting(auth, params) {
1288
+ return upsertMetadata(auth, buildRemoteSiteSettingXml(params));
1289
+ }
1290
+ export async function createCspSetting(auth, params) {
1291
+ return upsertMetadata(auth, buildCspTrustedSiteXml(params));
1292
+ }
1293
+ export async function createSharingRule(auth, params) {
1294
+ return upsertMetadata(auth, buildSharingRuleXml(params));
1295
+ }
1296
+ export async function createRecordType(auth, params) {
1297
+ return upsertMetadata(auth, buildRecordTypeXml(params));
1298
+ }
1299
+ export async function createBusinessProcess(auth, params) {
1300
+ return upsertMetadata(auth, buildBusinessProcessXml(params));
1301
+ }
1302
+ export async function createPageLayout(auth, params) {
1303
+ return upsertMetadata(auth, buildPageLayoutXml(params));
1304
+ }
1305
+ export async function createFieldDependency(auth, params) {
1306
+ return upsertMetadata(auth, buildFieldDependencyXml(params));
1307
+ }
1308
+ export async function createExperienceSite(auth, params) {
1309
+ return upsertMetadata(auth, buildNetworkXml(params));
1310
+ }
1311
+ export async function createAgent(auth, params) {
1312
+ return upsertMetadata(auth, buildBotXml(params));
1313
+ }
1314
+ export async function createAgentTopic(auth, params) {
1315
+ return upsertMetadata(auth, buildBotVersionXml(params));
1316
+ }
1317
+ //# sourceMappingURL=salesforce.js.map