@builder.io/sdk-svelte 0.7.0 → 0.7.1-0

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 (81) hide show
  1. package/lib/browser/blocks/custom-code/custom-code.svelte +35 -37
  2. package/lib/browser/components/content/components/enable-editor.svelte +82 -65
  3. package/lib/browser/components/content/components/enable-editor.svelte.d.ts +3 -3
  4. package/lib/browser/constants/sdk-version.d.ts +1 -1
  5. package/lib/browser/constants/sdk-version.js +1 -1
  6. package/lib/browser/functions/evaluate/choose-eval.d.ts +6 -0
  7. package/lib/browser/functions/evaluate/choose-eval.js +19 -0
  8. package/lib/browser/functions/evaluate/evaluate.d.ts +1 -5
  9. package/lib/browser/functions/evaluate/evaluate.js +7 -30
  10. package/lib/browser/functions/evaluate/helpers.d.ts +7 -1
  11. package/lib/browser/functions/evaluate/helpers.js +18 -0
  12. package/lib/browser/functions/evaluate/node-runtime/index.d.ts +1 -1
  13. package/lib/browser/functions/evaluate/node-runtime/index.js +1 -1
  14. package/lib/browser/functions/evaluate/node-runtime/node-runtime.d.ts +2 -0
  15. package/lib/browser/functions/evaluate/node-runtime/node-runtime.js +120 -0
  16. package/lib/browser/functions/evaluate/node-runtime/safeDynamicRequire.d.ts +13 -0
  17. package/lib/browser/functions/evaluate/node-runtime/safeDynamicRequire.js +18 -0
  18. package/lib/browser/functions/get-content/generate-content-url.js +27 -1
  19. package/lib/browser/functions/get-content/types.d.ts +94 -3
  20. package/lib/browser/functions/is-edge-runtime.js +2 -2
  21. package/lib/browser/functions/is-node-runtime.d.ts +4 -0
  22. package/lib/browser/functions/is-node-runtime.js +7 -0
  23. package/lib/edge/blocks/custom-code/custom-code.svelte +35 -37
  24. package/lib/edge/components/content/components/enable-editor.svelte +82 -65
  25. package/lib/edge/components/content/components/enable-editor.svelte.d.ts +3 -3
  26. package/lib/edge/constants/sdk-version.d.ts +1 -1
  27. package/lib/edge/constants/sdk-version.js +1 -1
  28. package/lib/edge/functions/evaluate/choose-eval.d.ts +6 -0
  29. package/lib/edge/functions/evaluate/choose-eval.js +19 -0
  30. package/lib/edge/functions/evaluate/evaluate.d.ts +1 -5
  31. package/lib/edge/functions/evaluate/evaluate.js +7 -30
  32. package/lib/edge/functions/evaluate/helpers.d.ts +7 -1
  33. package/lib/edge/functions/evaluate/helpers.js +18 -0
  34. package/lib/edge/functions/evaluate/node-runtime/index.d.ts +1 -1
  35. package/lib/edge/functions/evaluate/node-runtime/index.js +1 -1
  36. package/lib/edge/functions/evaluate/node-runtime/node-runtime.d.ts +2 -0
  37. package/lib/edge/functions/evaluate/node-runtime/node-runtime.js +120 -0
  38. package/lib/edge/functions/evaluate/node-runtime/safeDynamicRequire.d.ts +13 -0
  39. package/lib/edge/functions/evaluate/node-runtime/safeDynamicRequire.js +18 -0
  40. package/lib/edge/functions/get-content/generate-content-url.js +27 -1
  41. package/lib/edge/functions/get-content/types.d.ts +94 -3
  42. package/lib/edge/functions/is-edge-runtime.js +2 -2
  43. package/lib/edge/functions/is-node-runtime.d.ts +4 -0
  44. package/lib/edge/functions/is-node-runtime.js +7 -0
  45. package/lib/node/blocks/custom-code/custom-code.svelte +35 -37
  46. package/lib/node/components/content/components/enable-editor.svelte +82 -65
  47. package/lib/node/components/content/components/enable-editor.svelte.d.ts +3 -3
  48. package/lib/node/constants/sdk-version.d.ts +1 -1
  49. package/lib/node/constants/sdk-version.js +1 -1
  50. package/lib/node/functions/evaluate/choose-eval.d.ts +6 -0
  51. package/lib/node/functions/evaluate/choose-eval.js +19 -0
  52. package/lib/node/functions/evaluate/evaluate.d.ts +1 -5
  53. package/lib/node/functions/evaluate/evaluate.js +7 -30
  54. package/lib/node/functions/evaluate/helpers.d.ts +7 -1
  55. package/lib/node/functions/evaluate/helpers.js +18 -0
  56. package/lib/node/functions/evaluate/node-runtime/index.d.ts +1 -1
  57. package/lib/node/functions/evaluate/node-runtime/index.js +1 -1
  58. package/lib/node/functions/evaluate/node-runtime/node-runtime.d.ts +2 -0
  59. package/lib/node/functions/evaluate/node-runtime/node-runtime.js +120 -0
  60. package/lib/node/functions/evaluate/node-runtime/safeDynamicRequire.d.ts +13 -0
  61. package/lib/node/functions/evaluate/node-runtime/safeDynamicRequire.js +18 -0
  62. package/lib/node/functions/get-content/generate-content-url.js +27 -1
  63. package/lib/node/functions/get-content/types.d.ts +94 -3
  64. package/lib/node/functions/is-edge-runtime.js +2 -2
  65. package/lib/node/functions/is-node-runtime.d.ts +4 -0
  66. package/lib/node/functions/is-node-runtime.js +7 -0
  67. package/package.json +2 -1
  68. package/src/blocks/custom-code/custom-code.svelte +37 -40
  69. package/src/blocks/image/image.svelte +1 -1
  70. package/src/components/content/components/enable-editor.svelte +97 -79
  71. package/src/constants/sdk-version.ts +1 -1
  72. package/src/functions/evaluate/choose-eval.ts +22 -0
  73. package/src/functions/evaluate/evaluate.ts +8 -37
  74. package/src/functions/evaluate/helpers.ts +24 -1
  75. package/src/functions/evaluate/node-runtime/index.ts +1 -1
  76. package/src/functions/evaluate/node-runtime/node-runtime.ts +138 -0
  77. package/src/functions/evaluate/node-runtime/safeDynamicRequire.ts +18 -0
  78. package/src/functions/get-content/generate-content-url.ts +36 -1
  79. package/src/functions/get-content/types.ts +101 -3
  80. package/src/functions/is-edge-runtime.ts +2 -2
  81. package/src/functions/is-node-runtime.ts +8 -0
