@adobe/spacecat-shared-utils 1.103.0 → 1.105.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.105.0](https://github.com/adobe/spacecat-shared/compare/@adobe/spacecat-shared-utils-v1.104.0...@adobe/spacecat-shared-utils-v1.105.0) (2026-03-19)
2
+
3
+ ### Features
4
+
5
+ * **spacecat-shared-utils:** SITES-40623 - add token grant config and exports ([#1420](https://github.com/adobe/spacecat-shared/issues/1420)) ([a14e001](https://github.com/adobe/spacecat-shared/commit/a14e0012f43ad4a13c4f9347bd64f66a5fc535f8))
6
+
7
+ ## [@adobe/spacecat-shared-utils-v1.104.0](https://github.com/adobe/spacecat-shared/compare/@adobe/spacecat-shared-utils-v1.103.0...@adobe/spacecat-shared-utils-v1.104.0) (2026-03-19)
8
+
9
+ ### Features
10
+
11
+ * add experimentation topics field to llmo config model ([#1450](https://github.com/adobe/spacecat-shared/issues/1450)) ([ffcb886](https://github.com/adobe/spacecat-shared/commit/ffcb886e26895c5a0da02c9da9007b0eb6fe3f37))
12
+
1
13
  ## [@adobe/spacecat-shared-utils-v1.103.0](https://github.com/adobe/spacecat-shared/compare/@adobe/spacecat-shared-utils-v1.102.1...@adobe/spacecat-shared-utils-v1.103.0) (2026-03-18)
2
14
 
3
15
  ### Features
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adobe/spacecat-shared-utils",
3
- "version": "1.103.0",
3
+ "version": "1.105.0",
4
4
  "description": "Shared modules of the Spacecat Services - utils",
5
5
  "type": "module",
6
6
  "exports": {
package/src/index.d.ts CHANGED
@@ -371,6 +371,50 @@ export function extractUrlsFromOpportunity(opts: {
371
371
  opportunity: any;
372
372
  }): string[];
373
373
 
374
+ /** Token grant entry: tokens per cycle and cycle format (e.g. YYYY-MM). */
375
+ export interface TokenGrantEntry {
376
+ tokensPerCycle: number;
377
+ cycleFormat: string;
378
+ }
379
+
380
+ /** Per-opportunity grant config keyed by opportunity name. */
381
+ export const OPPORTUNITY_GRANT_CONFIG: Record<string, TokenGrantEntry>;
382
+
383
+ /** Cumulative token grant config keyed by token type. */
384
+ export const TOKEN_GRANT_CONFIG: Record<string, TokenGrantEntry>;
385
+
386
+ /**
387
+ * Converts an opportunity name to its token type key.
388
+ * @param opportunityName - e.g. "broken-backlinks".
389
+ * @returns e.g. "grant_broken_backlinks".
390
+ */
391
+ export function getTokenTypeForOpportunity(
392
+ opportunityName: string
393
+ ): string;
394
+
395
+ /**
396
+ * Returns the grant config for a token type.
397
+ * @param tokenType - e.g. "grant_cwv".
398
+ */
399
+ export function getTokenGrantConfig(
400
+ tokenType: string
401
+ ): (TokenGrantEntry & { currentCycle: string }) | undefined;
402
+
403
+ /**
404
+ * Returns the grant config for an opportunity name.
405
+ * @param opportunityName - e.g. "broken-backlinks".
406
+ */
407
+ export function getTokenGrantConfigByOpportunity(
408
+ opportunityName: string
409
+ ): (TokenGrantEntry & { currentCycle: string; tokenType: string }) | undefined;
410
+
411
+ /**
412
+ * Computes the current cycle string for a given cycleFormat
413
+ * using UTC time.
414
+ * Supported placeholders: YYYY (4-digit year), MM (zero-padded month).
415
+ */
416
+ export function getCurrentCycle(cycleFormat: string): string;
417
+
374
418
  export * as llmoConfig from './llmo-config.js';
375
419
  export * as llmoStrategy from './llmo-strategy.js';
376
420
  export * as schemas from './schemas.js';
package/src/index.js CHANGED
@@ -132,3 +132,12 @@ export {
132
132
  GRANULARITY_KEY_BUILDERS,
133
133
  ISSUE_GRANULARITY_MAP,
134
134
  } from './aggregation/aggregation-strategies.js';
135
+
136
+ export {
137
+ TOKEN_GRANT_CONFIG,
138
+ OPPORTUNITY_GRANT_CONFIG,
139
+ getTokenGrantConfig,
140
+ getTokenGrantConfigByOpportunity,
141
+ getTokenTypeForOpportunity,
142
+ getCurrentCycle,
143
+ } from './token-grant-config.js';
package/src/schemas.js CHANGED
@@ -51,6 +51,7 @@ const prompt = z.object({
51
51
  origin: z.union([z.literal('human'), z.literal('ai'), z.string()]),
52
52
  source: z.union([z.literal('config'), z.literal('api'), z.string()]),
53
53
  status: z.union([z.literal('completed'), z.literal('processing'), z.string()]).optional(),
54
+ source_url: z.string().optional(),
54
55
  ...auditFields,
55
56
  });
56
57
 
@@ -107,6 +108,7 @@ export const llmoConfig = z.object({
107
108
  categories: z.record(z.uuid(), category),
108
109
  topics: z.record(z.uuid(), topic),
109
110
  aiTopics: z.record(z.uuid(), topic).optional(),
111
+ experimentationTopics: z.record(z.uuid(), topic).optional(),
110
112
  brands: z.object({
111
113
  aliases: z.array(
112
114
  z.object({
@@ -0,0 +1,113 @@
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 { hasText } from './functions.js';
14
+
15
+ const TOKEN_TYPE_PREFIX = 'grant_';
16
+
17
+ /**
18
+ * Converts an opportunity name to its corresponding token type key.
19
+ * Replaces hyphens with underscores and prepends the grant prefix.
20
+ * @param {string} opportunityName - e.g. "broken-backlinks".
21
+ * @returns {string} e.g. "grant_broken_backlinks".
22
+ */
23
+ export function getTokenTypeForOpportunity(opportunityName) {
24
+ return `${TOKEN_TYPE_PREFIX}${opportunityName.replace(/-/g, '_')}`;
25
+ }
26
+
27
+ /**
28
+ * Per-opportunity grant configuration. Keys are opportunity names
29
+ * (matching OPPORTUNITY_TYPES values). Token type keys are derived
30
+ * automatically via getTokenTypeForOpportunity().
31
+ */
32
+ const OPPORTUNITY_GRANT_CONFIG = Object.freeze({
33
+ cwv: Object.freeze({
34
+ tokensPerCycle: 3,
35
+ cycleFormat: 'YYYY-MM',
36
+ }),
37
+ 'broken-backlinks': Object.freeze({
38
+ tokensPerCycle: 3,
39
+ cycleFormat: 'YYYY-MM',
40
+ }),
41
+ 'alt-text': Object.freeze({
42
+ tokensPerCycle: 3,
43
+ cycleFormat: 'YYYY-MM',
44
+ }),
45
+ });
46
+
47
+ export { OPPORTUNITY_GRANT_CONFIG };
48
+
49
+ /**
50
+ * Cumulative token grant configuration keyed by token type.
51
+ * Includes entries generated from OPPORTUNITY_GRANT_CONFIG plus
52
+ * any standalone (non-opportunity) token types added below.
53
+ *
54
+ * NOTE: For limited use cases this config lives here in code.
55
+ * When the number of token types grows or needs to be managed
56
+ * dynamically, consider migrating to a dedicated database table
57
+ * (e.g. token_grant_configs) in mysticat-data-service.
58
+ */
59
+ const TOKEN_GRANT_CONFIG = Object.freeze({
60
+ // Auto-generated from OPPORTUNITY_GRANT_CONFIG
61
+ ...Object.fromEntries(
62
+ Object.entries(OPPORTUNITY_GRANT_CONFIG).map(
63
+ ([name, cfg]) => [getTokenTypeForOpportunity(name), cfg],
64
+ ),
65
+ ),
66
+ // Add standalone (non-opportunity) token types here, e.g.:
67
+ // some_standalone_type: Object.freeze({ ... }),
68
+ });
69
+
70
+ export { TOKEN_GRANT_CONFIG };
71
+
72
+ /**
73
+ * Computes the current cycle string for a given cycleFormat using UTC time.
74
+ * Supported placeholders: YYYY (4-digit year), MM (zero-padded month).
75
+ * @param {string} cycleFormat - e.g. "YYYY-MM".
76
+ * @returns {string} e.g. "2026-03".
77
+ */
78
+ export function getCurrentCycle(cycleFormat) {
79
+ const now = new Date();
80
+ return cycleFormat
81
+ .replace('YYYY', String(now.getUTCFullYear()))
82
+ .replace('MM', String(now.getUTCMonth() + 1).padStart(2, '0'));
83
+ }
84
+
85
+ /**
86
+ * Returns the grant config for a token type, including the
87
+ * computed current cycle.
88
+ * @param {string} tokenType - e.g. "grant_cwv".
89
+ * @returns {{ tokensPerCycle: number,
90
+ * cycleFormat: string, currentCycle: string }|undefined}
91
+ */
92
+ export function getTokenGrantConfig(tokenType) {
93
+ if (!hasText(tokenType)) return undefined;
94
+ const entry = TOKEN_GRANT_CONFIG[tokenType];
95
+ if (!entry) return undefined;
96
+ return { ...entry, currentCycle: getCurrentCycle(entry.cycleFormat) };
97
+ }
98
+
99
+ /**
100
+ * Returns the grant config for an opportunity name, including
101
+ * the computed current cycle and the derived token type.
102
+ * @param {string} opportunityName - e.g. "broken-backlinks".
103
+ * @returns {{ tokensPerCycle: number, cycle: string,
104
+ * cycleFormat: string, currentCycle: string,
105
+ * tokenType: string }|undefined}
106
+ */
107
+ export function getTokenGrantConfigByOpportunity(opportunityName) {
108
+ if (!hasText(opportunityName)) return undefined;
109
+ const tokenType = getTokenTypeForOpportunity(opportunityName);
110
+ const config = getTokenGrantConfig(tokenType);
111
+ if (!config) return undefined;
112
+ return { ...config, tokenType };
113
+ }