@adobe/spacecat-shared-utils 1.110.0 → 1.112.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,15 @@
1
+ ## [@adobe/spacecat-shared-utils-v1.112.0](https://github.com/adobe/spacecat-shared/compare/@adobe/spacecat-shared-utils-v1.111.0...@adobe/spacecat-shared-utils-v1.112.0) (2026-04-02)
2
+
3
+ ### Features
4
+
5
+ * **spacecat-shared-utils:** add sub-path exports for slim imports ([#1486](https://github.com/adobe/spacecat-shared/issues/1486)) ([4e15c66](https://github.com/adobe/spacecat-shared/commit/4e15c6631f5f660283178d61891bf4773a6b564f))
6
+
7
+ ## [@adobe/spacecat-shared-utils-v1.111.0](https://github.com/adobe/spacecat-shared/compare/@adobe/spacecat-shared-utils-v1.110.0...@adobe/spacecat-shared-utils-v1.111.0) (2026-04-01)
8
+
9
+ ### Features
10
+
11
+ * LLMO-3758 info-gain ([#1488](https://github.com/adobe/spacecat-shared/issues/1488)) ([cc6bcc1](https://github.com/adobe/spacecat-shared/commit/cc6bcc16921e98f46b79efdff272004672fb455e))
12
+
1
13
  ## [@adobe/spacecat-shared-utils-v1.110.0](https://github.com/adobe/spacecat-shared/compare/@adobe/spacecat-shared-utils-v1.109.0...@adobe/spacecat-shared-utils-v1.110.0) (2026-04-01)
2
14
 
3
15
  ### Features
package/README.md CHANGED
@@ -121,6 +121,28 @@ This library includes a comprehensive test suite to ensure the reliability of th
121
121
  npm test
122
122
  ```
123
123
 
124
+ ## Sub-path Exports
125
+
126
+ To avoid pulling in the full dependency tree (~110MB), import from a sub-path:
127
+
128
+ | Import | Dependencies |
129
+ |--------|-------------|
130
+ | `@adobe/spacecat-shared-utils` | All (~110MB) |
131
+ | `@adobe/spacecat-shared-utils/core` | None — pure JS only |
132
+ | `@adobe/spacecat-shared-utils/aws` | `@aws-sdk/*`, `aws-xray-sdk`, `@adobe/fetch` ⚠ **Side effect:** initializes HTTP connection pool at import time — requires outbound internet access |
133
+ | `@adobe/spacecat-shared-utils/locale` | `cheerio`, `world-countries`, `franc-min`, `iso-639-3`, `@adobe/fetch` ⚠ **Side effect:** initializes HTTP connection pool at import time — requires outbound internet access |
134
+ | `@adobe/spacecat-shared-utils/calendar` | `date-fns` |
135
+ | `@adobe/spacecat-shared-utils/schemas` | `zod` |
136
+ | `@adobe/spacecat-shared-utils/constants` | None — pure data |
137
+
138
+ ### TypeScript
139
+
140
+ Sub-path exports require `"moduleResolution": "node16"`, `"nodenext"`, or `"bundler"` in `tsconfig.json`. Legacy `"moduleResolution": "node"` does not resolve sub-path exports.
141
+
142
+ ### Maintenance
143
+
144
+ Any new `src/` file that contains top-level imperative code (anything beyond `import`/`export` statements) must be added to the `sideEffects` array in `package.json`.
145
+
124
146
  ## License
125
147
 
126
148
  This project is licensed under the Apache License 2.0 - see the [LICENSE](LICENSE.txt) file for details.
package/package.json CHANGED
@@ -1,14 +1,43 @@
1
1
  {
2
2
  "name": "@adobe/spacecat-shared-utils",
3
- "version": "1.110.0",
3
+ "version": "1.112.0",
4
4
  "description": "Shared modules of the Spacecat Services - utils",
5
5
  "type": "module",
6
6
  "exports": {
7
7
  ".": {
8
+ "types": "./src/index.d.ts",
8
9
  "browser": "./src/browser.js",
9
10
  "default": "./src/index.js"
11
+ },
12
+ "./core": {
13
+ "types": "./src/core.d.ts",
14
+ "default": "./src/core.js"
15
+ },
16
+ "./aws": {
17
+ "types": "./src/aws.d.ts",
18
+ "default": "./src/aws.js"
19
+ },
20
+ "./locale": {
21
+ "types": "./src/locale.d.ts",
22
+ "default": "./src/locale.js"
23
+ },
24
+ "./calendar": {
25
+ "types": "./src/calendar.d.ts",
26
+ "default": "./src/calendar.js"
27
+ },
28
+ "./schemas": {
29
+ "types": "./src/schemas.d.ts",
30
+ "default": "./src/schemas.js"
31
+ },
32
+ "./constants": {
33
+ "types": "./src/constants.d.ts",
34
+ "default": "./src/constants.js"
10
35
  }
11
36
  },
37
+ "sideEffects": [
38
+ "./src/adobe-fetch.js",
39
+ "./src/url-helpers.js"
40
+ ],
12
41
  "engines": {
13
42
  "node": ">=22.0.0 <25.0.0",
14
43
  "npm": ">=10.9.0 <12.0.0"
@@ -16,6 +45,7 @@
16
45
  "main": "src/index.js",
17
46
  "types": "src/index.d.ts",
18
47
  "scripts": {
48
+ "pretest": "node scripts/check-subpath-deps.js",
19
49
  "test": "c8 mocha",
20
50
  "lint": "eslint .",
21
51
  "lint:fix": "eslint --fix .",
@@ -43,6 +73,7 @@
43
73
  "devDependencies": {
44
74
  "@adobe/helix-shared-wrap": "2.0.2",
45
75
  "@types/validator": "^13.15.2",
76
+ "esbuild": "0.27.4",
46
77
  "chai": "6.2.2",
47
78
  "chai-as-promised": "8.0.2",
48
79
  "esmock": "2.7.3",
package/src/aws.d.ts ADDED
@@ -0,0 +1,21 @@
1
+ /*
2
+ * Copyright 2025 Adobe. All rights reserved.
3
+ * This file is licensed to you under the Apache License, Version 2.0 (the "License");
4
+ * you may not use this file except in compliance with the License. You may obtain a copy
5
+ * of the License at http://www.apache.org/licenses/LICENSE-2.0
6
+ *
7
+ * Unless required by applicable law or agreed to in writing, software distributed under
8
+ * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
9
+ * OF ANY KIND, either express or implied. See the License for the specific language
10
+ * governing permissions and limitations under the License.
11
+ */
12
+
13
+ export {
14
+ s3Wrapper, getObjectFromKey,
15
+ sqsWrapper, sqsEventAdapter,
16
+ instrumentAWSClient, getTraceId, addTraceIdHeader,
17
+ logWrapper, isAWSLambda,
18
+ fetch, resetFetchContext, clearFetchCache,
19
+ tracingFetch, SPACECAT_USER_AGENT,
20
+ getStoredMetrics, storeMetrics, calculateCPCValue,
21
+ } from './index.js';
package/src/aws.js ADDED
@@ -0,0 +1,27 @@
1
+ /*
2
+ * Copyright 2025 Adobe. All rights reserved.
3
+ * This file is licensed to you under the Apache License, Version 2.0 (the "License");
4
+ * you may not use this file except in compliance with the License. You may obtain a copy
5
+ * of the License at http://www.apache.org/licenses/LICENSE-2.0
6
+ *
7
+ * Unless required by applicable law or agreed to in writing, software distributed under
8
+ * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
9
+ * OF ANY KIND, either express or implied. See the License for the specific language
10
+ * governing permissions and limitations under the License.
11
+ */
12
+
13
+ /**
14
+ * @sideeffect Importing this module initializes the @adobe/fetch HTTP connection pool
15
+ * (h1() or h2() based on HELIX_FETCH_FORCE_HTTP1) at module load time via adobe-fetch.js,
16
+ * before any fetch() call is made. In a VPC Lambda with restricted egress or no NAT gateway,
17
+ * this can cause a silent hang at import time. Ensure your Lambda has outbound internet
18
+ * access before importing this module.
19
+ */
20
+ export { s3Wrapper, getObjectFromKey } from './s3.js';
21
+ export { sqsWrapper, sqsEventAdapter } from './sqs.js';
22
+ export { instrumentAWSClient, getTraceId, addTraceIdHeader } from './xray.js';
23
+ export { logWrapper } from './log-wrapper.js';
24
+ export { isAWSLambda } from './runtimes.js';
25
+ export { fetch, resetFetchContext, clearFetchCache } from './adobe-fetch.js';
26
+ export { tracingFetch, SPACECAT_USER_AGENT } from './tracing-fetch.js';
27
+ export { getStoredMetrics, storeMetrics, calculateCPCValue } from './metrics-store.js';
@@ -0,0 +1,17 @@
1
+ /*
2
+ * Copyright 2025 Adobe. All rights reserved.
3
+ * This file is licensed to you under the Apache License, Version 2.0 (the "License");
4
+ * you may not use this file except in compliance with the License. You may obtain a copy
5
+ * of the License at http://www.apache.org/licenses/LICENSE-2.0
6
+ *
7
+ * Unless required by applicable law or agreed to in writing, software distributed under
8
+ * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
9
+ * OF ANY KIND, either express or implied. See the License for the specific language
10
+ * governing permissions and limitations under the License.
11
+ */
12
+
13
+ export {
14
+ getDateRanges, getLastNumberOfWeeks, getWeekInfo,
15
+ getMonthInfo, getTemporalCondition,
16
+ isoCalendarWeek, isoCalendarWeekSunday, isoCalendarWeekMonday,
17
+ } from './index.js';
@@ -0,0 +1,22 @@
1
+ /*
2
+ * Copyright 2025 Adobe. All rights reserved.
3
+ * This file is licensed to you under the Apache License, Version 2.0 (the "License");
4
+ * you may not use this file except in compliance with the License. You may obtain a copy
5
+ * of the License at http://www.apache.org/licenses/LICENSE-2.0
6
+ *
7
+ * Unless required by applicable law or agreed to in writing, software distributed under
8
+ * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
9
+ * OF ANY KIND, either express or implied. See the License for the specific language
10
+ * governing permissions and limitations under the License.
11
+ */
12
+
13
+ export {
14
+ getDateRanges,
15
+ getLastNumberOfWeeks,
16
+ getWeekInfo,
17
+ getMonthInfo,
18
+ getTemporalCondition,
19
+ isoCalendarWeek,
20
+ isoCalendarWeekSunday,
21
+ isoCalendarWeekMonday,
22
+ } from './calendar-week-helper.js';
@@ -0,0 +1,13 @@
1
+ /*
2
+ * Copyright 2025 Adobe. All rights reserved.
3
+ * This file is licensed to you under the Apache License, Version 2.0 (the "License");
4
+ * you may not use this file except in compliance with the License. You may obtain a copy
5
+ * of the License at http://www.apache.org/licenses/LICENSE-2.0
6
+ *
7
+ * Unless required by applicable law or agreed to in writing, software distributed under
8
+ * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
9
+ * OF ANY KIND, either express or implied. See the License for the specific language
10
+ * governing permissions and limitations under the License.
11
+ */
12
+
13
+ export { OPPORTUNITY_TYPES, DEFAULT_CPC_VALUE } from './index.js';
package/src/constants.js CHANGED
@@ -70,6 +70,7 @@ export const OPPORTUNITY_TYPES = /** @type {const} */ ({
70
70
  REDDIT_ANALYSIS: 'reddit-analysis',
71
71
  WIKIPEDIA_ANALYSIS: 'wikipedia-analysis',
72
72
  YOUTUBE_ANALYSIS: 'youtube-analysis',
73
+ INFO_GAIN: 'info-gain',
73
74
  });
74
75
 
75
76
  export const DEFAULT_CPC_VALUE = 1.5;
package/src/core.d.ts ADDED
@@ -0,0 +1,19 @@
1
+ /*
2
+ * Copyright 2025 Adobe. All rights reserved.
3
+ * This file is licensed to you under the Apache License, Version 2.0 (the "License");
4
+ * you may not use this file except in compliance with the License. You may obtain a copy
5
+ * of the License at http://www.apache.org/licenses/LICENSE-2.0
6
+ *
7
+ * Unless required by applicable law or agreed to in writing, software distributed under
8
+ * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
9
+ * OF ANY KIND, either express or implied. See the License for the specific language
10
+ * governing permissions and limitations under the License.
11
+ */
12
+
13
+ export {
14
+ arrayEquals, dateAfterDays, deepEqual, hasText,
15
+ isArray, isBoolean, isInteger, isIsoDate, isIsoTimeOffsetsDate,
16
+ isNonEmptyArray, isNonEmptyObject, isNumber, isObject, isString,
17
+ isValidDate, isValidHelixPreviewUrl, isValidIMSOrgId, isValidUrl,
18
+ isValidUUID, toBoolean,
19
+ } from './index.js';
package/src/core.js ADDED
@@ -0,0 +1,34 @@
1
+ /*
2
+ * Copyright 2025 Adobe. All rights reserved.
3
+ * This file is licensed to you under the Apache License, Version 2.0 (the "License");
4
+ * you may not use this file except in compliance with the License. You may obtain a copy
5
+ * of the License at http://www.apache.org/licenses/LICENSE-2.0
6
+ *
7
+ * Unless required by applicable law or agreed to in writing, software distributed under
8
+ * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
9
+ * OF ANY KIND, either express or implied. See the License for the specific language
10
+ * governing permissions and limitations under the License.
11
+ */
12
+
13
+ export {
14
+ arrayEquals,
15
+ dateAfterDays,
16
+ deepEqual,
17
+ hasText,
18
+ isArray,
19
+ isBoolean,
20
+ isInteger,
21
+ isIsoDate,
22
+ isIsoTimeOffsetsDate,
23
+ isNonEmptyArray,
24
+ isNonEmptyObject,
25
+ isNumber,
26
+ isObject,
27
+ isString,
28
+ isValidDate,
29
+ isValidHelixPreviewUrl,
30
+ isValidIMSOrgId,
31
+ isValidUrl,
32
+ isValidUUID,
33
+ toBoolean,
34
+ } from './functions.js';
package/src/email.js ADDED
@@ -0,0 +1,22 @@
1
+ /*
2
+ * Copyright 2025 Adobe. All rights reserved.
3
+ * This file is licensed to you under the Apache License, Version 2.0 (the "License");
4
+ * you may not use this file except in compliance with the License. You may obtain a copy
5
+ * of the License at http://www.apache.org/licenses/LICENSE-2.0
6
+ *
7
+ * Unless required by applicable law or agreed to in writing, software distributed under
8
+ * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
9
+ * OF ANY KIND, either express or implied. See the License for the specific language
10
+ * governing permissions and limitations under the License.
11
+ */
12
+
13
+ import isEmail from 'validator/lib/isEmail.js';
14
+
15
+ /**
16
+ * Validates whether the given string is a valid email address.
17
+ * @param {string} email - The string to validate.
18
+ * @returns {boolean} True if the given string is a valid email address, false otherwise.
19
+ */
20
+ export function isValidEmail(email) {
21
+ return typeof email === 'string' && isEmail(email);
22
+ }
package/src/functions.js CHANGED
@@ -10,8 +10,6 @@
10
10
  * governing permissions and limitations under the License.
11
11
  */
12
12
 
13
- import isEmail from 'validator/lib/isEmail.js';
14
-
15
13
  // Precompile regular expressions
16
14
  const REGEX_ISO_DATE = /\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.\d{3}Z/;
17
15
  const REGEX_TIME_OFFSET_DATE = /\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.\d{3}(Z|[+-]\d{2}:\d{2})/;
@@ -262,15 +260,6 @@ function isValidIMSOrgId(imsOrgId) {
262
260
  return IMS_ORG_ID_REGEX.test(imsOrgId);
263
261
  }
264
262
 
265
- /**
266
- * Validates whether the given string is a valid email address.
267
- * @param {string} email - The string to validate.
268
- * @returns {boolean} True if the given string is a valid email address, false otherwise.
269
- */
270
- function isValidEmail(email) {
271
- return typeof email === 'string' && isEmail(email);
272
- }
273
-
274
263
  /**
275
264
  * Validates whether the given string is a valid Helix preview URL.
276
265
  * Preview URLs have the format: https://ref--site--owner.domain
@@ -333,7 +322,6 @@ export {
333
322
  isObject,
334
323
  isString,
335
324
  isValidDate,
336
- isValidEmail,
337
325
  isValidUrl,
338
326
  isValidUUID,
339
327
  isValidIMSOrgId,
package/src/index.d.ts CHANGED
@@ -332,6 +332,10 @@ export function getObjectFromKey(
332
332
  */
333
333
  export function calculateCPCValue(context: object, siteId: string): Promise<number>;
334
334
 
335
+ export function isAWSLambda(): boolean;
336
+ export function resetFetchContext(): void;
337
+ export function clearFetchCache(): void;
338
+
335
339
  export function s3Wrapper(fn: (request: object, context: object) => Promise<Response>):
336
340
  (request: object, context: object) => Promise<Response>;
337
341
 
@@ -349,6 +353,38 @@ export function isoCalendarWeekSunday(date: Date): Date;
349
353
 
350
354
  export function isoCalendarWeekMonday(date: Date): Date;
351
355
 
356
+ interface DateRange {
357
+ year: number;
358
+ month: number;
359
+ startTime: string;
360
+ endTime: string;
361
+ }
362
+
363
+ interface WeekInfo {
364
+ week: number;
365
+ year: number;
366
+ month: number;
367
+ temporalCondition: string;
368
+ }
369
+
370
+ interface MonthInfo {
371
+ month: number;
372
+ year: number;
373
+ temporalCondition: string;
374
+ }
375
+
376
+ export function getDateRanges(week?: number, year?: number): DateRange[];
377
+ export function getWeekInfo(inputWeek?: number | null, inputYear?: number | null): WeekInfo;
378
+ export function getMonthInfo(inputMonth?: number | null, inputYear?: number | null): MonthInfo;
379
+ export function getTemporalCondition(options?: {
380
+ week?: number;
381
+ month?: number;
382
+ year?: number;
383
+ numSeries?: number;
384
+ log?: object | null;
385
+ }): string;
386
+ export function getLastNumberOfWeeks(number: number): { week: number; year: number }[];
387
+
352
388
  /**
353
389
  * Extracts URLs from a suggestion based on the opportunity type.
354
390
  * @param opts - Options object
@@ -419,5 +455,5 @@ export * as llmoConfig from './llmo-config.js';
419
455
  export * as llmoStrategy from './llmo-strategy.js';
420
456
  export * as schemas from './schemas.js';
421
457
 
422
- export { type detectLocale } from './locale-detect/index.js';
423
- export { type detectBotBlocker } from './bot-blocker-detect/index.js';
458
+ export { detectLocale } from './locale-detect/index.js';
459
+ export { detectBotBlocker } from './bot-blocker-detect/index.js';
package/src/index.js CHANGED
@@ -26,7 +26,6 @@ export {
26
26
  isObject,
27
27
  isString,
28
28
  isValidDate,
29
- isValidEmail,
30
29
  isValidUrl,
31
30
  isValidUUID,
32
31
  isValidIMSOrgId,
@@ -34,6 +33,8 @@ export {
34
33
  toBoolean,
35
34
  } from './functions.js';
36
35
 
36
+ export { isValidEmail } from './email.js';
37
+
37
38
  export {
38
39
  resolveSecretsName,
39
40
  resolveCustomerSecretsName,
@@ -0,0 +1,13 @@
1
+ /*
2
+ * Copyright 2025 Adobe. All rights reserved.
3
+ * This file is licensed to you under the Apache License, Version 2.0 (the "License");
4
+ * you may not use this file except in compliance with the License. You may obtain a copy
5
+ * of the License at http://www.apache.org/licenses/LICENSE-2.0
6
+ *
7
+ * Unless required by applicable law or agreed to in writing, software distributed under
8
+ * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
9
+ * OF ANY KIND, either express or implied. See the License for the specific language
10
+ * governing permissions and limitations under the License.
11
+ */
12
+
13
+ export { detectLocale } from './index.js';
package/src/locale.js ADDED
@@ -0,0 +1,20 @@
1
+ /*
2
+ * Copyright 2025 Adobe. All rights reserved.
3
+ * This file is licensed to you under the Apache License, Version 2.0 (the "License");
4
+ * you may not use this file except in compliance with the License. You may obtain a copy
5
+ * of the License at http://www.apache.org/licenses/LICENSE-2.0
6
+ *
7
+ * Unless required by applicable law or agreed to in writing, software distributed under
8
+ * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
9
+ * OF ANY KIND, either express or implied. See the License for the specific language
10
+ * governing permissions and limitations under the License.
11
+ */
12
+
13
+ /**
14
+ * @sideeffect Importing this module initializes the @adobe/fetch HTTP connection pool
15
+ * (h1() or h2() based on HELIX_FETCH_FORCE_HTTP1) at module load time, before any
16
+ * detectLocale() call is made. In a VPC Lambda with restricted egress or no NAT gateway,
17
+ * this can cause a silent hang at import time. Ensure your Lambda has outbound internet
18
+ * access before importing this module.
19
+ */
20
+ export { detectLocale } from './locale-detect/locale-detect.js';
@@ -79,6 +79,9 @@ export const AUDIT_OPPORTUNITY_MAP = {
79
79
  'wikipedia-analysis': ['wikipedia-analysis'],
80
80
  'reddit-analysis': ['reddit-analysis'],
81
81
  'youtube-analysis': ['youtube-analysis'],
82
+
83
+ // LLMO customer / GEO content catalog
84
+ 'llmo-customer-analysis': ['info-gain'],
82
85
  };
83
86
 
84
87
  // ─── Query helpers ───────────────────────────────────────────────────────────
@@ -97,6 +97,7 @@ export const OPPORTUNITY_DEPENDENCY_MAP = {
97
97
  'wikipedia-analysis': [DEPENDENCY_SOURCES.EXTERNAL_API],
98
98
  'reddit-analysis': [DEPENDENCY_SOURCES.EXTERNAL_API],
99
99
  'youtube-analysis': [DEPENDENCY_SOURCES.EXTERNAL_API],
100
+ 'info-gain': [DEPENDENCY_SOURCES.SCRAPING, DEPENDENCY_SOURCES.EXTERNAL_API],
100
101
  };
101
102
 
102
103
  // ─── Query helpers ───────────────────────────────────────────────────────────
@@ -73,6 +73,7 @@ export const OPPORTUNITY_TITLES = {
73
73
  'wikipedia-analysis': 'Wikipedia Analysis',
74
74
  'reddit-analysis': 'Reddit Analysis',
75
75
  'youtube-analysis': 'YouTube Analysis',
76
+ 'info-gain': 'Information Gain',
76
77
  };
77
78
 
78
79
  /**
@@ -0,0 +1,21 @@
1
+ /*
2
+ * Copyright 2025 Adobe. All rights reserved.
3
+ * This file is licensed to you under the Apache License, Version 2.0 (the "License");
4
+ * you may not use this file except in compliance with the License. You may obtain a copy
5
+ * of the License at http://www.apache.org/licenses/LICENSE-2.0
6
+ *
7
+ * Unless required by applicable law or agreed to in writing, software distributed under
8
+ * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
9
+ * OF ANY KIND, either express or implied. See the License for the specific language
10
+ * governing permissions and limitations under the License.
11
+ */
12
+
13
+ import type * as z from 'zod';
14
+
15
+ // NOTE: This file declares types directly rather than re-exporting from ./index.js
16
+ // because index.d.ts exposes schemas as a namespace (export * as schemas), not as
17
+ // flat named exports. The ZodEffects<ZodObject<any>> type is lossy — it erases the
18
+ // specific schema shape, so consumers get no field-level autocomplete or type errors.
19
+ // See "Unify .d.ts declaration strategy" in the design spec's Future Improvements.
20
+ export declare const llmoConfig: z.ZodEffects<z.ZodObject<any>>;
21
+ export type LLMOConfig = z.output<typeof llmoConfig>;
@@ -200,6 +200,33 @@ function extractUrlsFromOpportunity(opts) {
200
200
  }
201
201
  }
202
202
  break;
203
+ case OPPORTUNITY_TYPES.INFO_GAIN:
204
+ {
205
+ const pushCatalogRow = (row) => {
206
+ const entry = row?.data && typeof row.data === 'object' ? row.data : row;
207
+ if (!entry || typeof entry !== 'object') {
208
+ return;
209
+ }
210
+ const reportUrl = entry?.report?.url;
211
+ if (reportUrl && typeof reportUrl === 'string') {
212
+ urls.push(reportUrl);
213
+ }
214
+ const discovered = entry?.discoveredOpportunities;
215
+ if (Array.isArray(discovered)) {
216
+ discovered.forEach((opp) => {
217
+ const targetUrl = opp?.targetUrl;
218
+ if (targetUrl && typeof targetUrl === 'string') {
219
+ urls.push(targetUrl);
220
+ }
221
+ });
222
+ }
223
+ };
224
+ const embeddedSuggestions = data?.suggestions;
225
+ if (Array.isArray(embeddedSuggestions)) {
226
+ embeddedSuggestions.forEach(pushCatalogRow);
227
+ }
228
+ }
229
+ break;
203
230
  default:
204
231
  break;
205
232
  }