@adobe/spacecat-shared-data-access 2.8.4 → 2.9.1
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/models/site/config.js +106 -2
- package/src/models/site/index.d.ts +83 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,17 @@
|
|
|
1
|
+
# [@adobe/spacecat-shared-data-access-v2.9.1](https://github.com/adobe/spacecat-shared/compare/@adobe/spacecat-shared-data-access-v2.9.0...@adobe/spacecat-shared-data-access-v2.9.1) (2025-02-26)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Bug Fixes
|
|
5
|
+
|
|
6
|
+
* import-schema backwards compatibility ([#630](https://github.com/adobe/spacecat-shared/issues/630)) ([9ef74bf](https://github.com/adobe/spacecat-shared/commit/9ef74bfc89b0ccb9d27d34e5a10eef182b9ee527)), closes [#626](https://github.com/adobe/spacecat-shared/issues/626)
|
|
7
|
+
|
|
8
|
+
# [@adobe/spacecat-shared-data-access-v2.9.0](https://github.com/adobe/spacecat-shared/compare/@adobe/spacecat-shared-data-access-v2.8.4...@adobe/spacecat-shared-data-access-v2.9.0) (2025-02-25)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Features
|
|
12
|
+
|
|
13
|
+
* import config schema ([#626](https://github.com/adobe/spacecat-shared/issues/626)) ([df147d8](https://github.com/adobe/spacecat-shared/commit/df147d8c8f83cc45f373b1d89823229afe035129))
|
|
14
|
+
|
|
1
15
|
# [@adobe/spacecat-shared-data-access-v2.8.4](https://github.com/adobe/spacecat-shared/compare/@adobe/spacecat-shared-data-access-v2.8.3...@adobe/spacecat-shared-data-access-v2.8.4) (2025-02-25)
|
|
2
16
|
|
|
3
17
|
|
package/package.json
CHANGED
|
@@ -12,13 +12,76 @@
|
|
|
12
12
|
|
|
13
13
|
import Joi from 'joi';
|
|
14
14
|
|
|
15
|
+
export const IMPORT_TYPES = {
|
|
16
|
+
ORGANIC_KEYWORDS: 'organic-keywords',
|
|
17
|
+
ORGANIC_TRAFFIC: 'organic-traffic',
|
|
18
|
+
TOP_PAGES: 'top-pages',
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
export const IMPORT_DESTINATIONS = {
|
|
22
|
+
DEFAULT: 'default',
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
export const IMPORT_SOURCES = {
|
|
26
|
+
AHREFS: 'ahrefs',
|
|
27
|
+
GSC: 'google',
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
const IMPORT_BASE_KEYS = {
|
|
31
|
+
destinations: Joi.array().items(Joi.string().valid(IMPORT_DESTINATIONS.DEFAULT)).required(),
|
|
32
|
+
sources: Joi.array().items(Joi.string().valid(...Object.values(IMPORT_SOURCES))).required(),
|
|
33
|
+
// not required for now due backward compatibility
|
|
34
|
+
enabled: Joi.boolean().default(true),
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
export const IMPORT_TYPE_SCHEMAS = {
|
|
38
|
+
[IMPORT_TYPES.ORGANIC_KEYWORDS]: Joi.object({
|
|
39
|
+
type: Joi.string().valid(IMPORT_TYPES.ORGANIC_KEYWORDS).required(),
|
|
40
|
+
...IMPORT_BASE_KEYS,
|
|
41
|
+
pageUrl: Joi.string().uri(),
|
|
42
|
+
}),
|
|
43
|
+
[IMPORT_TYPES.ORGANIC_TRAFFIC]: Joi.object({
|
|
44
|
+
type: Joi.string().valid(IMPORT_TYPES.ORGANIC_TRAFFIC).required(),
|
|
45
|
+
...IMPORT_BASE_KEYS,
|
|
46
|
+
}),
|
|
47
|
+
[IMPORT_TYPES.TOP_PAGES]: Joi.object({
|
|
48
|
+
type: Joi.string().valid(IMPORT_TYPES.TOP_PAGES).required(),
|
|
49
|
+
...IMPORT_BASE_KEYS,
|
|
50
|
+
geo: Joi.string(),
|
|
51
|
+
}),
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
export const DEFAULT_IMPORT_CONFIGS = {
|
|
55
|
+
'organic-keywords': {
|
|
56
|
+
type: 'organic-keywords',
|
|
57
|
+
destinations: ['default'],
|
|
58
|
+
sources: ['ahrefs'],
|
|
59
|
+
enabled: true,
|
|
60
|
+
},
|
|
61
|
+
'organic-traffic': {
|
|
62
|
+
type: 'organic-traffic',
|
|
63
|
+
destinations: ['default'],
|
|
64
|
+
sources: ['ahrefs'],
|
|
65
|
+
enabled: true,
|
|
66
|
+
},
|
|
67
|
+
'top-pages': {
|
|
68
|
+
type: 'top-pages',
|
|
69
|
+
destinations: ['default'],
|
|
70
|
+
sources: ['ahrefs'],
|
|
71
|
+
enabled: true,
|
|
72
|
+
geo: 'global',
|
|
73
|
+
},
|
|
74
|
+
};
|
|
75
|
+
|
|
15
76
|
export const configSchema = Joi.object({
|
|
16
77
|
slack: Joi.object({
|
|
17
78
|
workspace: Joi.string(),
|
|
18
79
|
channel: Joi.string(),
|
|
19
80
|
invitedUserCount: Joi.number().integer().min(0),
|
|
20
81
|
}),
|
|
21
|
-
imports: Joi.array().items(
|
|
82
|
+
imports: Joi.array().items(
|
|
83
|
+
Joi.alternatives().try(...Object.values(IMPORT_TYPE_SCHEMAS)),
|
|
84
|
+
),
|
|
22
85
|
fetchConfig: Joi.object({
|
|
23
86
|
headers: Joi.object().pattern(Joi.string(), Joi.string()),
|
|
24
87
|
}).optional(),
|
|
@@ -56,7 +119,7 @@ export function validateConfiguration(config) {
|
|
|
56
119
|
const { error, value } = configSchema.validate(config);
|
|
57
120
|
|
|
58
121
|
if (error) {
|
|
59
|
-
throw new Error(`Configuration validation error: ${error.message}
|
|
122
|
+
throw new Error(`Configuration validation error: ${error.message}`, { cause: error });
|
|
60
123
|
}
|
|
61
124
|
|
|
62
125
|
return value; // Validated and sanitized configuration
|
|
@@ -136,6 +199,47 @@ export const Config = (data = {}) => {
|
|
|
136
199
|
state.fetchConfig = fetchConfig;
|
|
137
200
|
};
|
|
138
201
|
|
|
202
|
+
self.enableImport = (type, config = {}) => {
|
|
203
|
+
if (!IMPORT_TYPE_SCHEMAS[type]) {
|
|
204
|
+
throw new Error(`Unknown import type: ${type}`);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
const defaultConfig = DEFAULT_IMPORT_CONFIGS[type];
|
|
208
|
+
const newConfig = {
|
|
209
|
+
...defaultConfig, ...config, type, enabled: true,
|
|
210
|
+
};
|
|
211
|
+
|
|
212
|
+
// Validate the new config against its schema
|
|
213
|
+
const { error } = IMPORT_TYPE_SCHEMAS[type].validate(newConfig);
|
|
214
|
+
if (error) {
|
|
215
|
+
throw new Error(`Invalid import config: ${error.message}`);
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
state.imports = state.imports || [];
|
|
219
|
+
// Remove existing import of same type if present
|
|
220
|
+
state.imports = state.imports.filter((imp) => imp.type !== type);
|
|
221
|
+
state.imports.push(newConfig);
|
|
222
|
+
|
|
223
|
+
validateConfiguration(state);
|
|
224
|
+
};
|
|
225
|
+
|
|
226
|
+
self.disableImport = (type) => {
|
|
227
|
+
if (!state.imports) return;
|
|
228
|
+
|
|
229
|
+
state.imports = state.imports.map(
|
|
230
|
+
(imp) => (imp.type === type ? { ...imp, enabled: false } : imp),
|
|
231
|
+
);
|
|
232
|
+
|
|
233
|
+
validateConfiguration(state);
|
|
234
|
+
};
|
|
235
|
+
|
|
236
|
+
self.getImportConfig = (type) => state.imports?.find((imp) => imp.type === type);
|
|
237
|
+
|
|
238
|
+
self.isImportEnabled = (type) => {
|
|
239
|
+
const config = self.getImportConfig(type);
|
|
240
|
+
return config?.enabled ?? false;
|
|
241
|
+
};
|
|
242
|
+
|
|
139
243
|
return Object.freeze(self);
|
|
140
244
|
};
|
|
141
245
|
|
|
@@ -23,13 +23,95 @@ import type {
|
|
|
23
23
|
SiteTopPage,
|
|
24
24
|
} from '../index';
|
|
25
25
|
|
|
26
|
+
export type IMPORT_TYPES = {
|
|
27
|
+
readonly ORGANIC_KEYWORDS: 'organic-keywords';
|
|
28
|
+
readonly ORGANIC_TRAFFIC: 'organic-traffic';
|
|
29
|
+
readonly TOP_PAGES: 'top-pages';
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
export type IMPORT_DESTINATIONS = {
|
|
33
|
+
readonly DEFAULT: 'default';
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
export type IMPORT_SOURCES = {
|
|
37
|
+
readonly AHREFS: 'ahrefs';
|
|
38
|
+
readonly GSC: 'google';
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
export type ImportType = 'organic-keywords' | 'organic-traffic' | 'top-pages';
|
|
42
|
+
export type ImportDestination = 'default';
|
|
43
|
+
export type ImportSource = 'ahrefs' | 'google';
|
|
44
|
+
|
|
45
|
+
export interface ImportConfig {
|
|
46
|
+
type: ImportType;
|
|
47
|
+
destinations: ImportDestination[];
|
|
48
|
+
sources: ImportSource[];
|
|
49
|
+
enabled: boolean;
|
|
50
|
+
pageUrl?: string;
|
|
51
|
+
geo?: string;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export interface SiteConfig {
|
|
55
|
+
state: {
|
|
56
|
+
slack?: {
|
|
57
|
+
workspace?: string;
|
|
58
|
+
channel?: string;
|
|
59
|
+
invitedUserCount?: number;
|
|
60
|
+
};
|
|
61
|
+
imports?: ImportConfig[];
|
|
62
|
+
handlers?: Record<string, {
|
|
63
|
+
mentions?: Record<string, string[]>;
|
|
64
|
+
excludedURLs?: string[];
|
|
65
|
+
manualOverwrites?: Array<{
|
|
66
|
+
brokenTargetURL?: string;
|
|
67
|
+
targetURL?: string;
|
|
68
|
+
}>;
|
|
69
|
+
fixedURLs?: Array<{
|
|
70
|
+
brokenTargetURL?: string;
|
|
71
|
+
targetURL?: string;
|
|
72
|
+
}>;
|
|
73
|
+
includedURLs?: string[];
|
|
74
|
+
groupedURLs?: Array<{
|
|
75
|
+
name: string;
|
|
76
|
+
pattern: string;
|
|
77
|
+
}>;
|
|
78
|
+
latestMetrics?: {
|
|
79
|
+
pageViewsChange: number;
|
|
80
|
+
ctrChange: number;
|
|
81
|
+
projectedTrafficValue: number;
|
|
82
|
+
};
|
|
83
|
+
}>;
|
|
84
|
+
fetchConfig?: {
|
|
85
|
+
headers?: Record<string, string>;
|
|
86
|
+
};
|
|
87
|
+
};
|
|
88
|
+
getSlackConfig(): { workspace?: string; channel?: string; invitedUserCount?: number };
|
|
89
|
+
getImports(): ImportConfig[];
|
|
90
|
+
getImportConfig(type: ImportType): ImportConfig | undefined;
|
|
91
|
+
isImportEnabled(type: ImportType): boolean;
|
|
92
|
+
enableImport(type: ImportType, config?: Partial<ImportConfig>): void;
|
|
93
|
+
disableImport(type: ImportType): void;
|
|
94
|
+
getHandlers(): Record<string, object>;
|
|
95
|
+
getHandlerConfig(type: string): object;
|
|
96
|
+
getSlackMentions(type: string): string[] | undefined;
|
|
97
|
+
getExcludedURLs(type: string): string[] | undefined;
|
|
98
|
+
getManualOverwrites(type: string):
|
|
99
|
+
Array<{ brokenTargetURL?: string; targetURL?: string }> | undefined;
|
|
100
|
+
getFixedURLs(type: string): Array<{ brokenTargetURL?: string; targetURL?: string }> | undefined;
|
|
101
|
+
getIncludedURLs(type: string): string[] | undefined;
|
|
102
|
+
getGroupedURLs(type: string): Array<{ name: string; pattern: string }> | undefined;
|
|
103
|
+
getLatestMetrics(type: string):
|
|
104
|
+
{ pageViewsChange: number; ctrChange: number; projectedTrafficValue: number } | undefined;
|
|
105
|
+
getFetchConfig(): { headers?: Record<string, string> } | undefined;
|
|
106
|
+
}
|
|
107
|
+
|
|
26
108
|
export interface Site extends BaseModel {
|
|
27
109
|
getAudits(): Promise<Audit>;
|
|
28
110
|
getAuditsByAuditType(auditType: string): Promise<Audit>;
|
|
29
111
|
getAuditsByAuditTypeAndAuditedAt(auditType: string, auditedAt: string): Promise<Audit>;
|
|
30
112
|
getBaseURL(): string;
|
|
31
113
|
getName(): string;
|
|
32
|
-
getConfig():
|
|
114
|
+
getConfig(): SiteConfig;
|
|
33
115
|
getDeliveryType(): string;
|
|
34
116
|
getExperiments(): Promise<Experiment[]>;
|
|
35
117
|
getExperimentsByExpId(expId: string): Promise<Experiment[]>;
|