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

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 (117) hide show
  1. package/ComponentInputTraverser.js +4 -0
  2. package/ComponentInputTraverser.js.map +1 -1
  3. package/ComponentResolver.d.ts +3 -1
  4. package/ComponentResolver.js +4 -2
  5. package/ComponentResolver.js.map +1 -1
  6. package/ContentSdk.d.ts +64 -1
  7. package/ContentSdk.js +80 -8
  8. package/ContentSdk.js.map +1 -1
  9. package/DocumentStoreManager.d.ts +9 -2
  10. package/DocumentStoreManager.js +24 -5
  11. package/DocumentStoreManager.js.map +1 -1
  12. package/EditingSdk.d.ts +7 -1
  13. package/EditingSdk.js +5 -3
  14. package/EditingSdk.js.map +1 -1
  15. package/ElementFactory.js +3 -1
  16. package/ElementFactory.js.map +1 -1
  17. package/ElementFactory.test.js +102 -0
  18. package/ElementFactory.test.js.map +1 -1
  19. package/LiveSdk.d.ts +3 -1
  20. package/LiveSdk.js +3 -2
  21. package/LiveSdk.js.map +1 -1
  22. package/PreviewDocument.d.ts +2 -1
  23. package/PreviewDocument.js +2 -2
  24. package/PreviewDocument.js.map +1 -1
  25. package/PreviewSdk.d.ts +3 -1
  26. package/PreviewSdk.js +3 -2
  27. package/PreviewSdk.js.map +1 -1
  28. package/ResizeObserver.js +1 -1
  29. package/ResizeObserver.js.map +1 -1
  30. package/asset/deliveryUrl.test.js +1 -1
  31. package/asset/deliveryUrl.test.js.map +1 -1
  32. package/asset/imageSrcSet.test.js +1 -1
  33. package/asset/imageSrcSet.test.js.map +1 -1
  34. package/asset/normalize.d.ts +1 -1
  35. package/asset/normalize.js +18 -14
  36. package/asset/normalize.js.map +1 -1
  37. package/asset/normalize.test.js +15 -8
  38. package/asset/normalize.test.js.map +1 -1
  39. package/componentLoader/ComponentLoader.d.ts +16 -0
  40. package/componentLoader/ComponentLoader.js +0 -0
  41. package/componentLoader/RegistryOnlyComponentLoader.d.ts +9 -0
  42. package/componentLoader/RegistryOnlyComponentLoader.js +8 -0
  43. package/componentLoader/RegistryOnlyComponentLoader.js.map +1 -0
  44. package/componentLoader/createComponentLoader.d.ts +7 -0
  45. package/componentLoader/createComponentLoader.js +10 -0
  46. package/componentLoader/createComponentLoader.js.map +1 -0
  47. package/componentLoader/defaultComponentLoader.d.ts +7 -0
  48. package/componentLoader/defaultComponentLoader.js +8 -0
  49. package/componentLoader/defaultComponentLoader.js.map +1 -0
  50. package/componentLoader/index.d.ts +3 -0
  51. package/componentLoader/index.js +3 -0
  52. package/contentClientState.test.d.ts +1 -0
  53. package/contentClientState.test.js +384 -0
  54. package/contentClientState.test.js.map +1 -0
  55. package/contentEntry/ContentEntryBindingsResolver.d.ts +8 -5
  56. package/contentEntry/ContentEntryBindingsResolver.js +30 -23
  57. package/contentEntry/ContentEntryBindingsResolver.js.map +1 -1
  58. package/contentEntry/ContentEntryCache.d.ts +7 -4
  59. package/contentEntry/ContentEntryCache.js +10 -9
  60. package/contentEntry/ContentEntryCache.js.map +1 -1
  61. package/createContentClient.d.ts +17 -0
  62. package/createContentClient.js +16 -0
  63. package/createContentClient.js.map +1 -0
  64. package/createContentClient.test.d.ts +1 -0
  65. package/createContentClient.test.js +165 -0
  66. package/createContentClient.test.js.map +1 -0
  67. package/dataProviders/ApiClient.js.map +1 -1
  68. package/dataProviders/DefaultDataProvider.d.ts +4 -0
  69. package/dataProviders/DefaultDataProvider.js +35 -0
  70. package/dataProviders/DefaultDataProvider.js.map +1 -1
  71. package/dataProviders/GET_EXPERIMENT_PAUSED.d.ts +1 -0
  72. package/dataProviders/GET_EXPERIMENT_PAUSED.js +17 -0
  73. package/dataProviders/GET_EXPERIMENT_PAUSED.js.map +1 -0
  74. package/dataProviders/GET_PAGE_BY_ID.d.ts +1 -1
  75. package/dataProviders/GET_PAGE_BY_ID.js +2 -0
  76. package/dataProviders/GET_PAGE_BY_ID.js.map +1 -1
  77. package/dataProviders/GET_PAGE_BY_PATH.d.ts +1 -1
  78. package/dataProviders/GET_PAGE_BY_PATH.js +2 -0
  79. package/dataProviders/GET_PAGE_BY_PATH.js.map +1 -1
  80. package/dataProviders/GET_PAGE_EXPERIMENT.d.ts +1 -0
  81. package/dataProviders/GET_PAGE_EXPERIMENT.js +32 -0
  82. package/dataProviders/GET_PAGE_EXPERIMENT.js.map +1 -0
  83. package/dataProviders/GET_VARIANT_CONTENT.d.ts +1 -0
  84. package/dataProviders/GET_VARIANT_CONTENT.js +24 -0
  85. package/dataProviders/GET_VARIANT_CONTENT.js.map +1 -0
  86. package/dataProviders/NullDataProvider.d.ts +4 -0
  87. package/dataProviders/NullDataProvider.js +9 -0
  88. package/dataProviders/NullDataProvider.js.map +1 -1
  89. package/dataProviders/queries.test.d.ts +1 -0
  90. package/dataProviders/queries.test.js +45 -0
  91. package/dataProviders/queries.test.js.map +1 -0
  92. package/experiments/PostHogAnalyticsProvider.d.ts +31 -0
  93. package/experiments/PostHogAnalyticsProvider.js +28 -0
  94. package/experiments/PostHogAnalyticsProvider.js.map +1 -0
  95. package/experiments/analyticsProvider.d.ts +4 -0
  96. package/experiments/analyticsProvider.js +11 -0
  97. package/experiments/analyticsProvider.js.map +1 -0
  98. package/experiments/bucketing.d.ts +27 -0
  99. package/experiments/bucketing.js +91 -0
  100. package/experiments/bucketing.js.map +1 -0
  101. package/experiments/bucketing.test.d.ts +1 -0
  102. package/experiments/bucketing.test.js +183 -0
  103. package/experiments/bucketing.test.js.map +1 -0
  104. package/experiments/index.d.ts +5 -0
  105. package/experiments/index.js +5 -0
  106. package/experiments/render.d.ts +82 -0
  107. package/experiments/render.js +149 -0
  108. package/experiments/render.js.map +1 -0
  109. package/experiments/types.d.ts +108 -0
  110. package/experiments/types.js +4 -0
  111. package/experiments/types.js.map +1 -0
  112. package/headersProvider.d.ts +1 -2
  113. package/headersProvider.js.map +1 -1
  114. package/index.d.ts +5 -0
  115. package/index.js +5 -0
  116. package/package.json +6 -6
  117. package/types.d.ts +5 -0
