From 3ec894765f3a14cbc41e4c1fbce4fc216f5453bf Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 21 Aug 2026 13:06:26 +0000 Subject: [PATCH 1/2] Initial plan From 8496de3108b5cb2704be4a3c0bb05d30e4c5ef36 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 21 Aug 2026 13:15:22 +0000 Subject: [PATCH 2/2] fix: resolve namespace tokens in embedded object filter evaluation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Vlocity exports were failing with "Filter evaluated to empty object for embedded object %vlocity_namespace%__Element__c on OmniScript__c" because the filter evaluation code in the new local exporter did not resolve the %vlocity_namespace% placeholder tokens before: 1. Looking up values in the context object (evalFilterValueExp) – the context is keyed by the real resolved namespace (e.g. vlocity_cmt__OmniScript__c) but the filter template still contained the raw token, so every path lookup returned undefined. 2. Using filter object keys as Salesforce field names (buildLookupFilter) – the keys were passed to Salesforce queries with the raw token instead of the actual field name. Fix: call this.salesforce.updateNamespace() on the filter string template in evalFilterValueExp and on each filter object key in buildLookupFilter. Also adds updateNamespace to every inline salesforce mock in datapackExporter.test.ts and a dedicated test case for namespace token resolution in filter keys and values. Closes #474 --- .../src/__tests__/datapackExporter.test.ts | 34 +++++++++++++++++-- .../src/export/datapackExporter.ts | 7 +++- 2 files changed, 37 insertions(+), 4 deletions(-) diff --git a/packages/vlocity-deploy/src/__tests__/datapackExporter.test.ts b/packages/vlocity-deploy/src/__tests__/datapackExporter.test.ts index c3cba551..26456f2d 100644 --- a/packages/vlocity-deploy/src/__tests__/datapackExporter.test.ts +++ b/packages/vlocity-deploy/src/__tests__/datapackExporter.test.ts @@ -78,7 +78,8 @@ describe('DatapackExporter', () => { describeSObjectField: jest.fn(async (type: string, fieldName: string) => findDescribeField(describeFor(type), fieldName)) }, - replaceNamespace: jest.fn((value: string) => value) + replaceNamespace: jest.fn((value: string) => value), + updateNamespace: jest.fn((value: string) => value) }; const matchingKeys = { getMatchingKey: jest.fn(async (type: string) => ({ @@ -253,6 +254,31 @@ describe('DatapackExporter', () => { ); }); + it('resolves namespace placeholders in filter keys and values', () => { + const { exporter, salesforce } = createExporter(); + // Simulate a namespace service that resolves %vlocity_namespace% to the actual namespace + salesforce.updateNamespace.mockImplementation((value: string) => + value.replace(/%vlocity_namespace%/g, 'vlocity_cmt') + ); + + const datapack = { + id: 'a0M000000000001AAA', + objectType: 'vlocity_cmt__OmniScript__c', + normalizedObjectType: 'OmniScript__c', + data: { + Id: 'a0M000000000001AAA' + } + }; + + const filter = exporter.buildLookupFilter({ + '%vlocity_namespace%__OmniScriptId__c': '{%vlocity_namespace%__OmniScript__c:Id}' + }, datapack); + + expect(filter).toStrictEqual({ + 'vlocity_cmt__OmniScriptId__c': 'a0M000000000001AAA' + }); + }); + it('awaits lookup references included in matching key objects', async () => { const describe = { name: 'Child__c', @@ -1158,7 +1184,8 @@ describe('DatapackExporter', () => { describeSObjectField: jest.fn(async (type: string, fieldName: string) => findDescribeField(type === rootDescribe.name ? rootDescribe : relatedDescribe, fieldName)) }, - replaceNamespace: jest.fn((value: string) => value) + replaceNamespace: jest.fn((value: string) => value), + updateNamespace: jest.fn((value: string) => value) }; const matchingKeys = mockMatchingKeyService(); const expandedResults: any[] = []; @@ -1282,7 +1309,8 @@ describe('DatapackExporter', () => { describeSObjectField: jest.fn(async (_type: string, fieldName: string) => findDescribeField(childDescribe, fieldName)) }, - replaceNamespace: jest.fn((value: string) => value) + replaceNamespace: jest.fn((value: string) => value), + updateNamespace: jest.fn((value: string) => value) }; const matchingKeys = mockMatchingKeyService(); diff --git a/packages/vlocity-deploy/src/export/datapackExporter.ts b/packages/vlocity-deploy/src/export/datapackExporter.ts index 5fcc249d..ae08be37 100644 --- a/packages/vlocity-deploy/src/export/datapackExporter.ts +++ b/packages/vlocity-deploy/src/export/datapackExporter.ts @@ -1009,7 +1009,7 @@ export class DatapackExporter { // Object exp with field conditions if (typeof filter === 'object' && filter) { const entries = Object.entries(filter).map(([key, value]) => [ - key, + this.salesforce.updateNamespace(key), this.evalFilterValue(value, datapack) ]); return entries.some(([, value]) => value === undefined) @@ -1038,6 +1038,11 @@ export class DatapackExporter { } private evalFilterValueExp(stringFormat: string, datapack: ExportDatapack) { + // Resolve namespace placeholders (e.g. %vlocity_namespace%) so that the + // resulting lookup path can be matched against the context keys which use + // the real Salesforce namespace. + stringFormat = this.salesforce.updateNamespace(stringFormat); + const context = { Id: datapack.id, [datapack.objectType]: datapack.data,