Skip to content

Commit 78df8f9

Browse files
nitinjaclaude
andauthored
feat(audit-url): add moneyPages source to auditTargetURLs config (#1496)
Add moneyPages as a new audit target URL source alongside manual, with identical structure (array of { url } entries) and full cross-source deduplication support. Please ensure your pull request adheres to the following guidelines: - [ ] make sure to link the related issues in this description - [ ] when merging / squashing, make sure the fixed issue references are visible in the commits, for easy compilation of release notes ## Related Issues Thanks for contributing! --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 885066e commit 78df8f9

3 files changed

Lines changed: 110 additions & 4 deletions

File tree

packages/spacecat-shared-data-access/src/models/site/config.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -404,6 +404,9 @@ export const configSchema = Joi.object({
404404
manual: Joi.array().items(Joi.object({
405405
url: Joi.string().uri().required(),
406406
})).optional().default([]),
407+
moneyPages: Joi.array().items(Joi.object({
408+
url: Joi.string().uri().required(),
409+
})).optional().default([]),
407410
}).options({ stripUnknown: true }).optional(),
408411
handlers: Joi.object().pattern(Joi.string(), Joi.object({
409412
mentions: Joi.object().pattern(Joi.string(), Joi.array().items(Joi.string())),
@@ -515,7 +518,7 @@ export const Config = (data = {}) => {
515518
self.getEdgeOptimizeConfig = () => state?.edgeOptimizeConfig;
516519
self.getOnboardConfig = () => state?.onboardConfig;
517520
self.getCommerceLlmoConfig = () => state?.commerceLlmoConfig;
518-
const AUDIT_TARGET_SOURCES = ['manual'];
521+
const AUDIT_TARGET_SOURCES = ['manual', 'moneyPages'];
519522
const auditTargetEntrySchema = Joi.object({
520523
url: Joi.string().uri().required(),
521524
});

packages/spacecat-shared-data-access/src/models/site/index.d.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ export interface LlmoCustomerIntent {
110110
value: string;
111111
}
112112

113-
export type AuditTargetSource = 'manual';
113+
export type AuditTargetSource = 'manual' | 'moneyPages';
114114

115115
export interface AuditTargetEntry {
116116
url: string;
@@ -122,6 +122,7 @@ export interface AuditTargetEntryWithSource extends AuditTargetEntry {
122122

123123
export interface AuditTargetURLs {
124124
manual?: AuditTargetEntry[];
125+
moneyPages?: AuditTargetEntry[];
125126
}
126127

127128
export interface SiteConfig {

packages/spacecat-shared-data-access/test/unit/models/site/config.test.js

Lines changed: 104 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3041,6 +3041,20 @@ describe('Config Tests', () => {
30413041
expect(result[1].source).to.equal('manual');
30423042
});
30433043

3044+
it('returns entries from both manual and moneyPages with correct source tags', () => {
3045+
const config = Config({
3046+
auditTargetURLs: {
3047+
manual: [{ url: 'https://example.com/manual1' }],
3048+
moneyPages: [{ url: 'https://example.com/money1' }, { url: 'https://example.com/money2' }],
3049+
},
3050+
});
3051+
const result = config.getAuditTargetURLs();
3052+
expect(result).to.have.lengthOf(3);
3053+
expect(result[0]).to.deep.equal({ url: 'https://example.com/manual1', source: 'manual' });
3054+
expect(result[1]).to.deep.equal({ url: 'https://example.com/money1', source: 'moneyPages' });
3055+
expect(result[2]).to.deep.equal({ url: 'https://example.com/money2', source: 'moneyPages' });
3056+
});
3057+
30443058
describe('getAuditTargetURLsBySource', () => {
30453059
it('returns URLs for a specific source', () => {
30463060
const config = Config({
@@ -3054,9 +3068,22 @@ describe('Config Tests', () => {
30543068
expect(manual[1].url).to.equal('https://example.com/m2');
30553069
});
30563070

3071+
it('returns moneyPages URLs for moneyPages source', () => {
3072+
const config = Config({
3073+
auditTargetURLs: {
3074+
moneyPages: [{ url: 'https://example.com/mp1' }, { url: 'https://example.com/mp2' }],
3075+
},
3076+
});
3077+
const moneyPages = config.getAuditTargetURLsBySource('moneyPages');
3078+
expect(moneyPages).to.have.lengthOf(2);
3079+
expect(moneyPages[0].url).to.equal('https://example.com/mp1');
3080+
expect(moneyPages[1].url).to.equal('https://example.com/mp2');
3081+
});
3082+
30573083
it('returns empty array for source with no entries', () => {
30583084
const config = Config();
30593085
expect(config.getAuditTargetURLsBySource('manual')).to.deep.equal([]);
3086+
expect(config.getAuditTargetURLsBySource('moneyPages')).to.deep.equal([]);
30603087
});
30613088

30623089
it('rejects invalid source', () => {
@@ -3096,6 +3123,22 @@ describe('Config Tests', () => {
30963123
config.updateAuditTargetURLs('manual', []);
30973124
expect(config.getAuditTargetURLsBySource('manual')).to.deep.equal([]);
30983125
});
3126+
3127+
it('replaces URLs for moneyPages source', () => {
3128+
const config = Config({
3129+
auditTargetURLs: {
3130+
moneyPages: [{ url: 'https://old.com' }],
3131+
},
3132+
});
3133+
config.updateAuditTargetURLs('moneyPages', [
3134+
{ url: 'https://new1.com' },
3135+
{ url: 'https://new2.com' },
3136+
]);
3137+
const result = config.getAuditTargetURLsBySource('moneyPages');
3138+
expect(result).to.have.lengthOf(2);
3139+
expect(result[0].url).to.equal('https://new1.com');
3140+
expect(result[1].url).to.equal('https://new2.com');
3141+
});
30993142
});
31003143

31013144
describe('addAuditTargetURL', () => {
@@ -3129,6 +3172,25 @@ describe('Config Tests', () => {
31293172
const config = Config();
31303173
expect(() => config.addAuditTargetURL('invalid', { url: 'https://example.com' })).to.throw('Invalid audit target source');
31313174
});
3175+
3176+
it('appends a new URL to moneyPages source', () => {
3177+
const config = Config();
3178+
config.addAuditTargetURL('moneyPages', { url: 'https://example.com/mp1' });
3179+
config.addAuditTargetURL('moneyPages', { url: 'https://example.com/mp2' });
3180+
expect(config.getAuditTargetURLsBySource('moneyPages')).to.have.lengthOf(2);
3181+
expect(config.getAuditTargetURLsBySource('moneyPages')[1].url).to.equal('https://example.com/mp2');
3182+
});
3183+
3184+
it('deduplicates across manual and moneyPages sources', () => {
3185+
const config = Config({
3186+
auditTargetURLs: {
3187+
manual: [{ url: 'https://example.com/shared' }],
3188+
},
3189+
});
3190+
config.addAuditTargetURL('moneyPages', { url: 'https://example.com/shared' });
3191+
expect(config.getAuditTargetURLsBySource('moneyPages')).to.have.lengthOf(0);
3192+
expect(config.getAuditTargetURLs()).to.have.lengthOf(1);
3193+
});
31323194
});
31333195

31343196
describe('removeAuditTargetURL', () => {
@@ -3161,6 +3223,17 @@ describe('Config Tests', () => {
31613223
const config = Config();
31623224
expect(() => config.removeAuditTargetURL('invalid', 'https://example.com')).to.throw('Invalid audit target source');
31633225
});
3226+
3227+
it('removes by url string from moneyPages source', () => {
3228+
const config = Config({
3229+
auditTargetURLs: {
3230+
moneyPages: [{ url: 'https://example.com/mp1' }, { url: 'https://example.com/mp2' }],
3231+
},
3232+
});
3233+
config.removeAuditTargetURL('moneyPages', 'https://example.com/mp2');
3234+
expect(config.getAuditTargetURLsBySource('moneyPages')).to.have.lengthOf(1);
3235+
expect(config.getAuditTargetURLsBySource('moneyPages')[0].url).to.equal('https://example.com/mp1');
3236+
});
31643237
});
31653238

31663239
describe('serialization', () => {
@@ -3173,6 +3246,7 @@ describe('Config Tests', () => {
31733246
const item = Config.toDynamoItem(config);
31743247
expect(item.auditTargetURLs).to.deep.equal({
31753248
manual: [{ url: 'https://example.com/page1' }],
3249+
moneyPages: [],
31763250
});
31773251
});
31783252

@@ -3189,6 +3263,31 @@ describe('Config Tests', () => {
31893263
const restored = Config.fromDynamoItem(item);
31903264
expect(restored.getAuditTargetURLs()).to.deep.equal(config.getAuditTargetURLs());
31913265
});
3266+
3267+
it('includes moneyPages in toDynamoItem conversion', () => {
3268+
const config = Config({
3269+
auditTargetURLs: {
3270+
moneyPages: [{ url: 'https://example.com/mp1' }],
3271+
},
3272+
});
3273+
const item = Config.toDynamoItem(config);
3274+
expect(item.auditTargetURLs).to.deep.equal({
3275+
manual: [],
3276+
moneyPages: [{ url: 'https://example.com/mp1' }],
3277+
});
3278+
});
3279+
3280+
it('round-trips both manual and moneyPages through serialization', () => {
3281+
const config = Config({
3282+
auditTargetURLs: {
3283+
manual: [{ url: 'https://example.com/m1' }],
3284+
moneyPages: [{ url: 'https://example.com/mp1' }],
3285+
},
3286+
});
3287+
const item = Config.toDynamoItem(config);
3288+
const restored = Config.fromDynamoItem(item);
3289+
expect(restored.getAuditTargetURLs()).to.deep.equal(config.getAuditTargetURLs());
3290+
});
31923291
});
31933292

31943293
describe('field validation', () => {
@@ -3200,17 +3299,20 @@ describe('Config Tests', () => {
32003299
})).to.throw();
32013300
});
32023301

3203-
it('strips unknown source keys from auditTargetURLs', () => {
3302+
it('strips unknown source keys from auditTargetURLs but keeps moneyPages', () => {
32043303
const config = Config({
32053304
auditTargetURLs: {
32063305
manual: [{ url: 'https://example.com/page1' }],
3306+
moneyPages: [{ url: 'https://example.com/mp1' }],
32073307
unknown: [{ url: 'https://example.com/page2' }],
32083308
},
32093309
});
32103310
const result = config.getAuditTargetURLs();
3211-
expect(result).to.have.lengthOf(1);
3311+
expect(result).to.have.lengthOf(2);
32123312
expect(result[0].url).to.equal('https://example.com/page1');
32133313
expect(result[0].source).to.equal('manual');
3314+
expect(result[1].url).to.equal('https://example.com/mp1');
3315+
expect(result[1].source).to.equal('moneyPages');
32143316
});
32153317
});
32163318
});

0 commit comments

Comments
 (0)