@coveo/headless 3.29.2-pre.326946f8df → 3.29.2-pre.34abdcbabf
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/cjs/case-assist/headless.cjs +1 -1
- package/dist/cjs/commerce/headless.cjs +1 -1
- package/dist/cjs/headless.cjs +1 -1
- package/dist/cjs/insight/headless.cjs +1 -1
- package/dist/cjs/recommendation/headless.cjs +1 -1
- package/dist/cjs/ssr/headless.cjs +1 -1
- package/dist/cjs/ssr-commerce/headless.cjs +1 -1
- package/dist/cjs/ssr-commerce-next/headless.cjs +1 -1
- package/dist/cjs/ssr-next/headless.cjs +1 -1
- package/dist/definitions/ssr-next/commerce/controller-utils.d.ts +7 -5
- package/dist/definitions/ssr-next/commerce/controllers/recommendations/headless-recommendations.ssr.d.ts +8 -4
- package/dist/definitions/ssr-next/commerce/factories/build-factory.d.ts +5 -4
- package/dist/definitions/ssr-next/commerce/factories/hydrated-state-factory.d.ts +5 -2
- package/dist/definitions/ssr-next/commerce/factories/recommendation-hydrated-state-factory.d.ts +3 -1
- package/dist/definitions/ssr-next/commerce/factories/recommendation-static-state-factory.d.ts +12 -2
- package/dist/definitions/ssr-next/commerce/factories/static-state-factory.d.ts +7 -2
- package/dist/definitions/ssr-next/commerce/types/build.d.ts +55 -10
- package/dist/definitions/ssr-next/commerce/types/controller-definitions.d.ts +4 -119
- package/dist/definitions/ssr-next/commerce/types/controller-inference.d.ts +3 -3
- package/dist/definitions/ssr-next/commerce/types/engine.d.ts +5 -12
- package/dist/definitions/ssr-next/commerce/types/fetch-static-state.d.ts +1 -1
- package/dist/definitions/ssr-next/commerce/types/hydrate-static-state.d.ts +1 -1
- package/dist/definitions/ssr-next/commerce/utils/controller-wiring.d.ts +4 -7
- package/dist/definitions/ssr-next/commerce/utils/recommendation-filter.d.ts +15 -2
- package/dist/definitions/ssr-next/common/types/utilities.d.ts +0 -3
- package/dist/definitions/test/mock-ssr-controller-definitions.d.ts +12 -0
- package/dist/esm/ssr-next/commerce/controllers/recommendations/headless-recommendations.ssr.js +1 -1
- package/dist/esm/ssr-next/commerce/factories/build-factory.js +12 -11
- package/dist/esm/ssr-next/commerce/factories/hydrated-state-factory.js +0 -3
- package/dist/esm/ssr-next/commerce/factories/recommendation-hydrated-state-factory.js +1 -4
- package/dist/esm/ssr-next/commerce/factories/recommendation-static-state-factory.js +2 -11
- package/dist/esm/ssr-next/commerce/utils/controller-wiring.js +32 -15
- package/dist/esm/ssr-next/commerce/utils/recommendation-filter.js +27 -8
- package/dist/esm/test/mock-ssr-controller-definitions.js +15 -0
- package/dist/esm/utils/version.js +1 -1
- package/dist/quantic/case-assist/headless.js +1 -1
- package/dist/quantic/commerce/headless.js +1 -1
- package/dist/quantic/headless.js +1 -1
- package/dist/quantic/insight/headless.js +1 -1
- package/dist/quantic/recommendation/headless.js +1 -1
- package/package.json +1 -1
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { SearchEngine } from '../app/search-engine/search-engine.js';
|
|
2
2
|
import type { Controller } from '../controllers/controller/headless-controller.js';
|
|
3
3
|
import type { Kind } from '../ssr/commerce/types/kind.js';
|
|
4
|
+
import { recommendationInternalOptionKey } from '../ssr-next/commerce/types/controller-constants.js';
|
|
4
5
|
import type { ControllerDefinitionWithoutProps, ControllerDefinitionWithProps } from '../ssr-next/common/types/controllers.js';
|
|
5
6
|
interface MockController {
|
|
6
7
|
initialState?: Record<string, unknown>;
|
|
@@ -35,4 +36,15 @@ export declare function defineMockCommerceControllerWithProps(options?: Solution
|
|
|
35
36
|
standalone: boolean;
|
|
36
37
|
recommendation: boolean;
|
|
37
38
|
};
|
|
39
|
+
export declare function defineMockRecommendationDefinition(slotId: string): {
|
|
40
|
+
recommendation: boolean;
|
|
41
|
+
[recommendationInternalOptionKey]: {
|
|
42
|
+
slotId: string;
|
|
43
|
+
};
|
|
44
|
+
buildWithProps: import("vitest").Mock<(engine: any, props: any) => {
|
|
45
|
+
state: {};
|
|
46
|
+
subscribe(listener: () => void): import("redux").Unsubscribe;
|
|
47
|
+
_kind: Kind;
|
|
48
|
+
}>;
|
|
49
|
+
};
|
|
38
50
|
export {};
|
package/dist/esm/ssr-next/commerce/controllers/recommendations/headless-recommendations.ssr.js
CHANGED
|
@@ -17,7 +17,7 @@ export function defineRecommendations(props) {
|
|
|
17
17
|
buildWithProps: (engine, options) => {
|
|
18
18
|
const staticOptions = props.options;
|
|
19
19
|
const controller = buildRecommendations(engine, {
|
|
20
|
-
options: { ...staticOptions, ...options },
|
|
20
|
+
options: { ...staticOptions, ...options.initialState },
|
|
21
21
|
});
|
|
22
22
|
return createControllerWithKind(controller, Kind.Recommendations);
|
|
23
23
|
},
|
|
@@ -57,34 +57,35 @@ function buildSSRCommerceEngine(solutionType, options, recommendationCount) {
|
|
|
57
57
|
},
|
|
58
58
|
};
|
|
59
59
|
}
|
|
60
|
-
function fetchActiveRecommendationControllers(controllerProps, solutionType) {
|
|
61
|
-
return solutionType === SolutionType.recommendation
|
|
62
|
-
? Object.values(controllerProps).filter((controller) => controller &&
|
|
63
|
-
typeof controller === 'object' &&
|
|
64
|
-
'enabled' in controller &&
|
|
65
|
-
controller.enabled).length
|
|
66
|
-
: 0;
|
|
67
|
-
}
|
|
68
60
|
export const buildFactory = (controllerDefinitions, options) => (solutionType) => async (...[buildOptions]) => {
|
|
69
61
|
const controllerProps = wireControllerParams(solutionType, controllerDefinitions, buildOptions); // TODO: KIT-4754: remove non-null assertion operator
|
|
70
62
|
const logger = buildLogger(options.loggerOptions);
|
|
71
63
|
if (!options.navigatorContextProvider) {
|
|
72
64
|
logger.warn('[WARNING] Missing navigator context in server-side code. Make sure to set it with `setNavigatorContextProvider` before calling fetchStaticState()');
|
|
73
65
|
}
|
|
74
|
-
const enabledRecommendationControllers =
|
|
66
|
+
const enabledRecommendationControllers = buildOptions && 'recommendations' in buildOptions // TODO: KIT-4754: remove non-null assertion
|
|
67
|
+
? buildOptions
|
|
68
|
+
?.recommendations.length
|
|
69
|
+
: 0;
|
|
75
70
|
const engineOptions = {
|
|
76
71
|
...options,
|
|
77
72
|
configuration: extendEngineConfiguration(options.configuration, buildOptions), // TODO: KIT-4754: remove non-null assertion operator
|
|
78
73
|
};
|
|
79
74
|
const engine = buildSSRCommerceEngine(solutionType, engineOptions, enabledRecommendationControllers);
|
|
80
75
|
const controllers = buildControllerDefinitions({
|
|
81
|
-
definitionsMap:
|
|
76
|
+
definitionsMap: controllerDefinitions ?? {},
|
|
82
77
|
engine,
|
|
83
78
|
solutionType,
|
|
84
79
|
propsMap: controllerProps,
|
|
85
80
|
});
|
|
81
|
+
// If searchActions are provided (hydrate scenario), dispatch them
|
|
82
|
+
if (buildOptions && 'searchActions' in buildOptions) {
|
|
83
|
+
buildOptions.searchActions.forEach((action) => {
|
|
84
|
+
engine.dispatch(action);
|
|
85
|
+
});
|
|
86
|
+
}
|
|
86
87
|
return {
|
|
87
88
|
engine,
|
|
88
|
-
controllers,
|
|
89
|
+
controllers: controllers,
|
|
89
90
|
};
|
|
90
91
|
};
|
|
@@ -3,9 +3,6 @@ export function hydratedStaticStateFactory(controllerDefinitions, options) {
|
|
|
3
3
|
return (solutionType) => async (...params) => {
|
|
4
4
|
const solutionTypeBuild = await buildFactory(controllerDefinitions, options)(solutionType);
|
|
5
5
|
const { engine, controllers } = await solutionTypeBuild(...params);
|
|
6
|
-
params[0].searchActions.forEach((action) => {
|
|
7
|
-
engine.dispatch(action);
|
|
8
|
-
});
|
|
9
6
|
await engine.waitForRequestCompletedAction();
|
|
10
7
|
return { engine, controllers };
|
|
11
8
|
};
|
|
@@ -3,10 +3,7 @@ import { buildFactory, } from './build-factory.js';
|
|
|
3
3
|
export function hydratedRecommendationStaticStateFactory(controllerDefinitions, options) {
|
|
4
4
|
return async (...params) => {
|
|
5
5
|
const solutionTypeBuild = await buildFactory(controllerDefinitions, options)(SolutionType.recommendation);
|
|
6
|
-
const { engine, controllers } =
|
|
7
|
-
params[0].searchActions.forEach((action) => {
|
|
8
|
-
engine.dispatch(action);
|
|
9
|
-
});
|
|
6
|
+
const { engine, controllers } = await solutionTypeBuild(...params);
|
|
10
7
|
await engine.waitForRequestCompletedAction();
|
|
11
8
|
return { engine, controllers };
|
|
12
9
|
};
|
|
@@ -1,22 +1,13 @@
|
|
|
1
|
-
import { filterObject } from '../../../utils/utils.js';
|
|
2
1
|
import { createStaticState } from '../controller-utils.js';
|
|
3
2
|
import { SolutionType } from '../types/controller-constants.js';
|
|
4
3
|
import { filterRecommendationControllers } from '../utils/recommendation-filter.js';
|
|
5
4
|
import { buildFactory, } from './build-factory.js';
|
|
6
5
|
export function fetchRecommendationStaticStateFactory(controllerDefinitions, options) {
|
|
7
|
-
// TODO: KIT-4619: no longer the right way to get the allowed recommendation keys
|
|
8
|
-
const getAllowedRecommendationKeys = (props) => {
|
|
9
|
-
if (props && 'controllers' in props) {
|
|
10
|
-
const enabledRecommendationControllers = filterObject(props.controllers, (value) => Boolean(value.enabled));
|
|
11
|
-
return Object.keys(enabledRecommendationControllers);
|
|
12
|
-
}
|
|
13
|
-
return [];
|
|
14
|
-
};
|
|
15
6
|
return async (...params) => {
|
|
16
7
|
const [props] = params;
|
|
17
|
-
const allowedRecommendationKeys =
|
|
8
|
+
const allowedRecommendationKeys = props?.recommendations;
|
|
18
9
|
const solutionTypeBuild = await buildFactory(controllerDefinitions, options)(SolutionType.recommendation);
|
|
19
|
-
const { engine, controllers } =
|
|
10
|
+
const { engine, controllers } = await solutionTypeBuild(...params);
|
|
20
11
|
filterRecommendationControllers(controllers, controllerDefinitions ?? {}).refresh(allowedRecommendationKeys);
|
|
21
12
|
const searchActions = await Promise.all(engine.waitForRequestCompletedAction());
|
|
22
13
|
const staticState = createStaticState({
|
|
@@ -1,13 +1,9 @@
|
|
|
1
|
-
|
|
2
|
-
* Controller Wiring Utilities
|
|
3
|
-
*
|
|
4
|
-
* Transforms simple user configuration into complex internal controller structures.
|
|
5
|
-
*/
|
|
6
|
-
import { RecordValue, Schema } from '@coveo/bueno';
|
|
1
|
+
import { ArrayValue, RecordValue, Schema, StringValue } from '@coveo/bueno';
|
|
7
2
|
import { contextDefinition } from '../../../features/commerce/context/context-validation.js';
|
|
8
3
|
import { parametersDefinition } from '../../../features/commerce/parameters/parameters-schema.js';
|
|
9
|
-
import { requiredEmptyAllowedString } from '../../../utils/validate-payload.js';
|
|
4
|
+
import { nonEmptyString, requiredEmptyAllowedString, } from '../../../utils/validate-payload.js';
|
|
10
5
|
import { SolutionType } from '../types/controller-constants.js';
|
|
6
|
+
import { getRecommendationDefinitions, isRecommendationDefinition, } from './recommendation-filter.js';
|
|
11
7
|
const requiredDefinition = {
|
|
12
8
|
context: new RecordValue({
|
|
13
9
|
options: { required: true },
|
|
@@ -30,23 +26,31 @@ const searchDefinition = {
|
|
|
30
26
|
values: { query: requiredEmptyAllowedString, ...parametersDefinition },
|
|
31
27
|
}),
|
|
32
28
|
};
|
|
33
|
-
const recommendationsDefinition = {
|
|
29
|
+
const recommendationsDefinition = (recommendationName) => ({
|
|
34
30
|
...requiredDefinition,
|
|
35
|
-
|
|
36
|
-
|
|
31
|
+
recommendations: new ArrayValue({
|
|
32
|
+
each: new StringValue({
|
|
33
|
+
required: true,
|
|
34
|
+
constrainTo: recommendationName,
|
|
35
|
+
emptyAllowed: false,
|
|
36
|
+
}),
|
|
37
|
+
required: true,
|
|
38
|
+
}),
|
|
39
|
+
productId: nonEmptyString,
|
|
40
|
+
});
|
|
37
41
|
export const listingDefinitionSchema = new Schema(listingDefinition);
|
|
38
42
|
export const searchDefinitionSchema = new Schema(searchDefinition);
|
|
39
43
|
export const standaloneDefinitionSchema = new Schema(standaloneDefinition);
|
|
40
|
-
export const recommendationsDefinitionSchema = new Schema(recommendationsDefinition);
|
|
44
|
+
export const recommendationsDefinitionSchema = (recommendationName) => new Schema(recommendationsDefinition(recommendationName));
|
|
41
45
|
/**
|
|
42
46
|
* Validates the build configuration based on the solution type.
|
|
43
47
|
*/
|
|
44
|
-
function validateBuildConfig(solutionType, buildConfig) {
|
|
48
|
+
function validateBuildConfig(solutionType, controllerDefinitions, buildConfig) {
|
|
45
49
|
const validationMap = {
|
|
46
50
|
[SolutionType.listing]: listingDefinitionSchema,
|
|
47
51
|
[SolutionType.search]: searchDefinitionSchema,
|
|
48
52
|
[SolutionType.standalone]: standaloneDefinitionSchema,
|
|
49
|
-
[SolutionType.recommendation]: recommendationsDefinitionSchema,
|
|
53
|
+
[SolutionType.recommendation]: recommendationsDefinitionSchema(Object.keys(getRecommendationDefinitions(controllerDefinitions))),
|
|
50
54
|
};
|
|
51
55
|
const schema = validationMap[solutionType];
|
|
52
56
|
schema.validate(buildConfig);
|
|
@@ -95,7 +99,20 @@ class ControllerWirer {
|
|
|
95
99
|
};
|
|
96
100
|
}
|
|
97
101
|
wireRecommendations() {
|
|
98
|
-
|
|
102
|
+
if (!('recommendations' in this.buildConfig)) {
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
for (const recController in this.controllerDefinitions) {
|
|
106
|
+
if (isRecommendationDefinition(this.controllerDefinitions[recController])) {
|
|
107
|
+
this.controllerProps[recController] = {
|
|
108
|
+
initialState: {
|
|
109
|
+
...('productId' in this.buildConfig && {
|
|
110
|
+
productId: this.buildConfig.productId,
|
|
111
|
+
}),
|
|
112
|
+
},
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
}
|
|
99
116
|
}
|
|
100
117
|
/**
|
|
101
118
|
* Wires all controllers based on solution type and controller definitions.
|
|
@@ -138,7 +155,7 @@ class ControllerWirer {
|
|
|
138
155
|
* @returns Formatted and validated controller properties map defined for the controller in the definition
|
|
139
156
|
*/
|
|
140
157
|
export function wireControllerParams(solutionType, controllerDefinitions, buildConfig) {
|
|
141
|
-
validateBuildConfig(solutionType, buildConfig);
|
|
158
|
+
validateBuildConfig(solutionType, controllerDefinitions, buildConfig);
|
|
142
159
|
const controllerProps = buildConfig.controllers ?? {};
|
|
143
160
|
new ControllerWirer(buildConfig, controllerDefinitions, controllerProps).wire(solutionType);
|
|
144
161
|
return controllerProps;
|
|
@@ -1,15 +1,34 @@
|
|
|
1
1
|
import { MultipleRecommendationError } from '../../common/errors.js';
|
|
2
2
|
import { recommendationInternalOptionKey } from '../types/controller-constants.js';
|
|
3
|
+
/**
|
|
4
|
+
* Type guard to check if a controller definition is a recommendation controller.
|
|
5
|
+
* A recommendation controller must have both the recommendation flag and a slotId.
|
|
6
|
+
*/
|
|
7
|
+
export function isRecommendationDefinition(controllerDefinition) {
|
|
8
|
+
const hasRecommendationFlag = 'recommendation' in controllerDefinition &&
|
|
9
|
+
controllerDefinition.recommendation === true;
|
|
10
|
+
const hasValidSlotId = recommendationInternalOptionKey in controllerDefinition &&
|
|
11
|
+
'slotId' in
|
|
12
|
+
controllerDefinition[recommendationInternalOptionKey];
|
|
13
|
+
return hasRecommendationFlag && hasValidSlotId;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Extracts recommendation controller definitions from a controller definitions map.
|
|
17
|
+
*
|
|
18
|
+
* @param controllerDefinitions - Map of controller definitions
|
|
19
|
+
* @returns Object containing only the recommendation controller definitions
|
|
20
|
+
*/
|
|
21
|
+
export function getRecommendationDefinitions(controllerDefinitions) {
|
|
22
|
+
const recommendationMap = {};
|
|
23
|
+
for (const [name, definition] of Object.entries(controllerDefinitions)) {
|
|
24
|
+
if (isRecommendationDefinition(definition)) {
|
|
25
|
+
recommendationMap[name] = definition;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
return recommendationMap;
|
|
29
|
+
}
|
|
3
30
|
export function filterRecommendationControllers(controllers, controllerDefinitions) {
|
|
4
31
|
const slotIdSet = new Set();
|
|
5
|
-
const isRecommendationDefinition = (controllerDefinition) => {
|
|
6
|
-
const isControllerRecommendation = 'recommendation' in controllerDefinition &&
|
|
7
|
-
controllerDefinition.recommendation === true;
|
|
8
|
-
const hasSlotId = recommendationInternalOptionKey in controllerDefinition &&
|
|
9
|
-
'slotId' in
|
|
10
|
-
controllerDefinition[recommendationInternalOptionKey];
|
|
11
|
-
return isControllerRecommendation && hasSlotId;
|
|
12
|
-
};
|
|
13
32
|
const ensureSingleRecommendationPerSlot = (slotId) => {
|
|
14
33
|
throw new MultipleRecommendationError(slotId);
|
|
15
34
|
};
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { vi } from 'vitest';
|
|
2
|
+
import { recommendationInternalOptionKey } from '../ssr-next/commerce/types/controller-constants.js';
|
|
2
3
|
import { buildMockController, buildMockControllerWithInitialState, } from './mock-controller.js';
|
|
3
4
|
export function defineMockController() {
|
|
4
5
|
return {
|
|
@@ -41,3 +42,17 @@ export function defineMockCommerceControllerWithProps(options) {
|
|
|
41
42
|
recommendation: options?.recommendation ?? true,
|
|
42
43
|
};
|
|
43
44
|
}
|
|
45
|
+
export function defineMockRecommendationDefinition(slotId) {
|
|
46
|
+
return {
|
|
47
|
+
recommendation: true,
|
|
48
|
+
[recommendationInternalOptionKey]: {
|
|
49
|
+
slotId,
|
|
50
|
+
},
|
|
51
|
+
buildWithProps: vi.fn((engine, props) => ({
|
|
52
|
+
_kind: 'some-kind',
|
|
53
|
+
...buildMockControllerWithInitialState(engine, {
|
|
54
|
+
initialState: props?.initialState,
|
|
55
|
+
}),
|
|
56
|
+
})),
|
|
57
|
+
};
|
|
58
|
+
}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export const VERSION = "3.29.2-pre.
|
|
1
|
+
export const VERSION = "3.29.2-pre.34abdcbabf" || 'Test version';
|
|
2
2
|
export const COVEO_FRAMEWORK = ['@coveo/atomic', '@coveo/quantic'];
|