@@ -5,11 +5,42 @@ export interface GetContentOptions {
5
5
  apiKey: string;
6
6
  /** Number of items to fetch. Default is 1 */
7
7
  limit?: number;
8
- /** User attributes to target on, such as { urlPath: '/foo', device: 'mobile', ...etc } */
8
+ /**
9
+ * Use to specify an offset for pagination of results. The default is 0.
10
+ */
11
+ offset?: number;
12
+ /**
13
+ * User attribute key value pairs to be used for targeting
14
+ * https://www.builder.io/c/docs/custom-targeting-attributes
15
+ *
16
+ * e.g.
17
+ * ```js
18
+ * userAttributes: {
19
+ * urlPath: '/',
20
+ * returnVisitor: true,
21
+ * device: 'mobile'
22
+ * }
23
+ * ```
24
+ */
9
25
  userAttributes?: (Record<string, string> & {
10
26
  urlPath?: string;
11
27
  }) | null;
12
- /** Custom query */
28
+ /**
29
+ * Mongodb style query of your data. E.g.:
30
+ *
31
+ * ```js
32
+ * query: {
33
+ * id: 'abc123',
34
+ * data: {
35
+ * myCustomField: { $gt: 20 },
36
+ * }
37
+ * }
38
+ * ```
39
+ *
40
+ * See more info on MongoDB's query operators and format.
41
+ *
42
+ * @see {@link https://docs.mongodb.com/manual/reference/operator/query/}
43
+ */
13
44
  query?: Record<string, any>;
14
45
  /**
15
46
  * Any other API options.
@@ -30,7 +61,7 @@ export interface GetContentOptions {
30
61
  */
31
62
  canTrack?: boolean;
32
63
  /**
33
- * Include references in the response. Defaults to `true`.
64
+ * Include content of references in the response. Defaults to `true`.
34
65
  * @deprecated use `enrich` instead
35
66
  */
36
67
  includeRefs?: boolean;
@@ -48,4 +79,64 @@ export interface GetContentOptions {
48
79
  * Defaults to `v3`.
49
80
  */
50
81
  apiVersion?: 'v2' | 'v3';
82
+ /**
83
+ * Only include these fields.
84
+ * Note: 'omit' takes precedence over 'fields'
85
+ *
86
+ * @example
87
+ * ```
88
+ * fields: 'id, name, data.customField'
89
+ * ```
90
+ */
91
+ fields?: string;
92
+ /**
93
+ * Omit only these fields.
94
+ * Note: 'omit' takes precedence over 'fields'
95
+ *
96
+ * @example
97
+ * ```
98
+ * omit: 'data.bigField,data.blocks'
99
+ * ```
100
+ */
101
+ omit?: string;
102
+ /**
103
+ * Seconds to cache content. Sets the max-age of the cache-control header
104
+ * response header.
105
+ *
106
+ * Use a higher value for better performance, lower for content that will change more frequently
107
+ *
108
+ * @see {@link https://www.builder.io/c/docs/query-api#__next:~:text=%26includeRefs%3Dtrue-,cacheSeconds,-No}
109
+ */
110
+ cacheSeconds?: number;
111
+ /**
112
+ * Builder.io uses stale-while-revalidate caching at the CDN level. This means we always serve
113
+ * from edge cache and update caches in the background for maximum possible performance. This also
114
+ * means that the more frequently content is requested, the more fresh it will be. The longest we
115
+ * will ever hold something in stale cache is 1 day by default, and you can set this to be shorter
116
+ * yourself as well. We suggest keeping this high unless you have content that must change rapidly
117
+ * and gets very little traffic.
118
+ *
119
+ * @see {@link https://www.fastly.com/blog/prevent-application-network-instability-serve-stale-content}
120
+ */
121
+ staleCacheSeconds?: number;
122
+ /**
123
+ * Property to order results by.
124
+ * Use 1 for ascending and -1 for descending.
125
+ *
126
+ * The key is what you're sorting on, so the following example sorts by createdDate
127
+ * and because the value is 1, the sort is ascending.
128
+ *
129
+ * @example
130
+ * ```
131
+ * createdDate: 1
132
+ * ```
133
+ */
134
+ sort?: {
135
+ [key: string]: 1 | -1;
136
+ };
137
+ /**
138
+ * Include content entries in a response that are still in
139
+ * draft mode and un-archived. Default is false.
140
+ */
141
+ includeUnpublished?: boolean;
51
142
  }
@@ -1,8 +1,8 @@
1
1
  import { isBrowser } from './is-browser.js';
2
+ import { isNodeRuntime } from './is-node-runtime.js';
2
3
  /**
3
4
  * Identifies edge runtimes (edge, workers, serverless, etc.)
4
5
  */
5
6
  export function isEdgeRuntime() {
6
- const hasNode = () => typeof process !== 'undefined' && process?.versions?.node;
7
- return !isBrowser() && !hasNode();
7
+ return !isBrowser() && !isNodeRuntime();
8
8
  }
@@ -0,0 +1,4 @@
1
+ /**
2
+ * Identifies node runtime
3
+ */
4
+ export declare function isNodeRuntime(): boolean;
@@ -0,0 +1,7 @@
1
+ import { checkIsDefined } from '../helpers/nullable';
2
+ /**
3
+ * Identifies node runtime
4
+ */
5
+ export function isNodeRuntime() {
6
+ return typeof process !== 'undefined' && checkIsDefined(process?.versions?.node);
7
+ }
@@ -3,52 +3,50 @@
3
3
  <script>import { onMount } from "svelte";
4
4
  export let replaceNodes = undefined;
5
5
  export let code;
6
- function findAndRunScripts() {
6
+ let elementRef;
7
+ let scriptsInserted = [];
8
+ let scriptsRun = [];
9
+ onMount(() => {
7
10
  // TODO: Move this function to standalone one in '@builder.io/utils'
8
- if (elem && elem.getElementsByTagName && typeof window !== "undefined") {
9
- const scripts = elem.getElementsByTagName("script");
10
- for (let i = 0; i < scripts.length; i++) {
11
- const script = scripts[i];
12
- if (script.src) {
13
- if (scriptsInserted.includes(script.src)) {
14
- continue;
15
- }
16
- scriptsInserted.push(script.src);
17
- const newScript = document.createElement("script");
18
- newScript.async = true;
19
- newScript.src = script.src;
20
- document.head.appendChild(newScript);
11
+ if (!elementRef?.getElementsByTagName || typeof window === "undefined") {
12
+ return;
13
+ }
14
+ const scripts = elementRef.getElementsByTagName("script");
15
+ for (let i = 0; i < scripts.length; i++) {
16
+ const script = scripts[i];
17
+ if (script.src) {
18
+ if (scriptsInserted.includes(script.src)) {
19
+ continue;
20
+ }
21
+ scriptsInserted.push(script.src);
22
+ const newScript = document.createElement("script");
23
+ newScript.async = true;
24
+ newScript.src = script.src;
25
+ document.head.appendChild(newScript);
26
+ }
27
+ else if (!script.type ||
28
+ [
29
+ "text/javascript",
30
+ "application/javascript",
31
+ "application/ecmascript",
32
+ ].includes(script.type)) {
33
+ if (scriptsRun.includes(script.innerText)) {
34
+ continue;
35
+ }
36
+ try {
37
+ scriptsRun.push(script.innerText);
38
+ new Function(script.innerText)();
21
39
  }
22
- else if (!script.type ||
23
- [
24
- "text/javascript",
25
- "application/javascript",
26
- "application/ecmascript",
27
- ].includes(script.type)) {
28
- if (scriptsRun.includes(script.innerText)) {
29
- continue;
30
- }
31
- try {
32
- scriptsRun.push(script.innerText);
33
- new Function(script.innerText)();
34
- }
35
- catch (error) {
36
- console.warn("`CustomCode`: Error running script:", error);
37
- }
40
+ catch (error) {
41
+ console.warn("`CustomCode`: Error running script:", error);
38
42
  }
39
43
  }
40
44
  }
41
- }
42
- let elem;
43
- let scriptsInserted = [];
44
- let scriptsRun = [];
45
- onMount(() => {
46
- findAndRunScripts();
47
45
  });
48
46
  </script>
49
47
 
50
48
  <div
51
- bind:this={elem}
49
+ bind:this={elementRef}
52
50
  class={"builder-custom-code" + (replaceNodes ? " replace-nodes" : "")}
53
51
  >
54
52
  {@html code}
@@ -21,12 +21,12 @@ export let model = undefined;
21
21
  export let context = undefined;
22
22
  export let canTrack = undefined;
23
23
  export let apiKey;
24
- export let showContent;
25
- export let classNameProp;
26
- export let content = undefined;
27
24
  export let locale = undefined;
28
25
  export let includeRefs = undefined;
29
26
  export let enrich = undefined;
27
+ export let content = undefined;
28
+ export let showContent;
29
+ export let classNameProp;
30
30
  function mergeNewContent(newContent) {
31
31
  const newContentValue = {
32
32
  ...$builderContextSignal.content,
@@ -159,6 +159,61 @@ function emitStateUpdate() {
159
159
  }));
160
160
  }
161
161
  }
162
+ function elementRef_onIniteditingbldr(event) {
163
+ forceReRenderCount = forceReRenderCount + 1;
164
+ window.addEventListener("message", processMessage);
165
+ registerInsertMenu();
166
+ setupBrowserForEditing({
167
+ ...(locale
168
+ ? {
169
+ locale: locale,
170
+ }
171
+ : {}),
172
+ ...(includeRefs
173
+ ? {
174
+ includeRefs: includeRefs,
175
+ }
176
+ : {}),
177
+ ...(enrich
178
+ ? {
179
+ enrich: enrich,
180
+ }
181
+ : {}),
182
+ });
183
+ Object.values($builderContextSignal.componentInfos).forEach((registeredComponent) => {
184
+ const message = createRegisterComponentMessage(registeredComponent);
185
+ window.parent?.postMessage(message, "*");
186
+ });
187
+ window.addEventListener("builder:component:stateChangeListenerActivated", emitStateUpdate);
188
+ }
189
+ function elementRef_onInitpreviewingbldr(event) {
190
+ const searchParams = new URL(location.href).searchParams;
191
+ const searchParamPreviewModel = searchParams.get("builder.preview");
192
+ const searchParamPreviewId = searchParams.get(`builder.preview.${searchParamPreviewModel}`);
193
+ const previewApiKey = searchParams.get("apiKey") || searchParams.get("builder.space");
194
+ /**
195
+ * Make sure that:
196
+ * - the preview model name is the same as the one we're rendering, since there can be multiple models rendered
197
+ * at the same time, e.g. header/page/footer.
198
+ * - the API key is the same, since we don't want to preview content from other organizations.
199
+ * - if there is content, that the preview ID is the same as that of the one we receive.
200
+ *
201
+ * TO-DO: should we only update the state when there is a change?
202
+ **/
203
+ if (searchParamPreviewModel === model &&
204
+ previewApiKey === apiKey &&
205
+ (!content || searchParamPreviewId === content.id)) {
206
+ fetchOneEntry({
207
+ model: model,
208
+ apiKey: apiKey,
209
+ apiVersion: $builderContextSignal.apiVersion,
210
+ }).then((content) => {
211
+ if (content) {
212
+ mergeNewContent(content);
213
+ }
214
+ });
215
+ }
216
+ }
162
217
  let elementRef;
163
218
  let forceReRenderCount = 0;
164
219
  let lastUpdated = 0;
@@ -166,82 +221,37 @@ let shouldSendResetCookie = false;
166
221
  let httpReqsData = {};
167
222
  let clicked = false;
168
223
  onMount(() => {
169
- if (!apiKey) {
170
- logger.error("No API key provided to `RenderContent` component. This can cause issues. Please provide an API key using the `apiKey` prop.");
171
- }
172
224
  if (isBrowser()) {
173
- if (isEditing()) {
174
- forceReRenderCount = forceReRenderCount + 1;
175
- window.addEventListener("message", processMessage);
176
- registerInsertMenu();
177
- setupBrowserForEditing({
178
- ...(locale
179
- ? {
180
- locale: locale,
181
- }
182
- : {}),
183
- ...(includeRefs
184
- ? {
185
- includeRefs: includeRefs,
186
- }
187
- : {}),
188
- ...(enrich
189
- ? {
190
- enrich: enrich,
191
- }
192
- : {}),
193
- });
194
- Object.values($builderContextSignal.componentInfos).forEach((registeredComponent) => {
195
- const message = createRegisterComponentMessage(registeredComponent);
196
- window.parent?.postMessage(message, "*");
197
- });
198
- window.addEventListener("builder:component:stateChangeListenerActivated", emitStateUpdate);
225
+ if (isEditing() && elementRef) {
226
+ elementRef.dispatchEvent(new CustomEvent("initeditingbldr"));
199
227
  }
200
- if ($builderContextSignal.content) {
228
+ const shouldTrackImpression = $builderContextSignal.content && getDefaultCanTrack(canTrack);
229
+ if (shouldTrackImpression) {
201
230
  const variationId = $builderContextSignal.content?.testVariationId;
202
231
  const contentId = $builderContextSignal.content?.id;
232
+ const apiKeyProp = apiKey;
203
233
  _track({
204
234
  type: "impression",
205
- canTrack: getDefaultCanTrack(canTrack),
235
+ canTrack: true,
206
236
  contentId,
207
- apiKey: apiKey,
237
+ apiKey: apiKeyProp,
208
238
  variationId: variationId !== contentId ? variationId : undefined,
209
239
  });
210
240
  }
211
241
  // override normal content in preview mode
212
- if (isPreviewing()) {
213
- const searchParams = new URL(location.href).searchParams;
214
- const searchParamPreviewModel = searchParams.get("builder.preview");
215
- const searchParamPreviewId = searchParams.get(`builder.preview.${searchParamPreviewModel}`);
216
- const previewApiKey = searchParams.get("apiKey") || searchParams.get("builder.space");
217
- /**
218
- * Make sure that:
219
- * - the preview model name is the same as the one we're rendering, since there can be multiple models rendered
220
- * at the same time, e.g. header/page/footer.
221
- * - the API key is the same, since we don't want to preview content from other organizations.
222
- * - if there is content, that the preview ID is the same as that of the one we receive.
223
- *
224
- * TO-DO: should we only update the state when there is a change?
225
- **/
226
- if (searchParamPreviewModel === model &&
227
- previewApiKey === apiKey &&
228
- (!content || searchParamPreviewId === content.id)) {
229
- fetchOneEntry({
230
- model: model,
231
- apiKey: apiKey,
232
- apiVersion: $builderContextSignal.apiVersion,
233
- }).then((content) => {
234
- if (content) {
235
- mergeNewContent(content);
236
- }
237
- });
238
- }
242
+ if (isPreviewing() && elementRef) {
243
+ elementRef.dispatchEvent(new CustomEvent("initpreviewingbldr"));
239
244
  }
240
- evaluateJsCode();
241
- runHttpRequests();
242
- emitStateUpdate();
243
245
  }
244
246
  });
247
+ onMount(() => {
248
+ if (!apiKey) {
249
+ logger.error("No API key provided to `RenderContent` component. This can cause issues. Please provide an API key using the `apiKey` prop.");
250
+ }
251
+ evaluateJsCode();
252
+ runHttpRequests();
253
+ emitStateUpdate();
254
+ });
245
255
  function onUpdateFn_0(..._args) {
246
256
  if (content) {
247
257
  mergeNewContent(content);
@@ -276,6 +286,7 @@ onDestroy(() => {
276
286
 
277
287
  {#if $builderContextSignal.content}
278
288
  <div
289
+ {...{}}
279
290
  key={forceReRenderCount}
280
291
  bind:this={elementRef}
281
292
  on:click={(event) => {
@@ -291,6 +302,12 @@ onDestroy(() => {
291
302
  "aria-hidden": true,
292
303
  }}
293
304
  class={classNameProp}
305
+ on:initeditingbldr={(event) => {
306
+ elementRef_onIniteditingbldr(event);
307
+ }}
308
+ on:initpreviewingbldr={(event) => {
309
+ elementRef_onInitpreviewingbldr(event);
310
+ }}
294
311
  >
295
312
  <slot />
296
313
  </div>
@@ -14,12 +14,12 @@ declare const __propDef: {
14
14
  context?: BuilderEditorProps["context"];
15
15
  canTrack?: BuilderEditorProps["canTrack"];
16
16
  apiKey: BuilderEditorProps["apiKey"];
17
- showContent: BuilderEditorProps["showContent"];
18
- classNameProp: BuilderEditorProps["classNameProp"];
19
- content?: BuilderEditorProps["content"];
20
17
  locale?: BuilderEditorProps["locale"];
21
18
  includeRefs?: BuilderEditorProps["includeRefs"];
22
19
  enrich?: BuilderEditorProps["enrich"];
20
+ content?: BuilderEditorProps["content"];
21
+ showContent: BuilderEditorProps["showContent"];
22
+ classNameProp: BuilderEditorProps["classNameProp"];
23
23
  };
24
24
  events: {
25
25
  [evt: string]: CustomEvent<any>;
@@ -1 +1 @@
1
- export declare const SDK_VERSION = "0.7.0";
1
+ export declare const SDK_VERSION = "0.7.1-0";
@@ -1 +1 @@
1
- export const SDK_VERSION = "0.7.0";
1
+ export const SDK_VERSION = "0.7.1-0";
@@ -0,0 +1,6 @@
1
+ import type { ExecutorArgs } from './helpers.js';
2
+ /**
3
+ * Even though we have separate runtimes for browser/node/edge, sometimes frameworks will
4
+ * end up sending the server runtime code to the browser (most notably in dev mode).
5
+ */
6
+ export declare const chooseBrowserOrServerEval: (args: ExecutorArgs) => any;
@@ -0,0 +1,19 @@
1
+ import { runInBrowser } from './browser-runtime/browser.js';
2
+ import { isBrowser } from '../is-browser.js';
3
+ /**
4
+ * THIS IS A MAGICAL IMPORT. It is aliased by the build process of every SDK configuration, so that
5
+ * it points to the correct runtime for that configuration, which are expected to live exactly at:
6
+ * - ./browser-runtime/index.js
7
+ * - ./node-runtime/index.js
8
+ * - ./edge-runtime/index.js
9
+ *
10
+ * We have code in `/output-generation` that does this aliasing, and is re-used by each SDK.
11
+ * Also, each individual `tsconfig.json` aliases this import to the browser runtime so that the
12
+ * types can be resolved correctly.
13
+ */
14
+ import { evaluator } from '../../../edge/functions/evaluate/edge-runtime/index.js';
15
+ /**
16
+ * Even though we have separate runtimes for browser/node/edge, sometimes frameworks will
17
+ * end up sending the server runtime code to the browser (most notably in dev mode).
18
+ */
19
+ export const chooseBrowserOrServerEval = (args) => isBrowser() ? runInBrowser(args) : evaluator(args);
@@ -1,6 +1,2 @@
1
- import type { ExecutorArgs } from './helpers.js';
2
- export type EvaluatorArgs = Omit<ExecutorArgs, 'builder' | 'event'> & {
3
- event?: Event;
4
- isExpression?: boolean;
5
- };
1
+ import type { EvaluatorArgs } from './helpers.js';
6
2
  export declare function evaluate({ code, context, localState, rootState, rootSetState, event, isExpression }: EvaluatorArgs): any;
@@ -1,39 +1,16 @@
1
1
  import { logger } from '../../helpers/logger.js';
2
- import { isBrowser } from '../is-browser.js';
3
- import { isEditing } from '../is-editing.js';
4
- import { getUserAttributes } from '../track/helpers.js';
5
- /**
6
- * THIS IS A MAGICAL IMPORT. It is aliased by the build process of every SDK configuration, so that
7
- * it points to the correct runtime for that configuration, which are expected to live exactly at:
8
- * - ./browser-runtime/index.js
9
- * - ./node-runtime/index.js
10
- * - ./edge-runtime/index.js
11
- *
12
- * We have code in `/output-generation` that does this aliasing, and is re-used by each SDK.
13
- * Also, each individual `tsconfig.json` aliases this import to the browser runtime so that the
14
- * types can be resolved correctly.
15
- */
16
- import { evaluator } from '../../../edge/functions/evaluate/edge-runtime/index.js';
2
+ import { getBuilderGlobals, parseCode } from './helpers.js';
3
+ import { chooseBrowserOrServerEval } from './choose-eval.js';
17
4
  export function evaluate({ code, context, localState, rootState, rootSetState, event, isExpression = true }) {
18
5
  if (code === '') {
19
6
  logger.warn('Skipping evaluation of empty code block.');
20
7
  return;
21
8
  }
22
- const builder = {
23
- isEditing: isEditing(),
24
- isBrowser: isBrowser(),
25
- isServer: !isBrowser(),
26
- getUserAttributes: () => getUserAttributes()
27
- };
28
- // Be able to handle simple expressions like "state.foo" or "1 + 1"
29
- // as well as full blocks like "var foo = "bar"; return foo"
30
- const useReturn =
31
- // we disable this for cases where we definitely don't want a return
32
- isExpression && !(code.includes(';') || code.includes(' return ') || code.trim().startsWith('return '));
33
- const useCode = useReturn ? `return (${code});` : code;
34
9
  const args = {
35
- code: useCode,
36
- builder,
10
+ code: parseCode(code, {
11
+ isExpression
12
+ }),
13
+ builder: getBuilderGlobals(),
37
14
  context,
38
15
  event,
39
16
  rootSetState,
@@ -41,7 +18,7 @@ export function evaluate({ code, context, localState, rootState, rootSetState, e
41
18
  localState
42
19
  };
43
20
  try {
44
- return evaluator(args);
21
+ return chooseBrowserOrServerEval(args);
45
22
  }
46
23
  catch (e) {
47
24
  logger.error('Failed code evaluation: ' + e.message, {
@@ -1,5 +1,9 @@
1
1
  import type { BuilderContextInterface, BuilderRenderState } from '../../context/types.js';
2
- import type { getUserAttributes } from '../track/helpers.js';
2
+ import { getUserAttributes } from '../track/helpers.js';
3
+ export type EvaluatorArgs = Omit<ExecutorArgs, 'builder' | 'event'> & {
4
+ event?: Event;
5
+ isExpression?: boolean;
6
+ };
3
7
  export type BuilderGlobals = {
4
8
  isEditing: boolean | undefined;
5
9
  isBrowser: boolean | undefined;
@@ -16,3 +20,5 @@ export type FunctionArguments = ReturnType<typeof getFunctionArguments>;
16
20
  export declare const getFunctionArguments: ({ builder, context, event, state }: Pick<ExecutorArgs, "context" | "builder" | "event"> & {
17
21
  state: BuilderRenderState;
18
22
  }) => [string, Event | BuilderRenderState | import("../../context/types.js").BuilderRenderContext | BuilderGlobals | undefined][];
23
+ export declare const getBuilderGlobals: () => BuilderGlobals;
24
+ export declare const parseCode: (code: string, { isExpression }: Pick<EvaluatorArgs, 'isExpression'>) => string;
@@ -1,3 +1,6 @@
1
+ import { isBrowser } from '../is-browser.js';
2
+ import { isEditing } from '../is-editing.js';
3
+ import { getUserAttributes } from '../track/helpers.js';
1
4
  export const getFunctionArguments = ({ builder, context, event, state }) => {
2
5
  return Object.entries({
3
6
  state,
@@ -8,3 +11,18 @@ export const getFunctionArguments = ({ builder, context, event, state }) => {
8
11
  event
9
12
  });
10
13
  };
14
+ export const getBuilderGlobals = () => ({
15
+ isEditing: isEditing(),
16
+ isBrowser: isBrowser(),
17
+ isServer: !isBrowser(),
18
+ getUserAttributes: () => getUserAttributes()
19
+ });
20
+ export const parseCode = (code, { isExpression = true }) => {
21
+ // Be able to handle simple expressions like "state.foo" or "1 + 1"
22
+ // as well as full blocks like "var foo = "bar"; return foo"
23
+ const useReturn =
24
+ // we disable this for cases where we definitely don't want a return
25
+ isExpression && !(code.includes(';') || code.includes(' return ') || code.trim().startsWith('return '));
26
+ const useCode = useReturn ? `return (${code});` : code;
27
+ return useCode;
28
+ };
@@ -1 +1 @@
1
- export { evaluator } from '../browser-runtime/index.js';
1
+ export { runInNode as evaluator } from './node-runtime.js';
@@ -1 +1 @@
1
- export { evaluator } from '../browser-runtime/index.js';
1
+ export { runInNode as evaluator } from './node-runtime.js';
@@ -0,0 +1,2 @@
1
+ import type { ExecutorArgs } from '../helpers.js';
2
+ export declare const runInNode: ({ code, builder, context, event, localState, rootSetState, rootState }: ExecutorArgs) => any;