@webiny/website-builder-sdk 0.0.0-unstable.9f53ea597d → 0.0.0-unstable.a4f3e4ea8b

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.
Files changed (65) hide show
  1. package/BindingsResolver.d.ts +4 -1
  2. package/BindingsResolver.js.map +1 -1
  3. package/ComponentResolver.d.ts +3 -2
  4. package/ComponentResolver.js +6 -3
  5. package/ComponentResolver.js.map +1 -1
  6. package/ContentSdk.d.ts +0 -11
  7. package/ContentSdk.js +0 -20
  8. package/ContentSdk.js.map +1 -1
  9. package/contentEntry/ContentEntryBindingsResolver.d.ts +30 -0
  10. package/contentEntry/ContentEntryBindingsResolver.js +45 -0
  11. package/contentEntry/ContentEntryBindingsResolver.js.map +1 -0
  12. package/contentEntry/ContentEntryCache.d.ts +46 -0
  13. package/contentEntry/ContentEntryCache.js +50 -0
  14. package/contentEntry/ContentEntryCache.js.map +1 -0
  15. package/contentEntry/resolveContentEntry.d.ts +74 -0
  16. package/contentEntry/resolveContentEntry.js +53 -0
  17. package/contentEntry/resolveContentEntry.js.map +1 -0
  18. package/contentEntry/resolveContentEntry.test.js +213 -0
  19. package/contentEntry/resolveContentEntry.test.js.map +1 -0
  20. package/createComponent.d.ts +5 -0
  21. package/createComponent.js +32 -0
  22. package/createComponent.js.map +1 -0
  23. package/createInput.d.ts +10 -2
  24. package/createInput.js +8 -1
  25. package/createInput.js.map +1 -1
  26. package/dataProviders/ApiClient.js.map +1 -1
  27. package/dataProviders/DefaultDataProvider.d.ts +0 -4
  28. package/dataProviders/DefaultDataProvider.js +0 -35
  29. package/dataProviders/DefaultDataProvider.js.map +1 -1
  30. package/dataProviders/NullDataProvider.d.ts +0 -4
  31. package/dataProviders/NullDataProvider.js +0 -9
  32. package/dataProviders/NullDataProvider.js.map +1 -1
  33. package/index.d.ts +4 -1
  34. package/index.js +4 -1
  35. package/package.json +3 -3
  36. package/types.d.ts +69 -5
  37. package/dataProviders/GET_EXPERIMENT_PAUSED.d.ts +0 -1
  38. package/dataProviders/GET_EXPERIMENT_PAUSED.js +0 -17
  39. package/dataProviders/GET_EXPERIMENT_PAUSED.js.map +0 -1
  40. package/dataProviders/GET_PAGE_EXPERIMENT.d.ts +0 -1
  41. package/dataProviders/GET_PAGE_EXPERIMENT.js +0 -32
  42. package/dataProviders/GET_PAGE_EXPERIMENT.js.map +0 -1
  43. package/dataProviders/GET_VARIANT_CONTENT.d.ts +0 -1
  44. package/dataProviders/GET_VARIANT_CONTENT.js +0 -24
  45. package/dataProviders/GET_VARIANT_CONTENT.js.map +0 -1
  46. package/experiments/PostHogAnalyticsProvider.d.ts +0 -31
  47. package/experiments/PostHogAnalyticsProvider.js +0 -28
  48. package/experiments/PostHogAnalyticsProvider.js.map +0 -1
  49. package/experiments/analyticsProvider.d.ts +0 -4
  50. package/experiments/analyticsProvider.js +0 -11
  51. package/experiments/analyticsProvider.js.map +0 -1
  52. package/experiments/bucketing.d.ts +0 -27
  53. package/experiments/bucketing.js +0 -91
  54. package/experiments/bucketing.js.map +0 -1
  55. package/experiments/bucketing.test.js +0 -183
  56. package/experiments/bucketing.test.js.map +0 -1
  57. package/experiments/index.d.ts +0 -5
  58. package/experiments/index.js +0 -5
  59. package/experiments/render.d.ts +0 -79
  60. package/experiments/render.js +0 -149
  61. package/experiments/render.js.map +0 -1
  62. package/experiments/types.d.ts +0 -108
  63. package/experiments/types.js +0 -4
  64. package/experiments/types.js.map +0 -1
  65. /package/{experiments/bucketing.test.d.ts → contentEntry/resolveContentEntry.test.d.ts} +0 -0
@@ -9,7 +9,10 @@ export type ResolveElementParams = {
9
9
  inputAst: InputAstNode[];
10
10
  onResolved?: OnResolved;
11
11
  };
