@adobe/spacecat-shared-utils 1.54.0 → 1.56.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 +14 -0
- package/package.json +1 -1
- package/src/llmo-config.js +5 -0
- package/src/schemas.js +67 -30
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,17 @@
|
|
|
1
|
+
# [@adobe/spacecat-shared-utils-v1.56.0](https://github.com/adobe/spacecat-shared/compare/@adobe/spacecat-shared-utils-v1.55.0...@adobe/spacecat-shared-utils-v1.56.0) (2025-10-07)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Features
|
|
5
|
+
|
|
6
|
+
* deletedEntities and prompts ([#1005](https://github.com/adobe/spacecat-shared/issues/1005)) ([c7c0c8f](https://github.com/adobe/spacecat-shared/commit/c7c0c8f635fcde250936579bb42d9942d7b6a1ab))
|
|
7
|
+
|
|
8
|
+
# [@adobe/spacecat-shared-utils-v1.55.0](https://github.com/adobe/spacecat-shared/compare/@adobe/spacecat-shared-utils-v1.54.0...@adobe/spacecat-shared-utils-v1.55.0) (2025-10-03)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Features
|
|
12
|
+
|
|
13
|
+
* add topics with nested prompts + make categories and prompts top level entities ([#999](https://github.com/adobe/spacecat-shared/issues/999)) ([1b43970](https://github.com/adobe/spacecat-shared/commit/1b43970912478361b2eb4eaf1e7f173e77ad80e9))
|
|
14
|
+
|
|
1
15
|
# [@adobe/spacecat-shared-utils-v1.54.0](https://github.com/adobe/spacecat-shared/compare/@adobe/spacecat-shared-utils-v1.53.0...@adobe/spacecat-shared-utils-v1.54.0) (2025-10-02)
|
|
2
16
|
|
|
3
17
|
|
package/package.json
CHANGED
package/src/llmo-config.js
CHANGED
|
@@ -41,12 +41,17 @@ export function llmoConfigPath(siteId) {
|
|
|
41
41
|
export function defaultConfig() {
|
|
42
42
|
return {
|
|
43
43
|
entities: {},
|
|
44
|
+
categories: {},
|
|
45
|
+
topics: {},
|
|
44
46
|
brands: {
|
|
45
47
|
aliases: [],
|
|
46
48
|
},
|
|
47
49
|
competitors: {
|
|
48
50
|
competitors: [],
|
|
49
51
|
},
|
|
52
|
+
deleted: {
|
|
53
|
+
prompts: {},
|
|
54
|
+
},
|
|
50
55
|
};
|
|
51
56
|
}
|
|
52
57
|
|
package/src/schemas.js
CHANGED
|
@@ -38,14 +38,39 @@ const nonEmptyString = z.string().min(1);
|
|
|
38
38
|
|
|
39
39
|
const region = z.string().length(2).regex(/^[a-z][a-z]$/i);
|
|
40
40
|
|
|
41
|
-
const
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
z.
|
|
45
|
-
])
|
|
41
|
+
const prompt = z.object({
|
|
42
|
+
prompt: nonEmptyString,
|
|
43
|
+
regions: z.array(region),
|
|
44
|
+
origin: z.union([z.literal('human'), z.literal('ai'), z.string()]),
|
|
45
|
+
source: z.union([z.literal('config'), z.literal('api'), z.string()]),
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
const entity = z.object({
|
|
49
|
+
type: nonEmptyString,
|
|
50
|
+
name: nonEmptyString,
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
const category = z.object({
|
|
54
|
+
name: nonEmptyString,
|
|
55
|
+
region: z.union([region, z.array(region)]),
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
const topic = z.object({
|
|
59
|
+
name: nonEmptyString,
|
|
60
|
+
prompts: z.array(prompt).min(1),
|
|
61
|
+
category: z.union([z.uuid(), nonEmptyString]),
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
const deletedPrompt = prompt.extend({
|
|
65
|
+
topic: nonEmptyString,
|
|
66
|
+
category: nonEmptyString,
|
|
67
|
+
regions: z.array(region).min(1),
|
|
68
|
+
});
|
|
46
69
|
|
|
47
70
|
export const llmoConfig = z.object({
|
|
48
71
|
entities: z.record(z.uuid(), entity),
|
|
72
|
+
categories: z.record(z.uuid(), category),
|
|
73
|
+
topics: z.record(z.uuid(), topic),
|
|
49
74
|
brands: z.object({
|
|
50
75
|
aliases: z.array(
|
|
51
76
|
z.object({
|
|
@@ -66,60 +91,72 @@ export const llmoConfig = z.object({
|
|
|
66
91
|
}),
|
|
67
92
|
),
|
|
68
93
|
}),
|
|
94
|
+
deleted: z.object({
|
|
95
|
+
prompts: z.record(z.uuid(), deletedPrompt).optional(),
|
|
96
|
+
}).optional(),
|
|
69
97
|
}).superRefine((value, ctx) => {
|
|
70
|
-
const {
|
|
98
|
+
const {
|
|
99
|
+
categories, topics, brands, competitors,
|
|
100
|
+
} = value;
|
|
71
101
|
|
|
72
102
|
brands.aliases.forEach((alias, index) => {
|
|
73
|
-
|
|
74
|
-
ensureRegionCompatibility(
|
|
103
|
+
ensureCategoryExists(categories, ctx, alias.category, ['brands', 'aliases', index, 'category']);
|
|
104
|
+
ensureRegionCompatibility(categories, ctx, alias.category, alias.region, ['brands', 'aliases', index, 'region'], 'brand alias');
|
|
75
105
|
});
|
|
76
106
|
|
|
77
107
|
competitors.competitors.forEach((competitor, index) => {
|
|
78
|
-
|
|
79
|
-
ensureRegionCompatibility(
|
|
108
|
+
ensureCategoryExists(categories, ctx, competitor.category, ['competitors', 'competitors', index, 'category']);
|
|
109
|
+
ensureRegionCompatibility(categories, ctx, competitor.category, competitor.region, ['competitors', 'competitors', index, 'region'], 'competitor');
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
// Validate topic prompts regions against their category
|
|
113
|
+
Object.entries(topics).forEach(([topicId, topicEntity]) => {
|
|
114
|
+
if (topicEntity.prompts && topicEntity.category) {
|
|
115
|
+
// If category is a UUID, validate against the referenced category entity
|
|
116
|
+
if (topicEntity.category.match(/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i)) {
|
|
117
|
+
topicEntity.prompts.forEach((promptItem, promptIndex) => {
|
|
118
|
+
ensureRegionCompatibility(
|
|
119
|
+
categories,
|
|
120
|
+
ctx,
|
|
121
|
+
topicEntity.category,
|
|
122
|
+
promptItem.regions,
|
|
123
|
+
['topics', topicId, 'prompts', promptIndex, 'regions'],
|
|
124
|
+
'topic prompt',
|
|
125
|
+
);
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
}
|
|
80
129
|
});
|
|
81
130
|
});
|
|
82
131
|
|
|
83
132
|
/**
|
|
84
|
-
* @param {LLMOConfig['
|
|
133
|
+
* @param {LLMOConfig['categories']} categories
|
|
85
134
|
* @param {z.RefinementCtx} ctx
|
|
86
135
|
* @param {string} id
|
|
87
|
-
* @param {string} expectedType
|
|
88
136
|
* @param {Array<number | string>} path
|
|
89
|
-
* @param {string} refLabel
|
|
90
137
|
*/
|
|
91
|
-
function
|
|
92
|
-
|
|
93
|
-
if (!entityValue) {
|
|
94
|
-
ctx.addIssue({
|
|
95
|
-
code: 'custom',
|
|
96
|
-
path,
|
|
97
|
-
message: `Unknown ${refLabel} entity: ${id}`,
|
|
98
|
-
});
|
|
99
|
-
return;
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
if (entityValue.type !== expectedType) {
|
|
138
|
+
function ensureCategoryExists(categories, ctx, id, path) {
|
|
139
|
+
if (!categories[id]) {
|
|
103
140
|
ctx.addIssue({
|
|
104
141
|
code: 'custom',
|
|
105
142
|
path,
|
|
106
|
-
message: `
|
|
143
|
+
message: `Category ${id} does not exist`,
|
|
107
144
|
});
|
|
108
145
|
}
|
|
109
146
|
}
|
|
110
147
|
|
|
111
148
|
/**
|
|
112
|
-
* @param {LLMOConfig['
|
|
149
|
+
* @param {LLMOConfig['categories']} categories
|
|
113
150
|
* @param {z.RefinementCtx} ctx
|
|
114
151
|
* @param {string} categoryId
|
|
115
152
|
* @param {string | string[]} itemRegion
|
|
116
153
|
* @param {Array<number | string>} path
|
|
117
154
|
* @param {string} itemLabel
|
|
118
155
|
*/
|
|
119
|
-
function ensureRegionCompatibility(
|
|
120
|
-
const categoryEntity =
|
|
156
|
+
function ensureRegionCompatibility(categories, ctx, categoryId, itemRegion, path, itemLabel) {
|
|
157
|
+
const categoryEntity = categories[categoryId];
|
|
121
158
|
if (!categoryEntity) {
|
|
122
|
-
// Category validation is handled by
|
|
159
|
+
// Category validation is handled by ensureCategoryExists
|
|
123
160
|
return;
|
|
124
161
|
}
|
|
125
162
|
|