@adobe/mysticat-shared-seo-client 1.0.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 ADDED
@@ -0,0 +1,5 @@
1
+ ## @adobe/mysticat-shared-seo-client-v1.0.0 (2026-04-01)
2
+
3
+ ### Features
4
+
5
+ * **seo-client:** add mysticat-shared-seo-client package ([#1490](https://github.com/adobe/spacecat-shared/issues/1490)) ([27faade](https://github.com/adobe/spacecat-shared/commit/27faade8b3179ee213dce6044c08ebb5ceff1a19))
package/README.md ADDED
@@ -0,0 +1,48 @@
1
+ # Mysticat Shared - SEO Client
2
+
3
+ An SEO API client for SpaceCat services.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @adobe/mysticat-shared-seo-client
9
+ ```
10
+
11
+ ## Usage
12
+
13
+ ### Creating an instance from Helix UniversalContext
14
+
15
+ ```js
16
+ const client = SeoClient.createFrom(context);
17
+ ```
18
+
19
+ ### Constructor
20
+
21
+ ```js
22
+ import SeoClient from '@adobe/mysticat-shared-seo-client';
23
+
24
+ const config = {
25
+ apiKey: '<API_KEY>',
26
+ apiBaseUrl: '<API_BASE_URL>',
27
+ };
28
+
29
+ const client = new SeoClient(config, fetch);
30
+ ```
31
+
32
+ ## Testing
33
+
34
+ ```bash
35
+ npm run test
36
+ ```
37
+
38
+ ## Linting
39
+
40
+ ```bash
41
+ npm run lint
42
+ ```
43
+
44
+ ## Additional Information
45
+
46
+ - **Repository**: [GitHub](https://github.com/adobe/spacecat-shared.git)
47
+ - **Issue Tracking**: [GitHub Issues](https://github.com/adobe/spacecat-shared/issues)
48
+ - **License**: Apache-2.0
package/package.json ADDED
@@ -0,0 +1,49 @@
1
+ {
2
+ "name": "@adobe/mysticat-shared-seo-client",
3
+ "version": "1.0.0",
4
+ "description": "Shared modules of the SpaceCat Services - SEO Client",
5
+ "type": "module",
6
+ "engines": {
7
+ "node": ">=22.0.0 <25.0.0",
8
+ "npm": ">=10.9.0 <12.0.0"
9
+ },
10
+ "main": "src/index.js",
11
+ "types": "src/index.d.ts",
12
+ "scripts": {
13
+ "test": "c8 mocha",
14
+ "lint": "eslint .",
15
+ "clean": "rm -rf package-lock.json node_modules"
16
+ },
17
+ "mocha": {
18
+ "require": "test/setup-env.js",
19
+ "reporter": "mocha-multi-reporters",
20
+ "reporter-options": "configFile=.mocha-multi.json",
21
+ "spec": "test/**/*.test.js"
22
+ },
23
+ "repository": {
24
+ "type": "git",
25
+ "url": "https://github.com/adobe/spacecat-shared.git"
26
+ },
27
+ "author": "",
28
+ "license": "Apache-2.0",
29
+ "bugs": {
30
+ "url": "https://github.com/adobe/spacecat-shared/issues"
31
+ },
32
+ "homepage": "https://github.com/adobe/spacecat-shared#readme",
33
+ "publishConfig": {
34
+ "access": "public"
35
+ },
36
+ "dependencies": {
37
+ "@adobe/fetch": "4.2.3",
38
+ "@adobe/helix-universal": "5.4.0",
39
+ "@adobe/spacecat-shared-utils": "1.81.1"
40
+ },
41
+ "devDependencies": {
42
+ "chai": "6.2.2",
43
+ "chai-as-promised": "8.0.2",
44
+ "nock": "14.0.11",
45
+ "sinon": "21.0.3",
46
+ "sinon-chai": "4.0.1",
47
+ "typescript": "5.9.3"
48
+ }
49
+ }
package/src/client.js ADDED
@@ -0,0 +1,85 @@
1
+ /*
2
+ * Copyright 2026 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 { isValidUrl } from '@adobe/spacecat-shared-utils';
14
+ import { context as h2, h1 } from '@adobe/fetch';
15
+
16
+ /* c8 ignore next 3 */
17
+ export const { fetch } = process.env.HELIX_FETCH_FORCE_HTTP1
18
+ ? h1()
19
+ : h2();
20
+
21
+ const STUB_RESPONSE = { result: {}, fullAuditRef: '' };
22
+
23
+ export default class SeoClient {
24
+ static createFrom(context) {
25
+ const { SEO_API_BASE_URL: apiBaseUrl, SEO_API_KEY: apiKey } = context.env;
26
+ return new SeoClient({ apiBaseUrl, apiKey }, fetch, context.log);
27
+ }
28
+
29
+ constructor(config, fetchAPI, log = console) {
30
+ const { apiKey, apiBaseUrl } = config;
31
+
32
+ if (!isValidUrl(apiBaseUrl)) {
33
+ throw new Error(`Invalid SEO API Base URL: ${apiBaseUrl}`);
34
+ }
35
+
36
+ if (typeof fetchAPI !== 'function') {
37
+ throw Error('"fetchAPI" must be a function');
38
+ }
39
+
40
+ this.apiBaseUrl = apiBaseUrl;
41
+ this.apiKey = apiKey;
42
+ this.fetchAPI = fetchAPI;
43
+ this.log = log;
44
+ }
45
+
46
+ // eslint-disable-next-line no-unused-vars, class-methods-use-this
47
+ async sendRequest(endpoint, queryParams = {}) {
48
+ return STUB_RESPONSE;
49
+ }
50
+
51
+ // eslint-disable-next-line no-unused-vars, class-methods-use-this
52
+ async getBrokenBacklinks(url, limit = 50) {
53
+ return STUB_RESPONSE;
54
+ }
55
+
56
+ // eslint-disable-next-line no-unused-vars, class-methods-use-this
57
+ async getTopPages(url, limit = 200) {
58
+ return STUB_RESPONSE;
59
+ }
60
+
61
+ // eslint-disable-next-line no-unused-vars, class-methods-use-this
62
+ async getBacklinks(url, limit = 200) {
63
+ return STUB_RESPONSE;
64
+ }
65
+
66
+ // eslint-disable-next-line no-unused-vars, class-methods-use-this
67
+ async getOrganicKeywords(url, options = {}) {
68
+ return STUB_RESPONSE;
69
+ }
70
+
71
+ // eslint-disable-next-line no-unused-vars, class-methods-use-this
72
+ async getPaidPages(url, date = new Date().toISOString().split('T')[0], limit = 200, mode = 'prefix') {
73
+ return STUB_RESPONSE;
74
+ }
75
+
76
+ // eslint-disable-next-line no-unused-vars, class-methods-use-this
77
+ async getMetrics(url, date = new Date().toISOString().split('T')[0]) {
78
+ return STUB_RESPONSE;
79
+ }
80
+
81
+ // eslint-disable-next-line no-unused-vars, class-methods-use-this
82
+ async getMetricsByCountry(url, date = new Date().toISOString().split('T')[0]) {
83
+ return STUB_RESPONSE;
84
+ }
85
+ }
@@ -0,0 +1,26 @@
1
+ /*
2
+ * Copyright 2026 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
+ * Endpoint definitions for the SEO API.
15
+ * Each entry maps a method name to its API path and default query parameters.
16
+ * Paths and params are stubs - to be populated when implementing API calls.
17
+ */
18
+ export const ENDPOINTS = {
19
+ brokenBacklinks: { path: '', defaultParams: {} },
20
+ topPages: { path: '', defaultParams: {} },
21
+ backlinks: { path: '', defaultParams: {} },
22
+ organicKeywords: { path: '', defaultParams: {} },
23
+ paidPages: { path: '', defaultParams: {} },
24
+ metrics: { path: '', defaultParams: {} },
25
+ metricsByCountry: { path: '', defaultParams: {} },
26
+ };
package/src/index.d.ts ADDED
@@ -0,0 +1,114 @@
1
+ /*
2
+ * Copyright 2026 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 { UniversalContext } from '@adobe/helix-universal';
14
+
15
+ export interface SeoAPIOptions {
16
+ select: string;
17
+ where: string;
18
+ order_by: string;
19
+ date: string;
20
+ target: string;
21
+ limit: number;
22
+ mode: string;
23
+ output: string;
24
+ }
25
+
26
+ export default class SeoClient {
27
+ /**
28
+ * Static factory method to create an instance of SeoClient.
29
+ * @param {UniversalContext} context - An object containing the AWS Lambda context information
30
+ * @returns An instance of SeoClient.
31
+ */
32
+ static createFrom(context: UniversalContext): SeoClient;
33
+
34
+ /**
35
+ * Constructor for creating an instance of SeoClient.
36
+ * @param config
37
+ * @param fetchAPI
38
+ * @param log
39
+ */
40
+ constructor(config: object, fetchAPI, log?: Console);
41
+
42
+ /**
43
+ * Asynchronous method to send a request to the SEO API.
44
+ * @param endpoint
45
+ * @param queryParams
46
+ */
47
+ sendRequest(endpoint: string, queryParams?: SeoAPIOptions):
48
+ Promise<{ result: object, fullAuditRef: string }>;
49
+
50
+ /**
51
+ * Asynchronous method to get broken backlinks.
52
+ * @param url
53
+ * @param limit
54
+ */
55
+ getBrokenBacklinks(url: string, limit?: number):
56
+ Promise<{ result: object, fullAuditRef: string }>;
57
+
58
+ /**
59
+ * Asynchronous method to get top pages.
60
+ * @param url
61
+ * @param limit
62
+ */
63
+ getTopPages(url: string, limit?: number):
64
+ Promise<{ result: object, fullAuditRef: string }>;
65
+
66
+ /**
67
+ * Asynchronous method to get backlinks.
68
+ * @param url
69
+ * @param limit
70
+ */
71
+ getBacklinks(url: string, limit?: number):
72
+ Promise<{ result: object, fullAuditRef: string }>;
73
+
74
+ /**
75
+ * Asynchronous method to get organic keywords.
76
+ */
77
+ getOrganicKeywords(
78
+ url: string,
79
+ options?: {
80
+ country?: string,
81
+ keywordFilter?: string[],
82
+ limit?: number,
83
+ mode?: 'exact' | 'prefix',
84
+ excludeBranded?: boolean,
85
+ }):
86
+ Promise<{ result: object, fullAuditRef: string }>;
87
+
88
+ /**
89
+ * Asynchronous method to get paid pages for a URL.
90
+ * @param url - The target URL
91
+ * @param date - Optional date in YYYY-MM-DD format, defaults to today
92
+ * @param limit - Maximum number of results to return (max: 1000)
93
+ * @param mode - Search mode
94
+ */
95
+ getPaidPages(url: string, date?: string, limit?: number,
96
+ mode?: 'exact' | 'prefix' | 'domain' | 'subdomains'):
97
+ Promise<{ result: object, fullAuditRef: string }>;
98
+
99
+ /**
100
+ * Asynchronous method to get metrics for a URL.
101
+ * @param url - The target URL
102
+ * @param date - Optional date in YYYY-MM-DD format, defaults to today
103
+ */
104
+ getMetrics(url: string, date?: string):
105
+ Promise<{ result: object, fullAuditRef: string }>;
106
+
107
+ /**
108
+ * Asynchronous method to get metrics by country for a URL.
109
+ * @param url - The target URL
110
+ * @param date - Optional date in YYYY-MM-DD format, defaults to today
111
+ */
112
+ getMetricsByCountry(url: string, date?: string):
113
+ Promise<{ result: object, fullAuditRef: string }>;
114
+ }
package/src/index.js ADDED
@@ -0,0 +1,22 @@
1
+ /*
2
+ * Copyright 2026 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 SeoClient from './client.js';
14
+
15
+ export default SeoClient;
16
+ export { fetch } from './client.js';
17
+ export { ENDPOINTS } from './endpoints.js';
18
+ export { buildQueryParams, parseResponse } from './utils.js';
19
+
20
+ export const ORGANIC_KEYWORDS_FIELDS = /** @type {const} */ ([]);
21
+
22
+ export const METRICS_BY_COUNTRY_FILTER_FIELDS = /** @type {const} */ ([]);
package/src/utils.js ADDED
@@ -0,0 +1,31 @@
1
+ /*
2
+ * Copyright 2026 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
+ * Merges default query parameters with caller-provided overrides.
15
+ * @param {object} defaults - Default parameter values
16
+ * @param {object} overrides - Caller-provided overrides
17
+ * @returns {object} Merged parameters
18
+ */
19
+ export function buildQueryParams(defaults, overrides) {
20
+ return { ...defaults, ...overrides };
21
+ }
22
+
23
+ /**
24
+ * Parses/normalizes an API response.
25
+ * Stub - passes through unchanged. To be extended when implementing API calls.
26
+ * @param {*} response - Raw API response
27
+ * @returns {*} Parsed response
28
+ */
29
+ export function parseResponse(response) {
30
+ return response;
31
+ }