@envive-ai/react-hooks 0.3.17 → 0.3.19
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/dist/application/commerce-api.cjs +14 -13
- package/dist/application/commerce-api.js +14 -13
- package/dist/application/logging/logger.cjs +16 -10
- package/dist/application/logging/logger.js +16 -10
- package/dist/application/models/guards/api/isApiFormResponse.cjs +9 -8
- package/dist/application/models/guards/api/isApiFormResponse.js +9 -8
- package/dist/application/models/guards/api/isApiFormSubmittedResponseAttributes.cjs +6 -5
- package/dist/application/models/guards/api/isApiFormSubmittedResponseAttributes.js +6 -5
- package/dist/application/models/guards/api/isApiOrderResponseAttributes.cjs +19 -18
- package/dist/application/models/guards/api/isApiOrderResponseAttributes.js +19 -18
- package/dist/application/models/guards/api/isApiOrgConfigResults.cjs +27 -26
- package/dist/application/models/guards/api/isApiOrgConfigResults.js +27 -26
- package/dist/application/models/guards/api/isApiOrganizationConfig.cjs +23 -22
- package/dist/application/models/guards/api/isApiOrganizationConfig.js +23 -22
- package/dist/application/models/guards/api/isApiProductResponseAttributes.cjs +12 -11
- package/dist/application/models/guards/api/isApiProductResponseAttributes.js +12 -11
- package/dist/application/models/guards/api/isApiResponse.cjs +7 -6
- package/dist/application/models/guards/api/isApiResponse.js +7 -6
- package/dist/application/models/guards/graphQL/isGraphQLColorsConfig.cjs +5 -4
- package/dist/application/models/guards/graphQL/isGraphQLColorsConfig.js +5 -4
- package/dist/application/models/validators/validateGraphQLFrontendConfig.cjs +15 -14
- package/dist/application/models/validators/validateGraphQLFrontendConfig.js +15 -14
- package/dist/application/utils/analyticsUtils.cjs +4 -3
- package/dist/application/utils/analyticsUtils.js +4 -3
- package/dist/application/utils/nextMessageRequestToApiRequest.cjs +3 -1
- package/dist/application/utils/nextMessageRequestToApiRequest.js +3 -1
- package/dist/application/utils/widgetTextRequestToApiRequest.cjs +2 -2
- package/dist/application/utils/widgetTextRequestToApiRequest.js +2 -2
- package/dist/atoms/app/index.d.cts +7 -7
- package/dist/atoms/app/variant.cjs +3 -2
- package/dist/atoms/app/variant.js +3 -2
- package/dist/atoms/chat/chatState.d.cts +18 -18
- package/dist/atoms/chat/chatState.d.ts +18 -18
- package/dist/atoms/chat/form.d.cts +2 -2
- package/dist/atoms/chat/form.d.ts +2 -2
- package/dist/atoms/chat/index.d.cts +2 -2
- package/dist/atoms/chat/index.d.ts +2 -2
- package/dist/atoms/chat/lastMessage.d.cts +2 -2
- package/dist/atoms/chat/lastMessage.d.ts +2 -2
- package/dist/atoms/chat/messageQueue.d.cts +6 -6
- package/dist/atoms/chat/messageQueue.d.ts +6 -6
- package/dist/atoms/chat/performanceMetrics.cjs +3 -2
- package/dist/atoms/chat/performanceMetrics.d.cts +6 -6
- package/dist/atoms/chat/performanceMetrics.d.ts +6 -6
- package/dist/atoms/chat/performanceMetrics.js +3 -2
- package/dist/atoms/chat/renderedWidgetRefs.d.cts +2 -2
- package/dist/atoms/chat/renderedWidgetRefs.d.ts +2 -2
- package/dist/atoms/chat/replies.d.cts +2 -2
- package/dist/atoms/chat/replies.d.ts +3 -3
- package/dist/atoms/chat/suggestions.d.cts +2 -2
- package/dist/atoms/chat/suggestions.d.ts +2 -2
- package/dist/atoms/envive/enviveConfig.cjs +5 -4
- package/dist/atoms/envive/enviveConfig.d.cts +13 -13
- package/dist/atoms/envive/enviveConfig.d.ts +13 -13
- package/dist/atoms/envive/enviveConfig.js +5 -4
- package/dist/atoms/globalSearch/globalSearch.d.cts +5 -5
- package/dist/atoms/globalSearch/globalSearch.d.ts +5 -5
- package/dist/atoms/org/customerService.d.cts +6 -6
- package/dist/atoms/org/customerService.d.ts +6 -6
- package/dist/atoms/org/graphqlConfig.d.cts +4 -4
- package/dist/atoms/org/graphqlConfig.d.ts +4 -4
- package/dist/atoms/org/newOrgConfigAtom.d.cts +2 -2
- package/dist/atoms/org/newOrgConfigAtom.d.ts +2 -2
- package/dist/atoms/org/orgAnalyticsConfig.d.cts +5 -5
- package/dist/atoms/org/orgAnalyticsConfig.d.ts +5 -5
- package/dist/atoms/search/chatSearch.d.cts +17 -17
- package/dist/atoms/search/chatSearch.d.ts +17 -17
- package/dist/atoms/search/searchAPI.d.cts +13 -13
- package/dist/atoms/search/searchAPI.d.ts +13 -13
- package/dist/atoms/widget/chatPreviewLoading.d.cts +2 -2
- package/dist/atoms/widget/chatPreviewLoading.d.ts +2 -2
- package/dist/contexts/amplitudeContext/amplitudeContext.cjs +4 -3
- package/dist/contexts/amplitudeContext/amplitudeContext.js +3 -2
- package/dist/contexts/enviveConfigContext/enviveConfigContext.cjs +26 -15
- package/dist/contexts/enviveConfigContext/enviveConfigContext.d.cts +2 -4
- package/dist/contexts/enviveConfigContext/enviveConfigContext.d.ts +2 -4
- package/dist/contexts/enviveConfigContext/enviveConfigContext.js +29 -16
- package/dist/contexts/enviveConfigContext/index.cjs +2 -1
- package/dist/contexts/enviveConfigContext/index.d.cts +2 -1
- package/dist/contexts/enviveConfigContext/index.d.ts +2 -1
- package/dist/contexts/enviveConfigContext/index.js +2 -1
- package/dist/contexts/enviveConfigContext/useEnviveConfig.cjs +12 -0
- package/dist/contexts/enviveConfigContext/useEnviveConfig.d.cts +7 -0
- package/dist/contexts/enviveConfigContext/useEnviveConfig.d.ts +7 -0
- package/dist/contexts/enviveConfigContext/useEnviveConfig.js +11 -0
- package/dist/contexts/enviveContext/WindowChatToggleBinder.cjs +7 -5
- package/dist/contexts/enviveContext/WindowChatToggleBinder.js +6 -4
- package/dist/contexts/enviveContext/enviveContext.cjs +34 -39
- package/dist/contexts/enviveContext/enviveContext.js +35 -40
- package/dist/contexts/featureFlagServiceContext/featureFlagServiceContext.cjs +7 -6
- package/dist/contexts/featureFlagServiceContext/featureFlagServiceContext.js +7 -6
- package/dist/contexts/graphqlContext/graphqlContext.cjs +8 -7
- package/dist/contexts/graphqlContext/graphqlContext.js +8 -7
- package/dist/contexts/hardcopyContext/hardcopyContext.cjs +9 -8
- package/dist/contexts/hardcopyContext/hardcopyContext.js +9 -8
- package/dist/contexts/localStorageContext/localStorageContext.cjs +4 -3
- package/dist/contexts/localStorageContext/localStorageContext.js +4 -3
- package/dist/contexts/pageContext/pageContext.cjs +3 -2
- package/dist/contexts/pageContext/pageContext.js +3 -2
- package/dist/contexts/salesAgentContext/chatAPI.cjs +3 -2
- package/dist/contexts/salesAgentContext/chatAPI.js +3 -2
- package/dist/contexts/salesAgentContext/salesAgentContext.cjs +4 -3
- package/dist/contexts/salesAgentContext/salesAgentContext.js +4 -3
- package/dist/contexts/salesAgentContext/salesAgentService.cjs +3 -2
- package/dist/contexts/salesAgentContext/salesAgentService.js +3 -2
- package/dist/contexts/searchContext/searchContext.cjs +8 -6
- package/dist/contexts/searchContext/searchContext.js +7 -5
- package/dist/contexts/sessionStorageContext/sessionStorageContext.cjs +3 -2
- package/dist/contexts/sessionStorageContext/sessionStorageContext.js +3 -2
- package/dist/contexts/systemSettingsContext/systemSettingsContext.d.cts +2 -2
- package/dist/contexts/types.d.cts +1 -1
- package/dist/contexts/types.d.ts +1 -1
- package/dist/contexts/typesV3.d.cts +1 -1
- package/dist/contexts/typesV3.d.ts +1 -1
- package/dist/contexts/uiConfigContext/index.cjs +0 -1
- package/dist/contexts/uiConfigContext/index.d.cts +2 -2
- package/dist/contexts/uiConfigContext/index.d.ts +2 -2
- package/dist/contexts/uiConfigContext/index.js +2 -2
- package/dist/contexts/uiConfigContext/uiConfigContext.cjs +13 -30
- package/dist/contexts/uiConfigContext/uiConfigContext.d.cts +5 -9
- package/dist/contexts/uiConfigContext/uiConfigContext.d.ts +5 -9
- package/dist/contexts/uiConfigContext/uiConfigContext.js +14 -29
- package/dist/contexts/userIdentityContext/userIdentityContext.cjs +7 -7
- package/dist/contexts/userIdentityContext/userIdentityContext.js +7 -7
- package/dist/contexts/widgetConfigContext/widgetConfigContext.cjs +4 -3
- package/dist/contexts/widgetConfigContext/widgetConfigContext.js +4 -3
- package/dist/hooks/CustomerSupportHandoff/useCustomerSupportHandoff.cjs +4 -3
- package/dist/hooks/CustomerSupportHandoff/useCustomerSupportHandoff.js +4 -3
- package/dist/hooks/SystemSettingsContext/useSystemSettingsContext.d.cts +2 -2
- package/dist/hooks/WidgetInteraction/useWidgetInteraction.cjs +2 -2
- package/dist/hooks/WidgetInteraction/useWidgetInteraction.js +2 -2
- package/dist/hooks/WidgetInteraction/utils.cjs +2 -1
- package/dist/hooks/WidgetInteraction/utils.js +2 -1
- package/dist/hooks/utils.d.ts +1 -1
- package/dist/services/amplitudeService/amplitudeService.cjs +8 -7
- package/dist/services/amplitudeService/amplitudeService.js +8 -7
- package/dist/services/ga4ProjectionService/ga4ProjectionService.cjs +3 -2
- package/dist/services/ga4ProjectionService/ga4ProjectionService.js +3 -2
- package/dist/services/userIdentityService/userIdentityService.cjs +8 -7
- package/dist/services/userIdentityService/userIdentityService.js +8 -7
- package/package.json +2 -2
- package/src/application/commerce-api.ts +14 -12
- package/src/application/logging/logger.ts +33 -8
- package/src/application/models/guards/api/isApiFormResponse.ts +9 -7
- package/src/application/models/guards/api/isApiFormSubmittedResponseAttributes.ts +6 -4
- package/src/application/models/guards/api/isApiOrderResponseAttributes.ts +19 -17
- package/src/application/models/guards/api/isApiOrgConfigResults.ts +40 -48
- package/src/application/models/guards/api/isApiOrganizationConfig.ts +25 -38
- package/src/application/models/guards/api/isApiProductResponseAttributes.ts +12 -10
- package/src/application/models/guards/api/isApiResponse.ts +7 -5
- package/src/application/models/guards/graphQL/isGraphQLColorsConfig.ts +5 -3
- package/src/application/models/validators/validateGraphQLFrontendConfig.ts +15 -13
- package/src/application/utils/analyticsUtils.ts +4 -4
- package/src/application/utils/nextMessageRequestToApiRequest.ts +2 -0
- package/src/application/utils/widgetTextRequestToApiRequest.ts +1 -2
- package/src/atoms/app/variant.ts +3 -1
- package/src/atoms/chat/performanceMetrics.ts +3 -1
- package/src/atoms/envive/enviveConfig.ts +5 -3
- package/src/contexts/amplitudeContext/amplitudeContext.tsx +1 -1
- package/src/contexts/enviveConfigContext/__tests__/enviveConfigContext.test.tsx +4 -3
- package/src/contexts/enviveConfigContext/enviveConfigContext.tsx +50 -35
- package/src/contexts/enviveConfigContext/index.ts +1 -0
- package/src/contexts/enviveConfigContext/useEnviveConfig.ts +9 -0
- package/src/contexts/enviveContext/WindowChatToggleBinder.tsx +6 -4
- package/src/contexts/enviveContext/enviveContext.tsx +40 -45
- package/src/contexts/featureFlagServiceContext/featureFlagServiceContext.tsx +11 -12
- package/src/contexts/graphqlContext/__tests__/graphqlContext.test.tsx +4 -4
- package/src/contexts/graphqlContext/graphqlContext.tsx +8 -6
- package/src/contexts/hardcopyContext/hardcopyContext.tsx +9 -7
- package/src/contexts/localStorageContext/__tests__/localStorageContext.test.tsx +6 -6
- package/src/contexts/localStorageContext/localStorageContext.tsx +4 -2
- package/src/contexts/pageContext/__tests__/pageContext.test.tsx +5 -5
- package/src/contexts/pageContext/pageContext.tsx +3 -1
- package/src/contexts/salesAgentContext/chatAPI.ts +5 -5
- package/src/contexts/salesAgentContext/salesAgentContext.tsx +4 -2
- package/src/contexts/salesAgentContext/salesAgentService.ts +4 -2
- package/src/contexts/searchContext/__tests__/searchContext.test.tsx +15 -12
- package/src/contexts/searchContext/searchContext.tsx +6 -4
- package/src/contexts/sessionStorageContext/sessionStorageContext.tsx +3 -1
- package/src/contexts/uiConfigContext/__tests__/uiConfigContext.test.tsx +7 -32
- package/src/contexts/uiConfigContext/uiConfigContext.tsx +17 -29
- package/src/contexts/userIdentityContext/__tests__/userIdentityContext.test.tsx +5 -5
- package/src/contexts/userIdentityContext/userIdentityContext.tsx +7 -6
- package/src/contexts/widgetConfigContext/__tests__/widgetConfigContext.test.tsx +7 -7
- package/src/contexts/widgetConfigContext/widgetConfigContext.tsx +4 -2
- package/src/hooks/CustomerSupportHandoff/useCustomerSupportHandoff.ts +4 -2
- package/src/hooks/Search/__tests__/useSearch.test.tsx +14 -8
- package/src/hooks/WidgetInteraction/useWidgetInteraction.ts +3 -2
- package/src/hooks/WidgetInteraction/utils.ts +3 -1
- package/src/services/amplitudeService/__tests__/amplitudeService.test.ts +3 -3
- package/src/services/amplitudeService/amplitudeService.ts +8 -6
- package/src/services/ga4ProjectionService/ga4ProjectionService.ts +3 -1
- package/src/services/userIdentityService/userIdentityService.ts +8 -8
|
@@ -2,6 +2,8 @@ import Logger from 'src/application/logging/logger';
|
|
|
2
2
|
import { OrderItemInfo, OrderResponseAttributes } from '@spiffy-ai/commerce-api-client';
|
|
3
3
|
import { hasPropertyOfType } from 'src/application/models/guards/utils';
|
|
4
4
|
|
|
5
|
+
const logger = new Logger('isApiOrderResponseAttributes');
|
|
6
|
+
|
|
5
7
|
// the client SDK generates date-time format types as `Date` but the openapi typescript generator
|
|
6
8
|
// does not correctly deserialize date-time values so they are always `string` at runtime instead of
|
|
7
9
|
// `Date` objects. These interfaces override the SDK types so that we can validate against the actual
|
|
@@ -26,37 +28,37 @@ export interface ApiOrderResponseAttributes extends Omit<
|
|
|
26
28
|
|
|
27
29
|
const isApiOrderItemInfo = (data: unknown): data is ApiOrderItemInfo => {
|
|
28
30
|
if (data == null || typeof data !== 'object') {
|
|
29
|
-
|
|
31
|
+
logger.logError('OrderItemInfo must be an object', undefined, { data });
|
|
30
32
|
return false;
|
|
31
33
|
}
|
|
32
34
|
|
|
33
35
|
if (!hasPropertyOfType(data, 'order_item_id', 'string')) {
|
|
34
|
-
|
|
36
|
+
logger.logError('OrderItemInfo must have an order_item_id property', undefined, { data });
|
|
35
37
|
return false;
|
|
36
38
|
}
|
|
37
39
|
|
|
38
40
|
if (!hasPropertyOfType(data, 'item_title', 'string')) {
|
|
39
|
-
|
|
41
|
+
logger.logError('OrderItemInfo must have an item_title property', undefined, { data });
|
|
40
42
|
return false;
|
|
41
43
|
}
|
|
42
44
|
|
|
43
45
|
if (!hasPropertyOfType(data, 'item_price', 'number')) {
|
|
44
|
-
|
|
46
|
+
logger.logError('OrderItemInfo must have an item_price property', undefined, { data });
|
|
45
47
|
return false;
|
|
46
48
|
}
|
|
47
49
|
|
|
48
50
|
if (!hasPropertyOfType(data, 'item_quantity', 'number')) {
|
|
49
|
-
|
|
51
|
+
logger.logError('OrderItemInfo must have an item_quantity property', undefined, { data });
|
|
50
52
|
return false;
|
|
51
53
|
}
|
|
52
54
|
|
|
53
55
|
if (!hasPropertyOfType(data, 'image', 'string', true)) {
|
|
54
|
-
|
|
56
|
+
logger.logError('OrderItemInfo.image must be a string or null', undefined, { data });
|
|
55
57
|
return false;
|
|
56
58
|
}
|
|
57
59
|
|
|
58
60
|
if (!hasPropertyOfType(data, 'fulfillment_display_status', 'string', true)) {
|
|
59
|
-
|
|
61
|
+
logger.logError(
|
|
60
62
|
'OrderItemInfo.fulfillment_display_status must be a string or null',
|
|
61
63
|
undefined,
|
|
62
64
|
{
|
|
@@ -67,24 +69,24 @@ const isApiOrderItemInfo = (data: unknown): data is ApiOrderItemInfo => {
|
|
|
67
69
|
}
|
|
68
70
|
|
|
69
71
|
if (!hasPropertyOfType(data, 'tracking_url', 'string', true)) {
|
|
70
|
-
|
|
72
|
+
logger.logError('OrderItemInfo.tracking_url must be a string or null', undefined, { data });
|
|
71
73
|
return false;
|
|
72
74
|
}
|
|
73
75
|
|
|
74
76
|
if (!hasPropertyOfType(data, 'delivered_at', 'string', true)) {
|
|
75
|
-
|
|
77
|
+
logger.logError('OrderItemInfo.delivered_at must be a string or null', undefined, { data });
|
|
76
78
|
return false;
|
|
77
79
|
}
|
|
78
80
|
|
|
79
81
|
if (!hasPropertyOfType(data, 'estimated_delivery_at', 'string', true)) {
|
|
80
|
-
|
|
82
|
+
logger.logError('OrderItemInfo.estimated_delivery_at must be a string or null', undefined, {
|
|
81
83
|
data,
|
|
82
84
|
});
|
|
83
85
|
return false;
|
|
84
86
|
}
|
|
85
87
|
|
|
86
88
|
if (!hasPropertyOfType(data, 'in_transit_at', 'string', true)) {
|
|
87
|
-
|
|
89
|
+
logger.logError('OrderItemInfo.in_transit_at must be a string or null', undefined, { data });
|
|
88
90
|
return false;
|
|
89
91
|
}
|
|
90
92
|
|
|
@@ -93,12 +95,12 @@ const isApiOrderItemInfo = (data: unknown): data is ApiOrderItemInfo => {
|
|
|
93
95
|
|
|
94
96
|
export const isApiOrderResponseAttributes = (data: unknown): data is ApiOrderResponseAttributes => {
|
|
95
97
|
if (data == null || typeof data !== 'object') {
|
|
96
|
-
|
|
98
|
+
logger.logError('Order response attributes must be an object', undefined, { data });
|
|
97
99
|
return false;
|
|
98
100
|
}
|
|
99
101
|
|
|
100
102
|
if (!hasPropertyOfType(data, 'created_at', 'string')) {
|
|
101
|
-
|
|
103
|
+
logger.logError(
|
|
102
104
|
'Order response attributes must have a created_at property and have type string',
|
|
103
105
|
undefined,
|
|
104
106
|
{
|
|
@@ -109,7 +111,7 @@ export const isApiOrderResponseAttributes = (data: unknown): data is ApiOrderRes
|
|
|
109
111
|
}
|
|
110
112
|
|
|
111
113
|
if (!hasPropertyOfType(data, 'latest_event_date', 'string')) {
|
|
112
|
-
|
|
114
|
+
logger.logError(
|
|
113
115
|
'Order response attributes must have a latest_event_date property and have type string',
|
|
114
116
|
undefined,
|
|
115
117
|
{
|
|
@@ -123,7 +125,7 @@ export const isApiOrderResponseAttributes = (data: unknown): data is ApiOrderRes
|
|
|
123
125
|
!hasPropertyOfType(data, 'line_items', 'array') ||
|
|
124
126
|
!data.line_items.every((item: unknown) => isApiOrderItemInfo(item))
|
|
125
127
|
) {
|
|
126
|
-
|
|
128
|
+
logger.logError(
|
|
127
129
|
'Order response attributes must have a line_items property with at least one order item',
|
|
128
130
|
undefined,
|
|
129
131
|
{
|
|
@@ -134,7 +136,7 @@ export const isApiOrderResponseAttributes = (data: unknown): data is ApiOrderRes
|
|
|
134
136
|
}
|
|
135
137
|
|
|
136
138
|
if (!hasPropertyOfType(data, 'order_id', 'string')) {
|
|
137
|
-
|
|
139
|
+
logger.logError(
|
|
138
140
|
'Order response attributes must have an order_id property and have type string',
|
|
139
141
|
undefined,
|
|
140
142
|
{
|
|
@@ -145,7 +147,7 @@ export const isApiOrderResponseAttributes = (data: unknown): data is ApiOrderRes
|
|
|
145
147
|
}
|
|
146
148
|
|
|
147
149
|
if (!hasPropertyOfType(data, 'order_number', 'string')) {
|
|
148
|
-
|
|
150
|
+
logger.logError(
|
|
149
151
|
'Order response attributes must have an order_number property and have type string',
|
|
150
152
|
undefined,
|
|
151
153
|
{
|
|
@@ -15,22 +15,20 @@ interface ApiOrgConfigResults {
|
|
|
15
15
|
org: ApiOrgConfigOrganizationSettings;
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
+
const logger = new Logger('isApiOrgConfigResults');
|
|
19
|
+
|
|
18
20
|
const isApiOrgConfigExperiment = (data: unknown): data is ApiOrgConfigExperiment => {
|
|
19
21
|
if (data == null || typeof data !== 'object') {
|
|
20
|
-
|
|
22
|
+
logger.logDebug('isApiOrgConfigExperiment: data is not an object', undefined, {
|
|
21
23
|
data,
|
|
22
24
|
});
|
|
23
25
|
return false;
|
|
24
26
|
}
|
|
25
27
|
|
|
26
28
|
if ('group' in data && typeof data.group !== 'string' && data.group !== undefined) {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
{
|
|
31
|
-
data,
|
|
32
|
-
},
|
|
33
|
-
);
|
|
29
|
+
logger.logDebug('isApiOrgConfigExperiment: group is not a string or undefined', undefined, {
|
|
30
|
+
data,
|
|
31
|
+
});
|
|
34
32
|
return false;
|
|
35
33
|
}
|
|
36
34
|
|
|
@@ -39,28 +37,28 @@ const isApiOrgConfigExperiment = (data: unknown): data is ApiOrgConfigExperiment
|
|
|
39
37
|
typeof data.group_name !== 'string' &&
|
|
40
38
|
data.group_name !== undefined
|
|
41
39
|
) {
|
|
42
|
-
|
|
40
|
+
logger.logDebug('isApiOrgConfigExperiment: group_name is not a string', undefined, {
|
|
43
41
|
data,
|
|
44
42
|
});
|
|
45
43
|
return false;
|
|
46
44
|
}
|
|
47
45
|
|
|
48
46
|
if ('name' in data && typeof data.name !== 'string' && data.name !== undefined) {
|
|
49
|
-
|
|
47
|
+
logger.logDebug('isApiOrgConfigExperiment: name is not a string', undefined, {
|
|
50
48
|
data,
|
|
51
49
|
});
|
|
52
50
|
return false;
|
|
53
51
|
}
|
|
54
52
|
|
|
55
53
|
if ('rule_id' in data && typeof data.rule_id !== 'string' && data.rule_id !== undefined) {
|
|
56
|
-
|
|
54
|
+
logger.logDebug('isApiOrgConfigExperiment: rule_id is not a string', undefined, {
|
|
57
55
|
data,
|
|
58
56
|
});
|
|
59
57
|
return false;
|
|
60
58
|
}
|
|
61
59
|
|
|
62
60
|
if ('value' in data && typeof data.value !== 'object' && data.value !== undefined) {
|
|
63
|
-
|
|
61
|
+
logger.logDebug('isApiOrgConfigExperiment: value is not an object', undefined, {
|
|
64
62
|
data,
|
|
65
63
|
});
|
|
66
64
|
return false;
|
|
@@ -71,28 +69,28 @@ const isApiOrgConfigExperiment = (data: unknown): data is ApiOrgConfigExperiment
|
|
|
71
69
|
|
|
72
70
|
const isApiOrgConfigFeatureGate = (data: unknown): data is ApiOrgConfigFeatureGate => {
|
|
73
71
|
if (data == null || typeof data !== 'object') {
|
|
74
|
-
|
|
72
|
+
logger.logDebug('isApiOrgConfigFeatureGate: data is not an object', undefined, {
|
|
75
73
|
data,
|
|
76
74
|
});
|
|
77
75
|
return false;
|
|
78
76
|
}
|
|
79
77
|
|
|
80
78
|
if ('name' in data && typeof data.name !== 'string' && data.name !== undefined) {
|
|
81
|
-
|
|
79
|
+
logger.logDebug('isApiOrgConfigFeatureGate: name is not a string', undefined, {
|
|
82
80
|
data,
|
|
83
81
|
});
|
|
84
82
|
return false;
|
|
85
83
|
}
|
|
86
84
|
|
|
87
85
|
if ('rule_id' in data && typeof data.rule_id !== 'string' && data.rule_id !== undefined) {
|
|
88
|
-
|
|
86
|
+
logger.logDebug('isApiOrgConfigFeatureGate: rule_id is not a string', undefined, {
|
|
89
87
|
data,
|
|
90
88
|
});
|
|
91
89
|
return false;
|
|
92
90
|
}
|
|
93
91
|
|
|
94
92
|
if ('value' in data && typeof data.value !== 'boolean' && data.value !== undefined) {
|
|
95
|
-
|
|
93
|
+
logger.logDebug('isApiOrgConfigFeatureGate: value is not a boolean', undefined, {
|
|
96
94
|
data,
|
|
97
95
|
});
|
|
98
96
|
return false;
|
|
@@ -103,35 +101,35 @@ const isApiOrgConfigFeatureGate = (data: unknown): data is ApiOrgConfigFeatureGa
|
|
|
103
101
|
|
|
104
102
|
const isApiOrganization = (data: unknown): data is ApiOrganization => {
|
|
105
103
|
if (data == null || typeof data !== 'object') {
|
|
106
|
-
|
|
104
|
+
logger.logDebug('isApiOrganization: data is not an object', undefined, {
|
|
107
105
|
data,
|
|
108
106
|
});
|
|
109
107
|
return false;
|
|
110
108
|
}
|
|
111
109
|
|
|
112
110
|
if (!('id' in data) || typeof data.id !== 'string') {
|
|
113
|
-
|
|
111
|
+
logger.logDebug('isApiOrganization: id is not a string', undefined, {
|
|
114
112
|
data,
|
|
115
113
|
});
|
|
116
114
|
return false;
|
|
117
115
|
}
|
|
118
116
|
|
|
119
117
|
if (!('display_name' in data) || typeof data.display_name !== 'string') {
|
|
120
|
-
|
|
118
|
+
logger.logDebug('isApiOrganization: display_name is not a string', undefined, {
|
|
121
119
|
data,
|
|
122
120
|
});
|
|
123
121
|
return false;
|
|
124
122
|
}
|
|
125
123
|
|
|
126
124
|
if (!('domain' in data) || typeof data.domain !== 'string') {
|
|
127
|
-
|
|
125
|
+
logger.logDebug('isApiOrganization: domain is not a string', undefined, {
|
|
128
126
|
data,
|
|
129
127
|
});
|
|
130
128
|
return false;
|
|
131
129
|
}
|
|
132
130
|
|
|
133
131
|
if (!('short_name' in data) || typeof data.short_name !== 'string') {
|
|
134
|
-
|
|
132
|
+
logger.logDebug('isApiOrganization: short_name is not a string', undefined, {
|
|
135
133
|
data,
|
|
136
134
|
});
|
|
137
135
|
return false;
|
|
@@ -141,8 +139,8 @@ const isApiOrganization = (data: unknown): data is ApiOrganization => {
|
|
|
141
139
|
!('status' in data) ||
|
|
142
140
|
!Object.values(OrganizationStatusEnum).includes(data.status as OrganizationStatusEnum)
|
|
143
141
|
) {
|
|
144
|
-
|
|
145
|
-
'
|
|
142
|
+
logger.logDebug(
|
|
143
|
+
'isApiOrganization: status is not a valid OrganizationStatusEnum value',
|
|
146
144
|
undefined,
|
|
147
145
|
{
|
|
148
146
|
data,
|
|
@@ -157,7 +155,7 @@ const isApiOrganization = (data: unknown): data is ApiOrganization => {
|
|
|
157
155
|
typeof data.created_at !== 'string' &&
|
|
158
156
|
data.created_at !== undefined
|
|
159
157
|
) {
|
|
160
|
-
|
|
158
|
+
logger.logDebug('isApiOrganization: created_at is not a Date', undefined, {
|
|
161
159
|
data,
|
|
162
160
|
});
|
|
163
161
|
return false;
|
|
@@ -169,7 +167,7 @@ const isApiOrganization = (data: unknown): data is ApiOrganization => {
|
|
|
169
167
|
typeof data.updated_at !== 'string' &&
|
|
170
168
|
data.updated_at !== undefined
|
|
171
169
|
) {
|
|
172
|
-
|
|
170
|
+
logger.logDebug('isApiOrganization: updated_at is not a Date', undefined, {
|
|
173
171
|
data,
|
|
174
172
|
});
|
|
175
173
|
return false;
|
|
@@ -182,24 +180,16 @@ const isApiOrgConfigOrganizationSettings = (
|
|
|
182
180
|
data: unknown,
|
|
183
181
|
): data is ApiOrgConfigOrganizationSettings => {
|
|
184
182
|
if (data == null || typeof data !== 'object') {
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
{
|
|
189
|
-
data,
|
|
190
|
-
},
|
|
191
|
-
);
|
|
183
|
+
logger.logDebug('isApiOrgConfigOrganizationSettings: data is not an object', undefined, {
|
|
184
|
+
data,
|
|
185
|
+
});
|
|
192
186
|
return false;
|
|
193
187
|
}
|
|
194
188
|
|
|
195
189
|
if (!('org' in data) || !isApiOrganization(data.org)) {
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
{
|
|
200
|
-
data,
|
|
201
|
-
},
|
|
202
|
-
);
|
|
190
|
+
logger.logDebug('isApiOrgConfigOrganizationSettings: org is not an object', undefined, {
|
|
191
|
+
data,
|
|
192
|
+
});
|
|
203
193
|
return false;
|
|
204
194
|
}
|
|
205
195
|
|
|
@@ -215,7 +205,7 @@ const isApiOrgConfigOrganizationSettings = (
|
|
|
215
205
|
*/
|
|
216
206
|
export const isApiOrgConfigResults = (data: unknown): data is Required<ApiOrgConfigResults> => {
|
|
217
207
|
if (data == null || typeof data !== 'object') {
|
|
218
|
-
|
|
208
|
+
logger.logDebug('isApiOrgConfigResults: data is not an object', undefined, {
|
|
219
209
|
data,
|
|
220
210
|
});
|
|
221
211
|
return false;
|
|
@@ -226,7 +216,7 @@ export const isApiOrgConfigResults = (data: unknown): data is Required<ApiOrgCon
|
|
|
226
216
|
!Array.isArray(data.configs) ||
|
|
227
217
|
!data.configs.every(config => isApiOrganizationConfig(config))
|
|
228
218
|
) {
|
|
229
|
-
|
|
219
|
+
logger.logDebug('isApiOrgConfigResults: configs is not an array', undefined, {
|
|
230
220
|
data,
|
|
231
221
|
});
|
|
232
222
|
return false;
|
|
@@ -238,8 +228,8 @@ export const isApiOrgConfigResults = (data: unknown): data is Required<ApiOrgCon
|
|
|
238
228
|
(!Array.isArray(data.experiments) ||
|
|
239
229
|
!data.experiments.every(exp => isApiOrgConfigExperiment(exp)))
|
|
240
230
|
) {
|
|
241
|
-
|
|
242
|
-
'
|
|
231
|
+
logger.logDebug(
|
|
232
|
+
'isApiOrgConfigResults: experiments is not an array or contains invalid items',
|
|
243
233
|
undefined,
|
|
244
234
|
{
|
|
245
235
|
data,
|
|
@@ -253,8 +243,8 @@ export const isApiOrgConfigResults = (data: unknown): data is Required<ApiOrgCon
|
|
|
253
243
|
!Array.isArray(data.gates) ||
|
|
254
244
|
!data.gates.every(gate => isApiOrgConfigFeatureGate(gate))
|
|
255
245
|
) {
|
|
256
|
-
|
|
257
|
-
'
|
|
246
|
+
logger.logDebug(
|
|
247
|
+
'isApiOrgConfigResults: gates is not an array or contains invalid items',
|
|
258
248
|
undefined,
|
|
259
249
|
{
|
|
260
250
|
data,
|
|
@@ -264,10 +254,12 @@ export const isApiOrgConfigResults = (data: unknown): data is Required<ApiOrgCon
|
|
|
264
254
|
}
|
|
265
255
|
|
|
266
256
|
if (!('org' in data) || !isApiOrgConfigOrganizationSettings(data.org)) {
|
|
267
|
-
|
|
268
|
-
'
|
|
257
|
+
logger.logDebug(
|
|
258
|
+
'isApiOrgConfigResults: org is not an object or has invalid fields',
|
|
269
259
|
undefined,
|
|
270
|
-
{
|
|
260
|
+
{
|
|
261
|
+
data,
|
|
262
|
+
},
|
|
271
263
|
);
|
|
272
264
|
|
|
273
265
|
return false;
|
|
@@ -28,17 +28,19 @@ export interface ApiOrganizationConfig extends OrganizationConfig {
|
|
|
28
28
|
config: ApiOrgAnalyticsConfig;
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
+
const logger = new Logger('isApiOrganizationConfig');
|
|
32
|
+
|
|
31
33
|
const isApiOrgAnalyticsConfigAmplitude = (
|
|
32
34
|
data: unknown,
|
|
33
35
|
): data is ApiOrgAnalyticsConfigAmplitude => {
|
|
34
36
|
if (data == null || typeof data !== 'object') {
|
|
35
|
-
|
|
37
|
+
logger.logDebug('isApiOrgAnalyticsConfigAmplitude: data is not an object', data);
|
|
36
38
|
return false;
|
|
37
39
|
}
|
|
38
40
|
|
|
39
41
|
if (!('session_replay_enabled' in data) || typeof data.session_replay_enabled !== 'boolean') {
|
|
40
|
-
|
|
41
|
-
'
|
|
42
|
+
logger.logDebug(
|
|
43
|
+
'isApiOrgAnalyticsConfigAmplitude: session_replay_enabled is not a boolean',
|
|
42
44
|
data,
|
|
43
45
|
);
|
|
44
46
|
return false;
|
|
@@ -48,18 +50,15 @@ const isApiOrgAnalyticsConfigAmplitude = (
|
|
|
48
50
|
!('session_replay_sample_rate' in data) ||
|
|
49
51
|
typeof data.session_replay_sample_rate !== 'number'
|
|
50
52
|
) {
|
|
51
|
-
|
|
52
|
-
'
|
|
53
|
+
logger.logDebug(
|
|
54
|
+
'isApiOrgAnalyticsConfigAmplitude: session_replay_sample_rate is not a number',
|
|
53
55
|
data,
|
|
54
56
|
);
|
|
55
57
|
return false;
|
|
56
58
|
}
|
|
57
59
|
|
|
58
60
|
if (!('tracking_enabled' in data) || typeof data.tracking_enabled !== 'boolean') {
|
|
59
|
-
|
|
60
|
-
'[spiffy-ai] isApiOrgAnalyticsConfigAmplitude: tracking_enabled is not a boolean',
|
|
61
|
-
data,
|
|
62
|
-
);
|
|
61
|
+
logger.logDebug('isApiOrgAnalyticsConfigAmplitude: tracking_enabled is not a boolean', data);
|
|
63
62
|
return false;
|
|
64
63
|
}
|
|
65
64
|
|
|
@@ -70,18 +69,12 @@ const isApiOrgAnalyticsConfigCustomerService = (
|
|
|
70
69
|
data: unknown,
|
|
71
70
|
): data is ApiOrgAnalyticsConfigCustomerService => {
|
|
72
71
|
if (data == null || typeof data !== 'object') {
|
|
73
|
-
|
|
74
|
-
'[spiffy-ai] isApiOrgAnalyticsConfigCustomerService: data is not an object',
|
|
75
|
-
data,
|
|
76
|
-
);
|
|
72
|
+
logger.logDebug('isApiOrgAnalyticsConfigCustomerService: data is not an object', data);
|
|
77
73
|
return false;
|
|
78
74
|
}
|
|
79
75
|
|
|
80
76
|
if (!('provider' in data) || typeof data.provider !== 'string') {
|
|
81
|
-
|
|
82
|
-
'[spiffy-ai] isApiOrgAnalyticsConfigCustomerService: provider is not a string',
|
|
83
|
-
data,
|
|
84
|
-
);
|
|
77
|
+
logger.logDebug('isApiOrgAnalyticsConfigCustomerService: provider is not a string', data);
|
|
85
78
|
return false;
|
|
86
79
|
}
|
|
87
80
|
|
|
@@ -92,18 +85,12 @@ const isApiOrgAnalyticsConfigGoogleAnalytics = (
|
|
|
92
85
|
data: unknown,
|
|
93
86
|
): data is ApiOrgAnalyticsConfigGoogleAnalytics => {
|
|
94
87
|
if (data == null || typeof data !== 'object') {
|
|
95
|
-
|
|
96
|
-
'[spiffy-ai] isApiOrgAnalyticsConfigGoogleAnalytics: data is not an object',
|
|
97
|
-
data,
|
|
98
|
-
);
|
|
88
|
+
logger.logDebug('isApiOrgAnalyticsConfigGoogleAnalytics: data is not an object', data);
|
|
99
89
|
return false;
|
|
100
90
|
}
|
|
101
91
|
|
|
102
92
|
if (!('measurement_id' in data) || typeof data.measurement_id !== 'string') {
|
|
103
|
-
|
|
104
|
-
'[spiffy-ai] isApiOrgAnalyticsConfigGoogleAnalytics: measurement_id is not a string',
|
|
105
|
-
data,
|
|
106
|
-
);
|
|
93
|
+
logger.logDebug('isApiOrgAnalyticsConfigGoogleAnalytics: measurement_id is not a string', data);
|
|
107
94
|
return false;
|
|
108
95
|
}
|
|
109
96
|
|
|
@@ -117,12 +104,12 @@ const isApiOrgAnalyticsConfigGoogleAnalytics = (
|
|
|
117
104
|
*/
|
|
118
105
|
const isApiOrgAnalyticsConfig = (data: unknown): data is ApiOrgAnalyticsConfig => {
|
|
119
106
|
if (data == null || typeof data !== 'object') {
|
|
120
|
-
|
|
107
|
+
logger.logDebug('isOrgAnalyticsConfig: data is not an object', data);
|
|
121
108
|
return false;
|
|
122
109
|
}
|
|
123
110
|
|
|
124
111
|
if ('amplitude' in data && !isApiOrgAnalyticsConfigAmplitude(data.amplitude)) {
|
|
125
|
-
|
|
112
|
+
logger.logDebug('isOrgAnalyticsConfig: amplitude is not an object', data);
|
|
126
113
|
return false;
|
|
127
114
|
}
|
|
128
115
|
|
|
@@ -130,7 +117,7 @@ const isApiOrgAnalyticsConfig = (data: unknown): data is ApiOrgAnalyticsConfig =
|
|
|
130
117
|
'customer_service' in data &&
|
|
131
118
|
!isApiOrgAnalyticsConfigCustomerService(data.customer_service)
|
|
132
119
|
) {
|
|
133
|
-
|
|
120
|
+
logger.logDebug('isOrgAnalyticsConfig: customer_service is not an object', data);
|
|
134
121
|
return false;
|
|
135
122
|
}
|
|
136
123
|
|
|
@@ -138,7 +125,7 @@ const isApiOrgAnalyticsConfig = (data: unknown): data is ApiOrgAnalyticsConfig =
|
|
|
138
125
|
'google_analytics' in data &&
|
|
139
126
|
!isApiOrgAnalyticsConfigGoogleAnalytics(data.google_analytics)
|
|
140
127
|
) {
|
|
141
|
-
|
|
128
|
+
logger.logDebug('isOrgAnalyticsConfig: google_analytics is not an object', data);
|
|
142
129
|
return false;
|
|
143
130
|
}
|
|
144
131
|
|
|
@@ -152,32 +139,32 @@ const isApiOrgAnalyticsConfig = (data: unknown): data is ApiOrgAnalyticsConfig =
|
|
|
152
139
|
*/
|
|
153
140
|
export const isApiOrganizationConfig = (data: unknown): data is ApiOrganizationConfig => {
|
|
154
141
|
if (data == null || typeof data !== 'object') {
|
|
155
|
-
|
|
142
|
+
logger.logDebug('isOrgConfig: data is not an object', data);
|
|
156
143
|
return false;
|
|
157
144
|
}
|
|
158
145
|
|
|
159
146
|
if (!('created_at' in data)) {
|
|
160
|
-
|
|
147
|
+
logger.logDebug('isOrgConfig: created_at is not defined', data);
|
|
161
148
|
return false;
|
|
162
149
|
}
|
|
163
150
|
|
|
164
151
|
if (!('namespace' in data) || typeof data.namespace !== 'string') {
|
|
165
|
-
|
|
152
|
+
logger.logDebug('isOrgConfig: namespace is not a string', data);
|
|
166
153
|
return false;
|
|
167
154
|
}
|
|
168
155
|
|
|
169
156
|
if (!('is_latest' in data) || typeof data.is_latest !== 'boolean') {
|
|
170
|
-
|
|
157
|
+
logger.logDebug('isOrgConfig: is_latest is not a boolean', data);
|
|
171
158
|
return false;
|
|
172
159
|
}
|
|
173
160
|
|
|
174
161
|
if (!('version' in data) || typeof data.version !== 'string') {
|
|
175
|
-
|
|
162
|
+
logger.logDebug('isOrgConfig: version is not a string', data);
|
|
176
163
|
return false;
|
|
177
164
|
}
|
|
178
165
|
|
|
179
166
|
if (!('updated_at' in data)) {
|
|
180
|
-
|
|
167
|
+
logger.logDebug('isOrgConfig: updated_at is not defined', data);
|
|
181
168
|
return false;
|
|
182
169
|
}
|
|
183
170
|
|
|
@@ -186,17 +173,17 @@ export const isApiOrganizationConfig = (data: unknown): data is ApiOrganizationC
|
|
|
186
173
|
typeof data.config !== 'object' ||
|
|
187
174
|
!isApiOrgAnalyticsConfig(data.config)
|
|
188
175
|
) {
|
|
189
|
-
|
|
176
|
+
logger.logDebug('isOrgConfig: config is not an object', data);
|
|
190
177
|
return false;
|
|
191
178
|
}
|
|
192
179
|
|
|
193
180
|
if ('organization_id' in data && typeof data.organization_id !== 'string') {
|
|
194
|
-
|
|
181
|
+
logger.logDebug('isOrgConfig: organization_id is not a string', data);
|
|
195
182
|
return false;
|
|
196
183
|
}
|
|
197
184
|
|
|
198
185
|
if ('id' in data && typeof data.id !== 'string') {
|
|
199
|
-
|
|
186
|
+
logger.logDebug('isOrgConfig: id is not a string', data);
|
|
200
187
|
return false;
|
|
201
188
|
}
|
|
202
189
|
|
|
@@ -2,11 +2,13 @@ import Logger from 'src/application/logging/logger';
|
|
|
2
2
|
import { ResponseProductAttributes } from '@spiffy-ai/commerce-api-client';
|
|
3
3
|
import { hasPropertyOfType } from '../utils';
|
|
4
4
|
|
|
5
|
+
const logger = new Logger('isApiProductResponseAttributes');
|
|
6
|
+
|
|
5
7
|
export const isApiProductResponseAttributes = (
|
|
6
8
|
attributes: unknown,
|
|
7
9
|
): attributes is ResponseProductAttributes => {
|
|
8
10
|
if (attributes == null || typeof attributes !== 'object') {
|
|
9
|
-
|
|
11
|
+
logger.logError(
|
|
10
12
|
'isApiProductResponseAttributes: attributes is null or not an object',
|
|
11
13
|
undefined,
|
|
12
14
|
{
|
|
@@ -17,63 +19,63 @@ export const isApiProductResponseAttributes = (
|
|
|
17
19
|
}
|
|
18
20
|
|
|
19
21
|
if (!hasPropertyOfType(attributes, 'description', 'string', true)) {
|
|
20
|
-
|
|
22
|
+
logger.logError('isApiProductResponseAttributes: description is not a string', undefined, {
|
|
21
23
|
attributes,
|
|
22
24
|
});
|
|
23
25
|
return false;
|
|
24
26
|
}
|
|
25
27
|
|
|
26
28
|
if (!hasPropertyOfType(attributes, 'image_url', 'string', true)) {
|
|
27
|
-
|
|
29
|
+
logger.logError('isApiProductResponseAttributes: image_url is not a string', undefined, {
|
|
28
30
|
attributes,
|
|
29
31
|
});
|
|
30
32
|
return false;
|
|
31
33
|
}
|
|
32
34
|
|
|
33
35
|
if (!hasPropertyOfType(attributes, 'title', 'string')) {
|
|
34
|
-
|
|
36
|
+
logger.logError('isApiProductResponseAttributes: title is not a string', undefined, {
|
|
35
37
|
attributes,
|
|
36
38
|
});
|
|
37
39
|
return false;
|
|
38
40
|
}
|
|
39
41
|
|
|
40
42
|
if (!hasPropertyOfType(attributes, 'url', 'string')) {
|
|
41
|
-
|
|
43
|
+
logger.logError('isApiProductResponseAttributes: url is not a string', undefined, {
|
|
42
44
|
attributes,
|
|
43
45
|
});
|
|
44
46
|
return false;
|
|
45
47
|
}
|
|
46
48
|
|
|
47
49
|
if (!hasPropertyOfType(attributes, 'original_price', 'number', true)) {
|
|
48
|
-
|
|
50
|
+
logger.logError('isApiProductResponseAttributes: original_price is not a number', undefined, {
|
|
49
51
|
attributes,
|
|
50
52
|
});
|
|
51
53
|
return false;
|
|
52
54
|
}
|
|
53
55
|
|
|
54
56
|
if (!hasPropertyOfType(attributes, 'sale_price', 'number', true)) {
|
|
55
|
-
|
|
57
|
+
logger.logError('isApiProductResponseAttributes: sale_price is not a number', undefined, {
|
|
56
58
|
attributes,
|
|
57
59
|
});
|
|
58
60
|
return false;
|
|
59
61
|
}
|
|
60
62
|
|
|
61
63
|
if (!hasPropertyOfType(attributes, 'average_rating', 'number', true)) {
|
|
62
|
-
|
|
64
|
+
logger.logError('isApiProductResponseAttributes: average_rating is not a number', undefined, {
|
|
63
65
|
attributes,
|
|
64
66
|
});
|
|
65
67
|
return false;
|
|
66
68
|
}
|
|
67
69
|
|
|
68
70
|
if (!hasPropertyOfType(attributes, 'number_reviews', 'number', true)) {
|
|
69
|
-
|
|
71
|
+
logger.logError('isApiProductResponseAttributes: number_reviews is not a number', undefined, {
|
|
70
72
|
attributes,
|
|
71
73
|
});
|
|
72
74
|
return false;
|
|
73
75
|
}
|
|
74
76
|
|
|
75
77
|
if (!hasPropertyOfType(attributes, 'metadata', 'array', true)) {
|
|
76
|
-
|
|
78
|
+
logger.logError('isApiProductResponseAttributes: metadata is not an array', undefined, {
|
|
77
79
|
attributes,
|
|
78
80
|
});
|
|
79
81
|
return false;
|