@adobe/spacecat-shared-data-access 2.38.0 → 2.39.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.
package/CHANGELOG.md CHANGED
@@ -1,3 +1,17 @@
1
+ # [@adobe/spacecat-shared-data-access-v2.39.0](https://github.com/adobe/spacecat-shared/compare/@adobe/spacecat-shared-data-access-v2.38.1...@adobe/spacecat-shared-data-access-v2.39.0) (2025-07-22)
2
+
3
+
4
+ ### Features
5
+
6
+ * add llmo specific configuration in site config ([#853](https://github.com/adobe/spacecat-shared/issues/853)) ([476b8e8](https://github.com/adobe/spacecat-shared/commit/476b8e84009602a4c9d7ef8d42b9efcae3beae9e))
7
+
8
+ # [@adobe/spacecat-shared-data-access-v2.38.1](https://github.com/adobe/spacecat-shared/compare/@adobe/spacecat-shared-data-access-v2.38.0...@adobe/spacecat-shared-data-access-v2.38.1) (2025-07-22)
9
+
10
+
11
+ ### Bug Fixes
12
+
13
+ * return provided data when config error ([#862](https://github.com/adobe/spacecat-shared/issues/862)) ([eb418cd](https://github.com/adobe/spacecat-shared/commit/eb418cdf4e942f2da0b40d95cc991b9a4a34a393))
14
+
1
15
  # [@adobe/spacecat-shared-data-access-v2.38.0](https://github.com/adobe/spacecat-shared/compare/@adobe/spacecat-shared-data-access-v2.37.0...@adobe/spacecat-shared-data-access-v2.38.0) (2025-07-21)
2
16
 
3
17
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adobe/spacecat-shared-data-access",
3
- "version": "2.38.0",
3
+ "version": "2.39.0",
4
4
  "description": "Shared modules of the Spacecat Services - Data Access",
5
5
  "type": "module",
6
6
  "engines": {
@@ -37,6 +37,20 @@ export const IMPORT_SOURCES = {
37
37
  RUM: 'rum',
38
38
  };
39
39
 
40
+ // LLMO question schema for both Human and AI questions
41
+ const QUESTION_SCHEMA = Joi.object({
42
+ key: Joi.string().required(),
43
+ question: Joi.string().required(),
44
+ source: Joi.string().optional(),
45
+ country: Joi.string().optional(),
46
+ product: Joi.string().optional(),
47
+ volume: Joi.string().optional(),
48
+ keyword: Joi.string().optional(),
49
+ url: Joi.string().uri().optional(),
50
+ tags: Joi.array().items(Joi.string()).optional(),
51
+ importTime: Joi.string().isoDate().optional(),
52
+ });
53
+
40
54
  const IMPORT_BASE_KEYS = {
41
55
  destinations: Joi.array().items(Joi.string().valid(IMPORT_DESTINATIONS.DEFAULT)).required(),
42
56
  sources: Joi.array().items(Joi.string().valid(...Object.values(IMPORT_SOURCES))).required(),
@@ -201,6 +215,14 @@ export const configSchema = Joi.object({
201
215
  headers: Joi.object().pattern(Joi.string(), Joi.string()),
202
216
  overrideBaseURL: Joi.string().uri().optional(),
203
217
  }).optional(),
218
+ llmo: Joi.object({
219
+ dataFolder: Joi.string().required(),
220
+ brand: Joi.string().required(),
221
+ questions: Joi.object({
222
+ Human: Joi.array().items(QUESTION_SCHEMA).optional(),
223
+ AI: Joi.array().items(QUESTION_SCHEMA).optional(),
224
+ }).optional(),
225
+ }).optional(),
204
226
  cdnLogsConfig: Joi.object({
205
227
  bucketName: Joi.string().required(),
206
228
  filters: Joi.array().items(
@@ -258,22 +280,22 @@ export function validateConfiguration(config) {
258
280
  }
259
281
 
260
282
  export const Config = (data = {}) => {
261
- let validConfig;
283
+ let configData;
262
284
 
263
285
  try {
264
- validConfig = validateConfiguration(data);
286
+ configData = validateConfiguration(data);
265
287
  } catch (error) {
266
288
  const logger = getLogger();
267
289
  if (logger && logger !== console) {
268
- logger.error('Site configuration validation failed, using default config', {
290
+ logger.error('Site configuration validation failed, using provided data', {
269
291
  error: error.message,
270
292
  invalidConfig: data,
271
293
  });
272
294
  }
273
- validConfig = { ...DEFAULT_CONFIG };
295
+ configData = { ...data };
274
296
  }
275
297
 
276
- const state = { ...validConfig };
298
+ const state = { ...configData };
277
299
  const self = { state };
278
300
  self.getSlackConfig = () => state.slack;
279
301
  self.isInternalCustomer = () => state?.slack?.workspace === 'internal';
@@ -291,6 +313,11 @@ export const Config = (data = {}) => {
291
313
  self.getFetchConfig = () => state?.fetchConfig;
292
314
  self.getBrandConfig = () => state?.brandConfig;
293
315
  self.getCdnLogsConfig = () => state?.cdnLogsConfig;
316
+ self.getLlmoConfig = () => state?.llmo;
317
+ self.getLlmoDataFolder = () => state?.llmo?.dataFolder;
318
+ self.getLlmoBrand = () => state?.llmo?.brand;
319
+ self.getLlmoHumanQuestions = () => state?.llmo?.questions?.Human;
320
+ self.getLlmoAIQuestions = () => state?.llmo?.questions?.AI;
294
321
 
295
322
  self.updateSlackConfig = (channel, workspace, invitedUserCount) => {
296
323
  state.slack = {
@@ -300,6 +327,64 @@ export const Config = (data = {}) => {
300
327
  };
301
328
  };
302
329
 
330
+ self.updateLlmoConfig = (dataFolder, brand, questions) => {
331
+ state.llmo = {
332
+ dataFolder,
333
+ brand,
334
+ ...(questions !== undefined ? { questions } : {}),
335
+ };
336
+ };
337
+
338
+ self.updateLlmoDataFolder = (dataFolder) => {
339
+ state.llmo = state.llmo || {};
340
+ state.llmo.dataFolder = dataFolder;
341
+ };
342
+
343
+ self.updateLlmoBrand = (brand) => {
344
+ state.llmo = state.llmo || {};
345
+ state.llmo.brand = brand;
346
+ };
347
+
348
+ self.addLlmoHumanQuestions = (questions) => {
349
+ state.llmo = state.llmo || {};
350
+ state.llmo.questions = state.llmo.questions || {};
351
+ state.llmo.questions.Human = state.llmo.questions.Human || [];
352
+ state.llmo.questions.Human.push(...questions);
353
+ };
354
+
355
+ self.addLlmoAIQuestions = (questions) => {
356
+ state.llmo = state.llmo || {};
357
+ state.llmo.questions = state.llmo.questions || {};
358
+ state.llmo.questions.AI = state.llmo.questions.AI || [];
359
+ state.llmo.questions.AI.push(...questions);
360
+ };
361
+
362
+ self.removeLlmoQuestion = (key) => {
363
+ state.llmo = state.llmo || {};
364
+ state.llmo.questions = state.llmo.questions || {};
365
+ state.llmo.questions.Human = state.llmo.questions.Human || [];
366
+ state.llmo.questions.Human = state.llmo.questions.Human.filter(
367
+ (question) => question.key !== key,
368
+ );
369
+ state.llmo.questions.AI = state.llmo.questions.AI || [];
370
+ state.llmo.questions.AI = state.llmo.questions.AI.filter(
371
+ (question) => question.key !== key,
372
+ );
373
+ };
374
+
375
+ self.updateLlmoQuestion = (key, questionUpdate) => {
376
+ state.llmo = state.llmo || {};
377
+ state.llmo.questions = state.llmo.questions || {};
378
+ state.llmo.questions.Human = state.llmo.questions.Human || [];
379
+ state.llmo.questions.Human = state.llmo.questions.Human.map(
380
+ (question) => (question.key === key ? { ...question, ...questionUpdate, key } : question),
381
+ );
382
+ state.llmo.questions.AI = state.llmo.questions.AI || [];
383
+ state.llmo.questions.AI = state.llmo.questions.AI.map(
384
+ (question) => (question.key === key ? { ...question, ...questionUpdate, key } : question),
385
+ );
386
+ };
387
+
303
388
  self.updateImports = (imports) => {
304
389
  state.imports = imports;
305
390
  };
@@ -409,4 +494,5 @@ Config.toDynamoItem = (config) => ({
409
494
  fetchConfig: config.getFetchConfig(),
410
495
  brandConfig: config.getBrandConfig(),
411
496
  cdnLogsConfig: config.getCdnLogsConfig(),
497
+ llmo: config.getLlmoConfig(),
412
498
  });
@@ -61,6 +61,19 @@ export interface ImportConfig {
61
61
  limit?: number;
62
62
  }
63
63
 
64
+ export interface LlmoQuestion {
65
+ key: string;
66
+ question: string;
67
+ source?: string;
68
+ country?: string;
69
+ product?: string;
70
+ volume?: string;
71
+ importTime?: string;
72
+ keyword?: string;
73
+ url?: string;
74
+ tags?: string[];
75
+ }
76
+
64
77
  export interface SiteConfig {
65
78
  state: {
66
79
  slack?: {
@@ -97,6 +110,14 @@ export interface SiteConfig {
97
110
  headers?: Record<string, string>;
98
111
  overrideBaseURL?: string;
99
112
  };
113
+ llmo?: {
114
+ dataFolder: string;
115
+ brand: string;
116
+ questions?: {
117
+ Human?: Array<LlmoQuestion>;
118
+ AI?: Array<LlmoQuestion>;
119
+ };
120
+ };
100
121
  };
101
122
  getSlackConfig(): { workspace?: string; channel?: string; invitedUserCount?: number };
102
123
  getImports(): ImportConfig[];
@@ -116,6 +137,25 @@ export interface SiteConfig {
116
137
  getLatestMetrics(type: string):
117
138
  { pageViewsChange: number; ctrChange: number; projectedTrafficValue: number } | undefined;
118
139
  getFetchConfig(): { headers?: Record<string, string>, overrideBaseURL?: string } | undefined;
140
+ getLlmoConfig(): {
141
+ dataFolder: string;
142
+ brand: string;
143
+ questions?: { Human?: Array<LlmoQuestion>; AI?: Array<LlmoQuestion> };
144
+ } | undefined;
145
+ updateLlmoConfig(dataFolder: string, brand: string, questions?: {
146
+ Human?: Array<LlmoQuestion>;
147
+ AI?: Array<LlmoQuestion>;
148
+ }): void;
149
+ updateLlmoDataFolder(dataFolder: string): void;
150
+ updateLlmoBrand(brand: string): void;
151
+ getLlmoDataFolder(): string | undefined;
152
+ getLlmoBrand(): string | undefined;
153
+ getLlmoHumanQuestions(): LlmoQuestion[] | undefined;
154
+ getLlmoAIQuestions(): LlmoQuestion[] | undefined;
155
+ addLlmoHumanQuestions(questions: LlmoQuestion[]): void;
156
+ addLlmoAIQuestions(questions: LlmoQuestion[]): void;
157
+ removeLlmoQuestion(key: string): void;
158
+ updateLlmoQuestion(key: string, questionUpdate: Partial<LlmoQuestion>): void;
119
159
  }
120
160
 
121
161
  export interface Site extends BaseModel {