@adobe/spacecat-shared-data-access 3.15.1 → 3.17.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-data-access-v3.17.0](https://github.com/adobe/spacecat-shared/compare/@adobe/spacecat-shared-data-access-v3.16.0...@adobe/spacecat-shared-data-access-v3.17.0) (2026-03-12)
2
+
3
+ ### Features
4
+
5
+ * **data-access:** add cross-tenant query documentation for PlgOnboarding ([#1432](https://github.com/adobe/spacecat-shared/issues/1432)) ([d16c1ea](https://github.com/adobe/spacecat-shared/commit/d16c1ea95dff54ce801cd80e4177c3de853886c5))
6
+
7
+ ## [@adobe/spacecat-shared-data-access-v3.16.0](https://github.com/adobe/spacecat-shared/compare/@adobe/spacecat-shared-data-access-v3.15.1...@adobe/spacecat-shared-data-access-v3.16.0) (2026-03-12)
8
+
9
+ ### Features
10
+
11
+ * Added cwv-trends-daily import type ([#1375](https://github.com/adobe/spacecat-shared/issues/1375)) ([14148bb](https://github.com/adobe/spacecat-shared/commit/14148bbcdebc330ad0e4fea2534779c14f3ab30d))
12
+
1
13
  ## [@adobe/spacecat-shared-data-access-v3.15.1](https://github.com/adobe/spacecat-shared/compare/@adobe/spacecat-shared-data-access-v3.15.0...@adobe/spacecat-shared-data-access-v3.15.1) (2026-03-11)
2
14
 
3
15
  ### Bug Fixes
package/CLAUDE.md CHANGED
@@ -214,6 +214,70 @@ const liveSites = await dataAccess.Site.all(
214
214
  | `S3_CONFIG_BUCKET` | No | Only for `Configuration` entity |
215
215
  | `AWS_REGION` | No | Only for `Configuration` entity |
216
216
 
217
+ ## Site Config: Import Types
218
+
219
+ Site configuration lives in `src/models/site/config.js` and defines the available import types, their validation schemas, and default configs. This is one of the most frequently changed files in the package.
220
+
221
+ ### Adding a New Import Type
222
+
223
+ Update three locations in `src/models/site/config.js`:
224
+
225
+ **1. Add the constant to `IMPORT_TYPES`:**
226
+
227
+ ```js
228
+ export const IMPORT_TYPES = {
229
+ // ... existing types
230
+ MY_NEW_IMPORT: 'my-new-import',
231
+ };
232
+ ```
233
+
234
+ **2. Add the Joi validation schema to `IMPORT_TYPE_SCHEMAS`:**
235
+
236
+ ```js
237
+ export const IMPORT_TYPE_SCHEMAS = {
238
+ // ... existing schemas
239
+ [IMPORT_TYPES.MY_NEW_IMPORT]: Joi.object({
240
+ type: Joi.string().valid(IMPORT_TYPES.MY_NEW_IMPORT).required(),
241
+ ...IMPORT_BASE_KEYS,
242
+ // Add optional type-specific fields here (e.g., geo, limit, year, week)
243
+ }),
244
+ };
245
+ ```
246
+
247
+ `IMPORT_BASE_KEYS` includes `enabled`, `destinations`, and `sources`. Only add extra fields if the import type needs them.
248
+
249
+ **3. Add the default config to `DEFAULT_IMPORT_CONFIGS`:**
250
+
251
+ ```js
252
+ export const DEFAULT_IMPORT_CONFIGS = {
253
+ // ... existing defaults
254
+ 'my-new-import': {
255
+ type: 'my-new-import',
256
+ destinations: ['default'],
257
+ sources: ['rum'], // or 'ahrefs', 'google'
258
+ enabled: true,
259
+ },
260
+ };
261
+ ```
262
+
263
+ ### Test Updates
264
+
265
+ In `test/unit/models/site/config.test.js`, add:
266
+
267
+ 1. **Enable import test** — verify `config.enableImport('my-new-import')` produces the expected default config
268
+ 2. **Validation error string** — the long `.to.equal(...)` assertion for invalid import type errors must include the new type
269
+ 3. **Validation error details** — the `.to.eql([...])` array of expected error detail objects must include the new type
270
+
271
+ ### Available Sources
272
+
273
+ | Source | Constant | Used by |
274
+ |--------|----------|---------|
275
+ | `'ahrefs'` | `IMPORT_SOURCES.AHREFS` | Keyword, traffic, backlink imports |
276
+ | `'google'` | `IMPORT_SOURCES.GSC` | Google Search Console imports |
277
+ | `'rum'` | `IMPORT_SOURCES.RUM` | RUM/CWV/engagement imports |
278
+
279
+ ---
280
+
217
281
  ## Special Entities
218
282
 
219
283
  - **Configuration**: S3-backed (not PostgREST). Requires `S3_CONFIG_BUCKET`.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adobe/spacecat-shared-data-access",
3
- "version": "3.15.1",
3
+ "version": "3.17.0",
4
4
  "description": "Shared modules of the Spacecat Services - Data Access",
5
5
  "type": "module",
6
6
  "engines": {
@@ -43,6 +43,7 @@ import ReportCollection from '../report/report.collection.js';
43
43
  import TrialUserCollection from '../trial-user/trial-user.collection.js';
44
44
  import TrialUserActivityCollection from '../trial-user-activity/trial-user-activity.collection.js';
45
45
  import PageCitabilityCollection from '../page-citability/page-citability.collection.js';
46
+ import PlgOnboardingCollection from '../plg-onboarding/plg-onboarding.collection.js';
46
47
  import SentimentGuidelineCollection from '../sentiment-guideline/sentiment-guideline.collection.js';
47
48
  import SentimentTopicCollection from '../sentiment-topic/sentiment-topic.collection.js';
48
49
 
@@ -75,6 +76,7 @@ import ReportSchema from '../report/report.schema.js';
75
76
  import TrialUserSchema from '../trial-user/trial-user.schema.js';
76
77
  import TrialUserActivitySchema from '../trial-user-activity/trial-user-activity.schema.js';
77
78
  import PageCitabilitySchema from '../page-citability/page-citability.schema.js';
79
+ import PlgOnboardingSchema from '../plg-onboarding/plg-onboarding.schema.js';
78
80
  import SentimentGuidelineSchema from '../sentiment-guideline/sentiment-guideline.schema.js';
79
81
  import SentimentTopicSchema from '../sentiment-topic/sentiment-topic.schema.js';
80
82
 
@@ -202,6 +204,7 @@ EntityRegistry.registerEntity(ReportSchema, ReportCollection);
202
204
  EntityRegistry.registerEntity(TrialUserSchema, TrialUserCollection);
203
205
  EntityRegistry.registerEntity(TrialUserActivitySchema, TrialUserActivityCollection);
204
206
  EntityRegistry.registerEntity(PageCitabilitySchema, PageCitabilityCollection);
207
+ EntityRegistry.registerEntity(PlgOnboardingSchema, PlgOnboardingCollection);
205
208
  EntityRegistry.registerEntity(SentimentGuidelineSchema, SentimentGuidelineCollection);
206
209
  EntityRegistry.registerEntity(SentimentTopicSchema, SentimentTopicCollection);
207
210
  EntityRegistry.defaultEntities = { ...EntityRegistry.entities };
@@ -29,6 +29,7 @@ export type * from './opportunity';
29
29
  export type * from './organization';
30
30
  export type * from './page-citability';
31
31
  export type * from './page-intent';
32
+ export type * from './plg-onboarding';
32
33
  export type * from './project';
33
34
  export type * from './report';
34
35
  export type * from './scrape-job';
@@ -41,5 +41,6 @@ export * from './report/index.js';
41
41
  export * from './trial-user/index.js';
42
42
  export * from './trial-user-activity/index.js';
43
43
  export * from './page-citability/index.js';
44
+ export * from './plg-onboarding/index.js';
44
45
  export * from './sentiment-guideline/index.js';
45
46
  export * from './sentiment-topic/index.js';
@@ -0,0 +1,59 @@
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 type { BaseCollection, BaseModel } from '../index';
14
+
15
+ export type PlgOnboardingStatus =
16
+ | 'IN_PROGRESS'
17
+ | 'ONBOARDED'
18
+ | 'ERROR'
19
+ | 'WAITING_FOR_IP_ALLOWLISTING'
20
+ | 'WAITLISTED';
21
+
22
+ export interface PlgOnboarding extends BaseModel {
23
+ getImsOrgId(): string;
24
+ getDomain(): string;
25
+ getBaseURL(): string;
26
+ getStatus(): PlgOnboardingStatus;
27
+ getSiteId(): string | null;
28
+ getOrganizationId(): string | null;
29
+ getSteps(): object | null;
30
+ getError(): object | null;
31
+ getBotBlocker(): object | null;
32
+ getWaitlistReason(): string | null;
33
+ getCompletedAt(): string | null;
34
+ setStatus(status: PlgOnboardingStatus): PlgOnboarding;
35
+ setSiteId(siteId: string): PlgOnboarding;
36
+ setOrganizationId(organizationId: string): PlgOnboarding;
37
+ setSteps(steps: object): PlgOnboarding;
38
+ setError(error: object): PlgOnboarding;
39
+ setBotBlocker(botBlocker: object): PlgOnboarding;
40
+ setWaitlistReason(waitlistReason: string): PlgOnboarding;
41
+ setCompletedAt(completedAt: string): PlgOnboarding;
42
+ }
43
+
44
+ export interface PlgOnboardingCollection extends BaseCollection<PlgOnboarding> {
45
+ allByImsOrgId(imsOrgId: string): Promise<PlgOnboarding[]>;
46
+ findByImsOrgId(imsOrgId: string): Promise<PlgOnboarding | null>;
47
+ allByImsOrgIdAndUpdatedAt(imsOrgId: string, updatedAt: string): Promise<PlgOnboarding[]>;
48
+ findByImsOrgIdAndUpdatedAt(imsOrgId: string, updatedAt: string): Promise<PlgOnboarding | null>;
49
+ allByImsOrgIdAndDomain(imsOrgId: string, domain: string): Promise<PlgOnboarding[]>;
50
+ findByImsOrgIdAndDomain(imsOrgId: string, domain: string): Promise<PlgOnboarding | null>;
51
+ allByStatus(status: PlgOnboardingStatus): Promise<PlgOnboarding[]>;
52
+ findByStatus(status: PlgOnboardingStatus): Promise<PlgOnboarding | null>;
53
+ allByStatusAndUpdatedAt(status: PlgOnboardingStatus, updatedAt: string): Promise<PlgOnboarding[]>;
54
+ findByStatusAndUpdatedAt(status: PlgOnboardingStatus, updatedAt: string): Promise<PlgOnboarding | null>;
55
+ allByBaseURL(baseURL: string): Promise<PlgOnboarding[]>;
56
+ findByBaseURL(baseURL: string): Promise<PlgOnboarding | null>;
57
+ allByBaseURLAndStatus(baseURL: string, status: PlgOnboardingStatus): Promise<PlgOnboarding[]>;
58
+ findByBaseURLAndStatus(baseURL: string, status: PlgOnboardingStatus): Promise<PlgOnboarding | null>;
59
+ }
@@ -0,0 +1,19 @@
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 PlgOnboarding from './plg-onboarding.model.js';
14
+ import PlgOnboardingCollection from './plg-onboarding.collection.js';
15
+
16
+ export {
17
+ PlgOnboarding,
18
+ PlgOnboardingCollection,
19
+ };
@@ -0,0 +1,29 @@
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 BaseCollection from '../base/base.collection.js';
14
+
15
+ /**
16
+ * PlgOnboardingCollection - A collection class responsible for managing
17
+ * PlgOnboarding entities.
18
+ *
19
+ * Note: allByStatus and allByBaseURL return cross-tenant results
20
+ * intended for internal/admin use only.
21
+ *
22
+ * @class PlgOnboardingCollection
23
+ * @extends BaseCollection
24
+ */
25
+ class PlgOnboardingCollection extends BaseCollection {
26
+ static COLLECTION_NAME = 'PlgOnboardingCollection';
27
+ }
28
+
29
+ export default PlgOnboardingCollection;
@@ -0,0 +1,38 @@
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 BaseModel from '../base/base.model.js';
14
+
15
+ /**
16
+ * PlgOnboarding - A class representing a PLG onboarding entity.
17
+ * Tracks the self-service onboarding lifecycle for ASO customers.
18
+ *
19
+ * @class PlgOnboarding
20
+ * @extends BaseModel
21
+ */
22
+ class PlgOnboarding extends BaseModel {
23
+ static ENTITY_NAME = 'PlgOnboarding';
24
+
25
+ static IMS_ORG_ID_PATTERN = /^[a-z0-9]{24}@AdobeOrg$/i;
26
+
27
+ static DOMAIN_PATTERN = /^[a-z0-9]([a-z0-9-]*[a-z0-9])?(\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)*$/;
28
+
29
+ static STATUSES = {
30
+ IN_PROGRESS: 'IN_PROGRESS',
31
+ ONBOARDED: 'ONBOARDED',
32
+ ERROR: 'ERROR',
33
+ WAITING_FOR_IP_ALLOWLISTING: 'WAITING_FOR_IP_ALLOWLISTING',
34
+ WAITLISTED: 'WAITLISTED',
35
+ };
36
+ }
37
+
38
+ export default PlgOnboarding;
@@ -0,0 +1,113 @@
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 {
14
+ isIsoDate, isObject, isValidUrl, isValidUUID,
15
+ } from '@adobe/spacecat-shared-utils';
16
+ import SchemaBuilder from '../base/schema.builder.js';
17
+ import PlgOnboarding from './plg-onboarding.model.js';
18
+ import PlgOnboardingCollection from './plg-onboarding.collection.js';
19
+
20
+ /*
21
+ Schema Doc: https://electrodb.dev/en/modeling/schema/
22
+ Attribute Doc: https://electrodb.dev/en/modeling/attributes/
23
+ Indexes Doc: https://electrodb.dev/en/modeling/indexes/
24
+ */
25
+
26
+ const schema = new SchemaBuilder(PlgOnboarding, PlgOnboardingCollection)
27
+ .addAttribute('imsOrgId', {
28
+ type: 'string',
29
+ required: true,
30
+ readOnly: true,
31
+ validate: (value) => PlgOnboarding.IMS_ORG_ID_PATTERN.test(value),
32
+ })
33
+ .addAttribute('domain', {
34
+ type: 'string',
35
+ required: true,
36
+ readOnly: true,
37
+ validate: (value) => PlgOnboarding.DOMAIN_PATTERN.test(value) && value.length <= 253,
38
+ })
39
+ .addAttribute('baseURL', {
40
+ type: 'string',
41
+ required: true,
42
+ readOnly: true,
43
+ validate: (value) => isValidUrl(value),
44
+ })
45
+ .addAttribute('status', {
46
+ type: Object.values(PlgOnboarding.STATUSES),
47
+ required: true,
48
+ default: PlgOnboarding.STATUSES.IN_PROGRESS,
49
+ })
50
+ .addAttribute('siteId', {
51
+ type: 'string',
52
+ required: false,
53
+ validate: (value) => !value || isValidUUID(value),
54
+ })
55
+ .addAttribute('organizationId', {
56
+ type: 'string',
57
+ required: false,
58
+ validate: (value) => !value || isValidUUID(value),
59
+ })
60
+ .addAttribute('steps', {
61
+ type: 'map',
62
+ properties: {
63
+ orgResolved: { type: 'boolean' },
64
+ rumVerified: { type: 'boolean' },
65
+ siteCreated: { type: 'boolean' },
66
+ siteResolved: { type: 'boolean' },
67
+ configUpdated: { type: 'boolean' },
68
+ auditsEnabled: { type: 'boolean' },
69
+ entitlementCreated: { type: 'boolean' },
70
+ },
71
+ })
72
+ .addAttribute('error', {
73
+ type: 'any',
74
+ validate: (value) => !value || isObject(value),
75
+ })
76
+ .addAttribute('botBlocker', {
77
+ type: 'map',
78
+ properties: {
79
+ type: { type: 'string' },
80
+ ipsToAllowlist: { type: 'list', items: { type: 'string' } },
81
+ userAgent: { type: 'string' },
82
+ },
83
+ })
84
+ .addAttribute('waitlistReason', {
85
+ type: 'string',
86
+ required: false,
87
+ })
88
+ .addAttribute('completedAt', {
89
+ type: 'string',
90
+ validate: (value) => !value || isIsoDate(value),
91
+ })
92
+ // Index: by imsOrgId (PK=imsOrgId, SK=updatedAt) → allByImsOrgId / findByImsOrgId
93
+ .addIndex(
94
+ { composite: ['imsOrgId'] },
95
+ { composite: ['updatedAt'] },
96
+ )
97
+ // Index: by imsOrgId+domain (PK=imsOrgId, SK=domain) → findByImsOrgIdAndDomain
98
+ .addIndex(
99
+ { composite: ['imsOrgId'] },
100
+ { composite: ['domain'] },
101
+ )
102
+ // Index: by status (PK=status, SK=updatedAt) → allByStatus
103
+ .addIndex(
104
+ { composite: ['status'] },
105
+ { composite: ['updatedAt'] },
106
+ )
107
+ // Index: by baseURL (PK=baseURL, SK=status) → findByBaseURL
108
+ .addIndex(
109
+ { composite: ['baseURL'] },
110
+ { composite: ['status'] },
111
+ );
112
+
113
+ export default schema.build();
@@ -33,6 +33,8 @@ export const IMPORT_TYPES = {
33
33
  TOP_FORMS: 'top-forms',
34
34
  CODE: 'code',
35
35
  USER_ENGAGEMENT: 'user-engagement',
36
+ CWV_TRENDS_DAILY: 'cwv-trends-daily',
37
+ CWV_TRENDS_ONBOARD: 'cwv-trends-onboard',
36
38
  };
37
39
 
38
40
  export const IMPORT_DESTINATIONS = {
@@ -170,6 +172,14 @@ export const IMPORT_TYPE_SCHEMAS = {
170
172
  type: Joi.string().valid(IMPORT_TYPES.USER_ENGAGEMENT).required(),
171
173
  ...IMPORT_BASE_KEYS,
172
174
  }),
175
+ [IMPORT_TYPES.CWV_TRENDS_DAILY]: Joi.object({
176
+ type: Joi.string().valid(IMPORT_TYPES.CWV_TRENDS_DAILY).required(),
177
+ ...IMPORT_BASE_KEYS,
178
+ }),
179
+ [IMPORT_TYPES.CWV_TRENDS_ONBOARD]: Joi.object({
180
+ type: Joi.string().valid(IMPORT_TYPES.CWV_TRENDS_ONBOARD).required(),
181
+ ...IMPORT_BASE_KEYS,
182
+ }),
173
183
  };
174
184
 
175
185
  export const DEFAULT_IMPORT_CONFIGS = {
@@ -258,6 +268,18 @@ export const DEFAULT_IMPORT_CONFIGS = {
258
268
  sources: ['rum'],
259
269
  enabled: true,
260
270
  },
271
+ 'cwv-trends-daily': {
272
+ type: 'cwv-trends-daily',
273
+ destinations: ['default'],
274
+ sources: ['rum'],
275
+ enabled: true,
276
+ },
277
+ 'cwv-trends-onboard': {
278
+ type: 'cwv-trends-onboard',
279
+ destinations: ['default'],
280
+ sources: ['rum'],
281
+ enabled: true,
282
+ },
261
283
  };
262
284
 
263
285
  export const configSchema = Joi.object({
@@ -30,6 +30,7 @@ import type { OpportunityCollection } from '../models/opportunity';
30
30
  import type { OrganizationCollection } from '../models/organization';
31
31
  import type { PageCitabilityCollection } from '../models/page-citability';
32
32
  import type { PageIntentCollection } from '../models/page-intent';
33
+ import type { PlgOnboardingCollection } from '../models/plg-onboarding';
33
34
  import type { ProjectCollection } from '../models/project';
34
35
  import type { ReportCollection } from '../models/report';
35
36
  import type { ScrapeJobCollection } from '../models/scrape-job';
@@ -78,6 +79,7 @@ export interface DataAccess {
78
79
  Organization: OrganizationCollection;
79
80
  PageCitability: PageCitabilityCollection;
80
81
  PageIntent: PageIntentCollection;
82
+ PlgOnboarding: PlgOnboardingCollection;
81
83
  Project: ProjectCollection;
82
84
  Report: ReportCollection;
83
85
  ScrapeJob: ScrapeJobCollection;