@builder.io/sdk-svelte 0.3.1 → 0.4.1

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 (64) hide show
  1. package/package/--package.json +8 -5
  2. package/package/CHANGELOG.md +17 -0
  3. package/package/components/render-block/render-block.svelte +6 -6
  4. package/package/components/render-content/components/render-styles.svelte +1 -1
  5. package/package/components/render-content/render-content.svelte +84 -2
  6. package/package/components/render-content/render-content.svelte.d.ts +5 -0
  7. package/package/components/render-content/render-content.types.d.ts +11 -2
  8. package/package/components/render-content/wrap-component-ref.d.ts +6 -0
  9. package/package/components/render-content/wrap-component-ref.js +6 -0
  10. package/package/components/render-content-variants/helpers.d.ts +17 -0
  11. package/package/components/render-content-variants/helpers.js +182 -0
  12. package/package/components/render-content-variants/render-content-variants.svelte +70 -0
  13. package/package/components/render-content-variants/render-content-variants.svelte.d.ts +23 -0
  14. package/package/components/render-inlined-styles.svelte +3 -15
  15. package/package/components/render-inlined-styles.svelte.d.ts +2 -0
  16. package/package/constants/sdk-version.d.ts +1 -1
  17. package/package/constants/sdk-version.js +1 -1
  18. package/package/functions/get-builder-search-params/index.d.ts +6 -0
  19. package/package/functions/get-builder-search-params/index.js +6 -0
  20. package/package/functions/get-content/generate-content-url.js +2 -2
  21. package/package/functions/get-content/generate-content-url.test.js +15 -0
  22. package/package/functions/get-content/index.d.ts +7 -2
  23. package/package/functions/get-content/index.js +43 -20
  24. package/package/functions/get-content/types.d.ts +6 -0
  25. package/package/helpers/ab-tests.d.ts +8 -7
  26. package/package/helpers/ab-tests.js +103 -4
  27. package/package/helpers/canTrack.d.ts +1 -0
  28. package/package/helpers/canTrack.js +2 -0
  29. package/package/helpers/cookie.d.ts +7 -3
  30. package/package/helpers/cookie.js +9 -6
  31. package/package/helpers/logger.d.ts +1 -0
  32. package/package/helpers/logger.js +1 -0
  33. package/package/index-helpers/blocks-exports.d.ts +1 -1
  34. package/package/index-helpers/blocks-exports.js +1 -1
  35. package/package/index.d.ts +9 -7
  36. package/package/index.js +7 -7
  37. package/package/scripts/init-editing.d.ts +1 -0
  38. package/package/types/builder-content.d.ts +1 -3
  39. package/package.json +4 -5
  40. package/src/components/render-block/render-block.svelte +6 -6
  41. package/src/components/render-content/components/render-styles.svelte +1 -1
  42. package/src/components/render-content/render-content.svelte +86 -2
  43. package/src/components/render-content/render-content.types.ts +11 -2
  44. package/src/components/render-content/wrap-component-ref.ts +6 -0
  45. package/src/components/render-content-variants/helpers.ts +245 -0
  46. package/src/components/render-content-variants/render-content-variants.svelte +83 -0
  47. package/src/components/render-inlined-styles.svelte +3 -16
  48. package/src/constants/sdk-version.ts +1 -1
  49. package/src/functions/get-builder-search-params/index.ts +6 -0
  50. package/src/functions/get-content/generate-content-url.test.ts +17 -0
  51. package/src/functions/get-content/generate-content-url.ts +2 -1
  52. package/src/functions/get-content/index.ts +57 -26
  53. package/src/functions/get-content/types.ts +7 -0
  54. package/src/helpers/ab-tests.ts +164 -11
  55. package/src/helpers/canTrack.ts +4 -0
  56. package/src/helpers/cookie.ts +16 -11
  57. package/src/helpers/logger.ts +1 -0
  58. package/src/index-helpers/blocks-exports.ts +1 -1
  59. package/src/index.ts +19 -8
  60. package/src/scripts/init-editing.ts +1 -0
  61. package/src/types/builder-content.ts +1 -3
  62. package/package/functions/get-content/ab-testing.d.ts +0 -5
  63. package/package/functions/get-content/ab-testing.js +0 -78
  64. package/src/functions/get-content/ab-testing.ts +0 -132
