@builder.io/sdk-react 0.1.11 → 0.1.12

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 (25) hide show
  1. package/dist/react/blocks/symbol/symbol.js +40 -35
  2. package/dist/react/components/render-content/render-content.js +7 -0
  3. package/dist/react/context/builder.context.js +1 -0
  4. package/dist/react/functions/get-content/generate-content-url.js +5 -2
  5. package/dist/react/functions/get-content/generate-content-url.test.js +42 -0
  6. package/dist/react/types/api-version.js +1 -0
  7. package/dist/rsc/blocks/symbol/symbol.js +46 -19
  8. package/dist/rsc/components/render-content/render-content.js +1 -0
  9. package/dist/rsc/context/builder.context.js +1 -0
  10. package/dist/rsc/functions/get-content/generate-content-url.js +5 -2
  11. package/dist/rsc/functions/get-content/generate-content-url.test.js +42 -0
  12. package/dist/rsc/types/api-version.js +1 -0
  13. package/package.json +1 -1
  14. package/packages/react/src/blocks/symbol/symbol.jsx +36 -28
  15. package/packages/react/src/components/render-content/render-content.jsx +7 -0
  16. package/packages/react/src/context/builder.context.js +1 -0
  17. package/packages/react/src/functions/get-content/generate-content-url.js +6 -2
  18. package/packages/react/src/functions/get-content/generate-content-url.test.js +42 -0
  19. package/packages/react/src/types/api-version.js +0 -0
  20. package/packages/rsc/src/blocks/symbol/symbol.jsx +51 -18
  21. package/packages/rsc/src/components/render-content/render-content.jsx +1 -0
  22. package/packages/rsc/src/context/builder.context.js +1 -0
  23. package/packages/rsc/src/functions/get-content/generate-content-url.js +6 -2
  24. package/packages/rsc/src/functions/get-content/generate-content-url.test.js +42 -0
  25. package/packages/rsc/src/types/api-version.js +0 -0
@@ -5,27 +5,20 @@ import BuilderContext from "../../context/builder.context.js";
5
5
  import { getContent } from "../../functions/get-content/index.js";
6
6
  import { TARGET } from "../../constants/target";
7
7
  function Symbol(props) {
8
- function className() {
9
- return [
10
- ...(TARGET === "vue2" || TARGET === "vue3"
11
- ? Object.keys(props.attributes.class)
12
- : [props.attributes.class]),
13
- "builder-symbol",
14
- props.symbol?.inline ? "builder-inline-symbol" : undefined,
15
- props.symbol?.dynamic || props.dynamic
16
- ? "builder-dynamic-symbol"
17
- : undefined,
18
- ]
19
- .filter(Boolean)
20
- .join(" ");
21
- }
22
- const [fetchedContent, setFetchedContent] = useState(() => null);
23
- function contentToUse() {
24
- return props.symbol?.content || fetchedContent;
25
- }
26
- const builderContext = useContext(BuilderContext);
27
- useEffect(() => {
28
- const symbolToUse = props.symbol;
8
+ const [className, setClassName] = useState(() => [
9
+ ...(TARGET === "vue2" || TARGET === "vue3"
10
+ ? Object.keys(props.attributes.class)
11
+ : [props.attributes.class]),
12
+ "builder-symbol",
13
+ props.symbol?.inline ? "builder-inline-symbol" : undefined,
14
+ props.symbol?.dynamic || props.dynamic
15
+ ? "builder-dynamic-symbol"
16
+ : undefined,
17
+ ]
18
+ .filter(Boolean)
19
+ .join(" "));
20
+ const [contentToUse, setContentToUse] = useState(() => props.symbol?.content);
21
+ function fetchContent() {
29
22
  /**
30
23
  * If:
31
24
  * - we have a symbol prop
@@ -35,30 +28,42 @@ function Symbol(props) {
35
28
  *
36
29
  * then we want to re-fetch the symbol content.
37
30
  */
38
- if (symbolToUse &&
39
- !symbolToUse.content &&
40
- !fetchedContent &&
41
- symbolToUse.model &&
31
+ if (!contentToUse &&
32
+ props.symbol?.model &&
42
33
  // This is a hack, we should not need to check for this, but it is needed for Svelte.
43
34
  builderContext?.apiKey) {
44
35
  getContent({
45
- model: symbolToUse.model,
36
+ model: props.symbol.model,
46
37
  apiKey: builderContext.apiKey,
38
+ apiVersion: builderContext.apiVersion,
47
39
  query: {
48
- id: symbolToUse.entry,
40
+ id: props.symbol.entry,
49
41
  },
50
- }).then((response) => {
51
- setFetchedContent(response);
42
+ })
43
+ .then((response) => {
44
+ if (response) {
45
+ setContentToUse(response);
46
+ }
47
+ })
48
+ .catch((err) => {
49
+ console.error("[Builder.io]: Could not fetch symbol content: ", err);
52
50
  });
53
51
  }
54
- }, [props.symbol, fetchedContent]);
52
+ }
53
+ const builderContext = useContext(BuilderContext);
54
+ useEffect(() => {
55
+ fetchContent();
56
+ }, []);
57
+ useEffect(() => {
58
+ fetchContent();
59
+ }, [props.symbol]);
55
60
  return (React.createElement("div", { ...props.attributes, dataSet: {
56
- class: className(),
57
- }, className: className() },
58
- React.createElement(RenderContent, { apiKey: builderContext.apiKey, context: builderContext.context, customComponents: Object.values(builderContext.registeredComponents), data: {
61
+ class: className,
62
+ }, className: className },
63
+ React.createElement(RenderContent, { apiVersion: builderContext.apiVersion, apiKey: builderContext.apiKey, context: builderContext.context, customComponents: Object.values(builderContext.registeredComponents), data: {
59
64
  ...props.symbol?.data,
60
65
  ...builderContext.state,
61
- ...props.symbol?.content?.data?.state,
62
- }, model: props.symbol?.model, content: contentToUse() })));
66
+ ...contentToUse?.data?.state,
67
+ }, model: props.symbol?.model, content: contentToUse })));
63
68
  }