12
- export declare class BindingsResolver {
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[];
@@ -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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"}
@@ -1,14 +1,15 @@
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
4
  export type ResolveElementParams = {
5
5
  element: DocumentElement;
6
6
  elementBindings: DocumentElementBindings;
7
7
  state: DocumentState;
8
+ cache?: DocumentCache;
8
9
  onResolved?: OnResolved;
9
10
  };
10
11
  export declare class ComponentResolver {
11
12
  private components;
12
13
  constructor(registry: ComponentRegistry);
13
- resolve({ element, elementBindings, onResolved, state }: ResolveElementParams): ResolvedComponent[] | null;
14
+ resolve({ element, elementBindings, onResolved, state, cache }: ResolveElementParams): ResolvedComponent[] | null;
14
15
  }
@@ -1,19 +1,22 @@
1
1
  import { logger } from "./Logger.js";
2
2
  import { BindingsResolver } from "./BindingsResolver.js";
3
+ import { ContentEntryBindingsResolver } from "./contentEntry/ContentEntryBindingsResolver.js";
3
4
  import { ComponentManifestToAstConverter } from "./ComponentManifestToAstConverter.js";
4
5
  class ComponentResolver {
5
6
  constructor(registry){
6
7
  this.components = registry;
7
8
  }
8
- resolve({ element, elementBindings = {}, onResolved, state }) {
9
+ resolve({ element, elementBindings = {}, onResolved, state, cache }) {
9
10
  const componentName = element.component.name;
10
11
  const blueprint = this.components.get(componentName);
11
12
  if (!blueprint) {
12
13
  logger.warn(`Unknown component: ${componentName}`);
13
14
  return null;
14
15
  }
15
- const bindingsResolver = new BindingsResolver(state);
16
- const instances = bindingsResolver.resolveElement({
16
+ const embedded = cache?.contentEntries;
17
+ const resolvedEntries = embedded ? new Map(Object.entries(embedded)) : void 0;
18
+ const resolver = new ContentEntryBindingsResolver(new BindingsResolver(state), resolvedEntries);
19
+ const instances = resolver.resolveElement({
17
20
  element,
18
21
  elementBindings,
19
22
  inputAst: ComponentManifestToAstConverter.convert(blueprint.manifest.inputs ?? []),
@@ -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\";\n\nexport type ResolveElementParams = {\n element: DocumentElement;\n elementBindings: DocumentElementBindings;\n state: DocumentState;\n onResolved?: OnResolved;\n};\n\nexport class ComponentResolver {\n private components: ComponentRegistry;\n\n constructor(registry: ComponentRegistry) {\n this.components = registry;\n }\n\n resolve({\n element,\n elementBindings = {},\n onResolved,\n state\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 const bindingsResolver = new BindingsResolver(state);\n const instances = bindingsResolver.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","element","elementBindings","onResolved","state","componentName","blueprint","logger","bindingsResolver","BindingsResolver","instances","ComponentManifestToAstConverter","instance"],"mappings":";;;AAmBO,MAAMA;IAGT,YAAYC,QAA2B,CAAE;QACrC,IAAI,CAAC,UAAU,GAAGA;IACtB;IAEA,QAAQ,EACJC,OAAO,EACPC,kBAAkB,CAAC,CAAC,EACpBC,UAAU,EACVC,KAAK,EACc,EAA8B;QACjD,MAAMC,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;QAEA,MAAMG,mBAAmB,IAAIC,iBAAiBL;QAC9C,MAAMM,YAAYF,iBAAiB,cAAc,CAAC;YAC9CP;YACAC;YACA,UAAUS,gCAAgC,OAAO,CAACL,UAAU,QAAQ,CAAC,MAAM,IAAI,EAAE;YACjFH;QACJ;QAEA,OAAOO,UAAU,GAAG,CAACE,CAAAA,WAAa;gBAC9B,WAAWN,UAAU,SAAS;gBAC9B,UAAUA,UAAU,QAAQ;gBAC5B,QAAQM,SAAS,MAAM;gBACvB,QAAQA,SAAS,MAAM;YAC3B;IACJ;AACJ"}
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 { 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\n constructor(registry: ComponentRegistry) {\n this.components = registry;\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 );\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","element","elementBindings","onResolved","state","cache","componentName","blueprint","logger","embedded","resolvedEntries","Map","Object","undefined","resolver","ContentEntryBindingsResolver","BindingsResolver","instances","ComponentManifestToAstConverter","instance"],"mappings":";;;;AAqBO,MAAMA;IAGT,YAAYC,QAA2B,CAAE;QACrC,IAAI,CAAC,UAAU,GAAGA;IACtB;IAEA,QAAQ,EACJC,OAAO,EACPC,kBAAkB,CAAC,CAAC,EACpBC,UAAU,EACVC,KAAK,EACLC,KAAK,EACc,EAA8B;QACjD,MAAMC,gBAAgBL,QAAQ,SAAS,CAAC,IAAI;QAC5C,MAAMM,YAAY,IAAI,CAAC,UAAU,CAAC,GAAG,CAACD;QAEtC,IAAI,CAACC,WAAW;YACZC,OAAO,IAAI,CAAC,CAAC,mBAAmB,EAAEF,eAAe;YACjD,OAAO;QACX;QAIA,MAAMG,WAAWJ,OAAO;QACxB,MAAMK,kBAAkBD,WAAW,IAAIE,IAAIC,OAAO,OAAO,CAACH,aAAaI;QAEvE,MAAMC,WAAW,IAAIC,6BACjB,IAAIC,iBAAiBZ,QACrBM;QAGJ,MAAMO,YAAYH,SAAS,cAAc,CAAC;YACtCb;YACAC;YACA,UAAUgB,gCAAgC,OAAO,CAACX,UAAU,QAAQ,CAAC,MAAM,IAAI,EAAE;YACjFJ;QACJ;QAEA,OAAOc,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,6 +1,4 @@
1
1
  import type { Component, 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";
4
2
  import { LiveSdk } from "./LiveSdk.js";
5
3
  import { EditingSdk } from "./EditingSdk.js";
6
4
  import { type ResolveElementParams } from "./ComponentResolver.js";
@@ -35,15 +33,6 @@ export declare class ContentSdk implements IContentSdk, IRedirects {
35
33
  init(config: ContentSDKConfig, afterInit?: () => void): void;
36
34
  getEditingSdk(): EditingSdk | undefined;
37
35
  getPage(path: string): Promise<PublicPage | null>;
38
- getPageExperiment(path: string): Promise<ActiveExperiment | null>;
39
- getVariantContent(variantId: string): Promise<VariantContent | null>;
40
- getExperimentPaused(experimentId: string): Promise<boolean>;
41
- /**
42
- * Resolve and render the right page for the current visitor (control or a variant),
43
- * server-side. Bucketing, targeting, exposure emission, and cache-key handling are all
44
- * encapsulated here so projects do not reimplement them. See {@link getPageWithExperiment}.
45
- */
46
- getPageWithExperiment(path: string, options?: GetPageWithExperimentOptions): Promise<ExperimentRenderResult>;
47
36
  listPages(options?: ListPagesOptions): Promise<ListPagesResult>;
48
37
  getAllRedirects(): Promise<Map<string, PublicRedirect>>;
49
38
  getRedirectByPath(path: string): Promise<PublicRedirect | undefined>;
package/ContentSdk.js CHANGED
@@ -1,4 +1,3 @@
1
- import { getPageWithExperiment } from "./experiments/render.js";
2
1
  import { environment } from "./Environment.js";
3
2
  import { LiveSdk } from "./LiveSdk.js";
4
3
  import { EditingSdk } from "./EditingSdk.js";
@@ -67,25 +66,6 @@ class ContentSdk {
67
66
  this.assertInitialized();
68
67
  return this.sdk.getPage(path);
69
68
  }
70
- getPageExperiment(path) {
71
- return this.requireDataProvider().getPageExperiment(path);
72
- }
73
- getVariantContent(variantId) {
74
- return this.requireDataProvider().getVariantContent(variantId);
75
- }
76
- getExperimentPaused(experimentId) {
77
- return this.requireDataProvider().getExperimentPaused(experimentId);
78
- }
79
- getPageWithExperiment(path, options) {
80
- this.assertInitialized();
81
- this.requireDataProvider();
82
- return getPageWithExperiment({
83
- getPage: (p)=>this.getPage(p),
84
- getPageExperiment: (p)=>this.getPageExperiment(p),
85
- getVariantContent: (id)=>this.getVariantContent(id),
86
- getExperimentPaused: (id)=>this.getExperimentPaused(id)
87
- }, path, options);
88
- }
89
69
  listPages(options) {
90
70
  this.assertInitialized();
91
71
  return this.sdk.listPages(options);
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 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 { 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 previewParams?: string;\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 private dataProvider?: IDataProvider;\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({\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 this.dataProvider = dataProvider;\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, config.previewParams);\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 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 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 options\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 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 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","config","afterInit","configHash","JSON","apiClient","ApiClient","dataProvider","DefaultDataProvider","LiveSdk","environment","PreviewSdk","theme","Theme","viewportManager","EditingSdk","RedirectsProvider","variantId","experimentId","getPageWithExperiment","p","id","blueprint","componentRegistry","params","ComponentResolver","Error","contentSdk"],"mappings":";;;;;;;;;;;;AA0CA,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;IAMF,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,UAAU;YAC5B,SAASL,OAAO,OAAO;YACvB,QAAQA,OAAO,MAAM;YACrB,WAAWA,OAAO,SAAS;YAC3B,SAASA,OAAO,OAAO;QAC3B;QAEA,MAAMM,eAAe,IAAIC,oBAAoB;YAAEH;QAAU;QACzD,IAAI,CAAC,YAAY,GAAGE;QAEpB,IAAIX,UAAuB,IAAIa,QAAQF;QAEvC,IAAIN,OAAO,OAAO,IAAI,CAACS,YAAY,SAAS,IAAI;YAC5C,IAAI,CAAC,SAAS,GAAG;YACjBd,UAAU,IAAIe,WAAWJ,cAAcX,SAASK,OAAO,aAAa;QACxE;QAEA,MAAMW,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,kBAAkBA,IAAY,EAAoC;QACrE,OAAO,IAAI,CAAC,mBAAmB,GAAG,iBAAiB,CAACA;IACxD;IAEO,kBAAkBmB,SAAiB,EAAkC;QACxE,OAAO,IAAI,CAAC,mBAAmB,GAAG,iBAAiB,CAACA;IACxD;IAEO,oBAAoBC,YAAoB,EAAoB;QAC/D,OAAO,IAAI,CAAC,mBAAmB,GAAG,mBAAmB,CAACA;IAC1D;IAOO,sBACHpB,IAAY,EACZC,OAAsC,EACP;QAC/B,IAAI,CAAC,iBAAiB;QACtB,IAAI,CAAC,mBAAmB;QACxB,OAAOoB,sBACH;YACI,SAASC,CAAAA,IAAK,IAAI,CAAC,OAAO,CAACA;YAC3B,mBAAmBA,CAAAA,IAAK,IAAI,CAAC,iBAAiB,CAACA;YAC/C,mBAAmBC,CAAAA,KAAM,IAAI,CAAC,iBAAiB,CAACA;YAChD,qBAAqBA,CAAAA,KAAM,IAAI,CAAC,mBAAmB,CAACA;QACxD,GACAvB,MACAC;IAER;IAEO,UAAUA,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,kBAAkBwB,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,OAAOd,YAAY,SAAS;IAChC;IAEA,eAAe;QACX,OAAO,IAAI,CAAC,SAAS;IACzB;IAEQ,oBAEN;QACE,IAAI,CAAC,IAAI,CAAC,GAAG,EACT,MAAM,IAAIgB,MAAM;IAExB;IAEQ,sBAAqC;QACzC,IAAI,CAAC,IAAI,CAAC,YAAY,EAClB,MAAM,IAAIA,MAAM;QAEpB,OAAO,IAAI,CAAC,YAAY;IAC5B;;aA7IQ,SAAS,GAAG;;AA8IxB;AAEO,MAAMC,aAAa,IAAI3B"}
1
+ {"version":3,"file":"ContentSdk.js","sources":["../src/ContentSdk.ts"],"sourcesContent":["import type {\n Component,\n IContentSdk,\n IDataProvider,\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 previewParams?: string;\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 private dataProvider?: IDataProvider;\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({\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 this.dataProvider = dataProvider;\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, config.previewParams);\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 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","config","afterInit","configHash","JSON","apiClient","ApiClient","dataProvider","DefaultDataProvider","LiveSdk","environment","PreviewSdk","theme","Theme","viewportManager","EditingSdk","RedirectsProvider","blueprint","componentRegistry","params","ComponentResolver","Error","contentSdk"],"mappings":";;;;;;;;;;;AAoCA,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;IAMF,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,UAAU;YAC5B,SAASL,OAAO,OAAO;YACvB,QAAQA,OAAO,MAAM;YACrB,WAAWA,OAAO,SAAS;YAC3B,SAASA,OAAO,OAAO;QAC3B;QAEA,MAAMM,eAAe,IAAIC,oBAAoB;YAAEH;QAAU;QACzD,IAAI,CAAC,YAAY,GAAGE;QAEpB,IAAIX,UAAuB,IAAIa,QAAQF;QAEvC,IAAIN,OAAO,OAAO,IAAI,CAACS,YAAY,SAAS,IAAI;YAC5C,IAAI,CAAC,SAAS,GAAG;YACjBd,UAAU,IAAIe,WAAWJ,cAAcX,SAASK,OAAO,aAAa;QACxE;QAEA,MAAMW,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;IAEQ,sBAAqC;QACzC,IAAI,CAAC,IAAI,CAAC,YAAY,EAClB,MAAM,IAAIA,MAAM;QAEpB,OAAO,IAAI,CAAC,YAAY;IAC5B;;aA1GQ,SAAS,GAAG;;AA2GxB;AAEO,MAAMC,aAAa,IAAItB"}
@@ -0,0 +1,30 @@
1
+ import type { ResolvedElement } from "../types.js";
2
+ import type { IBindingsResolver, ResolveElementParams } from "../BindingsResolver.js";
3
+ /**
4
+ * Decorator for `IBindingsResolver` that resolves `contentEntry` inputs.
5
+ *
6
+ * The inner resolver evaluates binding expressions against the document state,
7
+ * producing raw values (`{ id, modelId }` references or query params). This
8
+ * decorator then replaces those raw values with pre-resolved CMS entries from
9
+ * a supplied map, or (on the client) triggers async resolution via the
10
+ * `contentEntryCache` singleton.
11
+ *
12
+ * **Server path**: `resolveContentEntries()` pre-fetches all entries, builds
13
+ * the `resolvedEntries` map, and passes it here. The decorator synchronously
14
+ * swaps raw values for resolved entries during render.
15
+ *
16
+ * **Client path (editor preview)**: `resolvedEntries` may be empty. The
17
+ * decorator falls back to `contentEntryCache.resolve()` which kicks off an
18
+ * async fetch; the mobx-observable cache triggers re-render when it lands.
19
+ */
20
+ export declare class ContentEntryBindingsResolver implements IBindingsResolver {
21
+ private readonly inner;
22
+ private readonly resolvedEntries;
23
+ constructor(inner: IBindingsResolver, resolvedEntries?: ReadonlyMap<string, unknown>);
24
+ resolveElement(params: ResolveElementParams): ResolvedElement[];
25
+ /**
26
+ * Walk the input AST and replace raw content-entry values with resolved
27
+ * entries from the map or the module-level cache.
28
+ */
29
+ private enrichContentEntryInputs;
30
+ }
@@ -0,0 +1,45 @@
1
+ import { contentEntryCache } from "./ContentEntryCache.js";
2
+ import { environment } from "../Environment.js";
3
+ class ContentEntryBindingsResolver {
4
+ constructor(inner, resolvedEntries = new Map()){
5
+ this.inner = inner;
6
+ this.resolvedEntries = resolvedEntries;
7
+ }
8
+ resolveElement(params) {
9
+ const results = this.inner.resolveElement(params);
10
+ for (const instance of results)this.enrichContentEntryInputs(params.element.id, params.inputAst, instance.inputs);
11
+ return results;
12
+ }
13
+ enrichContentEntryInputs(elementId, ast, inputs) {
14
+ for (const node of ast){
15
+ if ("contentEntry" === node.input.type) {
16
+ const key = `${elementId}:${node.name}`;
17
+ const rawValue = inputs[node.name];
18
+ const list = node.input.list ?? false;
19
+ if (this.resolvedEntries.has(key)) {
20
+ inputs[node.name] = this.resolvedEntries.get(key);
21
+ continue;
22
+ }
23
+ if (contentEntryCache.has(key)) {
24
+ inputs[node.name] = contentEntryCache.get(key);
25
+ continue;
26
+ }
27
+ if (environment.isClient() && contentEntryCache.getLoader()) {
28
+ const cacheKey = `${key}:${JSON.stringify(rawValue ?? null)}`;
29
+ contentEntryCache.resolve(cacheKey, rawValue, list);
30
+ const cached = contentEntryCache.get(cacheKey);
31
+ if (void 0 !== cached) inputs[node.name] = cached;
32
+ }
33
+ }
34
+ if (node.children.length > 0) {
35
+ const value = inputs[node.name];
36
+ if (node.list && Array.isArray(value)) {
37
+ for (const item of value)if ("object" == typeof item && null !== item) this.enrichContentEntryInputs(elementId, node.children, item);
38
+ } else if ("object" == typeof value && null !== value && !Array.isArray(value)) this.enrichContentEntryInputs(elementId, node.children, value);
39
+ }
40
+ }
41
+ }
42
+ }
43
+ export { ContentEntryBindingsResolver };
44
+
45
+ //# sourceMappingURL=ContentEntryBindingsResolver.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"contentEntry/ContentEntryBindingsResolver.js","sources":["../../src/contentEntry/ContentEntryBindingsResolver.ts"],"sourcesContent":["import type { ResolvedElement } from \"~/types.js\";\nimport type { IBindingsResolver, ResolveElementParams } from \"~/BindingsResolver.js\";\nimport type { InputAstNode } from \"~/ComponentManifestToAstConverter.js\";\nimport { contentEntryCache } from \"./ContentEntryCache.js\";\nimport { environment } from \"~/Environment.js\";\n\n/**\n * Decorator for `IBindingsResolver` that resolves `contentEntry` inputs.\n *\n * The inner resolver evaluates binding expressions against the document state,\n * producing raw values (`{ id, modelId }` references or query params). This\n * decorator then replaces those raw values with pre-resolved CMS entries from\n * a supplied map, or (on the client) triggers async resolution via the\n * `contentEntryCache` singleton.\n *\n * **Server path**: `resolveContentEntries()` pre-fetches all entries, builds\n * the `resolvedEntries` map, and passes it here. The decorator synchronously\n * swaps raw values for resolved entries during render.\n *\n * **Client path (editor preview)**: `resolvedEntries` may be empty. The\n * decorator falls back to `contentEntryCache.resolve()` which kicks off an\n * async fetch; the mobx-observable cache triggers re-render when it lands.\n */\nexport class ContentEntryBindingsResolver implements IBindingsResolver {\n constructor(\n private readonly inner: IBindingsResolver,\n private readonly resolvedEntries: ReadonlyMap<string, unknown> = new Map()\n ) {}\n\n resolveElement(params: ResolveElementParams): ResolvedElement[] {\n const results = this.inner.resolveElement(params);\n\n for (const instance of results) {\n this.enrichContentEntryInputs(params.element.id, params.inputAst, instance.inputs);\n }\n\n return results;\n }\n\n /**\n * Walk the input AST and replace raw content-entry values with resolved\n * entries from the map or the module-level cache.\n */\n private enrichContentEntryInputs(\n elementId: string,\n ast: InputAstNode[],\n inputs: Record<string, any>\n ): void {\n for (const node of ast) {\n if (node.input.type === \"contentEntry\") {\n const key = `${elementId}:${node.name}`;\n const rawValue = inputs[node.name];\n const list = node.input.list ?? false;\n\n // 1. Pre-resolved entries map (seeded by server pre-pass).\n if (this.resolvedEntries.has(key)) {\n inputs[node.name] = this.resolvedEntries.get(key);\n continue;\n }\n\n // 2. Module-level cache (populated by previous renders or\n // async resolves on the client).\n if (contentEntryCache.has(key)) {\n inputs[node.name] = contentEntryCache.get(key);\n continue;\n }\n\n // 3. Client-side async resolution: trigger a background fetch.\n // The observable cache write will cause a re-render.\n if (environment.isClient() && contentEntryCache.getLoader()) {\n const cacheKey = `${key}:${JSON.stringify(rawValue ?? null)}`;\n contentEntryCache.resolve(cacheKey, rawValue, list);\n const cached = contentEntryCache.get(cacheKey);\n if (cached !== undefined) {\n inputs[node.name] = cached;\n }\n }\n }\n\n // Recurse into children (object / object-list nodes).\n if (node.children.length > 0) {\n const value = inputs[node.name];\n if (node.list && Array.isArray(value)) {\n for (const item of value) {\n if (typeof item === \"object\" && item !== null) {\n this.enrichContentEntryInputs(elementId, node.children, item);\n }\n }\n } else if (typeof value === \"object\" && value !== null && !Array.isArray(value)) {\n this.enrichContentEntryInputs(elementId, node.children, value);\n }\n }\n }\n }\n}\n"],"names":["ContentEntryBindingsResolver","inner","resolvedEntries","Map","params","results","instance","elementId","ast","inputs","node","key","rawValue","list","contentEntryCache","environment","cacheKey","JSON","cached","undefined","value","Array","item"],"mappings":";;AAuBO,MAAMA;IACT,YACqBC,KAAwB,EACxBC,kBAAgD,IAAIC,KAAK,CAC5E;aAFmBF,KAAK,GAALA;aACAC,eAAe,GAAfA;IAClB;IAEH,eAAeE,MAA4B,EAAqB;QAC5D,MAAMC,UAAU,IAAI,CAAC,KAAK,CAAC,cAAc,CAACD;QAE1C,KAAK,MAAME,YAAYD,QACnB,IAAI,CAAC,wBAAwB,CAACD,OAAO,OAAO,CAAC,EAAE,EAAEA,OAAO,QAAQ,EAAEE,SAAS,MAAM;QAGrF,OAAOD;IACX;IAMQ,yBACJE,SAAiB,EACjBC,GAAmB,EACnBC,MAA2B,EACvB;QACJ,KAAK,MAAMC,QAAQF,IAAK;YACpB,IAAIE,AAAoB,mBAApBA,KAAK,KAAK,CAAC,IAAI,EAAqB;gBACpC,MAAMC,MAAM,GAAGJ,UAAU,CAAC,EAAEG,KAAK,IAAI,EAAE;gBACvC,MAAME,WAAWH,MAAM,CAACC,KAAK,IAAI,CAAC;gBAClC,MAAMG,OAAOH,KAAK,KAAK,CAAC,IAAI,IAAI;gBAGhC,IAAI,IAAI,CAAC,eAAe,CAAC,GAAG,CAACC,MAAM;oBAC/BF,MAAM,CAACC,KAAK,IAAI,CAAC,GAAG,IAAI,CAAC,eAAe,CAAC,GAAG,CAACC;oBAC7C;gBACJ;gBAIA,IAAIG,kBAAkB,GAAG,CAACH,MAAM;oBAC5BF,MAAM,CAACC,KAAK,IAAI,CAAC,GAAGI,kBAAkB,GAAG,CAACH;oBAC1C;gBACJ;gBAIA,IAAII,YAAY,QAAQ,MAAMD,kBAAkB,SAAS,IAAI;oBACzD,MAAME,WAAW,GAAGL,IAAI,CAAC,EAAEM,KAAK,SAAS,CAACL,YAAY,OAAO;oBAC7DE,kBAAkB,OAAO,CAACE,UAAUJ,UAAUC;oBAC9C,MAAMK,SAASJ,kBAAkB,GAAG,CAACE;oBACrC,IAAIE,AAAWC,WAAXD,QACAT,MAAM,CAACC,KAAK,IAAI,CAAC,GAAGQ;gBAE5B;YACJ;YAGA,IAAIR,KAAK,QAAQ,CAAC,MAAM,GAAG,GAAG;gBAC1B,MAAMU,QAAQX,MAAM,CAACC,KAAK,IAAI,CAAC;gBAC/B,IAAIA,KAAK,IAAI,IAAIW,MAAM,OAAO,CAACD,QAC3B;oBAAA,KAAK,MAAME,QAAQF,MACf,IAAI,AAAgB,YAAhB,OAAOE,QAAqBA,AAAS,SAATA,MAC5B,IAAI,CAAC,wBAAwB,CAACf,WAAWG,KAAK,QAAQ,EAAEY;gBAEhE,OACG,IAAI,AAAiB,YAAjB,OAAOF,SAAsBA,AAAU,SAAVA,SAAkB,CAACC,MAAM,OAAO,CAACD,QACrE,IAAI,CAAC,wBAAwB,CAACb,WAAWG,KAAK,QAAQ,EAAEU;YAEhE;QACJ;IACJ;AACJ"}
@@ -0,0 +1,46 @@
1
+ import { type ContentEntryLoader, type ResolvedContentEntry } from "./resolveContentEntry.js";
2
+ type RawValue = unknown | unknown[] | null | undefined;
3
+ /**
4
+ * SDK-level mobx cache for resolved content-entry inputs. Mirrors the CMS
5
+ * `RefCache` pattern: a singleton observable store that both the server
6
+ * pre-pass (`resolveAutoLoad`) and the editor preview path can seed / read.
7
+ *
8
+ * - **Server / SSR**: `resolveAutoLoad` calls `set(key, resolved)` for every
9
+ * entry it pre-resolves. `BindingsResolver.resolveSingleInstance` reads via
10
+ * `get(key)` synchronously during render — no React context needed.
11
+ *
12
+ * - **Editor preview**: `resolve(key, input, value, loader)` triggers an async
13
+ * fetch whose result is written inside a mobx action, so `observer`
14
+ * components re-render once it lands. Keyed by a signature of the raw value,
15
+ * so when the editor changes the selection/query the key changes and the
16
+ * entry is re-resolved.
17
+ */
18
+ declare class ContentEntryCacheImpl {
19
+ private cache;
20
+ private loader;
21
+ constructor();
22
+ get(key: string): ResolvedContentEntry | undefined;
23
+ has(key: string): boolean;
24
+ set(key: string, value: ResolvedContentEntry): void;
25
+ /**
26
+ * Register the CMS data loader that `resolve()` will use for async fetches.
27
+ * Called once during initialisation (e.g. by `resolveAutoLoad`). The loader
28
+ * is **not** mobx-observable — it's a plain service reference.
29
+ */
30
+ setLoader(loader: ContentEntryLoader): void;
31
+ /**
32
+ * Return the registered loader, if any.
33
+ */
34
+ getLoader(): ContentEntryLoader | undefined;
35
+ /**
36
+ * Lazily resolve `value` under `key`. Idempotent and safe to call during
37
+ * render: the observable write happens later, inside an action.
38
+ *
39
+ * Uses the loader registered via `setLoader()`. If no loader is registered,
40
+ * the call is a no-op (the raw value will be used instead).
41
+ */
42
+ resolve(key: string, value: RawValue, list: boolean): void;
43
+ clear(): void;
44
+ }
45
+ export declare const contentEntryCache: ContentEntryCacheImpl;
46
+ export {};
@@ -0,0 +1,50 @@
1
+ import { makeAutoObservable, runInAction } from "mobx";
2
+ import { resolveContentEntryValue } from "./resolveContentEntry.js";
3
+ const pending = new Set();
4
+ class ContentEntryCacheImpl {
5
+ constructor(){
6
+ this.cache = new Map();
7
+ makeAutoObservable(this, {
8
+ setLoader: false,
9
+ getLoader: false
10
+ });
11
+ }
12
+ get(key) {
13
+ return this.cache.get(key);
14
+ }
15
+ has(key) {
16
+ return this.cache.has(key);
17
+ }
18
+ set(key, value) {
19
+ runInAction(()=>{
20
+ this.cache.set(key, value);
21
+ });
22
+ }
23
+ setLoader(loader) {
24
+ this.loader = loader;
25
+ }
26
+ getLoader() {
27
+ return this.loader;
28
+ }
29
+ resolve(key, value, list) {
30
+ if (this.cache.has(key) || pending.has(key) || !this.loader) return;
31
+ pending.add(key);
32
+ resolveContentEntryValue(value, list, this.loader).then((resolved)=>{
33
+ runInAction(()=>{
34
+ this.cache.set(key, resolved);
35
+ });
36
+ pending.delete(key);
37
+ }).catch(()=>{
38
+ pending.delete(key);
39
+ });
40
+ }
41
+ clear() {
42
+ runInAction(()=>{
43
+ this.cache.clear();
44
+ });
45
+ }
46
+ }
47
+ const contentEntryCache = new ContentEntryCacheImpl();
48
+ export { contentEntryCache };
49
+
50
+ //# sourceMappingURL=ContentEntryCache.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"contentEntry/ContentEntryCache.js","sources":["../../src/contentEntry/ContentEntryCache.ts"],"sourcesContent":["import { makeAutoObservable, runInAction } from \"mobx\";\nimport {\n resolveContentEntryValue,\n type ContentEntryLoader,\n type ResolvedContentEntry\n} from \"./resolveContentEntry.js\";\n\ntype RawValue = unknown | unknown[] | null | undefined;\n\n// Non-observable dedupe set (kept out of the observable class so touching it\n// during render never counts as a mobx mutation-in-render).\nconst pending = new Set<string>();\n\n/**\n * SDK-level mobx cache for resolved content-entry inputs. Mirrors the CMS\n * `RefCache` pattern: a singleton observable store that both the server\n * pre-pass (`resolveAutoLoad`) and the editor preview path can seed / read.\n *\n * - **Server / SSR**: `resolveAutoLoad` calls `set(key, resolved)` for every\n * entry it pre-resolves. `BindingsResolver.resolveSingleInstance` reads via\n * `get(key)` synchronously during render — no React context needed.\n *\n * - **Editor preview**: `resolve(key, input, value, loader)` triggers an async\n * fetch whose result is written inside a mobx action, so `observer`\n * components re-render once it lands. Keyed by a signature of the raw value,\n * so when the editor changes the selection/query the key changes and the\n * entry is re-resolved.\n */\nclass ContentEntryCacheImpl {\n private cache = new Map<string, ResolvedContentEntry>();\n private loader: ContentEntryLoader | undefined;\n\n constructor() {\n makeAutoObservable(this, {\n // The loader is a plain service reference, not an observable value.\n setLoader: false,\n getLoader: false\n });\n }\n\n get(key: string): ResolvedContentEntry | undefined {\n return this.cache.get(key);\n }\n\n has(key: string): boolean {\n return this.cache.has(key);\n }\n\n set(key: string, value: ResolvedContentEntry): void {\n runInAction(() => {\n this.cache.set(key, value);\n });\n }\n\n /**\n * Register the CMS data loader that `resolve()` will use for async fetches.\n * Called once during initialisation (e.g. by `resolveAutoLoad`). The loader\n * is **not** mobx-observable — it's a plain service reference.\n */\n setLoader(loader: ContentEntryLoader): void {\n this.loader = loader;\n }\n\n /**\n * Return the registered loader, if any.\n */\n getLoader(): ContentEntryLoader | undefined {\n return this.loader;\n }\n\n /**\n * Lazily resolve `value` under `key`. Idempotent and safe to call during\n * render: the observable write happens later, inside an action.\n *\n * Uses the loader registered via `setLoader()`. If no loader is registered,\n * the call is a no-op (the raw value will be used instead).\n */\n resolve(key: string, value: RawValue, list: boolean): void {\n if (this.cache.has(key) || pending.has(key) || !this.loader) {\n return;\n }\n pending.add(key);\n resolveContentEntryValue(value as any, list, this.loader)\n .then(resolved => {\n runInAction(() => {\n this.cache.set(key, resolved);\n });\n pending.delete(key);\n })\n .catch(() => {\n pending.delete(key);\n });\n }\n\n clear(): void {\n runInAction(() => {\n this.cache.clear();\n });\n }\n}\n\nexport const contentEntryCache = new ContentEntryCacheImpl();\n"],"names":["pending","Set","ContentEntryCacheImpl","Map","makeAutoObservable","key","value","runInAction","loader","list","resolveContentEntryValue","resolved","contentEntryCache"],"mappings":";;AAWA,MAAMA,UAAU,IAAIC;AAiBpB,MAAMC;IAIF,aAAc;aAHN,KAAK,GAAG,IAAIC;QAIhBC,mBAAmB,IAAI,EAAE;YAErB,WAAW;YACX,WAAW;QACf;IACJ;IAEA,IAAIC,GAAW,EAAoC;QAC/C,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAACA;IAC1B;IAEA,IAAIA,GAAW,EAAW;QACtB,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAACA;IAC1B;IAEA,IAAIA,GAAW,EAAEC,KAA2B,EAAQ;QAChDC,YAAY;YACR,IAAI,CAAC,KAAK,CAAC,GAAG,CAACF,KAAKC;QACxB;IACJ;IAOA,UAAUE,MAA0B,EAAQ;QACxC,IAAI,CAAC,MAAM,GAAGA;IAClB;IAKA,YAA4C;QACxC,OAAO,IAAI,CAAC,MAAM;IACtB;IASA,QAAQH,GAAW,EAAEC,KAAe,EAAEG,IAAa,EAAQ;QACvD,IAAI,IAAI,CAAC,KAAK,CAAC,GAAG,CAACJ,QAAQL,QAAQ,GAAG,CAACK,QAAQ,CAAC,IAAI,CAAC,MAAM,EACvD;QAEJL,QAAQ,GAAG,CAACK;QACZK,yBAAyBJ,OAAcG,MAAM,IAAI,CAAC,MAAM,EACnD,IAAI,CAACE,CAAAA;YACFJ,YAAY;gBACR,IAAI,CAAC,KAAK,CAAC,GAAG,CAACF,KAAKM;YACxB;YACAX,QAAQ,MAAM,CAACK;QACnB,GACC,KAAK,CAAC;YACHL,QAAQ,MAAM,CAACK;QACnB;IACR;IAEA,QAAc;QACVE,YAAY;YACR,IAAI,CAAC,KAAK,CAAC,KAAK;QACpB;IACJ;AACJ;AAEO,MAAMK,oBAAoB,IAAIV"}
@@ -0,0 +1,74 @@
1
+ import type { ContentEntryReference, ContentEntryQueryValue } from "../types.js";
2
+ /**
3
+ * Minimal CMS data loader the content-entry resolver depends on. Injected by the
4
+ * caller (the render layer passes the CMS `contentSdk`) so this module stays
5
+ * decoupled from `@webiny/cms-sdk`.
6
+ */
7
+ export interface ContentEntryLoader {
8
+ getEntry(params: {
9
+ modelId: string;
10
+ entryId: string;
11
+ }): Promise<unknown | null>;
12
+ listEntries(params: {
13
+ modelId: string;
14
+ sort?: Record<string, "asc" | "desc">;
15
+ limit?: number;
16
+ search?: string;
17
+ after?: string;
18
+ }): Promise<{
19
+ data: unknown[];
20
+ meta: {
21
+ cursor: string | null;
22
+ hasMoreItems: boolean;
23
+ totalCount: number;
24
+ };
25
+ }>;
26
+ }
27
+ /**
28
+ * The query params used to produce a page. Embedded in the query result so the
29
+ * client can fetch further pages (loadMore) from `pageInfo.cursor`.
30
+ */
31
+ export interface ContentEntryQuerySpec {
32
+ modelId: string;
33
+ sort?: Record<string, "asc" | "desc">;
34
+ limit?: number;
35
+ search?: string;
36
+ }
37
+ export interface ResolvedContentEntryQuery<T = unknown> {
38
+ items: T[];
39
+ pageInfo: {
40
+ cursor: string | null;
41
+ hasMore: boolean;
42
+ totalCount: number;
43
+ };
44
+ /** Continuation params for loadMore. */
45
+ query?: ContentEntryQuerySpec;
46
+ }
47
+ /**
48
+ * The shape passed to a component for a content-entry input:
49
+ * - manual, single -> the resolved entry (or null)
50
+ * - manual, list -> an array of resolved entries
51
+ * - query -> `{ items, pageInfo, query? }`
52
+ */
53
+ export type ResolvedContentEntry = unknown | unknown[] | ResolvedContentEntryQuery | null;
54
+ /**
55
+ * Detect whether a raw binding value is a `ContentEntryQueryValue` (query mode)
56
+ * rather than a manual `ContentEntryReference`.
57
+ *
58
+ * Query values carry `modelId` but NOT `id`; manual references carry both.
59
+ */
60
+ export declare function isQueryValue(value: unknown): value is ContentEntryQueryValue;
61
+ /**
62
+ * Detect whether a content-entry input's value is already a resolved CMS entry
63
+ * rather than a bare reference that needs fetching.
64
+ */
65
+ export declare function isAlreadyResolved(value: unknown, list: boolean): boolean;
66
+ /**
67
+ * Resolve a content-entry binding value into CMS entries. Works entirely from
68
+ * the value shape — no component manifest needed.
69
+ *
70
+ * - `{ id, modelId }` → fetch single entry
71
+ * - `[{ id, modelId }, ...]` → fetch multiple entries
72
+ * - `{ modelId, sort?, limit?, search? }` → list query
73
+ */
74
+ export declare function resolveContentEntryValue(value: ContentEntryReference | ContentEntryReference[] | ContentEntryQueryValue | null | undefined, list: boolean, loader: ContentEntryLoader): Promise<ResolvedContentEntry>;
@@ -0,0 +1,53 @@
1
+ function isQueryValue(value) {
2
+ return "object" == typeof value && null !== value && "modelId" in value && !("id" in value) && !Array.isArray(value);
3
+ }
4
+ function isAlreadyResolved(value, list) {
5
+ if (null == value) return false;
6
+ if ("object" == typeof value && "items" in value) return true;
7
+ if (list && Array.isArray(value) && value.length > 0) {
8
+ const first = value[0];
9
+ return "object" == typeof first && null !== first && "values" in first;
10
+ }
11
+ if (!list && "object" == typeof value && "values" in value) return true;
12
+ return false;
13
+ }
14
+ async function resolveContentEntryValue(value, list, loader) {
15
+ if (null == value) return list ? [] : null;
16
+ if (isQueryValue(value)) {
17
+ const query = value;
18
+ const listParams = {
19
+ modelId: query.modelId,
20
+ sort: query.sort ? {
21
+ [query.sort.field]: query.sort.order
22
+ } : void 0,
23
+ limit: query.limit,
24
+ search: query.search
25
+ };
26
+ const result = await loader.listEntries(listParams);
27
+ return {
28
+ items: result.data,
29
+ pageInfo: {
30
+ cursor: result.meta.cursor,
31
+ hasMore: result.meta.hasMoreItems,
32
+ totalCount: result.meta.totalCount
33
+ },
34
+ query: listParams
35
+ };
36
+ }
37
+ if (Array.isArray(value)) {
38
+ const refs = value;
39
+ const entries = await Promise.all(refs.map((ref)=>loader.getEntry({
40
+ modelId: ref.modelId,
41
+ entryId: ref.id
42
+ })));
43
+ return entries.filter((entry)=>null !== entry);
44
+ }
45
+ const ref = value;
46
+ return loader.getEntry({
47
+ modelId: ref.modelId,
48
+ entryId: ref.id
49
+ });
50
+ }
51
+ export { isAlreadyResolved, isQueryValue, resolveContentEntryValue };
52
+
53
+ //# sourceMappingURL=resolveContentEntry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"contentEntry/resolveContentEntry.js","sources":["../../src/contentEntry/resolveContentEntry.ts"],"sourcesContent":["import type { ContentEntryReference, ContentEntryQueryValue } from \"~/types.js\";\n\n/**\n * Minimal CMS data loader the content-entry resolver depends on. Injected by the\n * caller (the render layer passes the CMS `contentSdk`) so this module stays\n * decoupled from `@webiny/cms-sdk`.\n */\nexport interface ContentEntryLoader {\n getEntry(params: { modelId: string; entryId: string }): Promise<unknown | null>;\n listEntries(params: {\n modelId: string;\n sort?: Record<string, \"asc\" | \"desc\">;\n limit?: number;\n search?: string;\n after?: string;\n }): Promise<{\n data: unknown[];\n meta: { cursor: string | null; hasMoreItems: boolean; totalCount: number };\n }>;\n}\n\n/**\n * The query params used to produce a page. Embedded in the query result so the\n * client can fetch further pages (loadMore) from `pageInfo.cursor`.\n */\nexport interface ContentEntryQuerySpec {\n modelId: string;\n sort?: Record<string, \"asc\" | \"desc\">;\n limit?: number;\n search?: string;\n}\n\nexport interface ResolvedContentEntryQuery<T = unknown> {\n items: T[];\n pageInfo: { cursor: string | null; hasMore: boolean; totalCount: number };\n /** Continuation params for loadMore. */\n query?: ContentEntryQuerySpec;\n}\n\n/**\n * The shape passed to a component for a content-entry input:\n * - manual, single -> the resolved entry (or null)\n * - manual, list -> an array of resolved entries\n * - query -> `{ items, pageInfo, query? }`\n */\nexport type ResolvedContentEntry = unknown | unknown[] | ResolvedContentEntryQuery | null;\n\n/**\n * Detect whether a raw binding value is a `ContentEntryQueryValue` (query mode)\n * rather than a manual `ContentEntryReference`.\n *\n * Query values carry `modelId` but NOT `id`; manual references carry both.\n */\nexport function isQueryValue(value: unknown): value is ContentEntryQueryValue {\n return (\n typeof value === \"object\" &&\n value !== null &&\n \"modelId\" in value &&\n !(\"id\" in value) &&\n !Array.isArray(value)\n );\n}\n\n/**\n * Detect whether a content-entry input's value is already a resolved CMS entry\n * rather than a bare reference that needs fetching.\n */\nexport function isAlreadyResolved(value: unknown, list: boolean): boolean {\n if (value == null) {\n return false;\n }\n // Query result — already resolved if it has `items`.\n if (typeof value === \"object\" && \"items\" in (value as any)) {\n return true;\n }\n // List of resolved entries — each has `values` (CMS entry shape).\n if (list && Array.isArray(value) && value.length > 0) {\n const first = value[0];\n return typeof first === \"object\" && first !== null && \"values\" in first;\n }\n // Single resolved entry.\n if (!list && typeof value === \"object\" && \"values\" in (value as any)) {\n return true;\n }\n return false;\n}\n\n/**\n * Resolve a content-entry binding value into CMS entries. Works entirely from\n * the value shape — no component manifest needed.\n *\n * - `{ id, modelId }` → fetch single entry\n * - `[{ id, modelId }, ...]` → fetch multiple entries\n * - `{ modelId, sort?, limit?, search? }` → list query\n */\nexport async function resolveContentEntryValue(\n value:\n | ContentEntryReference\n | ContentEntryReference[]\n | ContentEntryQueryValue\n | null\n | undefined,\n list: boolean,\n loader: ContentEntryLoader\n): Promise<ResolvedContentEntry> {\n if (value == null) {\n return list ? [] : null;\n }\n\n // Query mode: value is `{ modelId, sort?, limit?, search? }`.\n if (isQueryValue(value)) {\n const query = value;\n const listParams: ContentEntryQuerySpec = {\n modelId: query.modelId,\n sort: query.sort ? { [query.sort.field]: query.sort.order } : undefined,\n limit: query.limit,\n search: query.search\n };\n const result = await loader.listEntries(listParams);\n return {\n items: result.data,\n pageInfo: {\n cursor: result.meta.cursor,\n hasMore: result.meta.hasMoreItems,\n totalCount: result.meta.totalCount\n },\n query: listParams\n };\n }\n\n // Manual list: value is `[{ id, modelId }, ...]`.\n if (Array.isArray(value)) {\n const refs = value as ContentEntryReference[];\n const entries = await Promise.all(\n refs.map(ref => loader.getEntry({ modelId: ref.modelId, entryId: ref.id }))\n );\n return entries.filter(entry => entry !== null);\n }\n\n // Manual single: value is `{ id, modelId }`.\n const ref = value as ContentEntryReference;\n return loader.getEntry({ modelId: ref.modelId, entryId: ref.id });\n}\n"],"names":["isQueryValue","value","Array","isAlreadyResolved","list","first","resolveContentEntryValue","loader","query","listParams","undefined","result","refs","entries","Promise","ref","entry"],"mappings":"AAqDO,SAASA,aAAaC,KAAc;IACvC,OACI,AAAiB,YAAjB,OAAOA,SACPA,AAAU,SAAVA,SACA,aAAaA,SACb,CAAE,SAAQA,KAAI,KACd,CAACC,MAAM,OAAO,CAACD;AAEvB;AAMO,SAASE,kBAAkBF,KAAc,EAAEG,IAAa;IAC3D,IAAIH,AAAS,QAATA,OACA,OAAO;IAGX,IAAI,AAAiB,YAAjB,OAAOA,SAAsB,WAAYA,OACzC,OAAO;IAGX,IAAIG,QAAQF,MAAM,OAAO,CAACD,UAAUA,MAAM,MAAM,GAAG,GAAG;QAClD,MAAMI,QAAQJ,KAAK,CAAC,EAAE;QACtB,OAAO,AAAiB,YAAjB,OAAOI,SAAsBA,AAAU,SAAVA,SAAkB,YAAYA;IACtE;IAEA,IAAI,CAACD,QAAQ,AAAiB,YAAjB,OAAOH,SAAsB,YAAaA,OACnD,OAAO;IAEX,OAAO;AACX;AAUO,eAAeK,yBAClBL,KAKe,EACfG,IAAa,EACbG,MAA0B;IAE1B,IAAIN,AAAS,QAATA,OACA,OAAOG,OAAO,EAAE,GAAG;IAIvB,IAAIJ,aAAaC,QAAQ;QACrB,MAAMO,QAAQP;QACd,MAAMQ,aAAoC;YACtC,SAASD,MAAM,OAAO;YACtB,MAAMA,MAAM,IAAI,GAAG;gBAAE,CAACA,MAAM,IAAI,CAAC,KAAK,CAAC,EAAEA,MAAM,IAAI,CAAC,KAAK;YAAC,IAAIE;YAC9D,OAAOF,MAAM,KAAK;YAClB,QAAQA,MAAM,MAAM;QACxB;QACA,MAAMG,SAAS,MAAMJ,OAAO,WAAW,CAACE;QACxC,OAAO;YACH,OAAOE,OAAO,IAAI;YAClB,UAAU;gBACN,QAAQA,OAAO,IAAI,CAAC,MAAM;gBAC1B,SAASA,OAAO,IAAI,CAAC,YAAY;gBACjC,YAAYA,OAAO,IAAI,CAAC,UAAU;YACtC;YACA,OAAOF;QACX;IACJ;IAGA,IAAIP,MAAM,OAAO,CAACD,QAAQ;QACtB,MAAMW,OAAOX;QACb,MAAMY,UAAU,MAAMC,QAAQ,GAAG,CAC7BF,KAAK,GAAG,CAACG,CAAAA,MAAOR,OAAO,QAAQ,CAAC;gBAAE,SAASQ,IAAI,OAAO;gBAAE,SAASA,IAAI,EAAE;YAAC;QAE5E,OAAOF,QAAQ,MAAM,CAACG,CAAAA,QAASA,AAAU,SAAVA;IACnC;IAGA,MAAMD,MAAMd;IACZ,OAAOM,OAAO,QAAQ,CAAC;QAAE,SAASQ,IAAI,OAAO;QAAE,SAASA,IAAI,EAAE;IAAC;AACnE"}