@adobe/spacecat-shared-data-access 3.48.0 → 3.49.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 +6 -0
- package/package.json +1 -1
- package/src/models/audit-url/audit-url.collection.js +10 -3
- package/src/models/base/base.collection.js +39 -12
- package/src/models/base/schema.js +3 -1
- package/src/models/configuration/configuration.model.js +27 -9
- package/src/models/plg-onboarding/plg-onboarding.schema.js +3 -1
- package/src/models/site/config.js +24 -7
- package/src/models/site/index.d.ts +2 -1
- package/src/models/site-enrollment/site-enrollment.collection.js +3 -1
- package/src/models/suggestion/suggestion.projection-utils.js +12 -4
- package/src/models/suggestion-grant/suggestion-grant.collection.js +6 -2
- package/src/util/guards.js +24 -8
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
## [@adobe/spacecat-shared-data-access-v3.49.0](https://github.com/adobe/spacecat-shared/compare/@adobe/spacecat-shared-data-access-v3.48.0...@adobe/spacecat-shared-data-access-v3.49.0) (2026-04-10)
|
|
2
|
+
|
|
3
|
+
### Features
|
|
4
|
+
|
|
5
|
+
* **audit-url:** add moneyPages source to auditTargetURLs config ([#1496](https://github.com/adobe/spacecat-shared/issues/1496)) ([78df8f9](https://github.com/adobe/spacecat-shared/commit/78df8f91008e739bfd67e2277858523a276d70b2))
|
|
6
|
+
|
|
1
7
|
## [@adobe/spacecat-shared-data-access-v3.48.0](https://github.com/adobe/spacecat-shared/compare/@adobe/spacecat-shared-data-access-v3.47.0...@adobe/spacecat-shared-data-access-v3.48.0) (2026-04-08)
|
|
2
8
|
|
|
3
9
|
### Features
|
package/package.json
CHANGED
|
@@ -60,9 +60,16 @@ class AuditUrlCollection extends BaseCollection {
|
|
|
60
60
|
}
|
|
61
61
|
|
|
62
62
|
// Handle null/undefined values (push to end)
|
|
63
|
-
|
|
64
|
-
if (aValue == null)
|
|
65
|
-
|
|
63
|
+
/* c8 ignore next 6 */
|
|
64
|
+
if (aValue == null && bValue == null) {
|
|
65
|
+
return 0;
|
|
66
|
+
}
|
|
67
|
+
if (aValue == null) {
|
|
68
|
+
return 1;
|
|
69
|
+
}
|
|
70
|
+
if (bValue == null) {
|
|
71
|
+
return -1;
|
|
72
|
+
}
|
|
66
73
|
|
|
67
74
|
// Compare values
|
|
68
75
|
let comparison = 0;
|
|
@@ -75,7 +75,10 @@ class BaseCollection {
|
|
|
75
75
|
|
|
76
76
|
// eslint-disable-next-line class-methods-use-this
|
|
77
77
|
#resolveBulkKeyField(keys) {
|
|
78
|
-
|
|
78
|
+
/* c8 ignore next 3 */
|
|
79
|
+
if (!isNonEmptyArray(keys)) {
|
|
80
|
+
return null;
|
|
81
|
+
}
|
|
79
82
|
|
|
80
83
|
const [firstKey] = keys;
|
|
81
84
|
const fields = Object.keys(firstKey);
|
|
@@ -93,9 +96,13 @@ class BaseCollection {
|
|
|
93
96
|
}
|
|
94
97
|
|
|
95
98
|
#normalizeEnumValue(key, value) {
|
|
96
|
-
if (typeof value !== 'string')
|
|
99
|
+
if (typeof value !== 'string') {
|
|
100
|
+
return value;
|
|
101
|
+
}
|
|
97
102
|
const attr = this.schema.getAttribute(key);
|
|
98
|
-
if (!Array.isArray(attr?.type))
|
|
103
|
+
if (!Array.isArray(attr?.type)) {
|
|
104
|
+
return value;
|
|
105
|
+
}
|
|
99
106
|
const match = attr.type.find((v) => v.toLowerCase() === value.toLowerCase());
|
|
100
107
|
return match ?? value;
|
|
101
108
|
}
|
|
@@ -104,7 +111,9 @@ class BaseCollection {
|
|
|
104
111
|
#isInvalidInputError(error) {
|
|
105
112
|
let current = error;
|
|
106
113
|
while (current) {
|
|
107
|
-
if (current?.code === '22P02')
|
|
114
|
+
if (current?.code === '22P02') {
|
|
115
|
+
return true;
|
|
116
|
+
}
|
|
108
117
|
current = current.cause;
|
|
109
118
|
}
|
|
110
119
|
return false;
|
|
@@ -112,9 +121,16 @@ class BaseCollection {
|
|
|
112
121
|
|
|
113
122
|
#logAndThrowError(message, cause) {
|
|
114
123
|
const parts = [message];
|
|
115
|
-
if (cause?.code)
|
|
116
|
-
|
|
117
|
-
|
|
124
|
+
if (cause?.code) {
|
|
125
|
+
parts.push(`[${cause.code}] ${cause.message}`);
|
|
126
|
+
}
|
|
127
|
+
if (cause?.details) {
|
|
128
|
+
parts.push(cause.details);
|
|
129
|
+
}
|
|
130
|
+
/* c8 ignore next 3 */
|
|
131
|
+
if (cause?.hint) {
|
|
132
|
+
parts.push(`hint: ${cause.hint}`);
|
|
133
|
+
}
|
|
118
134
|
|
|
119
135
|
this.log.error(`[${this.entityName}] ${parts.join(' - ')}`);
|
|
120
136
|
|
|
@@ -595,7 +611,10 @@ class BaseCollection {
|
|
|
595
611
|
* @returns {object|null} A model instance, or null if the row is empty/invalid.
|
|
596
612
|
*/
|
|
597
613
|
createInstanceFromRow(row) {
|
|
598
|
-
|
|
614
|
+
/* c8 ignore next 3 */
|
|
615
|
+
if (!isNonEmptyObject(row)) {
|
|
616
|
+
return null;
|
|
617
|
+
}
|
|
599
618
|
return this.#createInstance(this.#toModelRecord(row));
|
|
600
619
|
}
|
|
601
620
|
|
|
@@ -748,7 +767,9 @@ class BaseCollection {
|
|
|
748
767
|
return instance;
|
|
749
768
|
} catch (error) {
|
|
750
769
|
/* c8 ignore next -- re-throw guard (exact match; excludes ValidationError subclass) */
|
|
751
|
-
if (error.constructor === DataAccessError)
|
|
770
|
+
if (error.constructor === DataAccessError) {
|
|
771
|
+
throw error;
|
|
772
|
+
}
|
|
752
773
|
return this.#logAndThrowError('Failed to create', error);
|
|
753
774
|
}
|
|
754
775
|
}
|
|
@@ -862,7 +883,9 @@ class BaseCollection {
|
|
|
862
883
|
return { createdItems, errorItems };
|
|
863
884
|
} catch (error) {
|
|
864
885
|
/* c8 ignore next -- re-throw guard (exact match; excludes ValidationError subclass) */
|
|
865
|
-
if (error.constructor === DataAccessError)
|
|
886
|
+
if (error.constructor === DataAccessError) {
|
|
887
|
+
throw error;
|
|
888
|
+
}
|
|
866
889
|
return this.#logAndThrowError('Failed to create many', error);
|
|
867
890
|
}
|
|
868
891
|
}
|
|
@@ -990,7 +1013,9 @@ class BaseCollection {
|
|
|
990
1013
|
return undefined;
|
|
991
1014
|
} catch (error) {
|
|
992
1015
|
/* c8 ignore next -- re-throw guard (exact match; excludes ValidationError subclass) */
|
|
993
|
-
if (error.constructor === DataAccessError)
|
|
1016
|
+
if (error.constructor === DataAccessError) {
|
|
1017
|
+
throw error;
|
|
1018
|
+
}
|
|
994
1019
|
return this.#logAndThrowError('Failed to save many', error);
|
|
995
1020
|
}
|
|
996
1021
|
}
|
|
@@ -1022,7 +1047,9 @@ class BaseCollection {
|
|
|
1022
1047
|
return undefined;
|
|
1023
1048
|
} catch (error) {
|
|
1024
1049
|
/* c8 ignore next -- re-throw guard (exact match; excludes ValidationError subclass) */
|
|
1025
|
-
if (error.constructor === DataAccessError)
|
|
1050
|
+
if (error.constructor === DataAccessError) {
|
|
1051
|
+
throw error;
|
|
1052
|
+
}
|
|
1026
1053
|
return this.#logAndThrowError('Failed to remove by IDs', error);
|
|
1027
1054
|
}
|
|
1028
1055
|
}
|
|
@@ -143,7 +143,9 @@ class Schema {
|
|
|
143
143
|
Object.keys(indexes).forEach((indexName) => {
|
|
144
144
|
const indexKeys = this.getIndexKeys(indexName);
|
|
145
145
|
|
|
146
|
-
if (!isNonEmptyArray(indexKeys))
|
|
146
|
+
if (!isNonEmptyArray(indexKeys)) {
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
147
149
|
|
|
148
150
|
const keySets = [];
|
|
149
151
|
for (let i = 1; i <= indexKeys.length; i += 1) {
|
|
@@ -176,7 +176,9 @@ class Configuration {
|
|
|
176
176
|
|
|
177
177
|
isHandlerEnabledForSite(type, site) {
|
|
178
178
|
const handler = this.getHandlers()?.[type];
|
|
179
|
-
if (!handler)
|
|
179
|
+
if (!handler) {
|
|
180
|
+
return false;
|
|
181
|
+
}
|
|
180
182
|
|
|
181
183
|
const siteId = site.getId();
|
|
182
184
|
const orgId = site.getOrganizationId();
|
|
@@ -203,7 +205,9 @@ class Configuration {
|
|
|
203
205
|
|
|
204
206
|
isHandlerEnabledForOrg(type, org) {
|
|
205
207
|
const handler = this.getHandlers()?.[type];
|
|
206
|
-
if (!handler)
|
|
208
|
+
if (!handler) {
|
|
209
|
+
return false;
|
|
210
|
+
}
|
|
207
211
|
|
|
208
212
|
const orgId = org.getId();
|
|
209
213
|
|
|
@@ -226,7 +230,9 @@ class Configuration {
|
|
|
226
230
|
const handlers = this.getHandlers();
|
|
227
231
|
const handler = handlers?.[type];
|
|
228
232
|
|
|
229
|
-
if (!isNonEmptyObject(handler))
|
|
233
|
+
if (!isNonEmptyObject(handler)) {
|
|
234
|
+
return;
|
|
235
|
+
}
|
|
230
236
|
|
|
231
237
|
if (!isNonEmptyObject(handler.disabled)) {
|
|
232
238
|
handler.disabled = { orgs: [], sites: [] };
|
|
@@ -267,7 +273,9 @@ class Configuration {
|
|
|
267
273
|
|
|
268
274
|
enableHandlerForSite(type, site) {
|
|
269
275
|
const siteId = site.getId();
|
|
270
|
-
if (this.isHandlerEnabledForSite(type, site))
|
|
276
|
+
if (this.isHandlerEnabledForSite(type, site)) {
|
|
277
|
+
return;
|
|
278
|
+
}
|
|
271
279
|
|
|
272
280
|
const deps = this.isHandlerDependencyMetForSite(type, site);
|
|
273
281
|
if (deps !== true) {
|
|
@@ -287,7 +295,9 @@ class Configuration {
|
|
|
287
295
|
isHandlerDependencyMetForOrg(type, org) {
|
|
288
296
|
const handler = this.getHandler(type);
|
|
289
297
|
|
|
290
|
-
if (!handler || !isNonEmptyArray(handler?.dependencies))
|
|
298
|
+
if (!handler || !isNonEmptyArray(handler?.dependencies)) {
|
|
299
|
+
return true;
|
|
300
|
+
}
|
|
291
301
|
|
|
292
302
|
const unmetDependencies = handler.dependencies
|
|
293
303
|
.filter(({ handler: depHandler }) => !this.isHandlerEnabledForOrg(depHandler, org))
|
|
@@ -305,7 +315,9 @@ class Configuration {
|
|
|
305
315
|
*/
|
|
306
316
|
isHandlerDependencyMetForSite(type, site) {
|
|
307
317
|
const handler = this.getHandler(type);
|
|
308
|
-
if (!handler || !isNonEmptyArray(handler?.dependencies))
|
|
318
|
+
if (!handler || !isNonEmptyArray(handler?.dependencies)) {
|
|
319
|
+
return true;
|
|
320
|
+
}
|
|
309
321
|
|
|
310
322
|
const unmetDependencies = handler.dependencies
|
|
311
323
|
.filter(({ handler: depHandler }) => !this.isHandlerEnabledForSite(depHandler, site))
|
|
@@ -316,7 +328,9 @@ class Configuration {
|
|
|
316
328
|
|
|
317
329
|
enableHandlerForOrg(type, org) {
|
|
318
330
|
const orgId = org.getId();
|
|
319
|
-
if (this.isHandlerEnabledForOrg(type, org))
|
|
331
|
+
if (this.isHandlerEnabledForOrg(type, org)) {
|
|
332
|
+
return;
|
|
333
|
+
}
|
|
320
334
|
const deps = this.isHandlerDependencyMetForOrg(type, org);
|
|
321
335
|
if (deps !== true) {
|
|
322
336
|
throw new Error(`Cannot enable handler ${type} for org ${orgId} because of missing dependencies: ${deps}`);
|
|
@@ -327,14 +341,18 @@ class Configuration {
|
|
|
327
341
|
|
|
328
342
|
disableHandlerForSite(type, site) {
|
|
329
343
|
const siteId = site.getId();
|
|
330
|
-
if (!this.isHandlerEnabledForSite(type, site))
|
|
344
|
+
if (!this.isHandlerEnabledForSite(type, site)) {
|
|
345
|
+
return;
|
|
346
|
+
}
|
|
331
347
|
|
|
332
348
|
this.updateHandlerSites(type, siteId, false);
|
|
333
349
|
}
|
|
334
350
|
|
|
335
351
|
disableHandlerForOrg(type, org) {
|
|
336
352
|
const orgId = org.getId();
|
|
337
|
-
if (!this.isHandlerEnabledForOrg(type, org))
|
|
353
|
+
if (!this.isHandlerEnabledForOrg(type, org)) {
|
|
354
|
+
return;
|
|
355
|
+
}
|
|
338
356
|
|
|
339
357
|
this.updateHandlerOrgs(type, orgId, false);
|
|
340
358
|
}
|
|
@@ -94,7 +94,9 @@ const schema = new SchemaBuilder(PlgOnboarding, PlgOnboardingCollection)
|
|
|
94
94
|
},
|
|
95
95
|
},
|
|
96
96
|
validate: (value) => {
|
|
97
|
-
if (!Array.isArray(value))
|
|
97
|
+
if (!Array.isArray(value)) {
|
|
98
|
+
return false;
|
|
99
|
+
}
|
|
98
100
|
const valid = Object.values(PlgOnboarding.REVIEW_DECISIONS);
|
|
99
101
|
return value.every((r) => valid.includes(r.decision) && isIsoDate(r.reviewedAt));
|
|
100
102
|
},
|
|
@@ -404,6 +404,9 @@ export const configSchema = Joi.object({
|
|
|
404
404
|
manual: Joi.array().items(Joi.object({
|
|
405
405
|
url: Joi.string().uri().required(),
|
|
406
406
|
})).optional().default([]),
|
|
407
|
+
moneyPages: Joi.array().items(Joi.object({
|
|
408
|
+
url: Joi.string().uri().required(),
|
|
409
|
+
})).optional().default([]),
|
|
407
410
|
}).options({ stripUnknown: true }).optional(),
|
|
408
411
|
handlers: Joi.object().pattern(Joi.string(), Joi.object({
|
|
409
412
|
mentions: Joi.object().pattern(Joi.string(), Joi.array().items(Joi.string())),
|
|
@@ -515,7 +518,7 @@ export const Config = (data = {}) => {
|
|
|
515
518
|
self.getEdgeOptimizeConfig = () => state?.edgeOptimizeConfig;
|
|
516
519
|
self.getOnboardConfig = () => state?.onboardConfig;
|
|
517
520
|
self.getCommerceLlmoConfig = () => state?.commerceLlmoConfig;
|
|
518
|
-
const AUDIT_TARGET_SOURCES = ['manual'];
|
|
521
|
+
const AUDIT_TARGET_SOURCES = ['manual', 'moneyPages'];
|
|
519
522
|
const auditTargetEntrySchema = Joi.object({
|
|
520
523
|
url: Joi.string().uri().required(),
|
|
521
524
|
});
|
|
@@ -530,7 +533,9 @@ export const Config = (data = {}) => {
|
|
|
530
533
|
|
|
531
534
|
self.getAuditTargetURLs = () => {
|
|
532
535
|
const targets = state?.auditTargetURLs;
|
|
533
|
-
if (!targets)
|
|
536
|
+
if (!targets) {
|
|
537
|
+
return [];
|
|
538
|
+
}
|
|
534
539
|
return AUDIT_TARGET_SOURCES.flatMap(
|
|
535
540
|
(source) => (targets[source] || []).map((entry) => ({ ...entry, source })),
|
|
536
541
|
);
|
|
@@ -564,7 +569,9 @@ export const Config = (data = {}) => {
|
|
|
564
569
|
|
|
565
570
|
self.removeAuditTargetURL = (source, url) => {
|
|
566
571
|
validateAuditTargetSource(source);
|
|
567
|
-
if (!state.auditTargetURLs?.[source])
|
|
572
|
+
if (!state.auditTargetURLs?.[source]) {
|
|
573
|
+
return;
|
|
574
|
+
}
|
|
568
575
|
state.auditTargetURLs[source] = state.auditTargetURLs[source]
|
|
569
576
|
.filter((t) => t.url !== url);
|
|
570
577
|
};
|
|
@@ -702,7 +709,10 @@ export const Config = (data = {}) => {
|
|
|
702
709
|
|
|
703
710
|
self.removeLlmoUrlPattern = (urlPattern) => {
|
|
704
711
|
const urlPatterns = state.llmo?.urlPatterns;
|
|
705
|
-
|
|
712
|
+
/* c8 ignore next 3 */
|
|
713
|
+
if (!urlPatterns) {
|
|
714
|
+
return;
|
|
715
|
+
}
|
|
706
716
|
|
|
707
717
|
state.llmo.urlPatterns = urlPatterns.filter(
|
|
708
718
|
(pattern) => pattern.urlPattern !== urlPattern,
|
|
@@ -733,7 +743,9 @@ export const Config = (data = {}) => {
|
|
|
733
743
|
};
|
|
734
744
|
|
|
735
745
|
self.removeLlmoTag = (tag) => {
|
|
736
|
-
if (!state.llmo?.tags)
|
|
746
|
+
if (!state.llmo?.tags) {
|
|
747
|
+
return;
|
|
748
|
+
}
|
|
737
749
|
state.llmo.tags = state.llmo.tags.filter((t) => t !== tag);
|
|
738
750
|
};
|
|
739
751
|
|
|
@@ -803,7 +815,10 @@ export const Config = (data = {}) => {
|
|
|
803
815
|
const prior = state.brandProfile || {};
|
|
804
816
|
// compute hash over all content except functional fields
|
|
805
817
|
const stripFunctional = (p) => {
|
|
806
|
-
|
|
818
|
+
/* c8 ignore next 3 */
|
|
819
|
+
if (!isNonEmptyObject(p)) {
|
|
820
|
+
return {};
|
|
821
|
+
}
|
|
807
822
|
const {
|
|
808
823
|
/* eslint-disable no-unused-vars */
|
|
809
824
|
version, updatedAt, contentHash, ...rest
|
|
@@ -861,7 +876,9 @@ export const Config = (data = {}) => {
|
|
|
861
876
|
};
|
|
862
877
|
|
|
863
878
|
self.disableImport = (type) => {
|
|
864
|
-
if (!state.imports)
|
|
879
|
+
if (!state.imports) {
|
|
880
|
+
return;
|
|
881
|
+
}
|
|
865
882
|
|
|
866
883
|
state.imports = state.imports.map(
|
|
867
884
|
(imp) => (imp.type === type ? { ...imp, enabled: false } : imp),
|
|
@@ -110,7 +110,7 @@ export interface LlmoCustomerIntent {
|
|
|
110
110
|
value: string;
|
|
111
111
|
}
|
|
112
112
|
|
|
113
|
-
export type AuditTargetSource = 'manual';
|
|
113
|
+
export type AuditTargetSource = 'manual' | 'moneyPages';
|
|
114
114
|
|
|
115
115
|
export interface AuditTargetEntry {
|
|
116
116
|
url: string;
|
|
@@ -122,6 +122,7 @@ export interface AuditTargetEntryWithSource extends AuditTargetEntry {
|
|
|
122
122
|
|
|
123
123
|
export interface AuditTargetURLs {
|
|
124
124
|
manual?: AuditTargetEntry[];
|
|
125
|
+
moneyPages?: AuditTargetEntry[];
|
|
125
126
|
}
|
|
126
127
|
|
|
127
128
|
export interface SiteConfig {
|
|
@@ -37,7 +37,9 @@ export const FIELD_TRANSFORMERS = {
|
|
|
37
37
|
* Used for accessibility-related opportunity types.
|
|
38
38
|
*/
|
|
39
39
|
filterIssuesOccurrences: (issues) => {
|
|
40
|
-
if (!Array.isArray(issues))
|
|
40
|
+
if (!Array.isArray(issues)) {
|
|
41
|
+
return issues;
|
|
42
|
+
}
|
|
41
43
|
return issues.map((issue) => ({
|
|
42
44
|
occurrences: issue.occurrences,
|
|
43
45
|
}));
|
|
@@ -47,7 +49,9 @@ export const FIELD_TRANSFORMERS = {
|
|
|
47
49
|
* Used for Core Web Vitals opportunity type.
|
|
48
50
|
*/
|
|
49
51
|
filterCwvMetrics: (metrics) => {
|
|
50
|
-
if (!Array.isArray(metrics))
|
|
52
|
+
if (!Array.isArray(metrics)) {
|
|
53
|
+
return metrics;
|
|
54
|
+
}
|
|
51
55
|
return metrics.map((metric) => ({
|
|
52
56
|
deviceType: metric.deviceType,
|
|
53
57
|
lcp: metric.lcp,
|
|
@@ -65,7 +69,9 @@ export const FIELD_TRANSFORMERS = {
|
|
|
65
69
|
* /AltText/handlers/AltTextOpportunityAdapter.tsx
|
|
66
70
|
*/
|
|
67
71
|
extractPageUrlFromRecommendations: (recommendations) => {
|
|
68
|
-
if (!Array.isArray(recommendations))
|
|
72
|
+
if (!Array.isArray(recommendations)) {
|
|
73
|
+
return recommendations;
|
|
74
|
+
}
|
|
69
75
|
return recommendations.map((rec) => ({
|
|
70
76
|
pageUrl: rec.pageUrl,
|
|
71
77
|
...(rec.isDecorative !== undefined && { isDecorative: rec.isDecorative }),
|
|
@@ -77,7 +83,9 @@ export const FIELD_TRANSFORMERS = {
|
|
|
77
83
|
* Used for security vulnerability opportunity types.
|
|
78
84
|
*/
|
|
79
85
|
extractCveUrls: (cves) => {
|
|
80
|
-
if (!Array.isArray(cves))
|
|
86
|
+
if (!Array.isArray(cves)) {
|
|
87
|
+
return cves;
|
|
88
|
+
}
|
|
81
89
|
return cves.map((cve) => ({
|
|
82
90
|
url: cve.url,
|
|
83
91
|
}));
|
|
@@ -100,7 +100,9 @@ class SuggestionGrantCollection extends BaseCollection {
|
|
|
100
100
|
|
|
101
101
|
return { grantedIds, notGrantedIds, grantIds };
|
|
102
102
|
} catch (err) {
|
|
103
|
-
if (err instanceof DataAccessError)
|
|
103
|
+
if (err instanceof DataAccessError) {
|
|
104
|
+
throw err;
|
|
105
|
+
}
|
|
104
106
|
this.log.error('splitSuggestionsByGrantStatus failed', err);
|
|
105
107
|
throw new DataAccessError('Failed to split suggestions by grant status', this, err);
|
|
106
108
|
}
|
|
@@ -115,7 +117,9 @@ class SuggestionGrantCollection extends BaseCollection {
|
|
|
115
117
|
* false otherwise or if id is empty.
|
|
116
118
|
*/
|
|
117
119
|
async isSuggestionGranted(suggestionId) {
|
|
118
|
-
if (!hasText(suggestionId))
|
|
120
|
+
if (!hasText(suggestionId)) {
|
|
121
|
+
return false;
|
|
122
|
+
}
|
|
119
123
|
const { grantedIds } = await this.splitSuggestionsByGrantStatus([suggestionId]);
|
|
120
124
|
return grantedIds.length > 0;
|
|
121
125
|
}
|
package/src/util/guards.js
CHANGED
|
@@ -74,14 +74,18 @@ export const guardAny = (propertyName, value, entityName, nullable = false) => {
|
|
|
74
74
|
* @throws Will throw an error if the value is not a valid boolean.
|
|
75
75
|
*/
|
|
76
76
|
export const guardBoolean = (propertyName, value, entityName, nullable = false) => {
|
|
77
|
-
if (checkNullable(value, nullable))
|
|
77
|
+
if (checkNullable(value, nullable)) {
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
78
80
|
if (typeof value !== 'boolean') {
|
|
79
81
|
throw new ValidationError(`Validation failed in ${entityName}: ${propertyName} must be a boolean`);
|
|
80
82
|
}
|
|
81
83
|
};
|
|
82
84
|
|
|
83
85
|
export const guardArray = (propertyName, value, entityName, type = 'string', nullable = false) => {
|
|
84
|
-
if (checkNullable(value, nullable))
|
|
86
|
+
if (checkNullable(value, nullable)) {
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
85
89
|
if (!Array.isArray(value)) {
|
|
86
90
|
throw new ValidationError(`Validation failed in ${entityName}: ${propertyName} must be an array`);
|
|
87
91
|
}
|
|
@@ -100,7 +104,9 @@ export const guardArray = (propertyName, value, entityName, type = 'string', nul
|
|
|
100
104
|
* @throws Will throw an error if the value is not a valid set (unique array) of a given type.
|
|
101
105
|
*/
|
|
102
106
|
export const guardSet = (propertyName, value, entityName, type = 'string', nullable = false) => {
|
|
103
|
-
if (checkNullable(value, nullable))
|
|
107
|
+
if (checkNullable(value, nullable)) {
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
104
110
|
if (!Array.isArray(value) || new Set(value).size !== value.length) {
|
|
105
111
|
throw new ValidationError(`Validation failed in ${entityName}: ${propertyName} must be a unique array (set)`);
|
|
106
112
|
}
|
|
@@ -118,7 +124,9 @@ export const guardSet = (propertyName, value, entityName, type = 'string', nulla
|
|
|
118
124
|
* @throws Will throw an error if the value is not a valid string.
|
|
119
125
|
*/
|
|
120
126
|
export const guardString = (propertyName, value, entityName, nullable = false) => {
|
|
121
|
-
if (checkNullable(value, nullable))
|
|
127
|
+
if (checkNullable(value, nullable)) {
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
122
130
|
if (!hasText(value)) {
|
|
123
131
|
throw new ValidationError(`Validation failed in ${entityName}: ${propertyName} is required`);
|
|
124
132
|
}
|
|
@@ -134,7 +142,9 @@ export const guardString = (propertyName, value, entityName, nullable = false) =
|
|
|
134
142
|
* @throws Will throw an error if the value is not a valid enum value.
|
|
135
143
|
*/
|
|
136
144
|
export const guardEnum = (propertyName, value, enumValues, entityName, nullable = false) => {
|
|
137
|
-
if (checkNullable(value, nullable))
|
|
145
|
+
if (checkNullable(value, nullable)) {
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
138
148
|
if (!enumValues.includes(value)) {
|
|
139
149
|
throw new ValidationError(`Validation failed in ${entityName}: ${propertyName} must be one of ${enumValues}`);
|
|
140
150
|
}
|
|
@@ -149,7 +159,9 @@ export const guardEnum = (propertyName, value, enumValues, entityName, nullable
|
|
|
149
159
|
* @throws Will throw an error if the value is not a valid ID.
|
|
150
160
|
*/
|
|
151
161
|
export const guardId = (propertyName, value, entityName, nullable = false) => {
|
|
152
|
-
if (checkNullable(value, nullable))
|
|
162
|
+
if (checkNullable(value, nullable)) {
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
153
165
|
if (!isValidUUID(value)) {
|
|
154
166
|
throw new ValidationError(`Validation failed in ${entityName}: ${propertyName} must be a valid UUID`);
|
|
155
167
|
}
|
|
@@ -164,7 +176,9 @@ export const guardId = (propertyName, value, entityName, nullable = false) => {
|
|
|
164
176
|
* @throws Will throw an error if the value is not a valid map (object).
|
|
165
177
|
*/
|
|
166
178
|
export const guardMap = (propertyName, value, entityName, nullable = false) => {
|
|
167
|
-
if (checkNullable(value, nullable))
|
|
179
|
+
if (checkNullable(value, nullable)) {
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
168
182
|
if (!isObject(value)) {
|
|
169
183
|
throw new ValidationError(`Validation failed in ${entityName}: ${propertyName} must be an object`);
|
|
170
184
|
}
|
|
@@ -179,7 +193,9 @@ export const guardMap = (propertyName, value, entityName, nullable = false) => {
|
|
|
179
193
|
* @throws Will throw an error if the value is not a valid number.
|
|
180
194
|
*/
|
|
181
195
|
export const guardNumber = (propertyName, value, entityName, nullable = false) => {
|
|
182
|
-
if (checkNullable(value, nullable))
|
|
196
|
+
if (checkNullable(value, nullable)) {
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
183
199
|
if (!isNumber(value)) {
|
|
184
200
|
throw new ValidationError(`Validation failed in ${entityName}: ${propertyName} must be a number`);
|
|
185
201
|
}
|