64
69
  export default Symbol;
@@ -241,6 +241,7 @@ function RenderContent(props) {
241
241
  getContent({
242
242
  model: props.model,
243
243
  apiKey: props.apiKey,
244
+ apiVersion: props.apiVersion,
244
245
  }).then((content) => {
245
246
  if (content) {
246
247
  mergeNewContent(content);
@@ -253,6 +254,11 @@ function RenderContent(props) {
253
254
  emitStateUpdate();
254
255
  }
255
256
  }, []);
257
+ useEffect(() => {
258
+ if (props.content) {
259
+ mergeNewContent(props.content);
260
+ }
261
+ }, [props.content]);
256
262
  useEffect(() => {
257
263
  evaluateJsCode();
258
264
  }, [useContent?.data?.jsCode, contentState]);
@@ -276,6 +282,7 @@ function RenderContent(props) {
276
282
  setState: setContextState,
277
283
  context: props.context || {},
278
284
  apiKey: props.apiKey,
285
+ apiVersion: props.apiVersion,
279
286
  registeredComponents: allRegisteredComponents,
280
287
  } }, useContent ? (React.createElement(React.Fragment, null,
281
288
  React.createElement("div", { ref: elementRef, onClick: (event) => onClick(event), "builder-content-id": useContent?.id, "builder-model": props.model },
@@ -6,6 +6,7 @@ var stdin_default = createContext({
6
6
  setState() {
7
7
  },
8
8
  apiKey: null,
9
+ apiVersion: void 0,
9
10
  registeredComponents: {},
10
11
  inheritedStyles: {}
11
12
  });
@@ -17,11 +17,14 @@ var __spreadValues = (a, b) => {
17
17
  import { flatten } from "../../helpers/flatten.js";
18
18
  import { getBuilderSearchParamsFromWindow, normalizeSearchParams } from "../get-builder-search-params/index.js";
19
19
  const generateContentUrl = (options) => {
20
- const { limit = 30, userAttributes, query, noTraverse = false, model, apiKey, includeRefs = true, locale } = options;
20
+ const { limit = 30, userAttributes, query, noTraverse = false, model, apiKey, includeRefs = true, locale, apiVersion = "v2" } = options;
21
21
  if (!apiKey) {
22
22
  throw new Error("Missing API key");
23
23
  }
24
- const url = new URL(`https://cdn.builder.io/api/v2/content/${model}?apiKey=${apiKey}&limit=${limit}&noTraverse=${noTraverse}&includeRefs=${includeRefs}${locale ? `&locale=${locale}` : ""}`);
24
+ if (!["v2", "v3"].includes(apiVersion)) {
25
+ throw new Error(`Invalid apiVersion: expected 'v2' or 'v3', received '${apiVersion}'`);
26
+ }
27
+ const url = new URL(`https://cdn.builder.io/api/${apiVersion}/content/${model}?apiKey=${apiKey}&limit=${limit}&noTraverse=${noTraverse}&includeRefs=${includeRefs}${locale ? `&locale=${locale}` : ""}`);
25
28
  const queryOptions = __spreadValues(__spreadValues({}, getBuilderSearchParamsFromWindow()), normalizeSearchParams(options.options || {}));
26
29
  const flattened = flatten(queryOptions);
27
30
  for (const key in flattened) {
@@ -28,4 +28,46 @@ describe("Generate Content URL", () => {
28
28
  });
29
29
  expect(output).toMatchSnapshot();
30
30
  });
31
+ test("generate content url with apiVersion as v2", () => {
32
+ const output = generateContentUrl({
33
+ apiKey: testKey,
34
+ model: testModel,
35
+ query: { id: testId },
36
+ options,
37
+ apiVersion: "v2"
38
+ });
39
+ expect(output).toMatchSnapshot();
40
+ });
41
+ test("generate content url with apiVersion as v3", () => {
42
+ const output = generateContentUrl({
43
+ apiKey: testKey,
44
+ model: testModel,
45
+ query: { id: testId },
46
+ options,
47
+ apiVersion: "v3"
48
+ });
49
+ expect(output).toMatchSnapshot();
50
+ });
51
+ test("throw error when trying to generate content url with apiVersion as v1", () => {
52
+ expect(() => {
53
+ generateContentUrl({
54
+ apiKey: testKey,
55
+ model: testModel,
56
+ query: { id: testId },
57
+ options,
58
+ apiVersion: "v1"
59
+ });
60
+ }).toThrow(`Invalid apiVersion: expected 'v2' or 'v3', received 'v1'`);
61
+ });
62
+ test("throw error when trying to generate content url with an invalid apiVersion value", () => {
63
+ expect(() => {
64
+ generateContentUrl({
65
+ apiKey: testKey,
66
+ model: testModel,
67
+ query: { id: testId },
68
+ options,
69
+ apiVersion: "INVALID_API_VERSION"
70
+ });
71
+ }).toThrow(`Invalid apiVersion: expected 'v2' or 'v3', received 'INVALID_API_VERSION'`);
72
+ });
31
73
  });
@@ -0,0 +1 @@
1
+ "use strict";
@@ -6,33 +6,60 @@ import { TARGET } from "../../constants/target";
6
6
  function Symbol(props) {
7
7
  const _context = { ...props["_context"] };
8
8
  const state = {
9
- get className() {
10
- return [
11
- ...(TARGET === "vue2" || TARGET === "vue3"
12
- ? Object.keys(props.attributes.class)
13
- : [props.attributes.class]),
14
- "builder-symbol",
15
- props.symbol?.inline ? "builder-inline-symbol" : undefined,
16
- props.symbol?.dynamic || props.dynamic
17
- ? "builder-dynamic-symbol"
18
- : undefined,
19
- ]
20
- .filter(Boolean)
21
- .join(" ");
22
- },
23
- fetchedContent: null,
24
- get contentToUse() {
25
- return props.symbol?.content || state.fetchedContent;
9
+ className: [
10
+ ...(TARGET === "vue2" || TARGET === "vue3"
11
+ ? Object.keys(props.attributes.class)
12
+ : [props.attributes.class]),
13
+ "builder-symbol",
14
+ props.symbol?.inline ? "builder-inline-symbol" : undefined,
15
+ props.symbol?.dynamic || props.dynamic
16
+ ? "builder-dynamic-symbol"
17
+ : undefined,
18
+ ]
19
+ .filter(Boolean)
20
+ .join(" "),
21
+ contentToUse: props.symbol?.content,
22
+ fetchContent() {
23
+ /**
24
+ * If:
25
+ * - we have a symbol prop
26
+ * - yet it does not have any content
27
+ * - and we have not already stored content from before
28
+ * - and it has a model name
29
+ *
30
+ * then we want to re-fetch the symbol content.
31
+ */
32
+ if (!state.contentToUse &&
33
+ props.symbol?.model &&
34
+ // This is a hack, we should not need to check for this, but it is needed for Svelte.
35
+ builderContext?.apiKey) {
36
+ getContent({
37
+ model: props.symbol.model,
38
+ apiKey: builderContext.apiKey,
39
+ apiVersion: builderContext.apiVersion,
40
+ query: {
41
+ id: props.symbol.entry,
42
+ },
43
+ })
44
+ .then((response) => {
45
+ if (response) {
46
+ state.contentToUse = response;
47
+ }
48
+ })
49
+ .catch((err) => {
50
+ console.error("[Builder.io]: Could not fetch symbol content: ", err);
51
+ });
52
+ }
26
53
  },
27
54
  };
28
55
  const builderContext = _context["BuilderContext"];
29
56
  return (React.createElement("div", { ...props.attributes, dataSet: {
30
57
  class: state.className,
31
58
  }, className: state.className },
32
- React.createElement(RenderContent, { apiKey: builderContext.apiKey, context: builderContext.context, customComponents: Object.values(builderContext.registeredComponents), data: {
59
+ React.createElement(RenderContent, { apiVersion: builderContext.apiVersion, apiKey: builderContext.apiKey, context: builderContext.context, customComponents: Object.values(builderContext.registeredComponents), data: {
33
60
  ...props.symbol?.data,
34
61
  ...builderContext.state,
35
- ...props.symbol?.content?.data?.state,
62
+ ...state.contentToUse?.data?.state,
36
63
  }, model: props.symbol?.model, content: state.contentToUse, _context: _context })));
37
64
  }
38
65
  export default Symbol;
@@ -192,6 +192,7 @@ function RenderContent(props) {
192
192
  setState: state.setContextState,
193
193
  context: props.context || {},
194
194
  apiKey: props.apiKey,
195
+ apiVersion: props.apiVersion,
195
196
  registeredComponents: state.allRegisteredComponents,
196
197
  };
197
198
  return (React.createElement(React.Fragment, null, state.useContent ? (React.createElement(React.Fragment, null,
@@ -5,6 +5,7 @@ var stdin_default = {
5
5
  setState() {
6
6
  },
7
7
  apiKey: null,
8
+ apiVersion: void 0,
8
9
  registeredComponents: {},
9
10
  inheritedStyles: {}
10
11
  };
@@ -17,11 +17,14 @@ var __spreadValues = (a, b) => {
17
17
  import { flatten } from "../../helpers/flatten.js";
18
18
  import { getBuilderSearchParamsFromWindow, normalizeSearchParams } from "../get-builder-search-params/index.js";
19
19
  const generateContentUrl = (options) => {
20
- const { limit = 30, userAttributes, query, noTraverse = false, model, apiKey, includeRefs = true, locale } = options;
20
+ const { limit = 30, userAttributes, query, noTraverse = false, model, apiKey, includeRefs = true, locale, apiVersion = "v2" } = options;
21
21
  if (!apiKey) {
22
22
  throw new Error("Missing API key");
23
23
  }
24
- const url = new URL(`https://cdn.builder.io/api/v2/content/${model}?apiKey=${apiKey}&limit=${limit}&noTraverse=${noTraverse}&includeRefs=${includeRefs}${locale ? `&locale=${locale}` : ""}`);
24
+ if (!["v2", "v3"].includes(apiVersion)) {
25
+ throw new Error(`Invalid apiVersion: expected 'v2' or 'v3', received '${apiVersion}'`);
26
+ }
27
+ const url = new URL(`https://cdn.builder.io/api/${apiVersion}/content/${model}?apiKey=${apiKey}&limit=${limit}&noTraverse=${noTraverse}&includeRefs=${includeRefs}${locale ? `&locale=${locale}` : ""}`);
25
28
  const queryOptions = __spreadValues(__spreadValues({}, getBuilderSearchParamsFromWindow()), normalizeSearchParams(options.options || {}));
26
29
  const flattened = flatten(queryOptions);
27
30
  for (const key in flattened) {
@@ -28,4 +28,46 @@ describe("Generate Content URL", () => {
28
28
  });
29
29
  expect(output).toMatchSnapshot();
30
30
  });
31
+ test("generate content url with apiVersion as v2", () => {
32
+ const output = generateContentUrl({
33
+ apiKey: testKey,
34
+ model: testModel,
35
+ query: { id: testId },
36
+ options,
37
+ apiVersion: "v2"
38
+ });
39
+ expect(output).toMatchSnapshot();
40
+ });
41
+ test("generate content url with apiVersion as v3", () => {
42
+ const output = generateContentUrl({
43
+ apiKey: testKey,
44
+ model: testModel,
45
+ query: { id: testId },
46
+ options,
47
+ apiVersion: "v3"
48
+ });
49
+ expect(output).toMatchSnapshot();
50
+ });
51
+ test("throw error when trying to generate content url with apiVersion as v1", () => {
52
+ expect(() => {
53
+ generateContentUrl({
54
+ apiKey: testKey,
55
+ model: testModel,
56
+ query: { id: testId },
57
+ options,
58
+ apiVersion: "v1"
59
+ });
60
+ }).toThrow(`Invalid apiVersion: expected 'v2' or 'v3', received 'v1'`);
61
+ });
62
+ test("throw error when trying to generate content url with an invalid apiVersion value", () => {
63
+ expect(() => {
64
+ generateContentUrl({
65
+ apiKey: testKey,
66
+ model: testModel,
67
+ query: { id: testId },
68
+ options,
69
+ apiVersion: "INVALID_API_VERSION"
70
+ });
71
+ }).toThrow(`Invalid apiVersion: expected 'v2' or 'v3', received 'INVALID_API_VERSION'`);
72
+ });
31
73
  });
@@ -0,0 +1 @@
1
+ "use strict";
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@builder.io/sdk-react",
3
3
  "description": "Builder.io SDK for React",
4
- "version": "0.1.11",
4
+ "version": "0.1.12",
5
5
  "main": "src/index.js",
6
6
  "type": "module",
7
7
  "exports": {
@@ -6,8 +6,8 @@ import { getContent } from "../../functions/get-content/index.js";
6
6
  import { TARGET } from "../../constants/target";
7
7
 
8
8
  function Symbol(props) {
9
- function className() {
10
- return [
9
+ const [className, setClassName] = useState(() =>
10
+ [
11
11
  ...(TARGET === "vue2" || TARGET === "vue3"
12
12
  ? Object.keys(props.attributes.class)
13
13
  : [props.attributes.class]),
@@ -18,20 +18,12 @@ function Symbol(props) {
18
18
  : undefined,
19
19
  ]
20
20
  .filter(Boolean)
21
- .join(" ");
22
- }
23
-
24
- const [fetchedContent, setFetchedContent] = useState(() => null);
25
-
26
- function contentToUse() {
27
- return props.symbol?.content || fetchedContent;
28
- }
29
-
30
- const builderContext = useContext(BuilderContext);
21
+ .join(" ")
22
+ );
31
23
 
32
- useEffect(() => {
33
- const symbolToUse = props.symbol;
24
+ const [contentToUse, setContentToUse] = useState(() => props.symbol?.content);
34
25
 
26
+ function fetchContent() {
35
27
  /**
36
28
  * If:
37
29
  * - we have a symbol prop
@@ -42,44 +34,60 @@ function Symbol(props) {
42
34
  * then we want to re-fetch the symbol content.
43
35
  */
44
36
  if (
45
- symbolToUse &&
46
- !symbolToUse.content &&
47
- !fetchedContent &&
48
- symbolToUse.model &&
37
+ !contentToUse &&
38
+ props.symbol?.model &&
49
39
  // This is a hack, we should not need to check for this, but it is needed for Svelte.
50
40
  builderContext?.apiKey
51
41
  ) {
52
42
  getContent({
53
- model: symbolToUse.model,
43
+ model: props.symbol.model,
54
44
  apiKey: builderContext.apiKey,
45
+ apiVersion: builderContext.apiVersion,
55
46
  query: {
56
- id: symbolToUse.entry,
47
+ id: props.symbol.entry,
57
48
  },
58
- }).then((response) => {
59
- setFetchedContent(response);
60
- });
49
+ })
50
+ .then((response) => {
51
+ if (response) {
52
+ setContentToUse(response);
53
+ }
54
+ })
55
+ .catch((err) => {
56
+ console.error("[Builder.io]: Could not fetch symbol content: ", err);
57
+ });
61
58
  }
62
- }, [props.symbol, fetchedContent]);
59
+ }
60
+
61
+ const builderContext = useContext(BuilderContext);
62
+
63
+ useEffect(() => {
64
+ fetchContent();
65
+ }, []);
66
+
67
+ useEffect(() => {
68
+ fetchContent();
69
+ }, [props.symbol]);
63
70
 
64
71
  return (
65
72
  <div
66
73
  {...props.attributes}
67
74
  dataSet={{
68
- class: className(),
75
+ class: className,
69
76
  }}
70
- className={className()}
77
+ className={className}
71
78
  >
72
79
  <RenderContent
80
+ apiVersion={builderContext.apiVersion}
73
81
  apiKey={builderContext.apiKey}
74
82
  context={builderContext.context}
75
83
  customComponents={Object.values(builderContext.registeredComponents)}
76
84
  data={{
77
85
  ...props.symbol?.data,
78
86
  ...builderContext.state,
79
- ...props.symbol?.content?.data?.state,
87
+ ...contentToUse?.data?.state,
80
88
  }}
81
89
  model={props.symbol?.model}
82
- content={contentToUse()}
90
+ content={contentToUse}
83
91
  />
84
92
  </div>
85
93
  );
@@ -300,6 +300,7 @@ function RenderContent(props) {
300
300
  getContent({
301
301
  model: props.model,
302
302
  apiKey: props.apiKey,
303
+ apiVersion: props.apiVersion,
303
304
  }).then((content) => {
304
305
  if (content) {
305
306
  mergeNewContent(content);
@@ -313,6 +314,11 @@ function RenderContent(props) {
313
314
  }
314
315
  }, []);
315
316
 
317
+ useEffect(() => {
318
+ if (props.content) {
319
+ mergeNewContent(props.content);
320
+ }
321
+ }, [props.content]);
316
322
  useEffect(() => {
317
323
  evaluateJsCode();
318
324
  }, [useContent?.data?.jsCode, contentState]);
@@ -343,6 +349,7 @@ function RenderContent(props) {
343
349
  setState: setContextState,
344
350
  context: props.context || {},
345
351
  apiKey: props.apiKey,
352
+ apiVersion: props.apiVersion,
346
353
  registeredComponents: allRegisteredComponents,
347
354
  }}
348
355
  >
@@ -6,6 +6,7 @@ var stdin_default = createContext({
6
6
  setState() {
7
7
  },
8
8
  apiKey: null,
9
+ apiVersion: void 0,
9
10
  registeredComponents: {},
10
11
  inheritedStyles: {}
11
12
  });
@@ -28,12 +28,16 @@ const generateContentUrl = (options) => {
28
28
  model,
29
29
  apiKey,
30
30
  includeRefs = true,
31
- locale
31
+ locale,
32
+ apiVersion = "v2"
32
33
  } = options;
33
34
  if (!apiKey) {
34
35
  throw new Error("Missing API key");
35
36
  }
36
- const url = new URL(`https://cdn.builder.io/api/v2/content/${model}?apiKey=${apiKey}&limit=${limit}&noTraverse=${noTraverse}&includeRefs=${includeRefs}${locale ? `&locale=${locale}` : ""}`);
37
+ if (!["v2", "v3"].includes(apiVersion)) {
38
+ throw new Error(`Invalid apiVersion: expected 'v2' or 'v3', received '${apiVersion}'`);
39
+ }
40
+ const url = new URL(`https://cdn.builder.io/api/${apiVersion}/content/${model}?apiKey=${apiKey}&limit=${limit}&noTraverse=${noTraverse}&includeRefs=${includeRefs}${locale ? `&locale=${locale}` : ""}`);
37
41
  const queryOptions = __spreadValues(__spreadValues({}, getBuilderSearchParamsFromWindow()), normalizeSearchParams(options.options || {}));
38
42
  const flattened = flatten(queryOptions);
39
43
  for (const key in flattened) {
@@ -28,4 +28,46 @@ describe("Generate Content URL", () => {
28
28
  });
29
29
  expect(output).toMatchSnapshot();
30
30
  });
31
+ test("generate content url with apiVersion as v2", () => {
32
+ const output = generateContentUrl({
33
+ apiKey: testKey,
34
+ model: testModel,
35
+ query: { id: testId },
36
+ options,
37
+ apiVersion: "v2"
38
+ });
39
+ expect(output).toMatchSnapshot();
40
+ });
41
+ test("generate content url with apiVersion as v3", () => {
42
+ const output = generateContentUrl({
43
+ apiKey: testKey,
44
+ model: testModel,
45
+ query: { id: testId },
46
+ options,
47
+ apiVersion: "v3"
48
+ });
49
+ expect(output).toMatchSnapshot();
50
+ });
51
+ test("throw error when trying to generate content url with apiVersion as v1", () => {
52
+ expect(() => {
53
+ generateContentUrl({
54
+ apiKey: testKey,
55
+ model: testModel,
56
+ query: { id: testId },
57
+ options,
58
+ apiVersion: "v1"
59
+ });
60
+ }).toThrow(`Invalid apiVersion: expected 'v2' or 'v3', received 'v1'`);
61
+ });
62
+ test("throw error when trying to generate content url with an invalid apiVersion value", () => {
63
+ expect(() => {
64
+ generateContentUrl({
65
+ apiKey: testKey,
66
+ model: testModel,
67
+ query: { id: testId },
68
+ options,
69
+ apiVersion: "INVALID_API_VERSION"
70
+ });
71
+ }).toThrow(`Invalid apiVersion: expected 'v2' or 'v3', received 'INVALID_API_VERSION'`);
72
+ });
31
73
  });
File without changes
@@ -8,23 +8,55 @@ function Symbol(props) {
8
8
  const _context = { ...props["_context"] };
9
9
 
10
10
  const state = {
11
- get className() {
12
- return [
13
- ...(TARGET === "vue2" || TARGET === "vue3"
14
- ? Object.keys(props.attributes.class)
15
- : [props.attributes.class]),
16
- "builder-symbol",
17
- props.symbol?.inline ? "builder-inline-symbol" : undefined,
18
- props.symbol?.dynamic || props.dynamic
19
- ? "builder-dynamic-symbol"
20
- : undefined,
21
- ]
22
- .filter(Boolean)
23
- .join(" ");
24
- },
25
- fetchedContent: null,
26
- get contentToUse() {
27
- return props.symbol?.content || state.fetchedContent;
11
+ className: [
12
+ ...(TARGET === "vue2" || TARGET === "vue3"
13
+ ? Object.keys(props.attributes.class)
14
+ : [props.attributes.class]),
15
+ "builder-symbol",
16
+ props.symbol?.inline ? "builder-inline-symbol" : undefined,
17
+ props.symbol?.dynamic || props.dynamic
18
+ ? "builder-dynamic-symbol"
19
+ : undefined,
20
+ ]
21
+ .filter(Boolean)
22
+ .join(" "),
23
+ contentToUse: props.symbol?.content,
24
+ fetchContent() {
25
+ /**
26
+ * If:
27
+ * - we have a symbol prop
28
+ * - yet it does not have any content
29
+ * - and we have not already stored content from before
30
+ * - and it has a model name
31
+ *
32
+ * then we want to re-fetch the symbol content.
33
+ */
34
+ if (
35
+ !state.contentToUse &&
36
+ props.symbol?.model &&
37
+ // This is a hack, we should not need to check for this, but it is needed for Svelte.
38
+ builderContext?.apiKey
39
+ ) {
40
+ getContent({
41
+ model: props.symbol.model,
42
+ apiKey: builderContext.apiKey,
43
+ apiVersion: builderContext.apiVersion,
44
+ query: {
45
+ id: props.symbol.entry,
46
+ },
47
+ })
48
+ .then((response) => {
49
+ if (response) {
50
+ state.contentToUse = response;
51
+ }
52
+ })
53
+ .catch((err) => {
54
+ console.error(
55
+ "[Builder.io]: Could not fetch symbol content: ",
56
+ err
57
+ );
58
+ });
59
+ }
28
60
  },
29
61
  };
30
62
 
@@ -39,13 +71,14 @@ function Symbol(props) {
39
71
  className={state.className}
40
72
  >
41
73
  <RenderContent
74
+ apiVersion={builderContext.apiVersion}
42
75
  apiKey={builderContext.apiKey}
43
76
  context={builderContext.context}
44
77
  customComponents={Object.values(builderContext.registeredComponents)}
45
78
  data={{
46
79
  ...props.symbol?.data,
47
80
  ...builderContext.state,
48
- ...props.symbol?.content?.data?.state,
81
+ ...state.contentToUse?.data?.state,
49
82
  }}
50
83
  model={props.symbol?.model}
51
84
  content={state.contentToUse}
@@ -214,6 +214,7 @@ function RenderContent(props) {
214
214
  setState: state.setContextState,
215
215
  context: props.context || {},
216
216
  apiKey: props.apiKey,
217
+ apiVersion: props.apiVersion,
217
218
  registeredComponents: state.allRegisteredComponents,
218
219
  };
219
220
 
@@ -5,6 +5,7 @@ var stdin_default = {
5
5
  setState() {
6
6
  },
7
7
  apiKey: null,
8
+ apiVersion: void 0,
8
9
  registeredComponents: {},
9
10
  inheritedStyles: {}
10
11
  };
@@ -28,12 +28,16 @@ const generateContentUrl = (options) => {
28
28
  model,
29
29
  apiKey,
30
30
  includeRefs = true,
31
- locale
31
+ locale,
32
+ apiVersion = "v2"
32
33
  } = options;
33
34
  if (!apiKey) {
34
35
  throw new Error("Missing API key");
35
36
  }
36
- const url = new URL(`https://cdn.builder.io/api/v2/content/${model}?apiKey=${apiKey}&limit=${limit}&noTraverse=${noTraverse}&includeRefs=${includeRefs}${locale ? `&locale=${locale}` : ""}`);
37
+ if (!["v2", "v3"].includes(apiVersion)) {
38
+ throw new Error(`Invalid apiVersion: expected 'v2' or 'v3', received '${apiVersion}'`);
39
+ }
40
+ const url = new URL(`https://cdn.builder.io/api/${apiVersion}/content/${model}?apiKey=${apiKey}&limit=${limit}&noTraverse=${noTraverse}&includeRefs=${includeRefs}${locale ? `&locale=${locale}` : ""}`);
37
41
  const queryOptions = __spreadValues(__spreadValues({}, getBuilderSearchParamsFromWindow()), normalizeSearchParams(options.options || {}));
38
42
  const flattened = flatten(queryOptions);
39
43
  for (const key in flattened) {
@@ -28,4 +28,46 @@ describe("Generate Content URL", () => {
28
28
  });
29
29
  expect(output).toMatchSnapshot();
30
30
  });
31
+ test("generate content url with apiVersion as v2", () => {
32
+ const output = generateContentUrl({
33
+ apiKey: testKey,
34
+ model: testModel,
35
+ query: { id: testId },
36
+ options,
37
+ apiVersion: "v2"
38
+ });
39
+ expect(output).toMatchSnapshot();
40
+ });
41
+ test("generate content url with apiVersion as v3", () => {
42
+ const output = generateContentUrl({
43
+ apiKey: testKey,
44
+ model: testModel,
45
+ query: { id: testId },
46
+ options,
47
+ apiVersion: "v3"
48
+ });
49
+ expect(output).toMatchSnapshot();
50
+ });
51
+ test("throw error when trying to generate content url with apiVersion as v1", () => {
52
+ expect(() => {
53
+ generateContentUrl({
54
+ apiKey: testKey,
55
+ model: testModel,
56
+ query: { id: testId },
57
+ options,
58
+ apiVersion: "v1"
59
+ });
60
+ }).toThrow(`Invalid apiVersion: expected 'v2' or 'v3', received 'v1'`);
61
+ });
62
+ test("throw error when trying to generate content url with an invalid apiVersion value", () => {
63
+ expect(() => {
64
+ generateContentUrl({
65
+ apiKey: testKey,
66
+ model: testModel,
67
+ query: { id: testId },
68
+ options,
69
+ apiVersion: "INVALID_API_VERSION"
70
+ });
71
+ }).toThrow(`Invalid apiVersion: expected 'v2' or 'v3', received 'INVALID_API_VERSION'`);
72
+ });
31
73
  });
File without changes