diff --git a/packages/headless/src/app/search-engine/search-engine.ssr.ts b/packages/headless/src/app/search-engine/search-engine.ssr.ts index 2c4d7358d62..79a4eb32b51 100644 --- a/packages/headless/src/app/search-engine/search-engine.ssr.ts +++ b/packages/headless/src/app/search-engine/search-engine.ssr.ts @@ -4,12 +4,9 @@ import {AnyAction} from '@reduxjs/toolkit'; import {Controller} from '../../controllers'; import {createWaitForActionMiddleware} from '../../utils/utils'; -import {EngineDefinitionBuildOptionsWithProps} from '../ssr-engine/types/build'; import { ControllerDefinitionsMap, - EngineStaticState, InferControllerPropsMapFromDefinitions, - InferControllerStaticStateMapFromDefinitions, OptionsExtender, } from '../ssr-engine/types/common'; import { @@ -67,11 +64,15 @@ export function defineSearchEngine< controllers: controllerDefinitions, ...engineOptions }: SearchEngineDefinitionOptions): SearchEngineDefinition { - const build: SearchEngineDefinition['build'] = async ( - ...[buildOptions]: Parameters< - SearchEngineDefinition['build'] - > - ) => { + type Definition = SearchEngineDefinition; + type BuildFunction = Definition['build']; + type FetchStaticStateFunction = Definition['fetchStaticState']; + type HydrateStaticStateFunction = Definition['hydrateStaticState']; + type BuildParameters = Parameters; + type FetchStaticStateParameters = Parameters; + type HydrateStaticStateParameters = Parameters; + + const build: BuildFunction = async (...[buildOptions]: BuildParameters) => { const engine = buildSearchEngine( buildOptions?.extend ? await buildOptions.extend(engineOptions) @@ -90,57 +91,50 @@ export function defineSearchEngine< }; }; - const fetchStaticState: SearchEngineDefinition['fetchStaticState'] = - async ( - ...[executeOptions]: Parameters< - SearchEngineDefinition['fetchStaticState'] - > - ): Promise< - EngineStaticState< - {type: string}, - InferControllerStaticStateMapFromDefinitions - > - > => { - const {middleware, promise: searchCompletedPromise} = - createWaitForActionMiddleware(isSearchCompletedAction); + const fetchStaticState: FetchStaticStateFunction = async ( + ...[fetchOptions]: FetchStaticStateParameters + ) => { + const {middleware, promise: searchCompletedPromise} = + createWaitForActionMiddleware(isSearchCompletedAction); - const extend: OptionsExtender = (options) => ({ - ...options, - middlewares: [...(options.middlewares ?? []), middleware], - }); - const {engine, controllers} = await build({ - extend, - ...(executeOptions?.controllers && { - controllers: executeOptions.controllers, - }), - }); + const extend: OptionsExtender = (options) => ({ + ...options, + middlewares: [...(options.middlewares ?? []), middleware], + }); + const {engine, controllers} = await build( + ...([ + { + extend, + ...(fetchOptions && + 'controllers' in fetchOptions && { + controllers: fetchOptions.controllers, + }), + }, + ] as BuildParameters) + ); - engine.executeFirstSearch(); - return createStaticState({ - searchAction: await searchCompletedPromise, - controllers, - }); - }; + engine.executeFirstSearch(); + return createStaticState({ + searchAction: await searchCompletedPromise, + controllers, + }); + }; - const hydrateStaticState: SearchEngineDefinition['hydrateStaticState'] = - async ( - ...[hydrateOptions]: Parameters< - SearchEngineDefinition['hydrateStaticState'] - > - ) => { - const {engine, controllers} = await build( - 'controllers' in hydrateOptions - ? ({ + const hydrateStaticState: HydrateStaticStateFunction = async ( + ...[hydrateOptions]: HydrateStaticStateParameters + ) => { + const {engine, controllers} = await build( + ...(('controllers' in hydrateOptions! + ? [ + { controllers: hydrateOptions.controllers, - } as EngineDefinitionBuildOptionsWithProps< - SearchEngineOptions, - TControllerDefinitions - >) - : {} - ); - engine.dispatch(hydrateOptions.searchAction); - return {engine, controllers}; - }; + }, + ] + : []) as BuildParameters) + ); + engine.dispatch(hydrateOptions!.searchAction); + return {engine, controllers}; + }; return { build, diff --git a/packages/headless/src/app/ssr-engine/types/build.ts b/packages/headless/src/app/ssr-engine/types/build.ts index ee765074b7d..eb8f70123b6 100644 --- a/packages/headless/src/app/ssr-engine/types/build.ts +++ b/packages/headless/src/app/ssr-engine/types/build.ts @@ -2,22 +2,17 @@ import {CoreEngine} from '../../engine'; import { ControllersMap, ControllersPropsMap, - HydratedState, + EngineDefinitionBuildResult, + EngineDefinitionControllersPropsOption, OptionsExtender, + OptionsTuple, } from './common'; -export interface EngineDefinitionBuildOptionsWithoutProps { +export interface BuildOptions { extend?: OptionsExtender; } -export interface EngineDefinitionBuildOptionsWithProps< - TEngineOptions, - TControllersProps extends ControllersPropsMap, -> extends EngineDefinitionBuildOptionsWithoutProps { - controllers: TControllersProps; -} - -export interface BuildWithProps< +export interface Build< TEngine extends CoreEngine, TEngineOptions, TControllersMap extends ControllersMap, @@ -26,23 +21,10 @@ export interface BuildWithProps< /** * Initializes an engine and controllers from the definition. */ - build( - options: EngineDefinitionBuildOptionsWithProps< - TEngineOptions, - TControllersProps + ( + ...params: OptionsTuple< + BuildOptions & + EngineDefinitionControllersPropsOption > - ): Promise>; -} - -export interface BuildWithoutProps< - TEngine extends CoreEngine, - TEngineOptions, - TControllersMap extends ControllersMap, -> { - /** - * Initializes an engine and controllers from the definition. - */ - build( - options?: EngineDefinitionBuildOptionsWithoutProps - ): Promise>; + ): Promise>; } diff --git a/packages/headless/src/app/ssr-engine/types/common.ts b/packages/headless/src/app/ssr-engine/types/common.ts index da68b72c425..c7ef30985b8 100644 --- a/packages/headless/src/app/ssr-engine/types/common.ts +++ b/packages/headless/src/app/ssr-engine/types/common.ts @@ -8,6 +8,20 @@ export type HasKeys = TObject extends {} : true : boolean; +export type ExtractRequiredOptions = { + [TKey in keyof TOptions as Pick extends Required< + Pick + > + ? TKey + : never]: TOptions[TKey]; +}; + +export type OptionsTuple = HasKeys extends false + ? [] + : HasKeys> extends false + ? [options?: TOptions] + : [options: TOptions]; + export interface OptionsExtender { (options: TOptions): TOptions | Promise; } @@ -68,6 +82,14 @@ export interface ControllerDefinitionsMap< [customName: string]: ControllerDefinition; } +export interface EngineDefinitionBuildResult< + TEngine extends CoreEngine, + TControllers extends ControllersMap, +> { + engine: TEngine; + controllers: TControllers; +} + export interface EngineStaticState< TSearchAction extends AnyAction, TControllers extends ControllerStaticStateMap, @@ -79,10 +101,7 @@ export interface EngineStaticState< export interface HydratedState< TEngine extends CoreEngine, TControllers extends ControllersMap, -> { - engine: TEngine; - controllers: TControllers; -} +> extends EngineDefinitionBuildResult {} export type InferControllerPropsFromDefinition< TController extends ControllerDefinition, @@ -141,3 +160,11 @@ export type InferControllerStaticStateMapFromControllers< TControllers[K] >; }; + +export type EngineDefinitionControllersPropsOption< + TControllersPropsMap extends ControllersPropsMap, +> = HasKeys extends false + ? {} + : { + controllers: TControllersPropsMap; + }; diff --git a/packages/headless/src/app/ssr-engine/types/core-engine.ts b/packages/headless/src/app/ssr-engine/types/core-engine.ts index 6672c52e93b..9ab8f473bc5 100644 --- a/packages/headless/src/app/ssr-engine/types/core-engine.ts +++ b/packages/headless/src/app/ssr-engine/types/core-engine.ts @@ -2,25 +2,15 @@ import {AnyAction} from '@reduxjs/toolkit'; import {Controller} from '../../../controllers'; import {CoreEngine} from '../../engine'; import {EngineConfiguration} from '../../engine-configuration'; -import {BuildWithProps, BuildWithoutProps} from './build'; +import {Build} from './build'; import { ControllerDefinitionsMap, - ControllersPropsMap, - HasKeys, InferControllerPropsMapFromDefinitions, InferControllerStaticStateMapFromDefinitions, InferControllersMapFromDefinition, - ControllerStaticStateMap, - ControllersMap, } from './common'; -import { - FetchStaticStateWithProps, - FetchStaticStateWithoutProps, -} from './fetch-static-state'; -import { - HydrateStaticStateWithProps, - HydrateStaticStateWithoutProps, -} from './hydrate-static-state'; +import {FetchStaticState} from './fetch-static-state'; +import {HydrateStaticState} from './hydrate-static-state'; export type EngineDefinitionOptions< TOptions extends {configuration: EngineConfiguration}, @@ -32,92 +22,44 @@ export type EngineDefinitionOptions< controllers?: TControllers; }; -export type EngineDefinition< - TEngine extends CoreEngine, - TControllers extends ControllerDefinitionsMap, - TEngineOptions, -> = HasKeys> extends true - ? EngineDefinitionWithProps< - TEngine, - TControllers, - TEngineOptions, - InferControllerPropsMapFromDefinitions - > - : HasKeys> extends false - ? EngineDefinitionWithoutProps - : - | EngineDefinitionWithProps< - TEngine, - TControllers, - TEngineOptions, - ControllersPropsMap - > - | EngineDefinitionWithoutProps; - -export interface EngineDefinitionWithoutProps< +export interface EngineDefinition< TEngine extends CoreEngine, TControllers extends ControllerDefinitionsMap, TEngineOptions, -> extends FetchStaticStateWithoutProps< - InferControllerStaticStateMapFromDefinitions, - AnyAction - >, - HydrateStaticStateWithoutProps< - TEngine, - InferControllersMapFromDefinition, - AnyAction - >, - BuildWithoutProps< - TEngine, - TEngineOptions, - InferControllersMapFromDefinition - > {} - -export interface EngineDefinitionWithProps< - TEngine extends CoreEngine, - TControllers extends ControllerDefinitionsMap, - TEngineOptions, - TControllerProps extends ControllersPropsMap, -> extends FetchStaticStateWithProps< - InferControllerStaticStateMapFromDefinitions, - AnyAction, - TControllerProps - >, - HydrateStaticStateWithProps< - TEngine, - InferControllersMapFromDefinition, - AnyAction, - TControllerProps - >, - BuildWithProps< - TEngine, - TEngineOptions, - InferControllersMapFromDefinition, - TControllerProps - > {} +> { + fetchStaticState: FetchStaticState< + InferControllerStaticStateMapFromDefinitions, + AnyAction, + InferControllerPropsMapFromDefinitions + >; + hydrateStaticState: HydrateStaticState< + TEngine, + InferControllersMapFromDefinition, + AnyAction, + InferControllerPropsMapFromDefinitions + >; + build: Build< + TEngine, + TEngineOptions, + InferControllersMapFromDefinition, + InferControllerPropsMapFromDefinitions + >; +} /** * @internal */ export type InferStaticState< - T extends - | FetchStaticStateWithoutProps - | FetchStaticStateWithProps< - ControllerStaticStateMap, - AnyAction, - ControllersPropsMap - >, + T extends { + fetchStaticState(...args: unknown[]): Promise; + }, > = Awaited>; + /** * @internal */ export type InferHydratedState< - T extends - | HydrateStaticStateWithoutProps - | HydrateStaticStateWithProps< - CoreEngine, - ControllersMap, - AnyAction, - ControllersPropsMap - >, + T extends { + hydrateStaticState(...args: unknown[]): Promise; + }, > = Awaited>; diff --git a/packages/headless/src/app/ssr-engine/types/fetch-static-state.ts b/packages/headless/src/app/ssr-engine/types/fetch-static-state.ts index d681f0b0d5b..3593793b6d2 100644 --- a/packages/headless/src/app/ssr-engine/types/fetch-static-state.ts +++ b/packages/headless/src/app/ssr-engine/types/fetch-static-state.ts @@ -2,28 +2,14 @@ import {AnyAction} from '@reduxjs/toolkit'; import { ControllerStaticStateMap, ControllersPropsMap, + EngineDefinitionControllersPropsOption, EngineStaticState, + OptionsTuple, } from './common'; -export type EngineDefinitionFetchStaticStateOptions< - TControllersStaticState extends ControllersPropsMap, -> = {controllers: TControllersStaticState}; +export type FetchStaticStateOptions = {}; -export type FetchStaticStateWithoutProps< - TControllersStaticState extends ControllerStaticStateMap, - TSearchAction extends AnyAction, -> = { - /** - * Executes only the initial search for a given configuration, then returns a resumable snapshot of engine state along with the state of the controllers. - * - * Useful for static generation and server-side rendering. - */ - fetchStaticState(): Promise< - EngineStaticState - >; -}; - -export type FetchStaticStateWithProps< +export type FetchStaticState< TControllersStaticState extends ControllerStaticStateMap, TSearchAction extends AnyAction, TControllersProps extends ControllersPropsMap, @@ -33,7 +19,10 @@ export type FetchStaticStateWithProps< * * Useful for static generation and server-side rendering. */ - fetchStaticState( - options: EngineDefinitionFetchStaticStateOptions + ( + ...params: OptionsTuple< + FetchStaticStateOptions & + EngineDefinitionControllersPropsOption + > ): Promise>; }; diff --git a/packages/headless/src/app/ssr-engine/types/hydrate-static-state.ts b/packages/headless/src/app/ssr-engine/types/hydrate-static-state.ts index da63abe2bd9..1694e4f3d56 100644 --- a/packages/headless/src/app/ssr-engine/types/hydrate-static-state.ts +++ b/packages/headless/src/app/ssr-engine/types/hydrate-static-state.ts @@ -1,36 +1,18 @@ import {AnyAction} from '@reduxjs/toolkit'; import {CoreEngine} from '../../engine'; -import {ControllersMap, ControllersPropsMap, HydratedState} from './common'; +import { + ControllersMap, + ControllersPropsMap, + EngineDefinitionControllersPropsOption, + HydratedState, + OptionsTuple, +} from './common'; -export interface EngineDefinitionHydrateOptionsWithoutProps< - TSearchAction extends AnyAction, -> { +export interface HydrateStaticStateOptions { searchAction: TSearchAction; } -export type HydrateStaticStateWithoutProps< - TEngine extends CoreEngine, - TControllers extends ControllersMap, - TSearchAction extends AnyAction, -> = { - /** - * Creates a new engine from the snapshot of the engine created in SSR with fetchStaticState. - * - * Useful when hydrating a server-side-rendered engine in CSR. - */ - hydrateStaticState( - options: EngineDefinitionHydrateOptionsWithoutProps - ): Promise>; -}; - -export interface EngineDefinitionHydrateOptionsWithProps< - TSearchAction extends AnyAction, - TControllersProps extends ControllersPropsMap, -> extends EngineDefinitionHydrateOptionsWithoutProps { - controllers: TControllersProps; -} - -export type HydrateStaticStateWithProps< +export type HydrateStaticState< TEngine extends CoreEngine, TControllers extends ControllersMap, TSearchAction extends AnyAction, @@ -41,10 +23,10 @@ export type HydrateStaticStateWithProps< * * Useful when hydrating a server-side-rendered engine. */ - hydrateStaticState( - options: EngineDefinitionHydrateOptionsWithProps< - TSearchAction, - TControllersProps + ( + ...params: OptionsTuple< + HydrateStaticStateOptions & + EngineDefinitionControllersPropsOption > ): Promise>; };