@adobe/spacecat-shared-data-access 3.74.0 → 3.74.2
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.74.2](https://github.com/adobe/spacecat-shared/compare/@adobe/spacecat-shared-data-access-v3.74.1...@adobe/spacecat-shared-data-access-v3.74.2) (2026-06-11)
|
|
2
|
+
|
|
3
|
+
### Bug Fixes
|
|
4
|
+
|
|
5
|
+
* reset linked issue status to NEW on FixEntity removal ([#1668](https://github.com/adobe/spacecat-shared/issues/1668)) ([46c54b8](https://github.com/adobe/spacecat-shared/commit/46c54b8829ea3b00029a4afa0cb835f3e7983dc9))
|
|
6
|
+
|
|
7
|
+
## [@adobe/spacecat-shared-data-access-v3.74.1](https://github.com/adobe/spacecat-shared/compare/@adobe/spacecat-shared-data-access-v3.74.0...@adobe/spacecat-shared-data-access-v3.74.1) (2026-06-09)
|
|
8
|
+
|
|
9
|
+
### Bug Fixes
|
|
10
|
+
|
|
11
|
+
* site-level handler overrides were ignored, org-level disable always won ([#1590](https://github.com/adobe/spacecat-shared/issues/1590)) ([cfeca81](https://github.com/adobe/spacecat-shared/commit/cfeca81266351c7523d939cb3a2f50831599b927)), closes [#updatedHandler](https://github.com/adobe/spacecat-shared/issues/updatedHandler)
|
|
12
|
+
|
|
1
13
|
## [@adobe/spacecat-shared-data-access-v3.74.0](https://github.com/adobe/spacecat-shared/compare/@adobe/spacecat-shared-data-access-v3.73.3...@adobe/spacecat-shared-data-access-v3.74.0) (2026-06-02)
|
|
2
14
|
|
|
3
15
|
### Features
|
package/package.json
CHANGED
|
@@ -174,6 +174,21 @@ class Configuration {
|
|
|
174
174
|
.map((job) => job.type);
|
|
175
175
|
}
|
|
176
176
|
|
|
177
|
+
/**
|
|
178
|
+
* Returns whether a handler is enabled for a given site.
|
|
179
|
+
*
|
|
180
|
+
* Precedence (highest to lowest):
|
|
181
|
+
* 1. disabled.sites includes siteId → false (site explicitly disabled)
|
|
182
|
+
* 2. enabled.sites includes siteId → true (site explicitly enabled; overrides org-level)
|
|
183
|
+
* 3. disabled.orgs includes orgId → false (org disabled, no site-level override present)
|
|
184
|
+
* 4. enabledByDefault → true
|
|
185
|
+
* 5. enabled.orgs includes orgId → true
|
|
186
|
+
* 6. otherwise → false
|
|
187
|
+
*
|
|
188
|
+
* Note: disabled.sites and enabled.sites are assumed disjoint; disabled.sites wins if violated
|
|
189
|
+
* (see #updatedHandler which keeps these lists disjoint on every write).
|
|
190
|
+
* isHandlerEnabledForOrg uses a different (simpler) precedence — see its JSDoc.
|
|
191
|
+
*/
|
|
177
192
|
isHandlerEnabledForSite(type, site) {
|
|
178
193
|
const handler = this.getHandlers()?.[type];
|
|
179
194
|
if (!handler) {
|
|
@@ -183,26 +198,53 @@ class Configuration {
|
|
|
183
198
|
const siteId = site.getId();
|
|
184
199
|
const orgId = site.getOrganizationId();
|
|
185
200
|
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
201
|
+
const disabledSites = handler.disabled?.sites || [];
|
|
202
|
+
const enabledSites = handler.enabled?.sites || [];
|
|
203
|
+
const disabledOrgs = handler.disabled?.orgs || [];
|
|
204
|
+
const enabledOrgs = handler.enabled?.orgs || [];
|
|
205
|
+
|
|
206
|
+
// Site-level takes priority over org-level: an explicit site enable/disable
|
|
207
|
+
// overrides the org-level setting, allowing a single site to be upgraded to
|
|
208
|
+
// a paid profile even if the org is in disabled.orgs.
|
|
209
|
+
if (disabledSites.includes(siteId)) {
|
|
210
|
+
return false;
|
|
211
|
+
}
|
|
212
|
+
if (enabledSites.includes(siteId)) {
|
|
213
|
+
if (disabledOrgs.includes(orgId)) {
|
|
214
|
+
// TODO(SITES-44467): demote to debug after 30-day canary window
|
|
215
|
+
this.log.info('[isHandlerEnabledForSite] site-override: site in enabled.sites overrides org in disabled.orgs', { type, siteId, orgId });
|
|
191
216
|
}
|
|
217
|
+
return true;
|
|
192
218
|
}
|
|
193
219
|
|
|
220
|
+
if (disabledOrgs.includes(orgId)) {
|
|
221
|
+
return false;
|
|
222
|
+
}
|
|
194
223
|
if (handler.enabledByDefault) {
|
|
195
224
|
return true;
|
|
196
225
|
}
|
|
197
|
-
|
|
198
|
-
const sites = handler.enabled.sites || [];
|
|
199
|
-
const orgs = handler.enabled.orgs || [];
|
|
200
|
-
return sites.includes(siteId) || orgs.includes(orgId);
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
return false;
|
|
226
|
+
return enabledOrgs.includes(orgId);
|
|
204
227
|
}
|
|
205
228
|
|
|
229
|
+
/**
|
|
230
|
+
* Returns whether a handler is enabled for a given org.
|
|
231
|
+
*
|
|
232
|
+
* Precedence (highest to lowest):
|
|
233
|
+
* 1. disabled.orgs includes orgId → false
|
|
234
|
+
* 2. enabledByDefault → true
|
|
235
|
+
* 3. enabled.orgs includes orgId → true
|
|
236
|
+
* 4. otherwise → false
|
|
237
|
+
*
|
|
238
|
+
* Note: unlike isHandlerEnabledForSite, there is no site-level override here.
|
|
239
|
+
* An org in disabled.orgs is always disabled regardless of site-level entries.
|
|
240
|
+
*
|
|
241
|
+
* Cross-system consequence: callers that fan out on org policy (e.g. org-scoped
|
|
242
|
+
* digests or batch jobs keyed on orgId) use this method as their gate. A site in
|
|
243
|
+
* enabled.sites whose org is in disabled.orgs will pass site-level evaluation
|
|
244
|
+
* (true via isHandlerEnabledForSite) but will NOT pass org-level evaluation
|
|
245
|
+
* (false here). This asymmetry is intentional: org-scoped fan-out follows org
|
|
246
|
+
* policy; site-level overrides do not propagate to org-scoped callers.
|
|
247
|
+
*/
|
|
206
248
|
isHandlerEnabledForOrg(type, org) {
|
|
207
249
|
const handler = this.getHandlers()?.[type];
|
|
208
250
|
if (!handler) {
|
|
@@ -243,20 +285,21 @@ class Configuration {
|
|
|
243
285
|
}
|
|
244
286
|
|
|
245
287
|
if (enabled) {
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
}
|
|
288
|
+
// Always remove from disabled first (handles re-enabling a previously disabled entry).
|
|
289
|
+
handler.disabled[entityKey] = (handler.disabled[entityKey] || [])
|
|
290
|
+
.filter((id) => id !== entityId);
|
|
291
|
+
// Always add to enabled so isHandlerEnabledForSite can find the site in enabled.sites
|
|
292
|
+
// and return true even when the org is in disabled.orgs (site-level override).
|
|
293
|
+
handler.enabled[entityKey] = Array
|
|
294
|
+
.from(new Set([...(handler.enabled[entityKey] || []), entityId]));
|
|
254
295
|
} else if (handler.enabledByDefault) {
|
|
255
296
|
handler.disabled[entityKey] = Array
|
|
256
297
|
.from(new Set([...(handler.disabled[entityKey] || []), entityId]));
|
|
298
|
+
handler.enabled[entityKey] = (handler.enabled[entityKey] || [])
|
|
299
|
+
.filter((id) => id !== entityId);
|
|
257
300
|
} else {
|
|
258
|
-
|
|
259
|
-
|
|
301
|
+
handler.enabled[entityKey] = (handler.enabled[entityKey] || [])
|
|
302
|
+
.filter((id) => id !== entityId);
|
|
260
303
|
}
|
|
261
304
|
|
|
262
305
|
handlers[type] = handler;
|
|
@@ -44,6 +44,50 @@ class FixEntity extends BaseModel {
|
|
|
44
44
|
return fixEntityCollection
|
|
45
45
|
.getSuggestionsByFixEntityId(this.getId());
|
|
46
46
|
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Removes this FixEntity. When the fix is bound to a specific issue (granular CWV
|
|
50
|
+
* model — `changeDetails.issueId` is set), also rewinds every linked Suggestion so
|
|
51
|
+
* the issue is reopenable: clears `data.issues[issueId].fixEntityId` and resets
|
|
52
|
+
* that issue's status to NEW. The fix row and its junction rows are deleted by the
|
|
53
|
+
* inherited remove flow.
|
|
54
|
+
*
|
|
55
|
+
* Skipped when the fix has no issueId (legacy / non-CWV fixes) — same behavior as
|
|
56
|
+
* before. Also skipped when this method is reached as a dependent cascade (parent
|
|
57
|
+
* removal goes through `_remove()` directly), since the parent teardown moots the
|
|
58
|
+
* per-issue rewind.
|
|
59
|
+
*/
|
|
60
|
+
async remove() {
|
|
61
|
+
const issueId = this.record?.changeDetails?.issueId;
|
|
62
|
+
if (issueId) {
|
|
63
|
+
await this.#resetLinkedIssues(issueId);
|
|
64
|
+
}
|
|
65
|
+
return super.remove();
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
async #resetLinkedIssues(issueId) {
|
|
69
|
+
const suggestions = await this.getSuggestions();
|
|
70
|
+
|
|
71
|
+
await Promise.all(suggestions.map(async (suggestion) => {
|
|
72
|
+
const data = suggestion.getData();
|
|
73
|
+
if (!data || !Array.isArray(data.issues)) {
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
let mutated = false;
|
|
77
|
+
const nextIssues = data.issues.map((issue) => {
|
|
78
|
+
if (issue && issue.id === issueId) {
|
|
79
|
+
mutated = true;
|
|
80
|
+
return { ...issue, status: 'NEW', fixEntityId: null };
|
|
81
|
+
}
|
|
82
|
+
return issue;
|
|
83
|
+
});
|
|
84
|
+
if (!mutated) {
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
suggestion.setData({ ...data, issues: nextIssues });
|
|
88
|
+
await suggestion.save();
|
|
89
|
+
}));
|
|
90
|
+
}
|
|
47
91
|
}
|
|
48
92
|
|
|
49
93
|
export default FixEntity;
|