@@ -23,6 +23,7 @@ export interface GetContentOptions {
23
23
  /**
24
24
  * If set to `true`, it will lazy load symbols/references.
25
25
  * If set to `false`, it will render the entire content tree eagerly.
26
+ * @deprecated use `enrich` instead
26
27
  */
27
28
  noTraverse?: boolean;
28
29
 
@@ -36,9 +37,15 @@ export interface GetContentOptions {
36
37
 
37
38
  /**
38
39
  * Include references in the response. Defaults to `true`.
40
+ * @deprecated use `enrich` instead
39
41
  */
40
42
  includeRefs?: boolean;
41
43
 
44
+ /**
45
+ * Include multilevel references in the response.
46
+ */
47
+ enrich?: boolean;
48
+
42
49
  /**
43
50
  * If provided, the API will auto-resolve localized objects to the value of this `locale` key.
44
51
  */
@@ -1,22 +1,175 @@
1
1
  import type { CanTrack } from '../types/can-track.js';
2
- import { getCookie, setCookie } from './cookie.js';
2
+ import { getCookie, getCookieSync, setCookie } from './cookie.js';
3
+ import type {
4
+ BuilderContent,
5
+ BuilderContentVariation,
6
+ } from '../types/builder-content.js';
7
+ import type { Nullable, Overwrite } from '../types/typescript.js';
8
+ import { checkIsDefined } from '../helpers/nullable.js';
9
+ import { logger } from './logger.js';
3
10
 
4
- const BUILDER_STORE_PREFIX = 'builderio.variations';
11
+ const BUILDER_STORE_PREFIX = 'builder.tests';
5
12
 
6
13
  const getContentTestKey = (id: string) => `${BUILDER_STORE_PREFIX}.${id}`;
7
14
 
8
- export const getContentVariationCookie = ({
9
- contentId,
10
- canTrack,
11
- }: { contentId: string } & CanTrack) =>
12
- getCookie({ name: getContentTestKey(contentId), canTrack });
15
+ const getContentVariationCookie = ({ contentId }: { contentId: string }) =>
16
+ getCookie({ name: getContentTestKey(contentId), canTrack: true });
13
17
 
14
- export const setContentVariationCookie = ({
18
+ const getContentVariationCookieSync = ({ contentId }: { contentId: string }) =>
19
+ getCookieSync({ name: getContentTestKey(contentId), canTrack: true });
20
+
21
+ const setContentVariationCookie = ({
15
22
  contentId,
16
- canTrack,
17
23
  value,
18
24
  }: {
19
25
  contentId: string;
20
26
  value: string;
21
- } & CanTrack) =>
22
- setCookie({ name: getContentTestKey(contentId), value, canTrack });
27
+ }) => setCookie({ name: getContentTestKey(contentId), value, canTrack: true });
28
+
29
+ type BuilderContentWithVariations = Overwrite<
30
+ BuilderContent,
31
+ Required<Pick<BuilderContent, 'variations' | 'id'>>
32
+ >;
33
+
34
+ const checkIsBuilderContentWithVariations = (
35
+ item: BuilderContent
36
+ ): item is BuilderContentWithVariations =>
37
+ checkIsDefined(item.id) &&
38
+ checkIsDefined(item.variations) &&
39
+ Object.keys(item.variations).length > 0;
40
+
41
+ /**
42
+ * Randomly assign a variation to a user
43
+ */
44
+ const getRandomVariationId = ({
45
+ id,
46
+ variations,
47
+ }: BuilderContentWithVariations) => {
48
+ let n = 0;
49
+ const random = Math.random();
50
+
51
+ // loop over variations test ratios, incrementing a counter,
52
+ // until we find the variation that this user should be assigned to
53
+ for (const id in variations) {
54
+ const testRatio = variations[id]?.testRatio;
55
+ n += testRatio!;
56
+
57
+ if (random < n) {
58
+ return id;
59
+ }
60
+ }
61
+
62
+ // the variations array does not include the default variation.
63
+ // if we arrive here, then it means that the random number fits in the default variation bucket.
64
+ return id;
65
+ };
66
+
67
+ const getAndSetVariantId = (args: BuilderContentWithVariations) => {
68
+ // if variation not found in storage, assign a random variation to this user
69
+ const randomVariationId = getRandomVariationId(args);
70
+
71
+ // store variation in cookies/storage
72
+ setContentVariationCookie({
73
+ contentId: args.id,
74
+ value: randomVariationId,
75
+ }).catch((err) => {
76
+ logger.error('could not store A/B test variation: ', err);
77
+ });
78
+
79
+ return randomVariationId;
80
+ };
81
+
82
+ type TestFields = {
83
+ data?: BuilderContentVariation['data'];
84
+ testVariationId?: string;
85
+ testVariationName: string;
86
+ };
87
+
88
+ const getTestFields = ({
89
+ item,
90
+ testGroupId,
91
+ }: {
92
+ item: BuilderContentWithVariations;
93
+ testGroupId: string;
94
+ }): TestFields => {
95
+ const variationValue = item.variations[testGroupId];
96
+ if (
97
+ testGroupId === item.id ||
98
+ // handle edge-case where `testGroupId` points to non-existing variation
99
+ !variationValue
100
+ ) {
101
+ return {
102
+ testVariationId: item.id,
103
+ testVariationName: 'Default',
104
+ };
105
+ } else {
106
+ return {
107
+ data: variationValue.data,
108
+ testVariationId: variationValue.id,
109
+ testVariationName:
110
+ variationValue.name || (variationValue.id === item.id ? 'Default' : ''),
111
+ };
112
+ }
113
+ };
114
+
115
+ export const handleABTestingSync = ({
116
+ item,
117
+ canTrack,
118
+ }: { item: Nullable<BuilderContent> } & CanTrack): Nullable<BuilderContent> => {
119
+ if (!canTrack) {
120
+ return item;
121
+ }
122
+
123
+ if (!item) {
124
+ return undefined;
125
+ }
126
+
127
+ if (!checkIsBuilderContentWithVariations(item)) {
128
+ return item;
129
+ }
130
+
131
+ const testGroupId =
132
+ getContentVariationCookieSync({
133
+ contentId: item.id,
134
+ }) ||
135
+ getAndSetVariantId({
136
+ variations: item.variations,
137
+ id: item.id,
138
+ });
139
+
140
+ const variationValue = getTestFields({ item, testGroupId });
141
+ return {
142
+ ...item,
143
+ ...variationValue,
144
+ };
145
+ };
146
+
147
+ export const handleABTesting = async ({
148
+ item,
149
+ canTrack,
150
+ }: { item: BuilderContent } & CanTrack): Promise<BuilderContent> => {
151
+ if (!canTrack) {
152
+ return item;
153
+ }
154
+
155
+ if (!checkIsBuilderContentWithVariations(item)) {
156
+ return item;
157
+ }
158
+
159
+ const cookieValue = await getContentVariationCookie({
160
+ contentId: item.id,
161
+ });
162
+
163
+ const testGroupId =
164
+ cookieValue ||
165
+ getAndSetVariantId({
166
+ variations: item.variations,
167
+ id: item.id,
168
+ });
169
+
170
+ const variationValue = getTestFields({ item, testGroupId });
171
+ return {
172
+ ...item,
173
+ ...variationValue,
174
+ };
175
+ };
@@ -0,0 +1,4 @@
1
+ import { checkIsDefined } from './nullable';
2
+
3
+ export const getDefaultCanTrack = (canTrack?: boolean) =>
4
+ checkIsDefined(canTrack) ? canTrack : true;
@@ -1,17 +1,17 @@
1
1
  import { isBrowser } from '../functions/is-browser.js';
2
2
  import type { CanTrack } from '../types/can-track.js';
3
+ import { logger } from './logger.js';
3
4
  import { checkIsDefined } from './nullable.js';
4
5
  import { getTopLevelDomain } from './url.js';
5
6
 
6
- /**
7
- * NOTE: This function is `async` because its react-native override is async. Do not remove the `async` keyword!
8
- */
9
- export const getCookie = async ({
7
+ type GetCookieArgs = {
8
+ name: string;
9
+ } & CanTrack;
10
+
11
+ export const getCookieSync = ({
10
12
  name,
11
13
  canTrack,
12
- }: {
13
- name: string;
14
- } & CanTrack): Promise<string | undefined> => {
14
+ }: GetCookieArgs): string | undefined => {
15
15
  try {
16
16
  if (!canTrack) {
17
17
  return undefined;
@@ -25,11 +25,16 @@ export const getCookie = async ({
25
25
  .split('; ')
26
26
  .find((row) => row.startsWith(`${name}=`))
27
27
  ?.split('=')[1];
28
- } catch (err) {
29
- console.debug('[COOKIE] GET error: ', err);
28
+ } catch (err: any) {
29
+ logger.warn('[COOKIE] GET error: ', err?.message || err);
30
30
  return undefined;
31
31
  }
32
32
  };
33
+ /**
34
+ * NOTE: This function is `async` because its react-native override is async. Do not remove the `async` keyword!
35
+ * The sync version is only safe to use in code blocks that `react-native` is guaranteed not to not run.
36
+ */
37
+ export const getCookie = async (args: GetCookieArgs) => getCookieSync(args);
33
38
 
34
39
  type CookieConfiguration = Array<
35
40
  | ['expires', string]
@@ -101,7 +106,7 @@ export const setCookie = async ({
101
106
  }
102
107
  const cookie = createCookieString({ name, value, expires });
103
108
  document.cookie = cookie;
104
- } catch (err) {
105
- console.warn('[COOKIE] SET error: ', err);
109
+ } catch (err: any) {
110
+ logger.warn('[COOKIE] SET error: ', err?.message || err);
106
111
  }
107
112
  };
@@ -3,4 +3,5 @@ export const logger = {
3
3
  log: (...message: any[]) => console.log(MSG_PREFIX, ...message),
4
4
  error: (...message: any[]) => console.error(MSG_PREFIX, ...message),
5
5
  warn: (...message: any[]) => console.warn(MSG_PREFIX, ...message),
6
+ debug: (...message: any[]) => console.debug(MSG_PREFIX, ...message),
6
7
  };
@@ -3,8 +3,8 @@ export { default as Columns } from '../blocks/columns/columns.svelte';
3
3
  export { default as Fragment } from '../blocks/fragment/fragment.svelte';
4
4
  export { default as Image } from '../blocks/image/image.svelte';
5
5
  export { default as RenderBlocks } from '../components/render-blocks.svelte';
6
- export { default as RenderContent } from '../components/render-content/render-content.svelte';
7
6
  export { default as Section } from '../blocks/section/section.svelte';
8
7
  export { default as Symbol } from '../blocks/symbol/symbol.svelte';
9
8
  export { default as Text } from '../blocks/text/text.svelte';
10
9
  export { default as Video } from '../blocks/video/video.svelte';
10
+ export { default as RenderContent } from '../components/render-content-variants/render-content-variants.svelte';
package/src/index.ts CHANGED
@@ -1,15 +1,26 @@
1
1
  export * from './index-helpers/top-of-file.js';
2
-
3
2
  export * from './index-helpers/blocks-exports.js';
4
3
 
5
- export * from './functions/is-editing.js';
6
- export * from './functions/is-previewing.js';
7
- export * from './functions/register-component.js';
8
- export * from './functions/register.js';
9
- export * from './functions/set-editor-settings.js';
10
- export * from './functions/get-content/index.js';
11
- export * from './functions/get-builder-search-params/index.js';
4
+ export { isEditing } from './functions/is-editing.js';
5
+ export { isPreviewing } from './functions/is-previewing.js';
6
+ export { createRegisterComponentMessage } from './functions/register-component.js';
7
+
8
+ export { register } from './functions/register.js';
9
+ export type { InsertMenuConfig, InsertMenuItem } from './functions/register.js';
10
+
11
+ export { setEditorSettings } from './functions/set-editor-settings.js';
12
+ export type { Settings } from './functions/set-editor-settings.js';
13
+
14
+ export {
15
+ getAllContent,
16
+ getContent,
17
+ processContentResult,
18
+ } from './functions/get-content/index.js';
19
+
20
+ export { getBuilderSearchParams } from './functions/get-builder-search-params/index.js';
21
+
12
22
  export { track } from './functions/track/index.js';
23
+
13
24
  export type { RegisteredComponent } from './context/types';
14
25
  export type { ComponentInfo } from './types/components';
15
26
  export type { RenderContentProps } from './components/render-content/render-content.types.js';
@@ -27,6 +27,7 @@ export const registerInsertMenu = () => {
27
27
  let isSetupForEditing = false;
28
28
  export const setupBrowserForEditing = (
29
29
  options: {
30
+ enrich?: boolean;
30
31
  includeRefs?: boolean;
31
32
  locale?: string;
32
33
  } = {}
@@ -30,8 +30,6 @@ export interface BuilderContentVariation {
30
30
  export interface BuilderContent extends BuilderContentVariation {
31
31
  // TODO: query
32
32
  '@version'?: number;
33
- id?: string;
34
- name?: string;
35
33
  published?: 'published' | 'draft' | 'archived';
36
34
  modelId?: string;
37
35
  priority?: number;
@@ -39,7 +37,7 @@ export interface BuilderContent extends BuilderContentVariation {
39
37
  startDate?: number;
40
38
  endDate?: number;
41
39
  variations?: {
42
- [id: string]: BuilderContentVariation | undefined;
40
+ [id: string]: BuilderContentVariation;
43
41
  };
44
42
  testVariationId?: string;
45
43
  testVariationName?: string;
@@ -1,5 +0,0 @@
1
- import type { BuilderContent } from '../../types/builder-content.js';
2
- import type { CanTrack } from '../../types/can-track.js';
3
- export declare const handleABTesting: ({ item, canTrack, }: {
4
- item: BuilderContent;
5
- } & CanTrack) => Promise<void>;
@@ -1,78 +0,0 @@
1
- import { getContentVariationCookie, setContentVariationCookie, } from '../../helpers/ab-tests.js';
2
- import { checkIsDefined } from '../../helpers/nullable.js';
3
- const checkIsBuilderContentWithVariations = (item) => checkIsDefined(item.id) &&
4
- checkIsDefined(item.variations) &&
5
- Object.keys(item.variations).length > 0;
6
- /**
7
- * Randomly assign a variation to this user and store it in cookies/storage
8
- */
9
- const getRandomVariationId = ({ id, variations, }) => {
10
- let n = 0;
11
- const random = Math.random();
12
- // loop over variations test ratios, incrementing a counter,
13
- // until we find the variation that this user should be assigned to
14
- for (const id in variations) {
15
- const testRatio = variations[id]?.testRatio;
16
- n += testRatio;
17
- if (random < n) {
18
- return id;
19
- }
20
- }
21
- // `item.variations` does not include the default variation
22
- // if we arrive here, then it means that the random number fits in the default variation bucket
23
- return id;
24
- };
25
- const getTestFields = ({ item, testGroupId, }) => {
26
- const variationValue = item.variations[testGroupId];
27
- if (testGroupId === item.id ||
28
- // handle edge-case where `testGroupId` points to non-existing variation
29
- !variationValue) {
30
- return {
31
- testVariationId: item.id,
32
- testVariationName: 'Default',
33
- };
34
- }
35
- else {
36
- return {
37
- data: variationValue.data,
38
- testVariationId: variationValue.id,
39
- testVariationName: variationValue.name || (variationValue.id === item.id ? 'Default' : ''),
40
- };
41
- }
42
- };
43
- const getContentVariation = async ({ item, canTrack, }) => {
44
- // try to find test variation in cookies/storage
45
- const testGroupId = await getContentVariationCookie({
46
- canTrack,
47
- contentId: item.id,
48
- });
49
- const testFields = testGroupId
50
- ? getTestFields({ item, testGroupId })
51
- : undefined;
52
- if (testFields) {
53
- return testFields;
54
- }
55
- else {
56
- // if variation not found in storage, assign a random variation to this user
57
- const randomVariationId = getRandomVariationId({
58
- variations: item.variations,
59
- id: item.id,
60
- });
61
- // store variation in cookies/storage
62
- setContentVariationCookie({
63
- contentId: item.id,
64
- value: randomVariationId,
65
- canTrack,
66
- }).catch((err) => {
67
- console.error('could not store A/B test variation: ', err);
68
- });
69
- return getTestFields({ item, testGroupId: randomVariationId });
70
- }
71
- };
72
- export const handleABTesting = async ({ item, canTrack, }) => {
73
- if (!checkIsBuilderContentWithVariations(item)) {
74
- return;
75
- }
76
- const variationValue = await getContentVariation({ item, canTrack });
77
- Object.assign(item, variationValue);
78
- };
@@ -1,132 +0,0 @@
1
- import type {
2
- BuilderContent,
3
- BuilderContentVariation,
4
- } from '../../types/builder-content.js';
5
- import {
6
- getContentVariationCookie,
7
- setContentVariationCookie,
8
- } from '../../helpers/ab-tests.js';
9
- import type { Overwrite } from '../../types/typescript.js';
10
- import type { CanTrack } from '../../types/can-track.js';
11
- import { checkIsDefined } from '../../helpers/nullable.js';
12
-
13
- type BuilderContentWithVariations = Overwrite<
14
- BuilderContent,
15
- Required<Pick<BuilderContent, 'variations' | 'id'>>
16
- >;
17
-
18
- const checkIsBuilderContentWithVariations = (
19
- item: BuilderContent
20
- ): item is BuilderContentWithVariations =>
21
- checkIsDefined(item.id) &&
22
- checkIsDefined(item.variations) &&
23
- Object.keys(item.variations).length > 0;
24
-
25
- /**
26
- * Randomly assign a variation to this user and store it in cookies/storage
27
- */
28
- const getRandomVariationId = ({
29
- id,
30
- variations,
31
- }: BuilderContentWithVariations) => {
32
- let n = 0;
33
- const random = Math.random();
34
-
35
- // loop over variations test ratios, incrementing a counter,
36
- // until we find the variation that this user should be assigned to
37
- for (const id in variations) {
38
- const testRatio = variations[id]?.testRatio;
39
- n += testRatio!;
40
-
41
- if (random < n) {
42
- return id;
43
- }
44
- }
45
-
46
- // `item.variations` does not include the default variation
47
- // if we arrive here, then it means that the random number fits in the default variation bucket
48
- return id;
49
- };
50
-
51
- const getTestFields = ({
52
- item,
53
- testGroupId,
54
- }: {
55
- item: BuilderContentWithVariations;
56
- testGroupId: string;
57
- }): TestFields => {
58
- const variationValue = item.variations[testGroupId];
59
- if (
60
- testGroupId === item.id ||
61
- // handle edge-case where `testGroupId` points to non-existing variation
62
- !variationValue
63
- ) {
64
- return {
65
- testVariationId: item.id,
66
- testVariationName: 'Default',
67
- };
68
- } else {
69
- return {
70
- data: variationValue.data,
71
- testVariationId: variationValue.id,
72
- testVariationName:
73
- variationValue.name || (variationValue.id === item.id ? 'Default' : ''),
74
- };
75
- }
76
- };
77
-
78
- type TestFields = {
79
- data?: BuilderContentVariation['data'];
80
- testVariationId?: string;
81
- testVariationName: string;
82
- };
83
-
84
- const getContentVariation = async ({
85
- item,
86
- canTrack,
87
- }: {
88
- item: BuilderContentWithVariations;
89
- } & CanTrack): Promise<TestFields> => {
90
- // try to find test variation in cookies/storage
91
- const testGroupId = await getContentVariationCookie({
92
- canTrack,
93
- contentId: item.id,
94
- });
95
-
96
- const testFields = testGroupId
97
- ? getTestFields({ item, testGroupId })
98
- : undefined;
99
-
100
- if (testFields) {
101
- return testFields;
102
- } else {
103
- // if variation not found in storage, assign a random variation to this user
104
- const randomVariationId = getRandomVariationId({
105
- variations: item.variations,
106
- id: item.id,
107
- });
108
-
109
- // store variation in cookies/storage
110
- setContentVariationCookie({
111
- contentId: item.id,
112
- value: randomVariationId,
113
- canTrack,
114
- }).catch((err) => {
115
- console.error('could not store A/B test variation: ', err);
116
- });
117
-
118
- return getTestFields({ item, testGroupId: randomVariationId });
119
- }
120
- };
121
-
122
- export const handleABTesting = async ({
123
- item,
124
- canTrack,
125
- }: { item: BuilderContent } & CanTrack) => {
126
- if (!checkIsBuilderContentWithVariations(item)) {
127
- return;
128
- }
129
-
130
- const variationValue = await getContentVariation({ item, canTrack });
131
- Object.assign(item, variationValue);
132
- };