salesforce-metadata-mcp 2.2.0 → 2.3.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.
@@ -2653,4 +2653,671 @@ export async function setExperienceSiteBranding(auth, params) {
2653
2653
  return { success: false, message: sanitizeError(err instanceof Error ? err.message : String(err)) };
2654
2654
  }
2655
2655
  }
2656
+ // ─── v2.3.0 OmniStudio Service Functions ─────────────────────────────────────
2657
+ function buildFlexCardDefinition(params) {
2658
+ return {
2659
+ name: params.cardName,
2660
+ sObjectType: params.objectApiName ?? "",
2661
+ dataSource: params.dataSourceType !== "None" ? {
2662
+ type: params.dataSourceType,
2663
+ value: params.dataSourceName ?? "",
2664
+ } : null,
2665
+ elements: (params.fields ?? []).map(f => ({
2666
+ type: "text",
2667
+ name: `field_${f.fieldName}`,
2668
+ label: f.label,
2669
+ fieldName: f.fieldName,
2670
+ dataType: f.type ?? "Text",
2671
+ })),
2672
+ actions: (params.actions ?? []).map(a => ({
2673
+ type: a.type,
2674
+ label: a.label,
2675
+ target: a.target,
2676
+ })),
2677
+ states: (params.states ?? [{ name: "Default", conditionType: "ALL", conditions: [] }]).map(s => ({
2678
+ name: s.name,
2679
+ conditionType: s.conditionType,
2680
+ conditions: s.conditions ?? [],
2681
+ })),
2682
+ };
2683
+ }
2684
+ export async function createFlexCard(auth, params) {
2685
+ try {
2686
+ const definition = buildFlexCardDefinition(params);
2687
+ const xml = `<met:metadata xsi:type="met:OmniUiCard" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
2688
+ <met:fullName>${x(params.cardName)}</met:fullName>
2689
+ <met:masterLabel>${x(params.label)}</met:masterLabel>
2690
+ ${params.description ? `<met:description>${x(params.description)}</met:description>` : ""}
2691
+ <met:omniUiCardType>Child</met:omniUiCardType>
2692
+ <met:versionNumber>1</met:versionNumber>
2693
+ <met:isActive>false</met:isActive>
2694
+ <met:omniUiCardDefinition>${x(JSON.stringify(definition))}</met:omniUiCardDefinition>
2695
+ </met:metadata>`;
2696
+ return await upsertMetadata(auth, xml);
2697
+ } catch (err) {
2698
+ return { success: false, message: sanitizeError(err instanceof Error ? err.message : String(err)) };
2699
+ }
2700
+ }
2701
+ export async function updateFlexCard(auth, params) {
2702
+ try {
2703
+ const existing = await readMetadataItem(auth, "OmniUiCard", params.cardName);
2704
+ if (!existing.success) return existing;
2705
+ const defMatch = existing.rawXml.match(/<omniUiCardDefinition[^>]*>([\s\S]*?)<\/omniUiCardDefinition>/i);
2706
+ let definition = {};
2707
+ if (defMatch) {
2708
+ try { definition = JSON.parse(defMatch[1].replace(/&amp;/g,"&").replace(/&lt;/g,"<").replace(/&gt;/g,">").replace(/&quot;/g,'"').replace(/&apos;/g,"'")); }
2709
+ catch { /* use empty definition */ }
2710
+ }
2711
+ const merged = {
2712
+ ...definition,
2713
+ ...(params.dataSourceType ? { dataSource: { type: params.dataSourceType, value: params.dataSourceName ?? "" } } : {}),
2714
+ ...(params.fields ? { elements: params.fields.map(f => ({ type: "text", name: `field_${f.fieldName}`, label: f.label, fieldName: f.fieldName })) } : {}),
2715
+ ...(params.actions ? { actions: params.actions } : {}),
2716
+ ...(params.states ? { states: params.states } : {}),
2717
+ };
2718
+ const labelMatch = existing.rawXml.match(/<masterLabel[^>]*>([\s\S]*?)<\/masterLabel>/i);
2719
+ const currentLabel = labelMatch?.[1] ?? params.cardName;
2720
+ const xml = `<met:metadata xsi:type="met:OmniUiCard" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
2721
+ <met:fullName>${x(params.cardName)}</met:fullName>
2722
+ <met:masterLabel>${x(params.label ?? currentLabel)}</met:masterLabel>
2723
+ ${params.description ? `<met:description>${x(params.description)}</met:description>` : ""}
2724
+ <met:omniUiCardType>Child</met:omniUiCardType>
2725
+ <met:isActive>false</met:isActive>
2726
+ <met:omniUiCardDefinition>${x(JSON.stringify(merged))}</met:omniUiCardDefinition>
2727
+ </met:metadata>`;
2728
+ return await upsertMetadata(auth, xml);
2729
+ } catch (err) {
2730
+ return { success: false, message: sanitizeError(err instanceof Error ? err.message : String(err)) };
2731
+ }
2732
+ }
2733
+ export async function activateFlexCard(auth, params) {
2734
+ try {
2735
+ const existing = await readMetadataItem(auth, "OmniUiCard", params.cardName);
2736
+ if (!existing.success) return { success: false, message: `FlexCard '${params.cardName}' not found.` };
2737
+ const labelMatch = existing.rawXml.match(/<masterLabel[^>]*>([\s\S]*?)<\/masterLabel>/i);
2738
+ const defMatch = existing.rawXml.match(/<omniUiCardDefinition[^>]*>([\s\S]*?)<\/omniUiCardDefinition>/i);
2739
+ const typeMatch = existing.rawXml.match(/<omniUiCardType[^>]*>([\s\S]*?)<\/omniUiCardType>/i);
2740
+ const xml = `<met:metadata xsi:type="met:OmniUiCard" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
2741
+ <met:fullName>${x(params.cardName)}</met:fullName>
2742
+ <met:masterLabel>${labelMatch?.[1] ?? params.cardName}</met:masterLabel>
2743
+ <met:omniUiCardType>${typeMatch?.[1] ?? "Child"}</met:omniUiCardType>
2744
+ <met:isActive>true</met:isActive>
2745
+ ${defMatch ? `<met:omniUiCardDefinition>${defMatch[1]}</met:omniUiCardDefinition>` : ""}
2746
+ </met:metadata>`;
2747
+ return await upsertMetadata(auth, xml);
2748
+ } catch (err) {
2749
+ return { success: false, message: sanitizeError(err instanceof Error ? err.message : String(err)) };
2750
+ }
2751
+ }
2752
+ export async function getFlexCard(auth, params) {
2753
+ try {
2754
+ const result = await readMetadataItem(auth, "OmniUiCard", params.cardName);
2755
+ if (!result.success) return result;
2756
+ const labelMatch = result.rawXml.match(/<masterLabel[^>]*>([\s\S]*?)<\/masterLabel>/i);
2757
+ const isActiveMatch = result.rawXml.match(/<isActive[^>]*>([\s\S]*?)<\/isActive>/i);
2758
+ const defMatch = result.rawXml.match(/<omniUiCardDefinition[^>]*>([\s\S]*?)<\/omniUiCardDefinition>/i);
2759
+ let definition = null;
2760
+ if (defMatch) {
2761
+ try { definition = JSON.parse(defMatch[1].replace(/&amp;/g,"&").replace(/&lt;/g,"<").replace(/&gt;/g,">").replace(/&quot;/g,'"').replace(/&apos;/g,"'")); }
2762
+ catch { definition = defMatch[1]; }
2763
+ }
2764
+ return { success: true, cardName: params.cardName, label: labelMatch?.[1] ?? "", isActive: isActiveMatch?.[1] === "true", definition, message: `FlexCard '${params.cardName}' retrieved.` };
2765
+ } catch (err) {
2766
+ return { success: false, message: sanitizeError(err instanceof Error ? err.message : String(err)) };
2767
+ }
2768
+ }
2769
+ export async function createOmniScript(auth, params) {
2770
+ try {
2771
+ const fullName = `${params.type}_${params.subType}_${params.language}`;
2772
+ const xml = `<met:metadata xsi:type="met:OmniScript" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
2773
+ <met:fullName>${x(fullName)}</met:fullName>
2774
+ <met:masterLabel>${x(params.label)}</met:masterLabel>
2775
+ <met:type>${x(params.type)}</met:type>
2776
+ <met:subType>${x(params.subType)}</met:subType>
2777
+ <met:language>${x(params.language)}</met:language>
2778
+ <met:omniProcessType>OmniScript</met:omniProcessType>
2779
+ <met:isActive>false</met:isActive>
2780
+ <met:isInternal>false</met:isInternal>
2781
+ <met:isLwcEnabled>${params.isLwcEnabled !== false ? "true" : "false"}</met:isLwcEnabled>
2782
+ <met:isOmniScriptEmbeddable>${params.isOmniScriptEmbeddable ? "true" : "false"}</met:isOmniScriptEmbeddable>
2783
+ ${params.description ? `<met:description>${x(params.description)}</met:description>` : ""}
2784
+ </met:metadata>`;
2785
+ return await upsertMetadata(auth, xml);
2786
+ } catch (err) {
2787
+ return { success: false, message: sanitizeError(err instanceof Error ? err.message : String(err)) };
2788
+ }
2789
+ }
2790
+ export async function updateOmniScript(auth, params) {
2791
+ try {
2792
+ const fullName = `${params.type}_${params.subType}_${params.language}`;
2793
+ const existing = await readMetadataItem(auth, "OmniScript", fullName);
2794
+ if (!existing.success) return { success: false, message: `OmniScript '${fullName}' not found.` };
2795
+ const labelMatch = existing.rawXml.match(/<masterLabel[^>]*>([\s\S]*?)<\/masterLabel>/i);
2796
+ const xml = `<met:metadata xsi:type="met:OmniScript" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
2797
+ <met:fullName>${x(fullName)}</met:fullName>
2798
+ <met:masterLabel>${labelMatch?.[1] ?? fullName}</met:masterLabel>
2799
+ <met:type>${x(params.type)}</met:type>
2800
+ <met:subType>${x(params.subType)}</met:subType>
2801
+ <met:language>${x(params.language)}</met:language>
2802
+ <met:omniProcessType>OmniScript</met:omniProcessType>
2803
+ <met:isActive>false</met:isActive>
2804
+ <met:isInternal>false</met:isInternal>
2805
+ ${params.isLwcEnabled !== undefined ? `<met:isLwcEnabled>${params.isLwcEnabled}</met:isLwcEnabled>` : ""}
2806
+ ${params.isOmniScriptEmbeddable !== undefined ? `<met:isOmniScriptEmbeddable>${params.isOmniScriptEmbeddable}</met:isOmniScriptEmbeddable>` : ""}
2807
+ ${params.description ? `<met:description>${x(params.description)}</met:description>` : ""}
2808
+ </met:metadata>`;
2809
+ return await upsertMetadata(auth, xml);
2810
+ } catch (err) {
2811
+ return { success: false, message: sanitizeError(err instanceof Error ? err.message : String(err)) };
2812
+ }
2813
+ }
2814
+ export async function activateOmniScript(auth, params) {
2815
+ try {
2816
+ const fullName = `${params.type}_${params.subType}_${params.language}`;
2817
+ const existing = await readMetadataItem(auth, "OmniScript", fullName);
2818
+ if (!existing.success) return { success: false, message: `OmniScript '${fullName}' not found.` };
2819
+ const labelMatch = existing.rawXml.match(/<masterLabel[^>]*>([\s\S]*?)<\/masterLabel>/i);
2820
+ const xml = `<met:metadata xsi:type="met:OmniScript" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
2821
+ <met:fullName>${x(fullName)}</met:fullName>
2822
+ <met:masterLabel>${labelMatch?.[1] ?? fullName}</met:masterLabel>
2823
+ <met:type>${x(params.type)}</met:type>
2824
+ <met:subType>${x(params.subType)}</met:subType>
2825
+ <met:language>${x(params.language)}</met:language>
2826
+ <met:omniProcessType>OmniScript</met:omniProcessType>
2827
+ <met:isActive>true</met:isActive>
2828
+ <met:isInternal>false</met:isInternal>
2829
+ <met:isLwcEnabled>true</met:isLwcEnabled>
2830
+ </met:metadata>`;
2831
+ return await upsertMetadata(auth, xml);
2832
+ } catch (err) {
2833
+ return { success: false, message: sanitizeError(err instanceof Error ? err.message : String(err)) };
2834
+ }
2835
+ }
2836
+ export async function getOmniScript(auth, params) {
2837
+ try {
2838
+ const fullName = `${params.type}_${params.subType}_${params.language}`;
2839
+ const result = await readMetadataItem(auth, "OmniScript", fullName);
2840
+ if (!result.success) return result;
2841
+ const get = (tag) => result.rawXml.match(new RegExp(`<${tag}[^>]*>([\\s\\S]*?)<\\/${tag}>`, "i"))?.[1] ?? "";
2842
+ return {
2843
+ success: true,
2844
+ fullName,
2845
+ type: get("type"),
2846
+ subType: get("subType"),
2847
+ language: get("language"),
2848
+ isActive: get("isActive") === "true",
2849
+ isLwcEnabled: get("isLwcEnabled") === "true",
2850
+ message: `OmniScript '${fullName}' retrieved.`,
2851
+ };
2852
+ } catch (err) {
2853
+ return { success: false, message: sanitizeError(err instanceof Error ? err.message : String(err)) };
2854
+ }
2855
+ }
2856
+ export async function createDataRaptor(auth, params) {
2857
+ try {
2858
+ const mapItemsXml = (params.fields ?? []).map((f, i) => {
2859
+ const isJSON = f.sourceField.startsWith("$.");
2860
+ return `
2861
+ <met:mapItems>
2862
+ <met:index>${i}</met:index>
2863
+ <met:objectName>${x(params.objectApiName ?? "")}</met:objectName>
2864
+ <met:field>${x(isJSON ? "" : f.sourceField)}</met:field>
2865
+ <met:JSONPath>${x(isJSON ? f.sourceField : "")}</met:JSONPath>
2866
+ <met:targetField>${x(f.targetField)}</met:targetField>
2867
+ <met:dataType>${x(f.dataType ?? "String")}</met:dataType>
2868
+ ${f.formula ? `<met:formula>${x(f.formula)}</met:formula>` : ""}
2869
+ <met:operationType>First</met:operationType>
2870
+ <met:sourceObjectName>${x(params.objectApiName ?? "")}</met:sourceObjectName>
2871
+ </met:mapItems>`;
2872
+ }).join("");
2873
+ const xml = `<met:metadata xsi:type="met:DataRaptorInterface" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
2874
+ <met:fullName>${x(params.dataRaptorName)}</met:fullName>
2875
+ <met:masterLabel>${x(params.label)}</met:masterLabel>
2876
+ <met:interfaceType>${x(params.interfaceType)}</met:interfaceType>
2877
+ ${params.objectApiName ? `<met:objectName>${x(params.objectApiName)}</met:objectName>` : ""}
2878
+ ${params.filterCriteria ? `<met:filterCriteria>${x(params.filterCriteria)}</met:filterCriteria>` : ""}
2879
+ ${params.description ? `<met:description>${x(params.description)}</met:description>` : ""}
2880
+ ${mapItemsXml}
2881
+ </met:metadata>`;
2882
+ return await upsertMetadata(auth, xml);
2883
+ } catch (err) {
2884
+ return { success: false, message: sanitizeError(err instanceof Error ? err.message : String(err)) };
2885
+ }
2886
+ }
2887
+ export async function getDataRaptor(auth, params) {
2888
+ try {
2889
+ const result = await readMetadataItem(auth, "DataRaptorInterface", params.dataRaptorName);
2890
+ if (!result.success) return result;
2891
+ const get = (tag) => result.rawXml.match(new RegExp(`<${tag}[^>]*>([\\s\\S]*?)<\\/${tag}>`, "i"))?.[1]?.trim() ?? "";
2892
+ const items = [...result.rawXml.matchAll(/<mapItems>([\s\S]*?)<\/mapItems>/gi)].map(m => {
2893
+ const inner = m[1];
2894
+ const gi = (t) => inner.match(new RegExp(`<${t}[^>]*>([\\s\\S]*?)<\\/${t}>`, "i"))?.[1]?.trim() ?? "";
2895
+ return { field: gi("field"), jsonPath: gi("JSONPath"), targetField: gi("targetField"), dataType: gi("dataType") };
2896
+ });
2897
+ return { success: true, dataRaptorName: params.dataRaptorName, label: get("masterLabel"), interfaceType: get("interfaceType"), objectName: get("objectName"), filterCriteria: get("filterCriteria"), fieldMappings: items, message: `DataRaptor '${params.dataRaptorName}' retrieved.` };
2898
+ } catch (err) {
2899
+ return { success: false, message: sanitizeError(err instanceof Error ? err.message : String(err)) };
2900
+ }
2901
+ }
2902
+ export async function createIntegrationProcedure(auth, params) {
2903
+ try {
2904
+ const fullName = `${params.procedureName}_${params.subType}`;
2905
+ const xml = `<met:metadata xsi:type="met:OmniScript" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
2906
+ <met:fullName>${x(fullName)}</met:fullName>
2907
+ <met:masterLabel>${x(params.label)}</met:masterLabel>
2908
+ <met:type>${x(params.procedureName)}</met:type>
2909
+ <met:subType>${x(params.subType)}</met:subType>
2910
+ <met:language>English</met:language>
2911
+ <met:omniProcessType>IntegrationProcedure</met:omniProcessType>
2912
+ <met:isActive>${params.isActive ? "true" : "false"}</met:isActive>
2913
+ <met:isInternal>false</met:isInternal>
2914
+ <met:isLwcEnabled>false</met:isLwcEnabled>
2915
+ ${params.description ? `<met:description>${x(params.description)}</met:description>` : ""}
2916
+ </met:metadata>`;
2917
+ return await upsertMetadata(auth, xml);
2918
+ } catch (err) {
2919
+ return { success: false, message: sanitizeError(err instanceof Error ? err.message : String(err)) };
2920
+ }
2921
+ }
2922
+ export async function updateIntegrationProcedure(auth, params) {
2923
+ try {
2924
+ const fullName = `${params.procedureName}_${params.subType}`;
2925
+ const existing = await readMetadataItem(auth, "OmniScript", fullName);
2926
+ if (!existing.success) return { success: false, message: `Integration Procedure '${fullName}' not found.` };
2927
+ const labelMatch = existing.rawXml.match(/<masterLabel[^>]*>([\s\S]*?)<\/masterLabel>/i);
2928
+ const xml = `<met:metadata xsi:type="met:OmniScript" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
2929
+ <met:fullName>${x(fullName)}</met:fullName>
2930
+ <met:masterLabel>${labelMatch?.[1] ?? fullName}</met:masterLabel>
2931
+ <met:type>${x(params.procedureName)}</met:type>
2932
+ <met:subType>${x(params.subType)}</met:subType>
2933
+ <met:language>English</met:language>
2934
+ <met:omniProcessType>IntegrationProcedure</met:omniProcessType>
2935
+ ${params.isActive !== undefined ? `<met:isActive>${params.isActive}</met:isActive>` : "<met:isActive>false</met:isActive>"}
2936
+ <met:isInternal>false</met:isInternal>
2937
+ <met:isLwcEnabled>false</met:isLwcEnabled>
2938
+ ${params.description ? `<met:description>${x(params.description)}</met:description>` : ""}
2939
+ </met:metadata>`;
2940
+ return await upsertMetadata(auth, xml);
2941
+ } catch (err) {
2942
+ return { success: false, message: sanitizeError(err instanceof Error ? err.message : String(err)) };
2943
+ }
2944
+ }
2945
+ export async function activateIntegrationProcedure(auth, params) {
2946
+ try {
2947
+ const fullName = `${params.procedureName}_${params.subType}`;
2948
+ const existing = await readMetadataItem(auth, "OmniScript", fullName);
2949
+ if (!existing.success) return { success: false, message: `Integration Procedure '${fullName}' not found.` };
2950
+ const labelMatch = existing.rawXml.match(/<masterLabel[^>]*>([\s\S]*?)<\/masterLabel>/i);
2951
+ const xml = `<met:metadata xsi:type="met:OmniScript" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
2952
+ <met:fullName>${x(fullName)}</met:fullName>
2953
+ <met:masterLabel>${labelMatch?.[1] ?? fullName}</met:masterLabel>
2954
+ <met:type>${x(params.procedureName)}</met:type>
2955
+ <met:subType>${x(params.subType)}</met:subType>
2956
+ <met:language>English</met:language>
2957
+ <met:omniProcessType>IntegrationProcedure</met:omniProcessType>
2958
+ <met:isActive>true</met:isActive>
2959
+ <met:isInternal>false</met:isInternal>
2960
+ <met:isLwcEnabled>false</met:isLwcEnabled>
2961
+ </met:metadata>`;
2962
+ return await upsertMetadata(auth, xml);
2963
+ } catch (err) {
2964
+ return { success: false, message: sanitizeError(err instanceof Error ? err.message : String(err)) };
2965
+ }
2966
+ }
2967
+ export async function getIntegrationProcedure(auth, params) {
2968
+ try {
2969
+ const fullName = `${params.procedureName}_${params.subType}`;
2970
+ const result = await readMetadataItem(auth, "OmniScript", fullName);
2971
+ if (!result.success) return result;
2972
+ const get = (tag) => result.rawXml.match(new RegExp(`<${tag}[^>]*>([\\s\\S]*?)<\\/${tag}>`, "i"))?.[1]?.trim() ?? "";
2973
+ return { success: true, fullName, type: get("type"), subType: get("subType"), isActive: get("isActive") === "true", description: get("description"), message: `Integration Procedure '${fullName}' retrieved.` };
2974
+ } catch (err) {
2975
+ return { success: false, message: sanitizeError(err instanceof Error ? err.message : String(err)) };
2976
+ }
2977
+ }
2978
+ export async function createCalculationMatrix(auth, params) {
2979
+ try {
2980
+ const inputVarsXml = params.inputVariables.map(v => `
2981
+ <met:inputVariables>
2982
+ <met:dataType>${x(v.dataType ?? "String")}</met:dataType>
2983
+ <met:name>${x(v.name)}</met:name>
2984
+ </met:inputVariables>`).join("");
2985
+ const outputVarsXml = params.outputVariables.map(v => `
2986
+ <met:outputVariables>
2987
+ <met:dataType>${x(v.dataType ?? "String")}</met:dataType>
2988
+ <met:name>${x(v.name)}</met:name>
2989
+ </met:outputVariables>`).join("");
2990
+ const rowsXml = (params.rows ?? []).map((row, ri) => {
2991
+ const cellsXml = Object.entries(row).map(([k, v]) => `
2992
+ <met:cells>
2993
+ <met:variableName>${x(k)}</met:variableName>
2994
+ <met:value>${x(v)}</met:value>
2995
+ </met:cells>`).join("");
2996
+ return `
2997
+ <met:matrixRows>
2998
+ <met:rowNumber>${ri + 1}</met:rowNumber>
2999
+ ${cellsXml}
3000
+ </met:matrixRows>`;
3001
+ }).join("");
3002
+ const xml = `<met:metadata xsi:type="met:CalculationMatrix" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
3003
+ <met:fullName>${x(params.matrixName)}</met:fullName>
3004
+ <met:masterLabel>${x(params.label)}</met:masterLabel>
3005
+ ${params.description ? `<met:description>${x(params.description)}</met:description>` : ""}
3006
+ ${inputVarsXml}
3007
+ ${outputVarsXml}
3008
+ ${rowsXml}
3009
+ </met:metadata>`;
3010
+ return await upsertMetadata(auth, xml);
3011
+ } catch (err) {
3012
+ return { success: false, message: sanitizeError(err instanceof Error ? err.message : String(err)) };
3013
+ }
3014
+ }
3015
+ export async function createCalculationProcedure(auth, params) {
3016
+ try {
3017
+ const stepsXml = (params.steps ?? []).map((s, i) => `
3018
+ <met:calculationProcedureSteps>
3019
+ <met:stepNumber>${i + 1}</met:stepNumber>
3020
+ <met:developerName>${x(s.name)}</met:developerName>
3021
+ <met:stepType>${x(s.type ?? "Expression")}</met:stepType>
3022
+ ${s.matrixName ? `<met:calculationMatrix>${x(s.matrixName)}</met:calculationMatrix>` : ""}
3023
+ ${s.expression ? `<met:expression>${x(s.expression)}</met:expression>` : ""}
3024
+ ${s.inputMap ? Object.entries(s.inputMap).map(([k,v]) => `<met:inputParameters><met:name>${x(k)}</met:name><met:value>${x(v)}</met:value></met:inputParameters>`).join("") : ""}
3025
+ ${s.outputMap ? Object.entries(s.outputMap).map(([k,v]) => `<met:outputParameters><met:name>${x(k)}</met:name><met:value>${x(v)}</met:value></met:outputParameters>`).join("") : ""}
3026
+ </met:calculationProcedureSteps>`).join("");
3027
+ const xml = `<met:metadata xsi:type="met:CalculationProcedure" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
3028
+ <met:fullName>${x(params.procedureName)}</met:fullName>
3029
+ <met:masterLabel>${x(params.label)}</met:masterLabel>
3030
+ ${params.description ? `<met:description>${x(params.description)}</met:description>` : ""}
3031
+ ${stepsXml}
3032
+ </met:metadata>`;
3033
+ return await upsertMetadata(auth, xml);
3034
+ } catch (err) {
3035
+ return { success: false, message: sanitizeError(err instanceof Error ? err.message : String(err)) };
3036
+ }
3037
+ }
3038
+ // ─── v2.3.0 OmniChannel Service Functions ────────────────────────────────────
3039
+ export async function createServiceChannel(auth, params) {
3040
+ try {
3041
+ const xml = `<met:metadata xsi:type="met:ServiceChannel" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
3042
+ <met:fullName>${x(params.channelName)}</met:fullName>
3043
+ <met:label>${x(params.label)}</met:label>
3044
+ <met:relatedEntity>${x(params.relatedObjectApiName ?? (params.channelType === "Case" ? "Case" : params.channelType === "Chat" ? "LiveChatTranscript" : params.channelType === "Email" ? "EmailMessage" : "Case"))}</met:relatedEntity>
3045
+ </met:metadata>`;
3046
+ return await upsertMetadata(auth, xml);
3047
+ } catch (err) {
3048
+ return { success: false, message: sanitizeError(err instanceof Error ? err.message : String(err)) };
3049
+ }
3050
+ }
3051
+ export async function createRoutingConfiguration(auth, params) {
3052
+ try {
3053
+ const xml = `<met:metadata xsi:type="met:RoutingConfiguration" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
3054
+ <met:fullName>${x(params.configName)}</met:fullName>
3055
+ <met:label>${x(params.label)}</met:label>
3056
+ <met:routingModel>${x(params.routingModel)}</met:routingModel>
3057
+ <met:routingPriority>${params.priority ?? 1}</met:routingPriority>
3058
+ ${params.unitType === "Items" ? `<met:capacityWeight>${params.capacity ?? 1}</met:capacityWeight>` : `<met:capacityPercentage>${params.capacity ?? 100}</met:capacityPercentage>`}
3059
+ <met:unitType>${x(params.unitType ?? "Percentage")}</met:unitType>
3060
+ ${params.pushTimeout !== undefined ? `<met:pushTimeout>${params.pushTimeout}</met:pushTimeout>` : ""}
3061
+ ${params.description ? `<met:description>${x(params.description)}</met:description>` : ""}
3062
+ </met:metadata>`;
3063
+ return await upsertMetadata(auth, xml);
3064
+ } catch (err) {
3065
+ return { success: false, message: sanitizeError(err instanceof Error ? err.message : String(err)) };
3066
+ }
3067
+ }
3068
+ export async function createQueueRoutingConfig(auth, params) {
3069
+ try {
3070
+ // Link a routing config to a queue by updating the Queue metadata
3071
+ const readResult = await readMetadataItem(auth, "Queue", params.queueDeveloperName);
3072
+ if (!readResult.success) return { success: false, message: `Queue '${params.queueDeveloperName}' not found.` };
3073
+ const labelMatch = readResult.rawXml.match(/<label[^>]*>([\s\S]*?)<\/label>/i);
3074
+ const emailMatch = readResult.rawXml.match(/<email[^>]*>([\s\S]*?)<\/email>/i);
3075
+ const xml = `<met:metadata xsi:type="met:Queue" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
3076
+ <met:fullName>${x(params.queueDeveloperName)}</met:fullName>
3077
+ <met:label>${labelMatch?.[1] ?? params.queueDeveloperName}</met:label>
3078
+ ${emailMatch?.[1] ? `<met:email>${emailMatch[1]}</met:email>` : ""}
3079
+ <met:routingConfiguration>${x(params.routingConfigName)}</met:routingConfiguration>
3080
+ </met:metadata>`;
3081
+ return await upsertMetadata(auth, xml);
3082
+ } catch (err) {
3083
+ return { success: false, message: sanitizeError(err instanceof Error ? err.message : String(err)) };
3084
+ }
3085
+ }
3086
+ export async function createPresenceConfiguration(auth, params) {
3087
+ try {
3088
+ const channelsXml = (params.serviceChannels ?? []).map(ch => `
3089
+ <met:presenceConfigAssignments>
3090
+ <met:serviceChannel>${x(ch.channelName)}</met:serviceChannel>
3091
+ ${ch.capacity ? `<met:capacity>${ch.capacity}</met:capacity>` : ""}
3092
+ </met:presenceConfigAssignments>`).join("");
3093
+ const xml = `<met:metadata xsi:type="met:PresenceUserConfig" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
3094
+ <met:fullName>${x(params.configName)}</met:fullName>
3095
+ <met:label>${x(params.label)}</met:label>
3096
+ <met:capacity>${params.capacity ?? 10}</met:capacity>
3097
+ <met:allowAgentsToChangeSatus>${params.allowAgentsToChangeStatus !== false ? "true" : "false"}</met:allowAgentsToChangeSatus>
3098
+ ${params.description ? `<met:description>${x(params.description)}</met:description>` : ""}
3099
+ ${channelsXml}
3100
+ </met:metadata>`;
3101
+ return await upsertMetadata(auth, xml);
3102
+ } catch (err) {
3103
+ return { success: false, message: sanitizeError(err instanceof Error ? err.message : String(err)) };
3104
+ }
3105
+ }
3106
+ export async function createPresenceStatus(auth, params) {
3107
+ try {
3108
+ const channelsXml = (params.serviceChannels ?? []).map(ch => `
3109
+ <met:serviceChannels>
3110
+ <met:channel>${x(ch)}</met:channel>
3111
+ </met:serviceChannels>`).join("");
3112
+ const xml = `<met:metadata xsi:type="met:ServicePresenceStatus" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
3113
+ <met:fullName>${x(params.statusName)}</met:fullName>
3114
+ <met:label>${x(params.label)}</met:label>
3115
+ <met:statusType>${x(params.statusType ?? "Online")}</met:statusType>
3116
+ ${channelsXml}
3117
+ </met:metadata>`;
3118
+ return await upsertMetadata(auth, xml);
3119
+ } catch (err) {
3120
+ return { success: false, message: sanitizeError(err instanceof Error ? err.message : String(err)) };
3121
+ }
3122
+ }
3123
+ export async function assignPresenceStatus(auth, params) {
3124
+ try {
3125
+ const results = [];
3126
+ for (const profileName of (params.profiles ?? [])) {
3127
+ const xml = `<met:metadata xsi:type="met:Profile" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
3128
+ <met:fullName>${x(profileName)}</met:fullName>
3129
+ <met:servicePresenceStatusAccesses>
3130
+ <met:servicePresenceStatus>${x(params.statusName)}</met:servicePresenceStatus>
3131
+ <met:visible>true</met:visible>
3132
+ </met:servicePresenceStatusAccesses>
3133
+ </met:metadata>`;
3134
+ results.push(await upsertMetadata(auth, xml));
3135
+ }
3136
+ for (const psName of (params.permissionSets ?? [])) {
3137
+ const xml = `<met:metadata xsi:type="met:PermissionSet" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
3138
+ <met:fullName>${x(psName)}</met:fullName>
3139
+ <met:servicePresenceStatusAccesses>
3140
+ <met:servicePresenceStatus>${x(params.statusName)}</met:servicePresenceStatus>
3141
+ <met:visible>true</met:visible>
3142
+ </met:servicePresenceStatusAccesses>
3143
+ </met:metadata>`;
3144
+ results.push(await upsertMetadata(auth, xml));
3145
+ }
3146
+ if (!results.length) return { success: false, message: "Provide at least one profile or permissionSet." };
3147
+ const allOk = results.every(r => r.success);
3148
+ return { success: allOk, message: allOk ? `Presence status '${params.statusName}' assigned to ${results.length} profile(s)/permission set(s).` : results.filter(r => !r.success).map(r => r.message).join("; ") };
3149
+ } catch (err) {
3150
+ return { success: false, message: sanitizeError(err instanceof Error ? err.message : String(err)) };
3151
+ }
3152
+ }
3153
+ export async function createSkill(auth, params) {
3154
+ try {
3155
+ // Skill is a REST SObject in Service Cloud
3156
+ const client = createClient(auth);
3157
+ const resp = await client.post("/sobjects/Skill", { MasterLabel: params.label, DeveloperName: params.skillName, Description: params.description ?? "" });
3158
+ return { success: true, fullName: resp.data.id, created: true, message: `Skill '${params.skillName}' created with ID ${resp.data.id}.` };
3159
+ } catch (err) {
3160
+ return { success: false, message: sanitizeError(err instanceof Error ? err.message : String(err)) };
3161
+ }
3162
+ }
3163
+ export async function assignSkillToAgent(auth, params) {
3164
+ try {
3165
+ const client = createClient(auth);
3166
+ // Get skill ID
3167
+ const skillResp = await client.get(`/query?q=${encodeURIComponent(`SELECT Id FROM Skill WHERE DeveloperName = '${params.skillName.replace(/'/g,"\\'")}' LIMIT 1`)}`);
3168
+ const skillId = skillResp.data.records?.[0]?.Id;
3169
+ if (!skillId) return { success: false, message: `Skill '${params.skillName}' not found.` };
3170
+ // Get user ID
3171
+ const userResp = await client.get(`/query?q=${encodeURIComponent(`SELECT Id FROM User WHERE Username = '${params.username.replace(/'/g,"\\'")}' LIMIT 1`)}`);
3172
+ const userId = userResp.data.records?.[0]?.Id;
3173
+ if (!userId) return { success: false, message: `User '${params.username}' not found.` };
3174
+ // Get or create ServiceResource
3175
+ const srResp = await client.get(`/query?q=${encodeURIComponent(`SELECT Id FROM ServiceResource WHERE RelatedRecordId = '${userId}' LIMIT 1`)}`);
3176
+ let srId = srResp.data.records?.[0]?.Id;
3177
+ if (!srId) {
3178
+ const newSr = await client.post("/sobjects/ServiceResource", { RelatedRecordId: userId, Name: params.username, ResourceType: "T", IsActive: true });
3179
+ srId = newSr.data.id;
3180
+ }
3181
+ // Create ServiceResourceSkill
3182
+ const resp = await client.post("/sobjects/ServiceResourceSkill", { ServiceResourceId: srId, SkillId: skillId, SkillLevel: params.skillLevel ?? 5, EffectiveStartDate: new Date().toISOString().slice(0, 10) });
3183
+ return { success: true, fullName: resp.data.id, created: true, message: `Skill '${params.skillName}' assigned to '${params.username}' with level ${params.skillLevel ?? 5}.` };
3184
+ } catch (err) {
3185
+ return { success: false, message: sanitizeError(err instanceof Error ? err.message : String(err)) };
3186
+ }
3187
+ }
3188
+ export async function createServiceTerritory(auth, params) {
3189
+ try {
3190
+ const client = createClient(auth);
3191
+ const payload = { Name: params.label, IsActive: params.isActive !== false };
3192
+ if (params.street) payload["Street"] = params.street;
3193
+ if (params.city) payload["City"] = params.city;
3194
+ if (params.state) payload["State"] = params.state;
3195
+ if (params.country) payload["Country"] = params.country;
3196
+ if (params.postalCode) payload["PostalCode"] = params.postalCode;
3197
+ if (params.operatingHoursName) {
3198
+ const ohResp = await client.get(`/query?q=${encodeURIComponent(`SELECT Id FROM OperatingHours WHERE Name = '${params.operatingHoursName.replace(/'/g,"\\'")}' LIMIT 1`)}`);
3199
+ const ohId = ohResp.data.records?.[0]?.Id;
3200
+ if (ohId) payload["OperatingHoursId"] = ohId;
3201
+ }
3202
+ const resp = await client.post("/sobjects/ServiceTerritory", payload);
3203
+ return { success: true, fullName: resp.data.id, created: true, message: `Service Territory '${params.label}' created with ID ${resp.data.id}.` };
3204
+ } catch (err) {
3205
+ return { success: false, message: sanitizeError(err instanceof Error ? err.message : String(err)) };
3206
+ }
3207
+ }
3208
+ export async function createWorkType(auth, params) {
3209
+ try {
3210
+ const client = createClient(auth);
3211
+ const durationInMinutes = params.durationType === "Hours" ? (params.estimatedDuration * 60) : params.estimatedDuration;
3212
+ const payload = {
3213
+ Name: params.label,
3214
+ EstimatedDuration: durationInMinutes,
3215
+ DurationType: "Minutes",
3216
+ BlockTimeBeforeWork: params.blockTimeBeforeWork ?? 0,
3217
+ BlockTimeAfterWork: params.blockTimeAfterWork ?? 0,
3218
+ Description: params.description ?? "",
3219
+ };
3220
+ const resp = await client.post("/sobjects/WorkType", payload);
3221
+ const workTypeId = resp.data.id;
3222
+ // Add skill requirements if provided
3223
+ for (const skillName of (params.skillRequirements ?? [])) {
3224
+ const skillResp = await client.get(`/query?q=${encodeURIComponent(`SELECT Id FROM Skill WHERE DeveloperName = '${skillName.replace(/'/g,"\\'")}' LIMIT 1`)}`);
3225
+ const skillId = skillResp.data.records?.[0]?.Id;
3226
+ if (skillId) await client.post("/sobjects/WorkTypeSkill", { WorkTypeId: workTypeId, SkillId: skillId, SkillType: "Required" }).catch(() => null);
3227
+ }
3228
+ return { success: true, fullName: workTypeId, created: true, message: `Work Type '${params.label}' created with ID ${workTypeId}.` };
3229
+ } catch (err) {
3230
+ return { success: false, message: sanitizeError(err instanceof Error ? err.message : String(err)) };
3231
+ }
3232
+ }
3233
+ export async function createMessagingChannel(auth, params) {
3234
+ try {
3235
+ const xml = `<met:metadata xsi:type="met:MessagingChannel" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
3236
+ <met:fullName>${x(params.channelName)}</met:fullName>
3237
+ <met:masterLabel>${x(params.label)}</met:masterLabel>
3238
+ <met:channelType>${x(params.channelType)}</met:channelType>
3239
+ <met:isActive>true</met:isActive>
3240
+ ${params.phoneNumber ? `<met:messagingPlatformKey>${x(params.phoneNumber)}</met:messagingPlatformKey>` : ""}
3241
+ ${params.pageId ? `<met:pageId>${x(params.pageId)}</met:pageId>` : ""}
3242
+ ${params.description ? `<met:description>${x(params.description)}</met:description>` : ""}
3243
+ </met:metadata>`;
3244
+ return await upsertMetadata(auth, xml);
3245
+ } catch (err) {
3246
+ return { success: false, message: sanitizeError(err instanceof Error ? err.message : String(err)) };
3247
+ }
3248
+ }
3249
+ export async function createChatButton(auth, params) {
3250
+ try {
3251
+ const xml = `<met:metadata xsi:type="met:LiveChatButton" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
3252
+ <met:fullName>${x(params.buttonName)}</met:fullName>
3253
+ <met:label>${x(params.label)}</met:label>
3254
+ <met:type>Standard</met:type>
3255
+ <met:routingType>${params.routingType === "Bot" ? "Choice" : "Choice"}</met:routingType>
3256
+ <met:optionsHasTimeoutAlert>${params.optionsHasTimeoutAlert ? "true" : "false"}</met:optionsHasTimeoutAlert>
3257
+ <met:windowLanguage>${x(params.windowLanguage ?? "en")}</met:windowLanguage>
3258
+ ${params.queueName ? `<met:overallQueueLength>0</met:overallQueueLength>` : ""}
3259
+ ${params.customAgentName ? `<met:customAgentCrxName>${x(params.customAgentName)}</met:customAgentCrxName>` : ""}
3260
+ ${params.inviteRenderer ? `<met:inviteRenderer>${x(params.inviteRenderer)}</met:inviteRenderer>` : ""}
3261
+ ${params.description ? `<met:description>${x(params.description)}</met:description>` : ""}
3262
+ </met:metadata>`;
3263
+ return await upsertMetadata(auth, xml);
3264
+ } catch (err) {
3265
+ return { success: false, message: sanitizeError(err instanceof Error ? err.message : String(err)) };
3266
+ }
3267
+ }
3268
+ export async function createEmbeddedService(auth, params) {
3269
+ try {
3270
+ const isLiveAgent = params.channelType === "LiveAgent";
3271
+ const xml = `<met:metadata xsi:type="met:EmbeddedServiceConfig" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
3272
+ <met:fullName>${x(params.deploymentName)}</met:fullName>
3273
+ <met:masterLabel>${x(params.label)}</met:masterLabel>
3274
+ <met:embeddedServiceType>${isLiveAgent ? "Chat" : "Messaging"}</met:embeddedServiceType>
3275
+ <met:isEnabled>true</met:isEnabled>
3276
+ <met:site>${x(params.site)}</met:site>
3277
+ ${isLiveAgent && params.chatButtonName ? `
3278
+ <met:embeddedServiceLiveAgent>
3279
+ <met:liveChatButton>${x(params.chatButtonName)}</met:liveChatButton>
3280
+ <met:embeddedServiceConfigName>${x(params.deploymentName)}</met:embeddedServiceConfigName>
3281
+ <met:offlineSupportEnabled>false</met:offlineSupportEnabled>
3282
+ </met:embeddedServiceLiveAgent>` : ""}
3283
+ ${!isLiveAgent && params.messagingChannelName ? `<met:embeddedServiceMessaging><met:messagingChannel>${x(params.messagingChannelName)}</met:messagingChannel></met:embeddedServiceMessaging>` : ""}
3284
+ ${params.description ? `<met:description>${x(params.description)}</met:description>` : ""}
3285
+ </met:metadata>`;
3286
+ return await upsertMetadata(auth, xml);
3287
+ } catch (err) {
3288
+ return { success: false, message: sanitizeError(err instanceof Error ? err.message : String(err)) };
3289
+ }
3290
+ }
3291
+ export async function createBotRouting(auth, params) {
3292
+ try {
3293
+ // Read the existing BotVersion to find the bot's ID
3294
+ const botVersions = await listMetadataType(auth, "BotVersion");
3295
+ if (!botVersions.success) return { success: false, message: "Could not list BotVersions." };
3296
+ const botFullName = botVersions.items.find(i => i.fullName.startsWith(params.botName + "."))?.fullName;
3297
+ if (!botFullName) return { success: false, message: `No BotVersion found for bot '${params.botName}'.` };
3298
+ const escalationsXml = (params.escalationConditions ?? [{ trigger: "agentRequested", action: "TransferToQueue" }]).map((ec, i) => `
3299
+ <met:botDialogs>
3300
+ <met:botSteps>
3301
+ <met:conversationStepType>Transfer</met:conversationStepType>
3302
+ <met:botMessage>${x(params.transferMessage ?? "Connecting you to an agent...")}</met:botMessage>
3303
+ <met:conversationTransfer>
3304
+ <met:transferToType>Queue</met:transferToType>
3305
+ <met:transferToName>${x(params.transferToQueueName)}</met:transferToName>
3306
+ </met:conversationTransfer>
3307
+ <met:stepIdentifier>step_${i + 1}</met:stepIdentifier>
3308
+ </met:botSteps>
3309
+ <met:developerName>Transfer_To_Agent_${i + 1}</met:developerName>
3310
+ <met:isGoalStep>false</met:isGoalStep>
3311
+ <met:label>Transfer To Agent ${i + 1}</met:label>
3312
+ <met:showInFooterMenu>false</met:showInFooterMenu>
3313
+ </met:botDialogs>`).join("");
3314
+ const xml = `<met:metadata xsi:type="met:BotVersion" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
3315
+ <met:fullName>${x(botFullName)}</met:fullName>
3316
+ ${escalationsXml}
3317
+ </met:metadata>`;
3318
+ return await upsertMetadata(auth, xml);
3319
+ } catch (err) {
3320
+ return { success: false, message: sanitizeError(err instanceof Error ? err.message : String(err)) };
3321
+ }
3322
+ }
2656
3323
  //# sourceMappingURL=salesforce.js.map