@adobe/spacecat-shared-utils 1.113.0 → 1.114.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 +6 -0
- package/package.json +1 -1
- package/src/index.js +1 -0
- package/src/llmo-config.js +47 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
## [@adobe/spacecat-shared-utils-v1.114.0](https://github.com/adobe/spacecat-shared/compare/@adobe/spacecat-shared-utils-v1.113.0...@adobe/spacecat-shared-utils-v1.114.0) (2026-05-04)
|
|
2
|
+
|
|
3
|
+
### Features
|
|
4
|
+
|
|
5
|
+
* **llmo-config:** fail-closed writeConfig validation (SITES-43238) ([#1574](https://github.com/adobe/spacecat-shared/issues/1574)) ([a177743](https://github.com/adobe/spacecat-shared/commit/a177743a7def37dd3fabb026241d0e0ea9e9bac3))
|
|
6
|
+
|
|
1
7
|
## [@adobe/spacecat-shared-utils-v1.113.0](https://github.com/adobe/spacecat-shared/compare/@adobe/spacecat-shared-utils-v1.112.5...@adobe/spacecat-shared-utils-v1.113.0) (2026-04-29)
|
|
2
8
|
|
|
3
9
|
### Features
|
package/package.json
CHANGED
package/src/index.js
CHANGED
|
@@ -109,6 +109,7 @@ export { detectAEMVersion, DELIVERY_TYPES, AUTHORING_TYPES } from './aem.js';
|
|
|
109
109
|
export { determineAEMCSPageId, getPageEditUrl } from './aem-content-api-utils.js';
|
|
110
110
|
|
|
111
111
|
export * as llmoConfig from './llmo-config.js';
|
|
112
|
+
export { LlmoConfigValidationError } from './llmo-config.js';
|
|
112
113
|
export * as llmoStrategy from './llmo-strategy.js';
|
|
113
114
|
export * as schemas from './schemas.js';
|
|
114
115
|
|
package/src/llmo-config.js
CHANGED
|
@@ -18,6 +18,31 @@ import { llmoConfig } from './schemas.js';
|
|
|
18
18
|
* @import { LLMOConfig } from "./schemas.js"
|
|
19
19
|
*/
|
|
20
20
|
|
|
21
|
+
/**
|
|
22
|
+
* Thrown by `writeConfig` when the supplied LLMO configuration does not match
|
|
23
|
+
* the published Zod schema. Exposes the offending site and the Zod issue list
|
|
24
|
+
* so callers and log readers can identify the failing fields without
|
|
25
|
+
* re-parsing the error.
|
|
26
|
+
*/
|
|
27
|
+
export class LlmoConfigValidationError extends Error {
|
|
28
|
+
constructor(siteId, zodError) {
|
|
29
|
+
// Use issue `code` rather than `message` in the summary: Zod's default
|
|
30
|
+
// messages can echo received values, which may include user-supplied
|
|
31
|
+
// content (brand names, competitor URLs) on the api-service write path.
|
|
32
|
+
// The full message and value remain on `this.issues` for trusted callers.
|
|
33
|
+
const summary = zodError.issues
|
|
34
|
+
.map((i) => `${i.path.join('.')}: ${i.code}`)
|
|
35
|
+
.join('; ');
|
|
36
|
+
super(
|
|
37
|
+
`LLMO config for site ${siteId} failed schema validation: ${summary}`,
|
|
38
|
+
{ cause: zodError },
|
|
39
|
+
);
|
|
40
|
+
this.name = 'LlmoConfigValidationError';
|
|
41
|
+
this.siteId = siteId;
|
|
42
|
+
this.issues = zodError.issues;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
21
46
|
/**
|
|
22
47
|
* @param {string} siteId The ID of the site to get the config directory for.
|
|
23
48
|
* @returns {string} The configuration directory path for the given site ID.
|
|
@@ -62,6 +87,10 @@ export function defaultConfig() {
|
|
|
62
87
|
* Reads the LLMO configuration for a given site.
|
|
63
88
|
* Returns an empty configuration if the configuration does not exist.
|
|
64
89
|
*
|
|
90
|
+
* If the persisted config exists but fails schema validation, throws
|
|
91
|
+
* `LlmoConfigValidationError` so callers have a uniform error contract
|
|
92
|
+
* across read and write paths.
|
|
93
|
+
*
|
|
65
94
|
* @param {string} sideId The ID of the site.
|
|
66
95
|
* @param {S3Client} s3Client The S3 client to use for reading the configuration.
|
|
67
96
|
* @param {object} [options]
|
|
@@ -70,6 +99,7 @@ export function defaultConfig() {
|
|
|
70
99
|
* @param {string} [options.s3Bucket] Optional S3 bucket name.
|
|
71
100
|
* @returns {Promise<{config: LLMOConfig, exists: boolean, version?: string}>} The configuration,
|
|
72
101
|
* a flag indicating if it existed, and the version ID if it exists.
|
|
102
|
+
* @throws {LlmoConfigValidationError} If the persisted config fails schema validation.
|
|
73
103
|
* @throws {Error} If reading the configuration fails for reasons other than it not existing.
|
|
74
104
|
*/
|
|
75
105
|
export async function readConfig(sideId, s3Client, options) {
|
|
@@ -97,20 +127,35 @@ export async function readConfig(sideId, s3Client, options) {
|
|
|
97
127
|
throw new Error('LLMO config body is empty');
|
|
98
128
|
}
|
|
99
129
|
const text = await body.transformToString();
|
|
100
|
-
const
|
|
101
|
-
|
|
130
|
+
const result = llmoConfig.safeParse(JSON.parse(text));
|
|
131
|
+
if (!result.success) {
|
|
132
|
+
throw new LlmoConfigValidationError(sideId, result.error);
|
|
133
|
+
}
|
|
134
|
+
return { config: result.data, exists: true, version: res.VersionId || undefined };
|
|
102
135
|
}
|
|
103
136
|
|
|
104
137
|
/**
|
|
105
138
|
* Writes the LLMO configuration for a given site.
|
|
139
|
+
*
|
|
140
|
+
* Validates `config` against the published Zod schema before issuing the S3
|
|
141
|
+
* `PutObject`. If validation fails, throws `LlmoConfigValidationError` and
|
|
142
|
+
* does not call S3, so invalid configs cannot reach the bucket through this
|
|
143
|
+
* function.
|
|
144
|
+
*
|
|
106
145
|
* @param {string} siteId The ID of the site.
|
|
107
146
|
* @param {LLMOConfig} config The configuration object to write.
|
|
108
147
|
* @param {S3Client} s3Client The S3 client to use for reading the configuration.
|
|
109
148
|
* @param {object} [options]
|
|
110
149
|
* @param {string} [options.s3Bucket] Optional S3 bucket name.
|
|
111
150
|
* @returns {Promise<{ version: string }>} The version of the configuration written.
|
|
151
|
+
* @throws {LlmoConfigValidationError} If `config` does not match the LLMO schema.
|
|
112
152
|
*/
|
|
113
153
|
export async function writeConfig(siteId, config, s3Client, options) {
|
|
154
|
+
const result = llmoConfig.safeParse(config);
|
|
155
|
+
if (!result.success) {
|
|
156
|
+
throw new LlmoConfigValidationError(siteId, result.error);
|
|
157
|
+
}
|
|
158
|
+
|
|
114
159
|
const s3Bucket = options?.s3Bucket || process.env.S3_BUCKET_NAME;
|
|
115
160
|
|
|
116
161
|
const putObjectCommand = new PutObjectCommand({
|