@webiny/website-builder-sdk 0.0.0-unstable.7be00a75a9 → 0.0.0-unstable.7c2def32a7
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/BindingsResolver.d.ts +4 -1
- package/BindingsResolver.js.map +1 -1
- package/ComponentInputTraverser.js +4 -0
- package/ComponentInputTraverser.js.map +1 -1
- package/ComponentResolver.d.ts +6 -3
- package/ComponentResolver.js +9 -4
- package/ComponentResolver.js.map +1 -1
- package/ContentSdk.d.ts +67 -1
- package/ContentSdk.js +90 -8
- package/ContentSdk.js.map +1 -1
- package/DocumentStoreManager.d.ts +9 -2
- package/DocumentStoreManager.js +24 -5
- package/DocumentStoreManager.js.map +1 -1
- package/EditingSdk.d.ts +7 -1
- package/EditingSdk.js +5 -3
- package/EditingSdk.js.map +1 -1
- package/ElementFactory.js +7 -2
- package/ElementFactory.js.map +1 -1
- package/ElementFactory.test.js +102 -0
- package/ElementFactory.test.js.map +1 -1
- package/LiveSdk.d.ts +3 -1
- package/LiveSdk.js +3 -2
- package/LiveSdk.js.map +1 -1
- package/PreviewDocument.d.ts +3 -1
- package/PreviewDocument.js +5 -2
- package/PreviewDocument.js.map +1 -1
- package/PreviewSdk.d.ts +4 -1
- package/PreviewSdk.js +6 -2
- package/PreviewSdk.js.map +1 -1
- package/ResizeObserver.js +1 -1
- package/ResizeObserver.js.map +1 -1
- package/StylesBindingsProcessor.js +3 -2
- package/StylesBindingsProcessor.js.map +1 -1
- package/Theme.js +2 -1
- package/Theme.js.map +1 -1
- package/asset/deliveryUrl.d.ts +41 -0
- package/asset/deliveryUrl.js +34 -0
- package/asset/deliveryUrl.js.map +1 -0
- package/asset/deliveryUrl.test.d.ts +1 -0
- package/asset/deliveryUrl.test.js +127 -0
- package/asset/deliveryUrl.test.js.map +1 -0
- package/asset/geometry.d.ts +7 -0
- package/asset/geometry.js +10 -0
- package/asset/geometry.js.map +1 -0
- package/asset/imageSrcSet.d.ts +63 -0
- package/asset/imageSrcSet.js +98 -0
- package/asset/imageSrcSet.js.map +1 -0
- package/asset/imageSrcSet.test.d.ts +1 -0
- package/asset/imageSrcSet.test.js +103 -0
- package/asset/imageSrcSet.test.js.map +1 -0
- package/asset/index.d.ts +5 -0
- package/asset/index.js +5 -0
- package/asset/normalize.d.ts +24 -0
- package/asset/normalize.js +106 -0
- package/asset/normalize.js.map +1 -0
- package/asset/normalize.test.d.ts +1 -0
- package/asset/normalize.test.js +263 -0
- package/asset/normalize.test.js.map +1 -0
- package/asset/types.d.ts +2 -0
- package/asset/types.js +0 -0
- package/componentLoader/ComponentLoader.d.ts +16 -0
- package/componentLoader/ComponentLoader.js +0 -0
- package/componentLoader/RegistryOnlyComponentLoader.d.ts +9 -0
- package/componentLoader/RegistryOnlyComponentLoader.js +8 -0
- package/componentLoader/RegistryOnlyComponentLoader.js.map +1 -0
- package/componentLoader/createComponentLoader.d.ts +7 -0
- package/componentLoader/createComponentLoader.js +10 -0
- package/componentLoader/createComponentLoader.js.map +1 -0
- package/componentLoader/defaultComponentLoader.d.ts +7 -0
- package/componentLoader/defaultComponentLoader.js +8 -0
- package/componentLoader/defaultComponentLoader.js.map +1 -0
- package/componentLoader/index.d.ts +3 -0
- package/componentLoader/index.js +3 -0
- package/contentClientState.test.d.ts +1 -0
- package/contentClientState.test.js +384 -0
- package/contentClientState.test.js.map +1 -0
- package/contentEntry/ContentEntryBindingsResolver.d.ts +33 -0
- package/contentEntry/ContentEntryBindingsResolver.js +52 -0
- package/contentEntry/ContentEntryBindingsResolver.js.map +1 -0
- package/contentEntry/ContentEntryCache.d.ts +49 -0
- package/contentEntry/ContentEntryCache.js +51 -0
- package/contentEntry/ContentEntryCache.js.map +1 -0
- package/contentEntry/resolveContentEntry.d.ts +74 -0
- package/contentEntry/resolveContentEntry.js +53 -0
- package/contentEntry/resolveContentEntry.js.map +1 -0
- package/contentEntry/resolveContentEntry.test.d.ts +1 -0
- package/contentEntry/resolveContentEntry.test.js +213 -0
- package/contentEntry/resolveContentEntry.test.js.map +1 -0
- package/createComponent.d.ts +5 -0
- package/createComponent.js +32 -0
- package/createComponent.js.map +1 -0
- package/createContentClient.d.ts +17 -0
- package/createContentClient.js +16 -0
- package/createContentClient.js.map +1 -0
- package/createContentClient.test.d.ts +1 -0
- package/createContentClient.test.js +165 -0
- package/createContentClient.test.js.map +1 -0
- package/createInput.d.ts +10 -2
- package/createInput.js +8 -1
- package/createInput.js.map +1 -1
- package/dataProviders/ApiClient.d.ts +10 -5
- package/dataProviders/ApiClient.js +10 -10
- package/dataProviders/ApiClient.js.map +1 -1
- package/dataProviders/DefaultDataProvider.d.ts +4 -0
- package/dataProviders/DefaultDataProvider.js +35 -0
- package/dataProviders/DefaultDataProvider.js.map +1 -1
- package/dataProviders/GET_EXPERIMENT_PAUSED.d.ts +1 -0
- package/dataProviders/GET_EXPERIMENT_PAUSED.js +17 -0
- package/dataProviders/GET_EXPERIMENT_PAUSED.js.map +1 -0
- package/dataProviders/GET_PAGE_BY_ID.d.ts +1 -1
- package/dataProviders/GET_PAGE_BY_ID.js +2 -0
- package/dataProviders/GET_PAGE_BY_ID.js.map +1 -1
- package/dataProviders/GET_PAGE_BY_PATH.d.ts +1 -1
- package/dataProviders/GET_PAGE_BY_PATH.js +2 -0
- package/dataProviders/GET_PAGE_BY_PATH.js.map +1 -1
- package/dataProviders/GET_PAGE_EXPERIMENT.d.ts +1 -0
- package/dataProviders/GET_PAGE_EXPERIMENT.js +32 -0
- package/dataProviders/GET_PAGE_EXPERIMENT.js.map +1 -0
- package/dataProviders/GET_VARIANT_CONTENT.d.ts +1 -0
- package/dataProviders/GET_VARIANT_CONTENT.js +24 -0
- package/dataProviders/GET_VARIANT_CONTENT.js.map +1 -0
- package/dataProviders/NullDataProvider.d.ts +4 -0
- package/dataProviders/NullDataProvider.js +9 -0
- package/dataProviders/NullDataProvider.js.map +1 -1
- package/dataProviders/queries.test.d.ts +1 -0
- package/dataProviders/queries.test.js +45 -0
- package/dataProviders/queries.test.js.map +1 -0
- package/defaultBreakpoints.js +23 -3
- package/defaultBreakpoints.js.map +1 -1
- package/experiments/PostHogAnalyticsProvider.d.ts +31 -0
- package/experiments/PostHogAnalyticsProvider.js +28 -0
- package/experiments/PostHogAnalyticsProvider.js.map +1 -0
- package/experiments/analyticsProvider.d.ts +4 -0
- package/experiments/analyticsProvider.js +11 -0
- package/experiments/analyticsProvider.js.map +1 -0
- package/experiments/bucketing.d.ts +27 -0
- package/experiments/bucketing.js +91 -0
- package/experiments/bucketing.js.map +1 -0
- package/experiments/bucketing.test.d.ts +1 -0
- package/experiments/bucketing.test.js +183 -0
- package/experiments/bucketing.test.js.map +1 -0
- package/experiments/index.d.ts +5 -0
- package/experiments/index.js +5 -0
- package/experiments/render.d.ts +82 -0
- package/experiments/render.js +149 -0
- package/experiments/render.js.map +1 -0
- package/experiments/types.d.ts +108 -0
- package/experiments/types.js +4 -0
- package/experiments/types.js.map +1 -0
- package/headersProvider.d.ts +1 -2
- package/headersProvider.js.map +1 -1
- package/image/geometry.d.ts +54 -0
- package/image/geometry.js +112 -0
- package/image/geometry.js.map +1 -0
- package/image/geometry.test.d.ts +1 -0
- package/image/geometry.test.js +190 -0
- package/image/geometry.test.js.map +1 -0
- package/image/index.d.ts +3 -0
- package/image/index.js +3 -0
- package/image/presets.d.ts +6 -0
- package/image/presets.js +20 -0
- package/image/presets.js.map +1 -0
- package/image/types.d.ts +10 -0
- package/image/types.js +0 -0
- package/index.d.ts +12 -0
- package/index.js +12 -0
- package/jsonPatch.js +3 -3
- package/package.json +7 -6
- package/types/WebsiteBuilderTheme.d.ts +5 -0
- package/types.d.ts +75 -1
package/BindingsResolver.d.ts
CHANGED
|
@@ -9,7 +9,10 @@ export type ResolveElementParams = {
|
|
|
9
9
|
inputAst: InputAstNode[];
|
|
10
10
|
onResolved?: OnResolved;
|
|
11
11
|
};
|
|
12
|
-
export
|
|
12
|
+
export interface IBindingsResolver {
|
|
13
|
+
resolveElement(params: ResolveElementParams): ResolvedElement[];
|
|
14
|
+
}
|
|
15
|
+
export declare class BindingsResolver implements IBindingsResolver {
|
|
13
16
|
private readonly state;
|
|
14
17
|
constructor(state: DocumentState);
|
|
15
18
|
resolveElement({ element, elementBindings, inputAst, onResolved }: ResolveElementParams): ResolvedElement[];
|
package/BindingsResolver.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BindingsResolver.js","sources":["../src/BindingsResolver.ts"],"sourcesContent":["import { toJS } from \"mobx\";\nimport type {\n ComponentInput,\n DocumentElement,\n DocumentElementBindings,\n DocumentElementStyleBindings,\n DocumentState,\n ResolvedElement,\n SerializableCSSStyleDeclaration,\n ValueBinding\n} from \"~/types.js\";\nimport type { InputAstNode } from \"./ComponentManifestToAstConverter.js\";\n\nexport interface OnResolved {\n (value: any, input: ComponentInput): any;\n}\n\nexport type ResolveElementParams = {\n element: DocumentElement;\n elementBindings: DocumentElementBindings;\n inputAst: InputAstNode[];\n onResolved?: OnResolved;\n};\n\nexport class BindingsResolver {\n private readonly state: DocumentState;\n\n constructor(state: DocumentState) {\n this.state = state;\n }\n\n public resolveElement({\n element,\n elementBindings,\n inputAst,\n onResolved\n }: ResolveElementParams): ResolvedElement[] {\n const repeatBindingArray = elementBindings.$repeat;\n\n if (repeatBindingArray) {\n const items = this.resolveBinding(repeatBindingArray, { state: toJS(this.state) });\n\n if (!Array.isArray(items)) {\n return [];\n }\n\n return items.map(item => {\n return this.resolveSingleInstance(\n element,\n elementBindings,\n item,\n inputAst,\n onResolved\n );\n });\n }\n\n return [\n this.resolveSingleInstance(element, elementBindings, undefined, inputAst, onResolved)\n ];\n }\n\n private resolveSingleInstance(\n element: DocumentElement,\n elementBindings: DocumentElementBindings,\n item: Record<string, any> | undefined,\n inputAst: InputAstNode[],\n onResolved?: OnResolved\n ): ResolvedElement {\n const resolvedElement: ResolvedElement = {\n id: element.id,\n inputs: {},\n styles: {}\n };\n\n const context = { state: this.state, $: item };\n const bindings = elementBindings.inputs ?? {};\n\n const resolveInputsFromAst = (\n nodes: InputAstNode[],\n prefix: string[],\n target: Record<string, any>\n ) => {\n for (const node of nodes) {\n const pathParts = [...prefix, node.name];\n const path = pathParts.join(\"/\");\n const binding = bindings[path];\n const value = this.resolveBinding(binding, context) ?? node.input.defaultValue;\n\n const finalValue = onResolved ? onResolved(value, node.input) : value;\n\n if (node.children.length > 0) {\n if (node.list) {\n const uniqueIndexes = this.getUniqueIndexesFromPath(path, bindings);\n\n target[node.name] = uniqueIndexes.map(index => {\n const childTarget: Record<string, any> = {};\n resolveInputsFromAst(\n node.children,\n [...pathParts.slice(0, -1), `${node.name}/${index}`],\n childTarget\n );\n return childTarget;\n });\n } else {\n const childTarget: Record<string, any> = {};\n resolveInputsFromAst(node.children, pathParts, childTarget);\n target[node.name] = childTarget;\n }\n } else if (node.list) {\n // List node with no children (e.g., slot or primitive list)\n const uniqueIndexes = this.getUniqueIndexesFromPath(path, bindings);\n\n // If binding is e.g., `leftColumn/0`, we'll have `0` in unique indexes.\n if (uniqueIndexes.length > 0) {\n target[node.name] = uniqueIndexes.map(index => {\n const binding = bindings[`${node.name}/${index}`];\n const value =\n this.resolveBinding(binding, context) ?? node.input.defaultValue;\n return onResolved ? onResolved(value, node.input) : value;\n });\n } else {\n // If binding is a simple `children`, we simply assign the resolved value.\n target[node.name] = finalValue;\n }\n } else if (finalValue !== undefined) {\n target[node.name] = finalValue;\n }\n }\n };\n\n resolveInputsFromAst(inputAst, [], resolvedElement.inputs);\n\n // Resolve styles\n const styles: DocumentElementStyleBindings = elementBindings.styles\n ? (elementBindings.styles ?? {})\n : {};\n\n const resolvedStyles: SerializableCSSStyleDeclaration = {};\n\n for (const [path, binding] of Object.entries(styles)) {\n if (binding) {\n // @ts-expect-error We're positive this is correct.\n resolvedStyles[path] = this.resolveBinding(binding, context);\n }\n }\n\n return {\n ...resolvedElement,\n styles: resolvedStyles\n };\n }\n\n private getUniqueIndexesFromPath(flatKey: string, bindings: DocumentElementBindings) {\n const pattern = new RegExp(`^${flatKey}\\\\/(\\\\d+)`);\n\n const indexes = Object.keys(bindings).reduce((acc: number[], key) => {\n const match = key.match(pattern);\n if (match) {\n acc.push(parseInt(match[1], 10));\n }\n return acc;\n }, []);\n\n return Array.from(new Set(indexes)).sort((a, b) => a - b);\n }\n\n private resolveBinding(binding: ValueBinding | undefined, context: Record<string, any>): any {\n if (typeof binding === \"undefined\") {\n return undefined;\n }\n\n if (binding.expression) {\n return this.evaluateExpression(binding.expression, context);\n }\n\n return binding.static;\n }\n\n private evaluateExpression(expression: string | undefined, context: Record<string, any> = {}) {\n if (!expression || expression === \"$noop\") {\n return undefined;\n }\n\n try {\n let finalExpression = expression.trim();\n\n if (finalExpression.startsWith(\"$state\")) {\n finalExpression = finalExpression.replace(/^\\$state/, \"state\");\n }\n\n finalExpression = finalExpression.replace(/\\.([0-9]+)/g, \"[$1]\");\n\n const scopedFn = new Function(...Object.keys(context), `return ${finalExpression};`);\n return scopedFn(...Object.values(context));\n } catch {\n return undefined;\n }\n }\n}\n"],"names":["BindingsResolver","state","element","elementBindings","inputAst","onResolved","repeatBindingArray","items","toJS","Array","item","undefined","resolvedElement","context","bindings","resolveInputsFromAst","nodes","prefix","target","node","pathParts","path","binding","value","finalValue","uniqueIndexes","index","childTarget","styles","resolvedStyles","Object","flatKey","pattern","RegExp","indexes","acc","key","match","parseInt","Set","a","b","expression","finalExpression","scopedFn","Function"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"BindingsResolver.js","sources":["../src/BindingsResolver.ts"],"sourcesContent":["import { toJS } from \"mobx\";\nimport type {\n ComponentInput,\n DocumentElement,\n DocumentElementBindings,\n DocumentElementStyleBindings,\n DocumentState,\n ResolvedElement,\n SerializableCSSStyleDeclaration,\n ValueBinding\n} from \"~/types.js\";\nimport type { InputAstNode } from \"./ComponentManifestToAstConverter.js\";\n\nexport interface OnResolved {\n (value: any, input: ComponentInput): any;\n}\n\nexport type ResolveElementParams = {\n element: DocumentElement;\n elementBindings: DocumentElementBindings;\n inputAst: InputAstNode[];\n onResolved?: OnResolved;\n};\n\nexport interface IBindingsResolver {\n resolveElement(params: ResolveElementParams): ResolvedElement[];\n}\n\nexport class BindingsResolver implements IBindingsResolver {\n private readonly state: DocumentState;\n\n constructor(state: DocumentState) {\n this.state = state;\n }\n\n public resolveElement({\n element,\n elementBindings,\n inputAst,\n onResolved\n }: ResolveElementParams): ResolvedElement[] {\n const repeatBindingArray = elementBindings.$repeat;\n\n if (repeatBindingArray) {\n const items = this.resolveBinding(repeatBindingArray, { state: toJS(this.state) });\n\n if (!Array.isArray(items)) {\n return [];\n }\n\n return items.map(item => {\n return this.resolveSingleInstance(\n element,\n elementBindings,\n item,\n inputAst,\n onResolved\n );\n });\n }\n\n return [\n this.resolveSingleInstance(element, elementBindings, undefined, inputAst, onResolved)\n ];\n }\n\n private resolveSingleInstance(\n element: DocumentElement,\n elementBindings: DocumentElementBindings,\n item: Record<string, any> | undefined,\n inputAst: InputAstNode[],\n onResolved?: OnResolved\n ): ResolvedElement {\n const resolvedElement: ResolvedElement = {\n id: element.id,\n inputs: {},\n styles: {}\n };\n\n const context = { state: this.state, $: item };\n const bindings = elementBindings.inputs ?? {};\n\n const resolveInputsFromAst = (\n nodes: InputAstNode[],\n prefix: string[],\n target: Record<string, any>\n ) => {\n for (const node of nodes) {\n const pathParts = [...prefix, node.name];\n const path = pathParts.join(\"/\");\n const binding = bindings[path];\n const value = this.resolveBinding(binding, context) ?? node.input.defaultValue;\n\n const finalValue = onResolved ? onResolved(value, node.input) : value;\n\n if (node.children.length > 0) {\n if (node.list) {\n const uniqueIndexes = this.getUniqueIndexesFromPath(path, bindings);\n\n target[node.name] = uniqueIndexes.map(index => {\n const childTarget: Record<string, any> = {};\n resolveInputsFromAst(\n node.children,\n [...pathParts.slice(0, -1), `${node.name}/${index}`],\n childTarget\n );\n return childTarget;\n });\n } else {\n const childTarget: Record<string, any> = {};\n resolveInputsFromAst(node.children, pathParts, childTarget);\n target[node.name] = childTarget;\n }\n } else if (node.list) {\n // List node with no children (e.g., slot or primitive list)\n const uniqueIndexes = this.getUniqueIndexesFromPath(path, bindings);\n\n // If binding is e.g., `leftColumn/0`, we'll have `0` in unique indexes.\n if (uniqueIndexes.length > 0) {\n target[node.name] = uniqueIndexes.map(index => {\n const binding = bindings[`${node.name}/${index}`];\n const value =\n this.resolveBinding(binding, context) ?? node.input.defaultValue;\n return onResolved ? onResolved(value, node.input) : value;\n });\n } else {\n // If binding is a simple `children`, we simply assign the resolved value.\n target[node.name] = finalValue;\n }\n } else if (finalValue !== undefined) {\n target[node.name] = finalValue;\n }\n }\n };\n\n resolveInputsFromAst(inputAst, [], resolvedElement.inputs);\n\n // Resolve styles\n const styles: DocumentElementStyleBindings = elementBindings.styles\n ? (elementBindings.styles ?? {})\n : {};\n\n const resolvedStyles: SerializableCSSStyleDeclaration = {};\n\n for (const [path, binding] of Object.entries(styles)) {\n if (binding) {\n // @ts-expect-error We're positive this is correct.\n resolvedStyles[path] = this.resolveBinding(binding, context);\n }\n }\n\n return {\n ...resolvedElement,\n styles: resolvedStyles\n };\n }\n\n private getUniqueIndexesFromPath(flatKey: string, bindings: DocumentElementBindings) {\n const pattern = new RegExp(`^${flatKey}\\\\/(\\\\d+)`);\n\n const indexes = Object.keys(bindings).reduce((acc: number[], key) => {\n const match = key.match(pattern);\n if (match) {\n acc.push(parseInt(match[1], 10));\n }\n return acc;\n }, []);\n\n return Array.from(new Set(indexes)).sort((a, b) => a - b);\n }\n\n private resolveBinding(binding: ValueBinding | undefined, context: Record<string, any>): any {\n if (typeof binding === \"undefined\") {\n return undefined;\n }\n\n if (binding.expression) {\n return this.evaluateExpression(binding.expression, context);\n }\n\n return binding.static;\n }\n\n private evaluateExpression(expression: string | undefined, context: Record<string, any> = {}) {\n if (!expression || expression === \"$noop\") {\n return undefined;\n }\n\n try {\n let finalExpression = expression.trim();\n\n if (finalExpression.startsWith(\"$state\")) {\n finalExpression = finalExpression.replace(/^\\$state/, \"state\");\n }\n\n finalExpression = finalExpression.replace(/\\.([0-9]+)/g, \"[$1]\");\n\n const scopedFn = new Function(...Object.keys(context), `return ${finalExpression};`);\n return scopedFn(...Object.values(context));\n } catch {\n return undefined;\n }\n }\n}\n"],"names":["BindingsResolver","state","element","elementBindings","inputAst","onResolved","repeatBindingArray","items","toJS","Array","item","undefined","resolvedElement","context","bindings","resolveInputsFromAst","nodes","prefix","target","node","pathParts","path","binding","value","finalValue","uniqueIndexes","index","childTarget","styles","resolvedStyles","Object","flatKey","pattern","RegExp","indexes","acc","key","match","parseInt","Set","a","b","expression","finalExpression","scopedFn","Function"],"mappings":"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"}
|
|
@@ -12,6 +12,10 @@ class ComponentInputTraverser {
|
|
|
12
12
|
if (node.list) {
|
|
13
13
|
value = value ?? [];
|
|
14
14
|
if (0 === value.length) visitor(node, currentPath, value);
|
|
15
|
+
if (0 === node.children.length && "slot" !== node.type) {
|
|
16
|
+
if (value.length > 0) visitor(node, currentPath, value);
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
15
19
|
value.forEach((item, index)=>{
|
|
16
20
|
if (node.children.length > 0) {
|
|
17
21
|
const itemPath = `${currentPath}/${index}`;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ComponentInputTraverser.js","sources":["../src/ComponentInputTraverser.ts"],"sourcesContent":["import type { InputAstNode } from \"./ComponentManifestToAstConverter.js\";\n\n// Visitor signature: called for every resolved leaf\nexport type InputVisitor = (node: InputAstNode, path: string, value: any) => void;\n\n/**\n * ComponentInputTraverser\n *\n * Walks an input AST and a matching data object,\n * invoking `visitor` for each leaf value found.\n */\nexport class ComponentInputTraverser {\n private readonly ast: InputAstNode[];\n\n constructor(ast: InputAstNode[]) {\n this.ast = ast;\n }\n\n /**\n * Traverse the given `data` object according to the AST,\n * calling `visitor(node, path, value)` for each leaf.\n */\n public traverse(data: Record<string, any>, visitor: InputVisitor): void {\n for (const node of this.ast) {\n const rootValue = data[node.name];\n this.traverseNode(node, rootValue, node.name, visitor);\n }\n }\n\n private traverseNode(\n node: InputAstNode,\n value: any,\n currentPath: string,\n visitor: InputVisitor\n ): void {\n if (node.list) {\n value = value ?? [];\n\n if (value.length === 0) {\n visitor(node, currentPath, value);\n }\n\n value.forEach((item: any, index: number) => {\n if (node.children.length > 0) {\n const itemPath = `${currentPath}/${index}`;\n for (const child of node.children) {\n const childValue = item?.[child.name];\n const childPath = `${itemPath}/${child.name}`;\n this.traverseNode(child, childValue, childPath, visitor);\n }\n } else {\n visitor(node, currentPath, item);\n }\n });\n } else {\n if (node.children.length > 0) {\n for (const child of node.children) {\n const childValue = value?.[child.name];\n const childPath = `${currentPath}/${child.name}`;\n this.traverseNode(child, childValue, childPath, visitor);\n }\n } else {\n visitor(node, currentPath, value);\n }\n }\n }\n}\n"],"names":["ComponentInputTraverser","ast","data","visitor","node","rootValue","value","currentPath","item","index","itemPath","child","childValue","childPath"],"mappings":"AAWO,MAAMA;IAGT,YAAYC,GAAmB,CAAE;QAC7B,IAAI,CAAC,GAAG,GAAGA;IACf;IAMO,SAASC,IAAyB,EAAEC,OAAqB,EAAQ;QACpE,KAAK,MAAMC,QAAQ,IAAI,CAAC,GAAG,CAAE;YACzB,MAAMC,YAAYH,IAAI,CAACE,KAAK,IAAI,CAAC;YACjC,IAAI,CAAC,YAAY,CAACA,MAAMC,WAAWD,KAAK,IAAI,EAAED;QAClD;IACJ;IAEQ,aACJC,IAAkB,EAClBE,KAAU,EACVC,WAAmB,EACnBJ,OAAqB,EACjB;QACJ,IAAIC,KAAK,IAAI,EAAE;YACXE,QAAQA,SAAS,EAAE;YAEnB,IAAIA,AAAiB,MAAjBA,MAAM,MAAM,EACZH,QAAQC,MAAMG,aAAaD;
|
|
1
|
+
{"version":3,"file":"ComponentInputTraverser.js","sources":["../src/ComponentInputTraverser.ts"],"sourcesContent":["import type { InputAstNode } from \"./ComponentManifestToAstConverter.js\";\n\n// Visitor signature: called for every resolved leaf\nexport type InputVisitor = (node: InputAstNode, path: string, value: any) => void;\n\n/**\n * ComponentInputTraverser\n *\n * Walks an input AST and a matching data object,\n * invoking `visitor` for each leaf value found.\n */\nexport class ComponentInputTraverser {\n private readonly ast: InputAstNode[];\n\n constructor(ast: InputAstNode[]) {\n this.ast = ast;\n }\n\n /**\n * Traverse the given `data` object according to the AST,\n * calling `visitor(node, path, value)` for each leaf.\n */\n public traverse(data: Record<string, any>, visitor: InputVisitor): void {\n for (const node of this.ast) {\n const rootValue = data[node.name];\n this.traverseNode(node, rootValue, node.name, visitor);\n }\n }\n\n private traverseNode(\n node: InputAstNode,\n value: any,\n currentPath: string,\n visitor: InputVisitor\n ): void {\n if (node.list) {\n value = value ?? [];\n\n if (value.length === 0) {\n visitor(node, currentPath, value);\n }\n\n // A list of primitives (e.g. tags) is a single leaf: its value is the whole array.\n // Visiting each item would write every item to the same path, leaving only the last.\n // Slot lists are still visited per item, as each item creates its own element.\n if (node.children.length === 0 && node.type !== \"slot\") {\n if (value.length > 0) {\n visitor(node, currentPath, value);\n }\n return;\n }\n\n value.forEach((item: any, index: number) => {\n if (node.children.length > 0) {\n const itemPath = `${currentPath}/${index}`;\n for (const child of node.children) {\n const childValue = item?.[child.name];\n const childPath = `${itemPath}/${child.name}`;\n this.traverseNode(child, childValue, childPath, visitor);\n }\n } else {\n visitor(node, currentPath, item);\n }\n });\n } else {\n if (node.children.length > 0) {\n for (const child of node.children) {\n const childValue = value?.[child.name];\n const childPath = `${currentPath}/${child.name}`;\n this.traverseNode(child, childValue, childPath, visitor);\n }\n } else {\n visitor(node, currentPath, value);\n }\n }\n }\n}\n"],"names":["ComponentInputTraverser","ast","data","visitor","node","rootValue","value","currentPath","item","index","itemPath","child","childValue","childPath"],"mappings":"AAWO,MAAMA;IAGT,YAAYC,GAAmB,CAAE;QAC7B,IAAI,CAAC,GAAG,GAAGA;IACf;IAMO,SAASC,IAAyB,EAAEC,OAAqB,EAAQ;QACpE,KAAK,MAAMC,QAAQ,IAAI,CAAC,GAAG,CAAE;YACzB,MAAMC,YAAYH,IAAI,CAACE,KAAK,IAAI,CAAC;YACjC,IAAI,CAAC,YAAY,CAACA,MAAMC,WAAWD,KAAK,IAAI,EAAED;QAClD;IACJ;IAEQ,aACJC,IAAkB,EAClBE,KAAU,EACVC,WAAmB,EACnBJ,OAAqB,EACjB;QACJ,IAAIC,KAAK,IAAI,EAAE;YACXE,QAAQA,SAAS,EAAE;YAEnB,IAAIA,AAAiB,MAAjBA,MAAM,MAAM,EACZH,QAAQC,MAAMG,aAAaD;YAM/B,IAAIF,AAAyB,MAAzBA,KAAK,QAAQ,CAAC,MAAM,IAAUA,AAAc,WAAdA,KAAK,IAAI,EAAa;gBACpD,IAAIE,MAAM,MAAM,GAAG,GACfH,QAAQC,MAAMG,aAAaD;gBAE/B;YACJ;YAEAA,MAAM,OAAO,CAAC,CAACE,MAAWC;gBACtB,IAAIL,KAAK,QAAQ,CAAC,MAAM,GAAG,GAAG;oBAC1B,MAAMM,WAAW,GAAGH,YAAY,CAAC,EAAEE,OAAO;oBAC1C,KAAK,MAAME,SAASP,KAAK,QAAQ,CAAE;wBAC/B,MAAMQ,aAAaJ,MAAM,CAACG,MAAM,IAAI,CAAC;wBACrC,MAAME,YAAY,GAAGH,SAAS,CAAC,EAAEC,MAAM,IAAI,EAAE;wBAC7C,IAAI,CAAC,YAAY,CAACA,OAAOC,YAAYC,WAAWV;oBACpD;gBACJ,OACIA,QAAQC,MAAMG,aAAaC;YAEnC;QACJ,OACI,IAAIJ,KAAK,QAAQ,CAAC,MAAM,GAAG,GACvB,KAAK,MAAMO,SAASP,KAAK,QAAQ,CAAE;YAC/B,MAAMQ,aAAaN,OAAO,CAACK,MAAM,IAAI,CAAC;YACtC,MAAME,YAAY,GAAGN,YAAY,CAAC,EAAEI,MAAM,IAAI,EAAE;YAChD,IAAI,CAAC,YAAY,CAACA,OAAOC,YAAYC,WAAWV;QACpD;aAEAA,QAAQC,MAAMG,aAAaD;IAGvC;AACJ"}
|
package/ComponentResolver.d.ts
CHANGED
|
@@ -1,14 +1,17 @@
|
|
|
1
1
|
import type { ComponentRegistry } from "./ComponentRegistry.js";
|
|
2
|
-
import type { DocumentElement, DocumentElementBindings, DocumentState, ResolvedComponent } from "./types.js";
|
|
2
|
+
import type { DocumentCache, DocumentElement, DocumentElementBindings, DocumentState, ResolvedComponent } from "./types.js";
|
|
3
3
|
import type { OnResolved } from "./BindingsResolver.js";
|
|
4
|
+
import type { ContentEntryCache } from "./contentEntry/ContentEntryCache.js";
|
|
4
5
|
export type ResolveElementParams = {
|
|
5
6
|
element: DocumentElement;
|
|
6
7
|
elementBindings: DocumentElementBindings;
|
|
7
8
|
state: DocumentState;
|
|
9
|
+
cache?: DocumentCache;
|
|
8
10
|
onResolved?: OnResolved;
|
|
9
11
|
};
|
|
10
12
|
export declare class ComponentResolver {
|
|
11
13
|
private components;
|
|
12
|
-
|
|
13
|
-
|
|
14
|
+
private contentEntryCache;
|
|
15
|
+
constructor(registry: ComponentRegistry, cache?: ContentEntryCache);
|
|
16
|
+
resolve({ element, elementBindings, onResolved, state, cache }: ResolveElementParams): ResolvedComponent[] | null;
|
|
14
17
|
}
|
package/ComponentResolver.js
CHANGED
|
@@ -1,19 +1,24 @@
|
|
|
1
1
|
import { logger } from "./Logger.js";
|
|
2
2
|
import { BindingsResolver } from "./BindingsResolver.js";
|
|
3
|
+
import { ContentEntryBindingsResolver } from "./contentEntry/ContentEntryBindingsResolver.js";
|
|
4
|
+
import { contentEntryCache } from "./contentEntry/ContentEntryCache.js";
|
|
3
5
|
import { ComponentManifestToAstConverter } from "./ComponentManifestToAstConverter.js";
|
|
4
6
|
class ComponentResolver {
|
|
5
|
-
constructor(registry){
|
|
7
|
+
constructor(registry, cache = contentEntryCache){
|
|
6
8
|
this.components = registry;
|
|
9
|
+
this.contentEntryCache = cache;
|
|
7
10
|
}
|
|
8
|
-
resolve({ element, elementBindings = {}, onResolved, state }) {
|
|
11
|
+
resolve({ element, elementBindings = {}, onResolved, state, cache }) {
|
|
9
12
|
const componentName = element.component.name;
|
|
10
13
|
const blueprint = this.components.get(componentName);
|
|
11
14
|
if (!blueprint) {
|
|
12
15
|
logger.warn(`Unknown component: ${componentName}`);
|
|
13
16
|
return null;
|
|
14
17
|
}
|
|
15
|
-
const
|
|
16
|
-
const
|
|
18
|
+
const embedded = cache?.contentEntries;
|
|
19
|
+
const resolvedEntries = embedded ? new Map(Object.entries(embedded)) : void 0;
|
|
20
|
+
const resolver = new ContentEntryBindingsResolver(new BindingsResolver(state), resolvedEntries, this.contentEntryCache);
|
|
21
|
+
const instances = resolver.resolveElement({
|
|
17
22
|
element,
|
|
18
23
|
elementBindings,
|
|
19
24
|
inputAst: ComponentManifestToAstConverter.convert(blueprint.manifest.inputs ?? []),
|
package/ComponentResolver.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ComponentResolver.js","sources":["../src/ComponentResolver.ts"],"sourcesContent":["import type { ComponentRegistry } from \"~/ComponentRegistry.js\";\nimport type {\n DocumentElement,\n DocumentElementBindings,\n DocumentState,\n ResolvedComponent\n} from \"~/types.js\";\nimport { logger } from \"./Logger.js\";\nimport type { OnResolved } from \"./BindingsResolver.js\";\nimport { BindingsResolver } from \"./BindingsResolver.js\";\nimport { ComponentManifestToAstConverter } from \"~/ComponentManifestToAstConverter.js\";\
|
|
1
|
+
{"version":3,"file":"ComponentResolver.js","sources":["../src/ComponentResolver.ts"],"sourcesContent":["import type { ComponentRegistry } from \"~/ComponentRegistry.js\";\nimport type {\n DocumentCache,\n DocumentElement,\n DocumentElementBindings,\n DocumentState,\n ResolvedComponent\n} from \"~/types.js\";\nimport { logger } from \"./Logger.js\";\nimport type { OnResolved } from \"./BindingsResolver.js\";\nimport { BindingsResolver } from \"./BindingsResolver.js\";\nimport { ContentEntryBindingsResolver } from \"./contentEntry/ContentEntryBindingsResolver.js\";\nimport type { ContentEntryCache } from \"./contentEntry/ContentEntryCache.js\";\nimport { contentEntryCache } from \"./contentEntry/ContentEntryCache.js\";\nimport { ComponentManifestToAstConverter } from \"~/ComponentManifestToAstConverter.js\";\nexport type ResolveElementParams = {\n element: DocumentElement;\n elementBindings: DocumentElementBindings;\n state: DocumentState;\n cache?: DocumentCache;\n onResolved?: OnResolved;\n};\n\nexport class ComponentResolver {\n private components: ComponentRegistry;\n private contentEntryCache: ContentEntryCache;\n\n constructor(registry: ComponentRegistry, cache: ContentEntryCache = contentEntryCache) {\n this.components = registry;\n this.contentEntryCache = cache;\n }\n\n resolve({\n element,\n elementBindings = {},\n onResolved,\n state,\n cache\n }: ResolveElementParams): ResolvedComponent[] | null {\n const componentName = element.component.name;\n const blueprint = this.components.get(componentName);\n\n if (!blueprint) {\n logger.warn(`Unknown component: ${componentName}`);\n return null;\n }\n\n // Build the pre-resolved entries map from the document cache\n // (populated by `resolveContentEntries` on the server).\n const embedded = cache?.contentEntries as Record<string, unknown> | undefined;\n const resolvedEntries = embedded ? new Map(Object.entries(embedded)) : undefined;\n\n const resolver = new ContentEntryBindingsResolver(\n new BindingsResolver(state),\n resolvedEntries,\n this.contentEntryCache\n );\n\n const instances = resolver.resolveElement({\n element,\n elementBindings,\n inputAst: ComponentManifestToAstConverter.convert(blueprint.manifest.inputs ?? []),\n onResolved\n });\n\n return instances.map(instance => ({\n component: blueprint.component,\n manifest: blueprint.manifest!,\n styles: instance.styles,\n inputs: instance.inputs\n }));\n }\n}\n"],"names":["ComponentResolver","registry","cache","contentEntryCache","element","elementBindings","onResolved","state","componentName","blueprint","logger","embedded","resolvedEntries","Map","Object","undefined","resolver","ContentEntryBindingsResolver","BindingsResolver","instances","ComponentManifestToAstConverter","instance"],"mappings":";;;;;AAuBO,MAAMA;IAIT,YAAYC,QAA2B,EAAEC,QAA2BC,iBAAiB,CAAE;QACnF,IAAI,CAAC,UAAU,GAAGF;QAClB,IAAI,CAAC,iBAAiB,GAAGC;IAC7B;IAEA,QAAQ,EACJE,OAAO,EACPC,kBAAkB,CAAC,CAAC,EACpBC,UAAU,EACVC,KAAK,EACLL,KAAK,EACc,EAA8B;QACjD,MAAMM,gBAAgBJ,QAAQ,SAAS,CAAC,IAAI;QAC5C,MAAMK,YAAY,IAAI,CAAC,UAAU,CAAC,GAAG,CAACD;QAEtC,IAAI,CAACC,WAAW;YACZC,OAAO,IAAI,CAAC,CAAC,mBAAmB,EAAEF,eAAe;YACjD,OAAO;QACX;QAIA,MAAMG,WAAWT,OAAO;QACxB,MAAMU,kBAAkBD,WAAW,IAAIE,IAAIC,OAAO,OAAO,CAACH,aAAaI;QAEvE,MAAMC,WAAW,IAAIC,6BACjB,IAAIC,iBAAiBX,QACrBK,iBACA,IAAI,CAAC,iBAAiB;QAG1B,MAAMO,YAAYH,SAAS,cAAc,CAAC;YACtCZ;YACAC;YACA,UAAUe,gCAAgC,OAAO,CAACX,UAAU,QAAQ,CAAC,MAAM,IAAI,EAAE;YACjFH;QACJ;QAEA,OAAOa,UAAU,GAAG,CAACE,CAAAA,WAAa;gBAC9B,WAAWZ,UAAU,SAAS;gBAC9B,UAAUA,UAAU,QAAQ;gBAC5B,QAAQY,SAAS,MAAM;gBACvB,QAAQA,SAAS,MAAM;YAC3B;IACJ;AACJ"}
|
package/ContentSdk.d.ts
CHANGED
|
@@ -1,9 +1,17 @@
|
|
|
1
|
-
import type { Component, IContentSdk, ListPagesOptions, ListPagesResult, PublicPage, PublicRedirect, ResolvedComponent } from "./types.js";
|
|
1
|
+
import type { Component, Document, IContentSdk, ListPagesOptions, ListPagesResult, PublicPage, PublicRedirect, ResolvedComponent } from "./types.js";
|
|
2
|
+
import type { ActiveExperiment, VariantContent } from "./experiments/types.js";
|
|
3
|
+
import { type ExperimentRenderResult, type GetPageWithExperimentOptions } from "./experiments/render.js";
|
|
2
4
|
import { LiveSdk } from "./LiveSdk.js";
|
|
3
5
|
import { EditingSdk } from "./EditingSdk.js";
|
|
4
6
|
import { type ResolveElementParams } from "./ComponentResolver.js";
|
|
7
|
+
import type { ComponentRegistry } from "./ComponentRegistry.js";
|
|
8
|
+
import type { ContentEntryCache } from "./contentEntry/ContentEntryCache.js";
|
|
9
|
+
import type { DocumentStoreManager } from "./DocumentStoreManager.js";
|
|
5
10
|
import type { WebsiteBuilderThemeInput } from "./types/WebsiteBuilderTheme.js";
|
|
6
11
|
import type { IRedirects } from "./IRedirects.js";
|
|
12
|
+
import type { HeadersProvider } from "./headersProvider.js";
|
|
13
|
+
import type { ContentEntryLoader } from "./contentEntry/resolveContentEntry.js";
|
|
14
|
+
import type { ComponentLoaderFactory } from "./componentLoader/ComponentLoader.js";
|
|
7
15
|
export type ApiConfig = {
|
|
8
16
|
apiKey: string;
|
|
9
17
|
apiHost: string;
|
|
@@ -11,7 +19,36 @@ export type ApiConfig = {
|
|
|
11
19
|
};
|
|
12
20
|
export type ContentSDKConfig = ApiConfig & {
|
|
13
21
|
preview?: boolean;
|
|
22
|
+
previewParams?: string;
|
|
14
23
|
theme?: WebsiteBuilderThemeInput;
|
|
24
|
+
/**
|
|
25
|
+
* Request headers for server-side preview and experiments. When omitted, the provider set
|
|
26
|
+
* with `setHeadersProvider` is used. Meant for apps that serve requests outside the
|
|
27
|
+
* framework hook; it never carries the tenant.
|
|
28
|
+
*/
|
|
29
|
+
headersProvider?: HeadersProvider;
|
|
30
|
+
/**
|
|
31
|
+
* Loads the CMS entries that `contentEntry` inputs reference, for this SDK's content
|
|
32
|
+
* entry cache. Pass one bound to the same tenant as this SDK. When omitted, the cache's
|
|
33
|
+
* loader is left as it is.
|
|
34
|
+
*/
|
|
35
|
+
contentEntryLoader?: ContentEntryLoader;
|
|
36
|
+
/**
|
|
37
|
+
* Creates the loader for components a document references but nobody registered. It gets
|
|
38
|
+
* this SDK's API client and API config. When omitted, the default set with
|
|
39
|
+
* `setDefaultComponentLoader` is used (`@webiny/sdk-nextjs` sets its remote component
|
|
40
|
+
* loading), and without one nothing is loaded.
|
|
41
|
+
*/
|
|
42
|
+
componentLoader?: ComponentLoaderFactory;
|
|
43
|
+
};
|
|
44
|
+
/**
|
|
45
|
+
* The state a `ContentSdk` renders with. Each piece defaults to its module-level singleton, so
|
|
46
|
+
* `new ContentSdk()` shares state with `contentSdk`. `createContentClient` passes new instances.
|
|
47
|
+
*/
|
|
48
|
+
export type ContentSdkState = {
|
|
49
|
+
componentRegistry?: ComponentRegistry;
|
|
50
|
+
contentEntryCache?: ContentEntryCache;
|
|
51
|
+
documentStoreManager?: DocumentStoreManager;
|
|
15
52
|
};
|
|
16
53
|
declare class InternalContentSdk implements IContentSdk, IRedirects {
|
|
17
54
|
private activeSdk;
|
|
@@ -28,17 +65,46 @@ export declare class ContentSdk implements IContentSdk, IRedirects {
|
|
|
28
65
|
protected sdk?: InternalContentSdk;
|
|
29
66
|
private isPreview;
|
|
30
67
|
private lastConfig;
|
|
68
|
+
private dataProvider?;
|
|
69
|
+
private headersProvider?;
|
|
70
|
+
private componentLoaderFactory?;
|
|
71
|
+
private componentLoaderParams?;
|
|
72
|
+
private componentLoader?;
|
|
73
|
+
private readonly componentRegistry;
|
|
74
|
+
private readonly contentEntryCache;
|
|
75
|
+
private readonly documentStoreManager;
|
|
76
|
+
constructor(state?: ContentSdkState);
|
|
31
77
|
init(config: ContentSDKConfig, afterInit?: () => void): void;
|
|
32
78
|
getEditingSdk(): EditingSdk | undefined;
|
|
33
79
|
getPage(path: string): Promise<PublicPage | null>;
|
|
80
|
+
getPageExperiment(path: string): Promise<ActiveExperiment | null>;
|
|
81
|
+
getVariantContent(variantId: string): Promise<VariantContent | null>;
|
|
82
|
+
getExperimentPaused(experimentId: string): Promise<boolean>;
|
|
83
|
+
/**
|
|
84
|
+
* Resolve and render the right page for the current visitor (control or a variant),
|
|
85
|
+
* server-side. Bucketing, targeting, exposure emission, and cache-key handling are all
|
|
86
|
+
* encapsulated here so projects do not reimplement them. See {@link getPageWithExperiment}.
|
|
87
|
+
*/
|
|
88
|
+
getPageWithExperiment(path: string, options?: GetPageWithExperimentOptions): Promise<ExperimentRenderResult>;
|
|
34
89
|
listPages(options?: ListPagesOptions): Promise<ListPagesResult>;
|
|
35
90
|
getAllRedirects(): Promise<Map<string, PublicRedirect>>;
|
|
36
91
|
getRedirectByPath(path: string): Promise<PublicRedirect | undefined>;
|
|
37
92
|
registerComponent(blueprint: Component): void;
|
|
38
93
|
resolveElement(params: ResolveElementParams): ResolvedComponent[] | null;
|
|
94
|
+
/**
|
|
95
|
+
* Load every component the document references that isn't registered yet, through the
|
|
96
|
+
* component loader, and register what it returns. Call it before rendering the document.
|
|
97
|
+
* Nothing is cached here: an unregistered component goes to the loader on every call.
|
|
98
|
+
*/
|
|
99
|
+
loadDocumentComponents(document: Document): Promise<void>;
|
|
100
|
+
private getComponentLoader;
|
|
101
|
+
getComponentRegistry(): ComponentRegistry;
|
|
102
|
+
getContentEntryCache(): ContentEntryCache;
|
|
103
|
+
getDocumentStoreManager(): DocumentStoreManager;
|
|
39
104
|
isEditing(): boolean;
|
|
40
105
|
isPreviewing(): boolean;
|
|
41
106
|
private assertInitialized;
|
|
107
|
+
private requireDataProvider;
|
|
42
108
|
}
|
|
43
109
|
export declare const contentSdk: ContentSdk;
|
|
44
110
|
export {};
|
package/ContentSdk.js
CHANGED
|
@@ -1,14 +1,18 @@
|
|
|
1
|
+
import { getPageWithExperiment } from "./experiments/render.js";
|
|
1
2
|
import { environment } from "./Environment.js";
|
|
2
3
|
import { LiveSdk } from "./LiveSdk.js";
|
|
3
4
|
import { EditingSdk } from "./EditingSdk.js";
|
|
4
5
|
import { ComponentResolver } from "./ComponentResolver.js";
|
|
5
6
|
import { PreviewSdk } from "./PreviewSdk.js";
|
|
6
7
|
import { componentRegistry } from "./ComponentRegistry.js";
|
|
8
|
+
import { contentEntryCache } from "./contentEntry/ContentEntryCache.js";
|
|
9
|
+
import { documentStoreManager } from "./DocumentStoreManager.js";
|
|
7
10
|
import { ApiClient } from "./dataProviders/ApiClient.js";
|
|
8
11
|
import { DefaultDataProvider } from "./dataProviders/DefaultDataProvider.js";
|
|
9
12
|
import { Theme } from "./Theme.js";
|
|
10
13
|
import { viewportManager } from "./ViewportManager.js";
|
|
11
14
|
import { RedirectsProvider } from "./dataProviders/RedirectsProvider.js";
|
|
15
|
+
import { createComponentLoader } from "./componentLoader/createComponentLoader.js";
|
|
12
16
|
class InternalContentSdk {
|
|
13
17
|
constructor(redirectsProvider, liveSdk, editingSdk){
|
|
14
18
|
this.redirectsProvider = redirectsProvider;
|
|
@@ -32,23 +36,50 @@ class InternalContentSdk {
|
|
|
32
36
|
}
|
|
33
37
|
}
|
|
34
38
|
class ContentSdk {
|
|
39
|
+
constructor(state = {}){
|
|
40
|
+
this.isPreview = false;
|
|
41
|
+
this.componentRegistry = state.componentRegistry ?? componentRegistry;
|
|
42
|
+
this.contentEntryCache = state.contentEntryCache ?? contentEntryCache;
|
|
43
|
+
this.documentStoreManager = state.documentStoreManager ?? documentStoreManager;
|
|
44
|
+
}
|
|
35
45
|
init(config, afterInit) {
|
|
36
46
|
const configHash = JSON.stringify(config);
|
|
37
47
|
if (this.lastConfig && this.lastConfig === configHash) return;
|
|
38
48
|
this.lastConfig = configHash;
|
|
39
|
-
|
|
49
|
+
this.headersProvider = config.headersProvider;
|
|
50
|
+
if (config.contentEntryLoader) this.contentEntryCache.setLoader(config.contentEntryLoader);
|
|
51
|
+
const apiClient = new ApiClient({
|
|
52
|
+
apiHost: config.apiHost,
|
|
53
|
+
apiKey: config.apiKey,
|
|
54
|
+
apiTenant: config.apiTenant,
|
|
55
|
+
preview: config.preview
|
|
56
|
+
});
|
|
40
57
|
const dataProvider = new DefaultDataProvider({
|
|
41
58
|
apiClient
|
|
42
59
|
});
|
|
43
|
-
|
|
60
|
+
this.componentLoaderFactory = config.componentLoader;
|
|
61
|
+
this.componentLoaderParams = {
|
|
62
|
+
apiClient,
|
|
63
|
+
config: {
|
|
64
|
+
apiHost: config.apiHost,
|
|
65
|
+
apiKey: config.apiKey,
|
|
66
|
+
apiTenant: config.apiTenant
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
this.componentLoader = void 0;
|
|
70
|
+
this.dataProvider = dataProvider;
|
|
71
|
+
let liveSdk = new LiveSdk(dataProvider, this.documentStoreManager);
|
|
44
72
|
if (config.preview && !environment.isEditing()) {
|
|
45
73
|
this.isPreview = true;
|
|
46
|
-
liveSdk = new PreviewSdk(dataProvider, liveSdk);
|
|
74
|
+
liveSdk = new PreviewSdk(dataProvider, liveSdk, config.previewParams, config.headersProvider);
|
|
47
75
|
}
|
|
48
76
|
const theme = Theme.from(config.theme ?? {});
|
|
49
77
|
if (environment.isClient()) viewportManager.setBreakpoints(theme.breakpoints);
|
|
50
78
|
let editingSdk;
|
|
51
|
-
if (environment.isEditing()) editingSdk = new EditingSdk(liveSdk, theme
|
|
79
|
+
if (environment.isEditing()) editingSdk = new EditingSdk(liveSdk, theme, {
|
|
80
|
+
componentRegistry: this.componentRegistry,
|
|
81
|
+
documentStoreManager: this.documentStoreManager
|
|
82
|
+
});
|
|
52
83
|
this.sdk = new InternalContentSdk(new RedirectsProvider(apiClient), liveSdk, editingSdk);
|
|
53
84
|
if ("function" == typeof afterInit) afterInit();
|
|
54
85
|
}
|
|
@@ -60,6 +91,29 @@ class ContentSdk {
|
|
|
60
91
|
this.assertInitialized();
|
|
61
92
|
return this.sdk.getPage(path);
|
|
62
93
|
}
|
|
94
|
+
getPageExperiment(path) {
|
|
95
|
+
return this.requireDataProvider().getPageExperiment(path);
|
|
96
|
+
}
|
|
97
|
+
getVariantContent(variantId) {
|
|
98
|
+
return this.requireDataProvider().getVariantContent(variantId);
|
|
99
|
+
}
|
|
100
|
+
getExperimentPaused(experimentId) {
|
|
101
|
+
return this.requireDataProvider().getExperimentPaused(experimentId);
|
|
102
|
+
}
|
|
103
|
+
getPageWithExperiment(path, options) {
|
|
104
|
+
this.assertInitialized();
|
|
105
|
+
this.requireDataProvider();
|
|
106
|
+
const experimentOptions = {
|
|
107
|
+
...options
|
|
108
|
+
};
|
|
109
|
+
if (this.headersProvider && !experimentOptions.headersProvider) experimentOptions.headersProvider = this.headersProvider;
|
|
110
|
+
return getPageWithExperiment({
|
|
111
|
+
getPage: (p)=>this.getPage(p),
|
|
112
|
+
getPageExperiment: (p)=>this.getPageExperiment(p),
|
|
113
|
+
getVariantContent: (id)=>this.getVariantContent(id),
|
|
114
|
+
getExperimentPaused: (id)=>this.getExperimentPaused(id)
|
|
115
|
+
}, path, experimentOptions);
|
|
116
|
+
}
|
|
63
117
|
listPages(options) {
|
|
64
118
|
this.assertInitialized();
|
|
65
119
|
return this.sdk.listPages(options);
|
|
@@ -74,11 +128,38 @@ class ContentSdk {
|
|
|
74
128
|
}
|
|
75
129
|
registerComponent(blueprint) {
|
|
76
130
|
this.assertInitialized();
|
|
77
|
-
componentRegistry.register(blueprint);
|
|
131
|
+
this.componentRegistry.register(blueprint);
|
|
78
132
|
}
|
|
79
133
|
resolveElement(params) {
|
|
80
134
|
this.assertInitialized();
|
|
81
|
-
return new ComponentResolver(componentRegistry).resolve(params);
|
|
135
|
+
return new ComponentResolver(this.componentRegistry, this.contentEntryCache).resolve(params);
|
|
136
|
+
}
|
|
137
|
+
async loadDocumentComponents(document) {
|
|
138
|
+
this.assertInitialized();
|
|
139
|
+
const names = new Set();
|
|
140
|
+
for (const element of Object.values(document.elements)){
|
|
141
|
+
const name = element.component?.name;
|
|
142
|
+
if (name && !this.componentRegistry.get(name)) names.add(name);
|
|
143
|
+
}
|
|
144
|
+
const loader = this.getComponentLoader();
|
|
145
|
+
const loads = Array.from(names).map((name)=>loader.loadComponent({
|
|
146
|
+
name
|
|
147
|
+
}));
|
|
148
|
+
const components = await Promise.all(loads);
|
|
149
|
+
for (const component of components)if (component) this.componentRegistry.register(component);
|
|
150
|
+
}
|
|
151
|
+
getComponentLoader() {
|
|
152
|
+
if (!this.componentLoader) this.componentLoader = createComponentLoader(this.componentLoaderFactory, this.componentLoaderParams);
|
|
153
|
+
return this.componentLoader;
|
|
154
|
+
}
|
|
155
|
+
getComponentRegistry() {
|
|
156
|
+
return this.componentRegistry;
|
|
157
|
+
}
|
|
158
|
+
getContentEntryCache() {
|
|
159
|
+
return this.contentEntryCache;
|
|
160
|
+
}
|
|
161
|
+
getDocumentStoreManager() {
|
|
162
|
+
return this.documentStoreManager;
|
|
82
163
|
}
|
|
83
164
|
isEditing() {
|
|
84
165
|
return environment.isEditing();
|
|
@@ -89,8 +170,9 @@ class ContentSdk {
|
|
|
89
170
|
assertInitialized() {
|
|
90
171
|
if (!this.sdk) throw new Error("ContentSdk has not been initialized!");
|
|
91
172
|
}
|
|
92
|
-
|
|
93
|
-
this.
|
|
173
|
+
requireDataProvider() {
|
|
174
|
+
if (!this.dataProvider) throw new Error("ContentSdk has not been initialized!");
|
|
175
|
+
return this.dataProvider;
|
|
94
176
|
}
|
|
95
177
|
}
|
|
96
178
|
const contentSdk = new ContentSdk();
|
package/ContentSdk.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ContentSdk.js","sources":["../src/ContentSdk.ts"],"sourcesContent":["import type {\n Component,\n IContentSdk,\n ListPagesOptions,\n ListPagesResult,\n PublicPage,\n PublicRedirect,\n ResolvedComponent\n} from \"~/types.js\";\nimport { environment } from \"./Environment.js\";\nimport { LiveSdk } from \"./LiveSdk.js\";\nimport { EditingSdk } from \"./EditingSdk.js\";\nimport { ComponentResolver, type ResolveElementParams } from \"~/ComponentResolver.js\";\nimport { PreviewSdk } from \"./PreviewSdk.js\";\nimport { componentRegistry } from \"~/ComponentRegistry.js\";\nimport { ApiClient } from \"~/dataProviders/ApiClient.js\";\nimport { DefaultDataProvider } from \"~/dataProviders/DefaultDataProvider.js\";\nimport type { WebsiteBuilderThemeInput } from \"./types/WebsiteBuilderTheme.js\";\nimport { Theme } from \"./Theme.js\";\nimport { viewportManager } from \"./ViewportManager.js\";\nimport type { IRedirects } from \"~/IRedirects.js\";\nimport { RedirectsProvider } from \"~/dataProviders/RedirectsProvider.js\";\n\nexport type ApiConfig = {\n apiKey: string;\n apiHost: string;\n apiTenant: string;\n};\n\nexport type ContentSDKConfig = ApiConfig & {\n preview?: boolean;\n theme?: WebsiteBuilderThemeInput;\n};\n\nclass InternalContentSdk implements IContentSdk, IRedirects {\n private activeSdk: IContentSdk;\n private editingSdk: EditingSdk | undefined;\n private redirectsProvider: IRedirects;\n\n constructor(redirectsProvider: IRedirects, liveSdk: LiveSdk, editingSdk?: EditingSdk) {\n this.redirectsProvider = redirectsProvider;\n this.activeSdk = editingSdk ?? liveSdk;\n this.editingSdk = editingSdk;\n }\n\n getEditingSdk() {\n return this.editingSdk;\n }\n\n async getPage(path: string): Promise<PublicPage | null> {\n return this.activeSdk.getPage(path);\n }\n\n listPages(options?: ListPagesOptions): Promise<ListPagesResult> {\n return this.activeSdk.listPages(options);\n }\n\n getAllRedirects(): Promise<Map<string, PublicRedirect>> {\n return this.redirectsProvider.getAllRedirects();\n }\n\n getRedirectByPath(path: string): Promise<PublicRedirect | undefined> {\n return this.redirectsProvider.getRedirectByPath(path);\n }\n}\n\nexport class ContentSdk implements IContentSdk, IRedirects {\n protected sdk?: InternalContentSdk;\n private isPreview = false;\n private lastConfig: any;\n\n public init(config: ContentSDKConfig, afterInit?: () => void): void {\n const configHash = JSON.stringify(config);\n if (this.lastConfig && this.lastConfig === configHash) {\n return;\n }\n\n this.lastConfig = configHash;\n const apiClient = new ApiClient(config.apiHost, config.apiKey, config.apiTenant);\n\n const dataProvider = new DefaultDataProvider({ apiClient });\n\n let liveSdk: IContentSdk = new LiveSdk(dataProvider);\n\n if (config.preview && !environment.isEditing()) {\n this.isPreview = true;\n liveSdk = new PreviewSdk(dataProvider, liveSdk);\n }\n\n const theme = Theme.from(config.theme ?? {});\n\n if (environment.isClient()) {\n viewportManager.setBreakpoints(theme.breakpoints);\n }\n\n let editingSdk;\n if (environment.isEditing()) {\n editingSdk = new EditingSdk(liveSdk, theme);\n }\n\n this.sdk = new InternalContentSdk(\n new RedirectsProvider(apiClient),\n liveSdk as LiveSdk,\n editingSdk\n );\n\n if (typeof afterInit === \"function\") {\n afterInit();\n }\n }\n\n public getEditingSdk() {\n this.assertInitialized();\n return this.sdk.getEditingSdk();\n }\n\n public getPage(path: string) {\n this.assertInitialized();\n return this.sdk.getPage(path);\n }\n\n public listPages(options?: ListPagesOptions) {\n this.assertInitialized();\n return this.sdk.listPages(options);\n }\n\n public async getAllRedirects() {\n this.assertInitialized();\n return this.sdk.getAllRedirects();\n }\n\n getRedirectByPath(path: string): Promise<PublicRedirect | undefined> {\n this.assertInitialized();\n return this.sdk.getRedirectByPath(path);\n }\n\n registerComponent(blueprint: Component): void {\n this.assertInitialized();\n componentRegistry.register(blueprint);\n }\n\n resolveElement(params: ResolveElementParams): ResolvedComponent[] | null {\n this.assertInitialized();\n return new ComponentResolver(componentRegistry).resolve(params);\n }\n\n isEditing() {\n return environment.isEditing();\n }\n\n isPreviewing() {\n return this.isPreview;\n }\n\n private assertInitialized(): asserts this is this & {\n sdk: IContentSdk;\n } {\n if (!this.sdk) {\n throw new Error(`ContentSdk has not been initialized!`);\n }\n }\n}\n\nexport const contentSdk = new ContentSdk();\n"],"names":["InternalContentSdk","redirectsProvider","liveSdk","editingSdk","path","options","ContentSdk","config","afterInit","configHash","JSON","apiClient","ApiClient","dataProvider","DefaultDataProvider","LiveSdk","environment","PreviewSdk","theme","Theme","viewportManager","EditingSdk","RedirectsProvider","blueprint","componentRegistry","params","ComponentResolver","Error","contentSdk"],"mappings":";;;;;;;;;;;AAkCA,MAAMA;IAKF,YAAYC,iBAA6B,EAAEC,OAAgB,EAAEC,UAAuB,CAAE;QAClF,IAAI,CAAC,iBAAiB,GAAGF;QACzB,IAAI,CAAC,SAAS,GAAGE,cAAcD;QAC/B,IAAI,CAAC,UAAU,GAAGC;IACtB;IAEA,gBAAgB;QACZ,OAAO,IAAI,CAAC,UAAU;IAC1B;IAEA,MAAM,QAAQC,IAAY,EAA8B;QACpD,OAAO,IAAI,CAAC,SAAS,CAAC,OAAO,CAACA;IAClC;IAEA,UAAUC,OAA0B,EAA4B;QAC5D,OAAO,IAAI,CAAC,SAAS,CAAC,SAAS,CAACA;IACpC;IAEA,kBAAwD;QACpD,OAAO,IAAI,CAAC,iBAAiB,CAAC,eAAe;IACjD;IAEA,kBAAkBD,IAAY,EAAuC;QACjE,OAAO,IAAI,CAAC,iBAAiB,CAAC,iBAAiB,CAACA;IACpD;AACJ;AAEO,MAAME;IAKF,KAAKC,MAAwB,EAAEC,SAAsB,EAAQ;QAChE,MAAMC,aAAaC,KAAK,SAAS,CAACH;QAClC,IAAI,IAAI,CAAC,UAAU,IAAI,IAAI,CAAC,UAAU,KAAKE,YACvC;QAGJ,IAAI,CAAC,UAAU,GAAGA;QAClB,MAAME,YAAY,IAAIC,UAAUL,OAAO,OAAO,EAAEA,OAAO,MAAM,EAAEA,OAAO,SAAS;QAE/E,MAAMM,eAAe,IAAIC,oBAAoB;YAAEH;QAAU;QAEzD,IAAIT,UAAuB,IAAIa,QAAQF;QAEvC,IAAIN,OAAO,OAAO,IAAI,CAACS,YAAY,SAAS,IAAI;YAC5C,IAAI,CAAC,SAAS,GAAG;YACjBd,UAAU,IAAIe,WAAWJ,cAAcX;QAC3C;QAEA,MAAMgB,QAAQC,MAAM,IAAI,CAACZ,OAAO,KAAK,IAAI,CAAC;QAE1C,IAAIS,YAAY,QAAQ,IACpBI,gBAAgB,cAAc,CAACF,MAAM,WAAW;QAGpD,IAAIf;QACJ,IAAIa,YAAY,SAAS,IACrBb,aAAa,IAAIkB,WAAWnB,SAASgB;QAGzC,IAAI,CAAC,GAAG,GAAG,IAAIlB,mBACX,IAAIsB,kBAAkBX,YACtBT,SACAC;QAGJ,IAAI,AAAqB,cAArB,OAAOK,WACPA;IAER;IAEO,gBAAgB;QACnB,IAAI,CAAC,iBAAiB;QACtB,OAAO,IAAI,CAAC,GAAG,CAAC,aAAa;IACjC;IAEO,QAAQJ,IAAY,EAAE;QACzB,IAAI,CAAC,iBAAiB;QACtB,OAAO,IAAI,CAAC,GAAG,CAAC,OAAO,CAACA;IAC5B;IAEO,UAAUC,OAA0B,EAAE;QACzC,IAAI,CAAC,iBAAiB;QACtB,OAAO,IAAI,CAAC,GAAG,CAAC,SAAS,CAACA;IAC9B;IAEA,MAAa,kBAAkB;QAC3B,IAAI,CAAC,iBAAiB;QACtB,OAAO,IAAI,CAAC,GAAG,CAAC,eAAe;IACnC;IAEA,kBAAkBD,IAAY,EAAuC;QACjE,IAAI,CAAC,iBAAiB;QACtB,OAAO,IAAI,CAAC,GAAG,CAAC,iBAAiB,CAACA;IACtC;IAEA,kBAAkBmB,SAAoB,EAAQ;QAC1C,IAAI,CAAC,iBAAiB;QACtBC,kBAAkB,QAAQ,CAACD;IAC/B;IAEA,eAAeE,MAA4B,EAA8B;QACrE,IAAI,CAAC,iBAAiB;QACtB,OAAO,IAAIC,kBAAkBF,mBAAmB,OAAO,CAACC;IAC5D;IAEA,YAAY;QACR,OAAOT,YAAY,SAAS;IAChC;IAEA,eAAe;QACX,OAAO,IAAI,CAAC,SAAS;IACzB;IAEQ,oBAEN;QACE,IAAI,CAAC,IAAI,CAAC,GAAG,EACT,MAAM,IAAIW,MAAM;IAExB;;aA5FQ,SAAS,GAAG;;AA6FxB;AAEO,MAAMC,aAAa,IAAItB"}
|
|
1
|
+
{"version":3,"file":"ContentSdk.js","sources":["../src/ContentSdk.ts"],"sourcesContent":["import type {\n Component,\n Document,\n IContentSdk,\n IDataProvider,\n ListPagesOptions,\n ListPagesResult,\n PublicPage,\n PublicRedirect,\n ResolvedComponent\n} from \"~/types.js\";\nimport type { ActiveExperiment, VariantContent } from \"~/experiments/types.js\";\nimport {\n getPageWithExperiment,\n type ExperimentRenderResult,\n type GetPageWithExperimentOptions\n} from \"~/experiments/render.js\";\nimport { environment } from \"./Environment.js\";\nimport { LiveSdk } from \"./LiveSdk.js\";\nimport { EditingSdk } from \"./EditingSdk.js\";\nimport { ComponentResolver, type ResolveElementParams } from \"~/ComponentResolver.js\";\nimport { PreviewSdk } from \"./PreviewSdk.js\";\nimport type { ComponentRegistry } from \"~/ComponentRegistry.js\";\nimport { componentRegistry } from \"~/ComponentRegistry.js\";\nimport type { ContentEntryCache } from \"~/contentEntry/ContentEntryCache.js\";\nimport { contentEntryCache } from \"~/contentEntry/ContentEntryCache.js\";\nimport type { DocumentStoreManager } from \"~/DocumentStoreManager.js\";\nimport { documentStoreManager } from \"~/DocumentStoreManager.js\";\nimport { ApiClient } from \"~/dataProviders/ApiClient.js\";\nimport { DefaultDataProvider } from \"~/dataProviders/DefaultDataProvider.js\";\nimport type { WebsiteBuilderThemeInput } from \"./types/WebsiteBuilderTheme.js\";\nimport { Theme } from \"./Theme.js\";\nimport { viewportManager } from \"./ViewportManager.js\";\nimport type { IRedirects } from \"~/IRedirects.js\";\nimport { RedirectsProvider } from \"~/dataProviders/RedirectsProvider.js\";\nimport type { HeadersProvider } from \"~/headersProvider.js\";\nimport type { ContentEntryLoader } from \"~/contentEntry/resolveContentEntry.js\";\nimport type { ComponentLoader, ComponentLoaderFactory } from \"~/componentLoader/ComponentLoader.js\";\nimport type { ComponentLoaderFactoryParams } from \"~/componentLoader/ComponentLoader.js\";\nimport { createComponentLoader } from \"~/componentLoader/createComponentLoader.js\";\n\nexport type ApiConfig = {\n apiKey: string;\n apiHost: string;\n apiTenant: string;\n};\n\nexport type ContentSDKConfig = ApiConfig & {\n preview?: boolean;\n previewParams?: string;\n theme?: WebsiteBuilderThemeInput;\n /**\n * Request headers for server-side preview and experiments. When omitted, the provider set\n * with `setHeadersProvider` is used. Meant for apps that serve requests outside the\n * framework hook; it never carries the tenant.\n */\n headersProvider?: HeadersProvider;\n /**\n * Loads the CMS entries that `contentEntry` inputs reference, for this SDK's content\n * entry cache. Pass one bound to the same tenant as this SDK. When omitted, the cache's\n * loader is left as it is.\n */\n contentEntryLoader?: ContentEntryLoader;\n /**\n * Creates the loader for components a document references but nobody registered. It gets\n * this SDK's API client and API config. When omitted, the default set with\n * `setDefaultComponentLoader` is used (`@webiny/sdk-nextjs` sets its remote component\n * loading), and without one nothing is loaded.\n */\n componentLoader?: ComponentLoaderFactory;\n};\n\n/**\n * The state a `ContentSdk` renders with. Each piece defaults to its module-level singleton, so\n * `new ContentSdk()` shares state with `contentSdk`. `createContentClient` passes new instances.\n */\nexport type ContentSdkState = {\n componentRegistry?: ComponentRegistry;\n contentEntryCache?: ContentEntryCache;\n documentStoreManager?: DocumentStoreManager;\n};\n\nclass InternalContentSdk implements IContentSdk, IRedirects {\n private activeSdk: IContentSdk;\n private editingSdk: EditingSdk | undefined;\n private redirectsProvider: IRedirects;\n\n constructor(redirectsProvider: IRedirects, liveSdk: LiveSdk, editingSdk?: EditingSdk) {\n this.redirectsProvider = redirectsProvider;\n this.activeSdk = editingSdk ?? liveSdk;\n this.editingSdk = editingSdk;\n }\n\n getEditingSdk() {\n return this.editingSdk;\n }\n\n async getPage(path: string): Promise<PublicPage | null> {\n return this.activeSdk.getPage(path);\n }\n\n listPages(options?: ListPagesOptions): Promise<ListPagesResult> {\n return this.activeSdk.listPages(options);\n }\n\n getAllRedirects(): Promise<Map<string, PublicRedirect>> {\n return this.redirectsProvider.getAllRedirects();\n }\n\n getRedirectByPath(path: string): Promise<PublicRedirect | undefined> {\n return this.redirectsProvider.getRedirectByPath(path);\n }\n}\n\nexport class ContentSdk implements IContentSdk, IRedirects {\n protected sdk?: InternalContentSdk;\n private isPreview = false;\n private lastConfig: any;\n private dataProvider?: IDataProvider;\n private headersProvider?: HeadersProvider;\n private componentLoaderFactory?: ComponentLoaderFactory;\n private componentLoaderParams?: ComponentLoaderFactoryParams;\n private componentLoader?: ComponentLoader;\n private readonly componentRegistry: ComponentRegistry;\n private readonly contentEntryCache: ContentEntryCache;\n private readonly documentStoreManager: DocumentStoreManager;\n\n constructor(state: ContentSdkState = {}) {\n this.componentRegistry = state.componentRegistry ?? componentRegistry;\n this.contentEntryCache = state.contentEntryCache ?? contentEntryCache;\n this.documentStoreManager = state.documentStoreManager ?? documentStoreManager;\n }\n\n public init(config: ContentSDKConfig, afterInit?: () => void): void {\n const configHash = JSON.stringify(config);\n if (this.lastConfig && this.lastConfig === configHash) {\n return;\n }\n\n this.lastConfig = configHash;\n this.headersProvider = config.headersProvider;\n if (config.contentEntryLoader) {\n this.contentEntryCache.setLoader(config.contentEntryLoader);\n }\n const apiClient = new ApiClient({\n apiHost: config.apiHost,\n apiKey: config.apiKey,\n apiTenant: config.apiTenant,\n preview: config.preview\n });\n\n const dataProvider = new DefaultDataProvider({ apiClient });\n\n // The loader is created on first use, so a default set after this call still applies.\n this.componentLoaderFactory = config.componentLoader;\n this.componentLoaderParams = {\n apiClient,\n config: {\n apiHost: config.apiHost,\n apiKey: config.apiKey,\n apiTenant: config.apiTenant\n }\n };\n this.componentLoader = undefined;\n this.dataProvider = dataProvider;\n\n let liveSdk: IContentSdk = new LiveSdk(dataProvider, this.documentStoreManager);\n\n if (config.preview && !environment.isEditing()) {\n this.isPreview = true;\n liveSdk = new PreviewSdk(\n dataProvider,\n liveSdk,\n config.previewParams,\n config.headersProvider\n );\n }\n\n const theme = Theme.from(config.theme ?? {});\n\n if (environment.isClient()) {\n viewportManager.setBreakpoints(theme.breakpoints);\n }\n\n let editingSdk;\n if (environment.isEditing()) {\n editingSdk = new EditingSdk(liveSdk, theme, {\n componentRegistry: this.componentRegistry,\n documentStoreManager: this.documentStoreManager\n });\n }\n\n this.sdk = new InternalContentSdk(\n new RedirectsProvider(apiClient),\n liveSdk as LiveSdk,\n editingSdk\n );\n\n if (typeof afterInit === \"function\") {\n afterInit();\n }\n }\n\n public getEditingSdk() {\n this.assertInitialized();\n return this.sdk.getEditingSdk();\n }\n\n public getPage(path: string) {\n this.assertInitialized();\n return this.sdk.getPage(path);\n }\n\n public getPageExperiment(path: string): Promise<ActiveExperiment | null> {\n return this.requireDataProvider().getPageExperiment(path);\n }\n\n public getVariantContent(variantId: string): Promise<VariantContent | null> {\n return this.requireDataProvider().getVariantContent(variantId);\n }\n\n public getExperimentPaused(experimentId: string): Promise<boolean> {\n return this.requireDataProvider().getExperimentPaused(experimentId);\n }\n\n /**\n * Resolve and render the right page for the current visitor (control or a variant),\n * server-side. Bucketing, targeting, exposure emission, and cache-key handling are all\n * encapsulated here so projects do not reimplement them. See {@link getPageWithExperiment}.\n */\n public getPageWithExperiment(\n path: string,\n options?: GetPageWithExperimentOptions\n ): Promise<ExperimentRenderResult> {\n this.assertInitialized();\n this.requireDataProvider();\n const experimentOptions: GetPageWithExperimentOptions = { ...options };\n if (this.headersProvider && !experimentOptions.headersProvider) {\n experimentOptions.headersProvider = this.headersProvider;\n }\n return getPageWithExperiment(\n {\n getPage: p => this.getPage(p),\n getPageExperiment: p => this.getPageExperiment(p),\n getVariantContent: id => this.getVariantContent(id),\n getExperimentPaused: id => this.getExperimentPaused(id)\n },\n path,\n experimentOptions\n );\n }\n\n public listPages(options?: ListPagesOptions) {\n this.assertInitialized();\n return this.sdk.listPages(options);\n }\n\n public async getAllRedirects() {\n this.assertInitialized();\n return this.sdk.getAllRedirects();\n }\n\n getRedirectByPath(path: string): Promise<PublicRedirect | undefined> {\n this.assertInitialized();\n return this.sdk.getRedirectByPath(path);\n }\n\n registerComponent(blueprint: Component): void {\n this.assertInitialized();\n this.componentRegistry.register(blueprint);\n }\n\n resolveElement(params: ResolveElementParams): ResolvedComponent[] | null {\n this.assertInitialized();\n return new ComponentResolver(this.componentRegistry, this.contentEntryCache).resolve(\n params\n );\n }\n\n /**\n * Load every component the document references that isn't registered yet, through the\n * component loader, and register what it returns. Call it before rendering the document.\n * Nothing is cached here: an unregistered component goes to the loader on every call.\n */\n public async loadDocumentComponents(document: Document): Promise<void> {\n this.assertInitialized();\n const names = new Set<string>();\n for (const element of Object.values(document.elements)) {\n const name = element.component?.name;\n if (name && !this.componentRegistry.get(name)) {\n names.add(name);\n }\n }\n\n const loader = this.getComponentLoader();\n const loads = Array.from(names).map(name => loader.loadComponent({ name }));\n const components = await Promise.all(loads);\n\n for (const component of components) {\n if (component) {\n this.componentRegistry.register(component);\n }\n }\n }\n\n private getComponentLoader(): ComponentLoader {\n if (!this.componentLoader) {\n this.componentLoader = createComponentLoader(\n this.componentLoaderFactory,\n this.componentLoaderParams!\n );\n }\n return this.componentLoader;\n }\n\n public getComponentRegistry(): ComponentRegistry {\n return this.componentRegistry;\n }\n\n public getContentEntryCache(): ContentEntryCache {\n return this.contentEntryCache;\n }\n\n public getDocumentStoreManager(): DocumentStoreManager {\n return this.documentStoreManager;\n }\n\n isEditing() {\n return environment.isEditing();\n }\n\n isPreviewing() {\n return this.isPreview;\n }\n\n private assertInitialized(): asserts this is this & {\n sdk: IContentSdk;\n } {\n if (!this.sdk) {\n throw new Error(`ContentSdk has not been initialized!`);\n }\n }\n\n private requireDataProvider(): IDataProvider {\n if (!this.dataProvider) {\n throw new Error(`ContentSdk has not been initialized!`);\n }\n return this.dataProvider;\n }\n}\n\nexport const contentSdk = new ContentSdk();\n"],"names":["InternalContentSdk","redirectsProvider","liveSdk","editingSdk","path","options","ContentSdk","state","componentRegistry","contentEntryCache","documentStoreManager","config","afterInit","configHash","JSON","apiClient","ApiClient","dataProvider","DefaultDataProvider","undefined","LiveSdk","environment","PreviewSdk","theme","Theme","viewportManager","EditingSdk","RedirectsProvider","variantId","experimentId","experimentOptions","getPageWithExperiment","p","id","blueprint","params","ComponentResolver","document","names","Set","element","Object","name","loader","loads","Array","components","Promise","component","createComponentLoader","Error","contentSdk"],"mappings":"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"}
|
|
@@ -1,11 +1,18 @@
|
|
|
1
1
|
import type { Document } from "./types.js";
|
|
2
2
|
import { DocumentStore } from "./DocumentStore.js";
|
|
3
|
-
declare
|
|
3
|
+
export declare const DEFAULT_MAX_DOCUMENT_STORES = 10000;
|
|
4
|
+
export type DocumentStoreManagerOptions = {
|
|
5
|
+
maxEntries?: number;
|
|
6
|
+
};
|
|
7
|
+
export declare class DocumentStoreManager {
|
|
4
8
|
private stores;
|
|
9
|
+
private readonly maxEntries;
|
|
10
|
+
constructor(options?: DocumentStoreManagerOptions);
|
|
5
11
|
getStores(): Map<string, DocumentStore<Document>>;
|
|
6
12
|
getStore<TDocument extends Document>(id: string): DocumentStore<TDocument>;
|
|
7
13
|
removeStore(id: string): void;
|
|
8
14
|
hasStore(id: string): boolean;
|
|
15
|
+
clear(): void;
|
|
16
|
+
private evict;
|
|
9
17
|
}
|
|
10
18
|
export declare const documentStoreManager: DocumentStoreManager;
|
|
11
|
-
export {};
|
package/DocumentStoreManager.js
CHANGED
|
@@ -1,11 +1,24 @@
|
|
|
1
1
|
import { DocumentStore } from "./DocumentStore.js";
|
|
2
|
+
const DEFAULT_MAX_DOCUMENT_STORES = 10000;
|
|
2
3
|
class DocumentStoreManager {
|
|
4
|
+
constructor(options = {}){
|
|
5
|
+
this.stores = new Map();
|
|
6
|
+
this.maxEntries = options.maxEntries ?? DEFAULT_MAX_DOCUMENT_STORES;
|
|
7
|
+
}
|
|
3
8
|
getStores() {
|
|
4
9
|
return this.stores;
|
|
5
10
|
}
|
|
6
11
|
getStore(id) {
|
|
7
|
-
|
|
8
|
-
|
|
12
|
+
const existing = this.stores.get(id);
|
|
13
|
+
if (existing) {
|
|
14
|
+
this.stores.delete(id);
|
|
15
|
+
this.stores.set(id, existing);
|
|
16
|
+
return existing;
|
|
17
|
+
}
|
|
18
|
+
const store = new DocumentStore();
|
|
19
|
+
this.stores.set(id, store);
|
|
20
|
+
this.evict();
|
|
21
|
+
return store;
|
|
9
22
|
}
|
|
10
23
|
removeStore(id) {
|
|
11
24
|
this.stores.delete(id);
|
|
@@ -13,11 +26,17 @@ class DocumentStoreManager {
|
|
|
13
26
|
hasStore(id) {
|
|
14
27
|
return this.stores.has(id);
|
|
15
28
|
}
|
|
16
|
-
|
|
17
|
-
this.stores
|
|
29
|
+
clear() {
|
|
30
|
+
this.stores.clear();
|
|
31
|
+
}
|
|
32
|
+
evict() {
|
|
33
|
+
while(this.stores.size > this.maxEntries){
|
|
34
|
+
const oldest = this.stores.keys().next().value;
|
|
35
|
+
this.stores.delete(oldest);
|
|
36
|
+
}
|
|
18
37
|
}
|
|
19
38
|
}
|
|
20
39
|
const documentStoreManager = new DocumentStoreManager();
|
|
21
|
-
export { documentStoreManager };
|
|
40
|
+
export { DEFAULT_MAX_DOCUMENT_STORES, DocumentStoreManager, documentStoreManager };
|
|
22
41
|
|
|
23
42
|
//# sourceMappingURL=DocumentStoreManager.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DocumentStoreManager.js","sources":["../src/DocumentStoreManager.ts"],"sourcesContent":["import type { Document } from \"./types.js\";\nimport { DocumentStore } from \"./DocumentStore.js\";\n\
|
|
1
|
+
{"version":3,"file":"DocumentStoreManager.js","sources":["../src/DocumentStoreManager.ts"],"sourcesContent":["import type { Document } from \"./types.js\";\nimport { DocumentStore } from \"./DocumentStore.js\";\n\n// High enough that an app serving one site never reaches it.\nexport const DEFAULT_MAX_DOCUMENT_STORES = 10_000;\n\nexport type DocumentStoreManagerOptions = {\n // Stores kept before the least recently used one is dropped.\n maxEntries?: number;\n};\n\nexport class DocumentStoreManager {\n private stores = new Map<string, DocumentStore>();\n private readonly maxEntries: number;\n\n constructor(options: DocumentStoreManagerOptions = {}) {\n this.maxEntries = options.maxEntries ?? DEFAULT_MAX_DOCUMENT_STORES;\n }\n\n getStores() {\n return this.stores;\n }\n\n getStore<TDocument extends Document>(id: string): DocumentStore<TDocument> {\n const existing = this.stores.get(id);\n if (existing) {\n // Move it to the end, so the map stays ordered from least to most recently used.\n this.stores.delete(id);\n this.stores.set(id, existing);\n return existing as DocumentStore<TDocument>;\n }\n\n const store = new DocumentStore<TDocument>();\n this.stores.set(id, store);\n this.evict();\n return store;\n }\n\n removeStore(id: string) {\n this.stores.delete(id);\n }\n\n hasStore(id: string): boolean {\n return this.stores.has(id);\n }\n\n clear() {\n this.stores.clear();\n }\n\n private evict() {\n while (this.stores.size > this.maxEntries) {\n const oldest = this.stores.keys().next().value!;\n this.stores.delete(oldest);\n }\n }\n}\n\nexport const documentStoreManager = new DocumentStoreManager();\n"],"names":["DEFAULT_MAX_DOCUMENT_STORES","DocumentStoreManager","options","Map","id","existing","store","DocumentStore","oldest","documentStoreManager"],"mappings":";AAIO,MAAMA,8BAA8B;AAOpC,MAAMC;IAIT,YAAYC,UAAuC,CAAC,CAAC,CAAE;aAH/C,MAAM,GAAG,IAAIC;QAIjB,IAAI,CAAC,UAAU,GAAGD,QAAQ,UAAU,IAAIF;IAC5C;IAEA,YAAY;QACR,OAAO,IAAI,CAAC,MAAM;IACtB;IAEA,SAAqCI,EAAU,EAA4B;QACvE,MAAMC,WAAW,IAAI,CAAC,MAAM,CAAC,GAAG,CAACD;QACjC,IAAIC,UAAU;YAEV,IAAI,CAAC,MAAM,CAAC,MAAM,CAACD;YACnB,IAAI,CAAC,MAAM,CAAC,GAAG,CAACA,IAAIC;YACpB,OAAOA;QACX;QAEA,MAAMC,QAAQ,IAAIC;QAClB,IAAI,CAAC,MAAM,CAAC,GAAG,CAACH,IAAIE;QACpB,IAAI,CAAC,KAAK;QACV,OAAOA;IACX;IAEA,YAAYF,EAAU,EAAE;QACpB,IAAI,CAAC,MAAM,CAAC,MAAM,CAACA;IACvB;IAEA,SAASA,EAAU,EAAW;QAC1B,OAAO,IAAI,CAAC,MAAM,CAAC,GAAG,CAACA;IAC3B;IAEA,QAAQ;QACJ,IAAI,CAAC,MAAM,CAAC,KAAK;IACrB;IAEQ,QAAQ;QACZ,MAAO,IAAI,CAAC,MAAM,CAAC,IAAI,GAAG,IAAI,CAAC,UAAU,CAAE;YACvC,MAAMI,SAAS,IAAI,CAAC,MAAM,CAAC,IAAI,GAAG,IAAI,GAAG,KAAK;YAC9C,IAAI,CAAC,MAAM,CAAC,MAAM,CAACA;QACvB;IACJ;AACJ;AAEO,MAAMC,uBAAuB,IAAIR"}
|
package/EditingSdk.d.ts
CHANGED
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
import type { ComponentGroup, IContentSdk, ListPagesOptions, ListPagesResult, PublicPage } from "./types.js";
|
|
2
2
|
import { Messenger } from "./messenger/index.js";
|
|
3
|
+
import type { ComponentRegistry } from "./ComponentRegistry.js";
|
|
4
|
+
import type { DocumentStoreManager } from "./DocumentStoreManager.js";
|
|
3
5
|
import type { WebsiteBuilderTheme } from "./types/WebsiteBuilderTheme.js";
|
|
6
|
+
export type EditingSdkState = {
|
|
7
|
+
componentRegistry?: ComponentRegistry;
|
|
8
|
+
documentStoreManager?: DocumentStoreManager;
|
|
9
|
+
};
|
|
4
10
|
export declare class EditingSdk implements IContentSdk {
|
|
5
11
|
readonly messenger: Messenger;
|
|
6
12
|
private positionReportingEnabled;
|
|
@@ -9,7 +15,7 @@ export declare class EditingSdk implements IContentSdk {
|
|
|
9
15
|
private documentStore;
|
|
10
16
|
private previewDocument;
|
|
11
17
|
private lastBoxesHash;
|
|
12
|
-
constructor(liveSdk: IContentSdk, theme: WebsiteBuilderTheme);
|
|
18
|
+
constructor(liveSdk: IContentSdk, theme: WebsiteBuilderTheme, state?: EditingSdkState);
|
|
13
19
|
getPage(path: string): Promise<PublicPage | null>;
|
|
14
20
|
listPages(options?: ListPagesOptions): Promise<ListPagesResult>;
|
|
15
21
|
registerComponentGroup(group: ComponentGroup): void;
|
package/EditingSdk.js
CHANGED
|
@@ -9,17 +9,19 @@ import { documentStoreManager } from "./DocumentStoreManager.js";
|
|
|
9
9
|
import { PreviewDocument } from "./PreviewDocument.js";
|
|
10
10
|
import { hashObject } from "./HashObject.js";
|
|
11
11
|
class EditingSdk {
|
|
12
|
-
constructor(liveSdk, theme){
|
|
12
|
+
constructor(liveSdk, theme, state = {}){
|
|
13
13
|
this.positionReportingEnabled = false;
|
|
14
14
|
this.previewViewport = null;
|
|
15
15
|
this.lastBoxesHash = 0;
|
|
16
16
|
this.liveSdk = liveSdk;
|
|
17
|
+
const registry = state.componentRegistry ?? componentRegistry;
|
|
18
|
+
const stores = state.documentStoreManager ?? documentStoreManager;
|
|
17
19
|
const source = new MessageOrigin(()=>window, window.location.origin);
|
|
18
20
|
const target = new MessageOrigin(()=>window.parent, this.getReferrerOrigin());
|
|
19
21
|
this.previewDocument = PreviewDocument.createFromWindow();
|
|
20
|
-
this.documentStore =
|
|
22
|
+
this.documentStore = stores.getStore(this.previewDocument.getId());
|
|
21
23
|
this.messenger = new Messenger(source, target, "wb.editor.*");
|
|
22
|
-
|
|
24
|
+
registry.onRegister((reg)=>{
|
|
23
25
|
this.messenger.send("preview.component.register", reg.component.manifest);
|
|
24
26
|
});
|
|
25
27
|
this.setupListeners();
|