@@ -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;YAG/BA,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"}
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"}
@@ -1,6 +1,7 @@
1
1
  import type { ComponentRegistry } from "./ComponentRegistry.js";
2
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;
@@ -10,6 +11,7 @@ export type ResolveElementParams = {
10
11
  };
11
12
  export declare class ComponentResolver {
12
13
  private components;
13
- constructor(registry: ComponentRegistry);
14
+ private contentEntryCache;
15
+ constructor(registry: ComponentRegistry, cache?: ContentEntryCache);
14
16
  resolve({ element, elementBindings, onResolved, state, cache }: ResolveElementParams): ResolvedComponent[] | null;
15
17
  }
@@ -1,10 +1,12 @@
1
1
  import { logger } from "./Logger.js";
2
2
  import { BindingsResolver } from "./BindingsResolver.js";
3
3
  import { ContentEntryBindingsResolver } from "./contentEntry/ContentEntryBindingsResolver.js";
4
+ import { contentEntryCache } from "./contentEntry/ContentEntryCache.js";
4
5
  import { ComponentManifestToAstConverter } from "./ComponentManifestToAstConverter.js";
5
6
  class ComponentResolver {
6
- constructor(registry){
7
+ constructor(registry, cache = contentEntryCache){
7
8
  this.components = registry;
9
+ this.contentEntryCache = cache;
8
10
  }
9
11
  resolve({ element, elementBindings = {}, onResolved, state, cache }) {
10
12
  const componentName = element.component.name;
@@ -15,7 +17,7 @@ class ComponentResolver {
15
17
  }
16
18
  const embedded = cache?.contentEntries;
17
19
  const resolvedEntries = embedded ? new Map(Object.entries(embedded)) : void 0;
18
- const resolver = new ContentEntryBindingsResolver(new BindingsResolver(state), resolvedEntries);
20
+ const resolver = new ContentEntryBindingsResolver(new BindingsResolver(state), resolvedEntries, this.contentEntryCache);
19
21
  const instances = resolver.resolveElement({
20
22
  element,
21
23
  elementBindings,
@@ -1 +1 @@
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"}
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;
@@ -13,6 +21,34 @@ export type ContentSDKConfig = ApiConfig & {
13
21
  preview?: boolean;
14
22
  previewParams?: string;
15
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;
16
52
  };
17
53
  declare class InternalContentSdk implements IContentSdk, IRedirects {
18
54
  private activeSdk;
@@ -30,14 +66,41 @@ export declare class ContentSdk implements IContentSdk, IRedirects {
30
66
  private isPreview;
31
67
  private lastConfig;
32
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);
33
77
  init(config: ContentSDKConfig, afterInit?: () => void): void;
34
78
  getEditingSdk(): EditingSdk | undefined;
35
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>;
36
89
  listPages(options?: ListPagesOptions): Promise<ListPagesResult>;
37
90
  getAllRedirects(): Promise<Map<string, PublicRedirect>>;
38
91
  getRedirectByPath(path: string): Promise<PublicRedirect | undefined>;
39
92
  registerComponent(blueprint: Component): void;
40
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;
41
104
  isEditing(): boolean;
42
105
  isPreviewing(): boolean;
43
106
  private assertInitialized;
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,10 +36,18 @@ 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;
49
+ this.headersProvider = config.headersProvider;
50
+ if (config.contentEntryLoader) this.contentEntryCache.setLoader(config.contentEntryLoader);
39
51
  const apiClient = new ApiClient({
40
52
  apiHost: config.apiHost,
41
53
  apiKey: config.apiKey,
@@ -45,16 +57,29 @@ class ContentSdk {
45
57
  const dataProvider = new DefaultDataProvider({
46
58
  apiClient
47
59
  });
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;
48
70
  this.dataProvider = dataProvider;
49
- let liveSdk = new LiveSdk(dataProvider);
71
+ let liveSdk = new LiveSdk(dataProvider, this.documentStoreManager);
50
72
  if (config.preview && !environment.isEditing()) {
51
73
  this.isPreview = true;
52
- liveSdk = new PreviewSdk(dataProvider, liveSdk, config.previewParams);
74
+ liveSdk = new PreviewSdk(dataProvider, liveSdk, config.previewParams, config.headersProvider);
53
75
  }
54
76
  const theme = Theme.from(config.theme ?? {});
55
77
  if (environment.isClient()) viewportManager.setBreakpoints(theme.breakpoints);
56
78
  let editingSdk;
57
- 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
+ });
58
83
  this.sdk = new InternalContentSdk(new RedirectsProvider(apiClient), liveSdk, editingSdk);
59
84
  if ("function" == typeof afterInit) afterInit();
60
85
  }
@@ -66,6 +91,29 @@ class ContentSdk {
66
91
  this.assertInitialized();
67
92
  return this.sdk.getPage(path);
68
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
+ }
69
117
  listPages(options) {
70
118
  this.assertInitialized();
71
119
  return this.sdk.listPages(options);
@@ -80,11 +128,38 @@ class ContentSdk {
80
128
  }
81
129
  registerComponent(blueprint) {
82
130
  this.assertInitialized();
83
- componentRegistry.register(blueprint);
131
+ this.componentRegistry.register(blueprint);
84
132
  }
85
133
  resolveElement(params) {
86
134
  this.assertInitialized();
87
- 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;
88
163
  }
89
164
  isEditing() {
90
165
  return environment.isEditing();
@@ -99,9 +174,6 @@ class ContentSdk {
99
174
  if (!this.dataProvider) throw new Error("ContentSdk has not been initialized!");
100
175
  return this.dataProvider;
101
176
  }
102
- constructor(){
103
- this.isPreview = false;
104
- }
105
177
  }
106
178
  const contentSdk = new ContentSdk();
107
179
  export { ContentSdk, 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 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"}
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 class DocumentStoreManager {
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 {};
@@ -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
- if (!this.stores.has(id)) this.stores.set(id, new DocumentStore());
8
- return this.stores.get(id);
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
- constructor(){
17
- this.stores = new Map();
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\nclass DocumentStoreManager {\n private stores = new Map<string, DocumentStore>();\n\n getStores() {\n return this.stores;\n }\n\n getStore<TDocument extends Document>(id: string): DocumentStore<TDocument> {\n if (!this.stores.has(id)) {\n this.stores.set(id, new DocumentStore<TDocument>());\n }\n return this.stores.get(id)! as DocumentStore<TDocument>;\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\nexport const documentStoreManager = new DocumentStoreManager();\n"],"names":["DocumentStoreManager","id","DocumentStore","Map","documentStoreManager"],"mappings":";AAGA,MAAMA;IAGF,YAAY;QACR,OAAO,IAAI,CAAC,MAAM;IACtB;IAEA,SAAqCC,EAAU,EAA4B;QACvE,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAACA,KACjB,IAAI,CAAC,MAAM,CAAC,GAAG,CAACA,IAAI,IAAIC;QAE5B,OAAO,IAAI,CAAC,MAAM,CAAC,GAAG,CAACD;IAC3B;IAEA,YAAYA,EAAU,EAAE;QACpB,IAAI,CAAC,MAAM,CAAC,MAAM,CAACA;IACvB;IAEA,SAASA,EAAU,EAAW;QAC1B,OAAO,IAAI,CAAC,MAAM,CAAC,GAAG,CAACA;IAC3B;;aAnBQ,MAAM,GAAG,IAAIE;;AAoBzB;AAEO,MAAMC,uBAAuB,IAAIJ"}
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 = documentStoreManager.getStore(this.previewDocument.getId());
22
+ this.documentStore = stores.getStore(this.previewDocument.getId());
21
23
  this.messenger = new Messenger(source, target, "wb.editor.*");
22
- componentRegistry.onRegister((reg)=>{
24
+ registry.onRegister((reg)=>{
23
25
  this.messenger.send("preview.component.register", reg.component.manifest);
24
26
  });
25
27
  this.setupListeners();
package/EditingSdk.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"EditingSdk.js","sources":["../src/EditingSdk.ts"],"sourcesContent":["\"use client\";\nimport type {\n ComponentGroup,\n IContentSdk,\n ListPagesOptions,\n ListPagesResult,\n PublicPage\n} from \"./types.js\";\nimport { Messenger, MessageOrigin } from \"./messenger/index.js\";\nimport { logger } from \"./Logger.js\";\nimport { PreviewViewport } from \"./PreviewViewport.js\";\nimport { viewportManager } from \"./ViewportManager.js\";\nimport { componentRegistry } from \"./ComponentRegistry.js\";\nimport { functionConverter } from \"./FunctionConverter.js\";\nimport { documentStoreManager } from \"~/DocumentStoreManager.js\";\nimport type { DocumentStore } from \"~/DocumentStore.js\";\nimport { PreviewDocument } from \"./PreviewDocument.js\";\nimport { hashObject } from \"~/HashObject.js\";\nimport type { WebsiteBuilderTheme } from \"~/types/WebsiteBuilderTheme.js\";\n\nexport class EditingSdk implements IContentSdk {\n public readonly messenger: Messenger;\n private positionReportingEnabled = false;\n private previewViewport: PreviewViewport | null = null;\n private liveSdk: IContentSdk;\n private documentStore: DocumentStore<PublicPage>;\n private previewDocument: PreviewDocument;\n private lastBoxesHash = 0;\n\n constructor(liveSdk: IContentSdk, theme: WebsiteBuilderTheme) {\n this.liveSdk = liveSdk;\n\n const source = new MessageOrigin(() => window, window.location.origin);\n const target = new MessageOrigin(() => window.parent, this.getReferrerOrigin());\n\n this.previewDocument = PreviewDocument.createFromWindow();\n\n this.documentStore = documentStoreManager.getStore<PublicPage>(\n this.previewDocument.getId()\n );\n\n this.messenger = new Messenger(source, target, \"wb.editor.*\");\n\n componentRegistry.onRegister(reg => {\n this.messenger.send(\"preview.component.register\", reg.component.manifest);\n });\n\n this.setupListeners();\n\n this.messenger.send(\"preview.ready\", true);\n\n if (theme) {\n this.messenger.send(\"preview.theme\", { theme });\n }\n\n this.disableLinks();\n }\n\n public async getPage(path: string): Promise<PublicPage | null> {\n if (!this.previewDocument.matches({ type: \"page\", path })) {\n return this.liveSdk.getPage(path);\n }\n\n await this.documentStore.waitForDocument();\n return this.documentStore.getDocument();\n }\n\n public async listPages(options?: ListPagesOptions): Promise<ListPagesResult> {\n return this.liveSdk.listPages(options);\n }\n\n registerComponentGroup(group: ComponentGroup) {\n this.messenger.send(\"preview.componentGroup.register\", {\n ...group,\n filter: group.filter ? functionConverter.serialize(group.filter) : undefined\n });\n }\n\n private getReferrerOrigin(): string {\n try {\n const searchParams = new URLSearchParams(window.location.search);\n return searchParams.get(\"wb.referrer\")!;\n } catch {\n return \"\";\n }\n }\n\n private setupListeners() {\n if (!this.messenger) {\n return;\n }\n\n this.messenger.on(\"document.set\", data => {\n this.documentStore.setDocument(data);\n\n if (!this.positionReportingEnabled) {\n // Initialize position reporting\n this.initPositionReporting();\n }\n });\n\n this.messenger.on(\"element.set\", data => {\n this.documentStore.updateElement(data.id, data.patch);\n });\n\n this.messenger.on(\"document.patch\", patch => {\n this.documentStore.applyPatch(patch);\n });\n }\n\n private initPositionReporting(): void {\n if (this.positionReportingEnabled) {\n return;\n }\n\n // Initialize element positions tracker\n this.previewViewport = new PreviewViewport();\n\n // Add event listeners\n viewportManager.onViewportChangeStart(() => {\n if (this.messenger) {\n this.messenger.send(\"preview.viewport.change.start\");\n }\n });\n\n viewportManager.onViewportChangeEnd(() => {\n if (this.messenger) {\n this.messenger.send(\"preview.viewport.change.end\");\n }\n });\n\n // Enable position reporting by default\n this.positionReportingEnabled = true;\n\n // Report positions periodically\n setInterval(() => this.reportBoxes(), 300);\n }\n\n private reportBoxes(): void {\n if (!this.messenger || !this.previewViewport) {\n logger.warn(\"No messenger or preview viewport. Skipping position reporting.\");\n return;\n }\n\n const newBoxes = this.previewViewport.getBoxes();\n const hash = hashObject.hash(newBoxes);\n if (hash === this.lastBoxesHash) {\n return;\n }\n\n this.lastBoxesHash = hash;\n // Send positions to the editor\n this.messenger.send(\"preview.viewport\", {\n boxes: this.previewViewport.getBoxes(),\n viewport: this.previewViewport.getViewport()\n });\n }\n\n private disableLinks() {\n // Intercept link clicks when we're in the editing mode (loaded via iframe from the editor).\n document.addEventListener(\n \"click\",\n event => {\n const target = event.target as HTMLElement;\n\n // Check if the clicked element or any of its ancestors is a link\n const anchor = target.closest(\"a\");\n\n if (anchor && anchor.href) {\n event.preventDefault();\n event.stopPropagation();\n }\n },\n // https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener#usecapture\n true\n );\n }\n}\n"],"names":["EditingSdk","liveSdk","theme","source","MessageOrigin","window","target","PreviewDocument","documentStoreManager","Messenger","componentRegistry","reg","path","options","group","functionConverter","undefined","searchParams","URLSearchParams","data","patch","PreviewViewport","viewportManager","setInterval","logger","newBoxes","hash","hashObject","document","event","anchor"],"mappings":"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"}
1
+ {"version":3,"file":"EditingSdk.js","sources":["../src/EditingSdk.ts"],"sourcesContent":["\"use client\";\nimport type {\n ComponentGroup,\n IContentSdk,\n ListPagesOptions,\n ListPagesResult,\n PublicPage\n} from \"./types.js\";\nimport { Messenger, MessageOrigin } from \"./messenger/index.js\";\nimport { logger } from \"./Logger.js\";\nimport { PreviewViewport } from \"./PreviewViewport.js\";\nimport { viewportManager } from \"./ViewportManager.js\";\nimport type { ComponentRegistry } from \"./ComponentRegistry.js\";\nimport { componentRegistry } from \"./ComponentRegistry.js\";\nimport { functionConverter } from \"./FunctionConverter.js\";\nimport type { DocumentStoreManager } from \"~/DocumentStoreManager.js\";\nimport { documentStoreManager } from \"~/DocumentStoreManager.js\";\nimport type { DocumentStore } from \"~/DocumentStore.js\";\nimport { PreviewDocument } from \"./PreviewDocument.js\";\nimport { hashObject } from \"~/HashObject.js\";\nimport type { WebsiteBuilderTheme } from \"~/types/WebsiteBuilderTheme.js\";\n\nexport type EditingSdkState = {\n componentRegistry?: ComponentRegistry;\n documentStoreManager?: DocumentStoreManager;\n};\n\nexport class EditingSdk implements IContentSdk {\n public readonly messenger: Messenger;\n private positionReportingEnabled = false;\n private previewViewport: PreviewViewport | null = null;\n private liveSdk: IContentSdk;\n private documentStore: DocumentStore<PublicPage>;\n private previewDocument: PreviewDocument;\n private lastBoxesHash = 0;\n\n constructor(liveSdk: IContentSdk, theme: WebsiteBuilderTheme, state: EditingSdkState = {}) {\n this.liveSdk = liveSdk;\n const registry = state.componentRegistry ?? componentRegistry;\n const stores = state.documentStoreManager ?? documentStoreManager;\n\n const source = new MessageOrigin(() => window, window.location.origin);\n const target = new MessageOrigin(() => window.parent, this.getReferrerOrigin());\n\n this.previewDocument = PreviewDocument.createFromWindow();\n\n this.documentStore = stores.getStore<PublicPage>(this.previewDocument.getId());\n\n this.messenger = new Messenger(source, target, \"wb.editor.*\");\n\n registry.onRegister(reg => {\n this.messenger.send(\"preview.component.register\", reg.component.manifest);\n });\n\n this.setupListeners();\n\n this.messenger.send(\"preview.ready\", true);\n\n if (theme) {\n this.messenger.send(\"preview.theme\", { theme });\n }\n\n this.disableLinks();\n }\n\n public async getPage(path: string): Promise<PublicPage | null> {\n if (!this.previewDocument.matches({ type: \"page\", path })) {\n return this.liveSdk.getPage(path);\n }\n\n await this.documentStore.waitForDocument();\n return this.documentStore.getDocument();\n }\n\n public async listPages(options?: ListPagesOptions): Promise<ListPagesResult> {\n return this.liveSdk.listPages(options);\n }\n\n registerComponentGroup(group: ComponentGroup) {\n this.messenger.send(\"preview.componentGroup.register\", {\n ...group,\n filter: group.filter ? functionConverter.serialize(group.filter) : undefined\n });\n }\n\n private getReferrerOrigin(): string {\n try {\n const searchParams = new URLSearchParams(window.location.search);\n return searchParams.get(\"wb.referrer\")!;\n } catch {\n return \"\";\n }\n }\n\n private setupListeners() {\n if (!this.messenger) {\n return;\n }\n\n this.messenger.on(\"document.set\", data => {\n this.documentStore.setDocument(data);\n\n if (!this.positionReportingEnabled) {\n // Initialize position reporting\n this.initPositionReporting();\n }\n });\n\n this.messenger.on(\"element.set\", data => {\n this.documentStore.updateElement(data.id, data.patch);\n });\n\n this.messenger.on(\"document.patch\", patch => {\n this.documentStore.applyPatch(patch);\n });\n }\n\n private initPositionReporting(): void {\n if (this.positionReportingEnabled) {\n return;\n }\n\n // Initialize element positions tracker\n this.previewViewport = new PreviewViewport();\n\n // Add event listeners\n viewportManager.onViewportChangeStart(() => {\n if (this.messenger) {\n this.messenger.send(\"preview.viewport.change.start\");\n }\n });\n\n viewportManager.onViewportChangeEnd(() => {\n if (this.messenger) {\n this.messenger.send(\"preview.viewport.change.end\");\n }\n });\n\n // Enable position reporting by default\n this.positionReportingEnabled = true;\n\n // Report positions periodically\n setInterval(() => this.reportBoxes(), 300);\n }\n\n private reportBoxes(): void {\n if (!this.messenger || !this.previewViewport) {\n logger.warn(\"No messenger or preview viewport. Skipping position reporting.\");\n return;\n }\n\n const newBoxes = this.previewViewport.getBoxes();\n const hash = hashObject.hash(newBoxes);\n if (hash === this.lastBoxesHash) {\n return;\n }\n\n this.lastBoxesHash = hash;\n // Send positions to the editor\n this.messenger.send(\"preview.viewport\", {\n boxes: this.previewViewport.getBoxes(),\n viewport: this.previewViewport.getViewport()\n });\n }\n\n private disableLinks() {\n // Intercept link clicks when we're in the editing mode (loaded via iframe from the editor).\n document.addEventListener(\n \"click\",\n event => {\n const target = event.target as HTMLElement;\n\n // Check if the clicked element or any of its ancestors is a link\n const anchor = target.closest(\"a\");\n\n if (anchor && anchor.href) {\n event.preventDefault();\n event.stopPropagation();\n }\n },\n // https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener#usecapture\n true\n );\n }\n}\n"],"names":["EditingSdk","liveSdk","theme","state","registry","componentRegistry","stores","documentStoreManager","source","MessageOrigin","window","target","PreviewDocument","Messenger","reg","path","options","group","functionConverter","undefined","searchParams","URLSearchParams","data","patch","PreviewViewport","viewportManager","setInterval","logger","newBoxes","hash","hashObject","document","event","anchor"],"mappings":"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"}
package/ElementFactory.js CHANGED
@@ -26,12 +26,14 @@ class ElementFactory {
26
26
  defaultOperations.addElement(element),
27
27
  defaultOperations.addToParent(element, index)
28
28
  ];
29
+ const baseStyles = bindings?.styles ?? componentManifest.defaults?.styles ?? {};
30
+ const resolvedStyles = false === componentManifest.applyDefaultStyles ? baseStyles : withDefaultStyles(baseStyles);
29
31
  documentOps.push(...this.generateOperations({
30
32
  element,
31
33
  inputsAst,
32
34
  bindings: {
33
35
  inputs: bindings?.inputs ?? componentManifest.defaults?.inputs ?? {},
34
- styles: withDefaultStyles(bindings?.styles ?? componentManifest.defaults?.styles ?? {}),
36
+ styles: resolvedStyles,
35
37
  overrides: bindings?.overrides ?? {}
36
38
  },
37
39
  operations: defaultOperations