@finsweet/webflow-apps-utils 1.0.18 → 1.0.20

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 (56) hide show
  1. package/dist/types/index.d.ts +0 -1
  2. package/dist/types/index.js +0 -1
  3. package/dist/ui/components/LoadingScreen.svelte +0 -1
  4. package/dist/ui/components/button/Button.svelte +0 -1
  5. package/dist/ui/components/color-picker/ColorPicker.svelte +0 -1
  6. package/dist/ui/components/color-picker/ColorSelect.svelte +0 -2
  7. package/dist/ui/components/copy-text/CopyText.svelte +0 -2
  8. package/dist/ui/components/input/Input.svelte +0 -1
  9. package/dist/ui/components/layout/Layout.svelte +1 -2
  10. package/dist/ui/components/layout/examples/ExampleLayout.svelte +3 -3
  11. package/dist/ui/components/modal/Modal.svelte +0 -1
  12. package/dist/ui/components/notification/Notification.svelte +2 -2
  13. package/dist/ui/components/select/Select.svelte +4 -4
  14. package/dist/ui/components/text/Text.svelte +1 -6
  15. package/dist/ui/components/tooltip/Tooltip.svelte +1 -1
  16. package/dist/ui/index.css +1 -0
  17. package/dist/ui/providers/GlobalProvider.svelte +0 -10
  18. package/dist/ui/providers/GlobalProviderDemo.svelte +1 -3
  19. package/dist/ui/router/examples/RouterExample.svelte +0 -1
  20. package/dist/ui/router/examples/pages/AboutPage.svelte +0 -2
  21. package/dist/ui/router/examples/pages/HomePage.svelte +0 -2
  22. package/dist/ui/router/examples/pages/NotFoundPage.svelte +0 -2
  23. package/dist/ui/router/providers/Link.svelte +0 -1
  24. package/dist/ui/stores/forms/FormDemo.svelte +1 -5
  25. package/dist/ui/stores/siteInfo.d.ts +2 -0
  26. package/dist/ui/utils/api/clipboard/handlePaste.js +1 -3
  27. package/dist/ui/utils/api/index.d.ts +0 -1
  28. package/dist/ui/utils/api/index.js +0 -1
  29. package/dist/ui/utils/diff-mapper/DiffMapperDemo.svelte +2 -3
  30. package/dist/ui/utils/index.d.ts +0 -1
  31. package/dist/ui/utils/index.js +0 -1
  32. package/dist/utils/api/clipboard/handlePaste.js +1 -3
  33. package/dist/utils/api/index.d.ts +0 -1
  34. package/dist/utils/api/index.js +0 -1
  35. package/dist/utils/browser-storage/sessionStorage.js +1 -3
  36. package/dist/utils/index.d.ts +0 -1
  37. package/dist/utils/index.js +0 -1
  38. package/dist/utils/webflow-canvas/attributes/getAllWebflowElementAttributes.js +1 -3
  39. package/dist/utils/webflow-canvas/attributes/getWebflowElementAttribute.js +1 -3
  40. package/dist/utils/webflow-canvas/attributes/removeWebflowElementAttribute.js +1 -3
  41. package/dist/utils/webflow-canvas/attributes/setWebflowElementAttribute.js +2 -4
  42. package/dist/utils/webflow-canvas/findInstanceElement.js +1 -3
  43. package/dist/utils/webflow-canvas/getAllPages.js +1 -3
  44. package/package.json +2 -2
  45. package/dist/types/auth.d.ts +0 -40
  46. package/dist/types/auth.js +0 -1
  47. package/dist/ui/utils/api/getFinsweetComponentsEnvironment.d.ts +0 -8
  48. package/dist/ui/utils/api/getFinsweetComponentsEnvironment.js +0 -66
  49. package/dist/ui/utils/auth/crossWindowLogin.d.ts +0 -5
  50. package/dist/ui/utils/auth/crossWindowLogin.js +0 -52
  51. package/dist/ui/utils/auth/index.d.ts +0 -45
  52. package/dist/ui/utils/auth/index.js +0 -178
  53. package/dist/utils/api/getFinsweetComponentsEnvironment.d.ts +0 -8
  54. package/dist/utils/api/getFinsweetComponentsEnvironment.js +0 -67
  55. package/dist/utils/logger/index.d.ts +0 -16
  56. package/dist/utils/logger/index.js +0 -39
@@ -1,4 +1,3 @@
1
- export * from './auth';
2
1
  export * from './dom';
3
2
  export * from './customCode';
4
3
  export * from './license';
@@ -1,4 +1,3 @@
1
- export * from './auth';
2
1
  export * from './dom';
3
2
  export * from './customCode';
4
3
  export * from './license';
@@ -61,7 +61,6 @@
61
61
  gap: 10px;
62
62
  color: var(--actionSecondaryText);
63
63
  text-align: center;
64
- font-family: Inter;
65
64
  font-size: 11.5px;
66
65
  font-style: normal;
67
66
  font-weight: 400;
@@ -269,7 +269,6 @@
269
269
 
270
270
  /* Styling */
271
271
  border-radius: var(--border-radius, 4px);
272
- font-family: var(--font-stack, Inter, sans-serif);
273
272
  font-weight: var(--font-weight-normal, 400);
274
273
  font-size: 11.5px;
275
274
  min-height: 24px;
@@ -290,7 +290,6 @@
290
290
  width: 80px;
291
291
  padding: 4px 8px 4px 0px;
292
292
  border-radius: 4px;
293
- font-family: monospace;
294
293
  font-size: 12px;
295
294
  border: none;
296
295
  background: transparent;
@@ -1048,7 +1048,6 @@
1048
1048
  border-radius: 4px;
1049
1049
  color: var(--text1, #ebebeb);
1050
1050
  font-size: 11px;
1051
- font-family: Inter, sans-serif;
1052
1051
  font-weight: 400;
1053
1052
  line-height: 16px;
1054
1053
  outline: none;
@@ -1068,7 +1067,6 @@
1068
1067
  .label {
1069
1068
  color: var(--text1, #ebebeb);
1070
1069
  font-size: 11px;
1071
- font-family: Inter, sans-serif;
1072
1070
  font-weight: 400;
1073
1071
  line-height: 16px;
1074
1072
  text-align: center;
@@ -167,7 +167,6 @@
167
167
  .copy-text__title {
168
168
  margin: 0;
169
169
  color: var(--text-color-primary, #ffffff);
170
- font-family: Inter, sans-serif;
171
170
  font-size: 12px;
172
171
  font-weight: 500;
173
172
  line-height: 16px;
@@ -181,7 +180,6 @@
181
180
  align-items: flex-start;
182
181
  align-self: stretch;
183
182
  color: var(--text2);
184
- font-family: Inter;
185
183
  font-size: 12px;
186
184
  font-style: normal;
187
185
  font-weight: 500;
@@ -628,7 +628,6 @@
628
628
  gap: var(--border-radius, 2px);
629
629
  flex: 1 0 0;
630
630
  color: var(--text3);
631
- font-family: Inter;
632
631
  font-size: 11.5px;
633
632
  font-style: normal;
634
633
  font-weight: 400;
@@ -327,7 +327,6 @@
327
327
 
328
328
  .tab-text {
329
329
  color: inherit;
330
- font-family: Inter;
331
330
  font-size: 11.5px;
332
331
  font-style: normal;
333
332
  font-weight: 400;
@@ -402,7 +401,7 @@
402
401
 
403
402
  .preview-bar-content span {
404
403
  color: var(--actionPrimaryText);
405
- font-family: Inter;
404
+
406
405
  font-size: 11.5px;
407
406
  font-style: normal;
408
407
  font-weight: 500;
@@ -462,7 +462,7 @@
462
462
  font-weight: 500;
463
463
  font-size: 11.5px;
464
464
  color: var(--text1);
465
- font-family: var(--font-stack);
465
+
466
466
  text-align: center;
467
467
  }
468
468
 
@@ -474,7 +474,7 @@
474
474
  background: var(--background1);
475
475
  color: var(--text1);
476
476
  font-size: 11.5px;
477
- font-family: var(--font-stack);
477
+
478
478
  box-shadow: var(--boxShadows-input-inner);
479
479
  transition: all 0.2s ease;
480
480
  }
@@ -530,7 +530,7 @@
530
530
  flex: 1;
531
531
  font-size: 11.5px;
532
532
  color: var(--text1);
533
- font-family: var(--font-stack);
533
+
534
534
  line-height: 1.2;
535
535
  }
536
536
 
@@ -439,7 +439,6 @@
439
439
  user-select: none;
440
440
  width: 24px;
441
441
  padding: 0px 4px;
442
- font-family: inherit;
443
442
  font-size: inherit;
444
443
  position: relative;
445
444
  display: flex;
@@ -237,7 +237,7 @@
237
237
 
238
238
  .message {
239
239
  color: var(--text-text-2, #bdbdbd);
240
- font-family: Inter;
240
+
241
241
  font-size: 11px;
242
242
  font-style: normal;
243
243
  font-weight: 400;
@@ -252,7 +252,7 @@
252
252
 
253
253
  .link {
254
254
  color: var(--blue-blue-text, #8ac2ff);
255
- font-family: Inter;
255
+
256
256
  font-size: 11px;
257
257
  font-style: normal;
258
258
  font-weight: 400;
@@ -553,7 +553,7 @@
553
553
  }
554
554
  .label .label-name {
555
555
  color: var(--text1);
556
- font-family: Inter;
556
+
557
557
  font-size: 11.5px;
558
558
  font-style: normal;
559
559
  font-weight: 400;
@@ -566,7 +566,7 @@
566
566
 
567
567
  .label .label-description {
568
568
  color: var(--text2, #bdbdbd);
569
- font-family: Inter;
569
+
570
570
  font-size: 10px;
571
571
  font-style: normal;
572
572
  font-weight: 400;
@@ -645,7 +645,7 @@
645
645
  gap: 4px;
646
646
  align-self: stretch;
647
647
  color: var(--text2, #bdbdbd);
648
- font-family: Inter;
648
+
649
649
  font-size: 11px;
650
650
  font-style: normal;
651
651
  font-weight: 500;
@@ -679,7 +679,7 @@
679
679
  gap: 4px;
680
680
  align-self: stretch;
681
681
  color: var(--text-text-1, #d9d9d9);
682
- font-family: Inter;
682
+
683
683
  font-size: 11px;
684
684
  font-style: normal;
685
685
  font-weight: 400;
@@ -813,10 +813,6 @@
813
813
  {/if}
814
814
 
815
815
  <style>
816
- .text {
817
- font-family: inherit;
818
- }
819
-
820
816
  .labels.link {
821
817
  cursor: pointer;
822
818
  padding: 4px;
@@ -882,7 +878,6 @@
882
878
  }
883
879
 
884
880
  * {
885
- font-family: Inter;
886
881
  font-style: normal;
887
882
  line-height: 16px;
888
883
  letter-spacing: -0.115px;
@@ -950,7 +945,7 @@
950
945
 
951
946
  .popup-description span {
952
947
  color: var(--text2, #bdbdbd);
953
- font-family: Inter;
948
+
954
949
  font-size: 11px;
955
950
  font-style: normal;
956
951
  font-weight: 400;
@@ -382,7 +382,7 @@
382
382
  0px -0.5px 0.5px 0px rgb(0 0 0 / 0%) inset,
383
383
  0px 0.5px 0.5px 0px rgb(255 255 255 / 34%) inset;
384
384
  color: var(--text2, #b9b9b9);
385
- font-family: Inter;
385
+
386
386
  line-height: 120%;
387
387
  width: 150px;
388
388
  padding: 6px;
package/dist/ui/index.css CHANGED
@@ -159,6 +159,7 @@ body,
159
159
  #app {
160
160
  height: 100%;
161
161
  background: var(--background1);
162
+ font-family: var(--font-stack);
162
163
  /* Prevents layout shift when scrollbar appears, does not work in Safari browsers */
163
164
  /* scrollbar-gutter: stable; */
164
165
  }
@@ -1,6 +1,4 @@
1
1
  <script lang="ts">
2
- import { getFinsweetComponentsEnvironment } from '../../utils/index.js';
3
-
4
2
  import { createGlobalContext, setGlobalContext } from './globalContext.svelte';
5
3
  import type { GlobalProviderProps } from './types';
6
4
 
@@ -41,14 +39,6 @@
41
39
  // Create and set the global context
42
40
  const globalContext = createGlobalContext(mergedContexts, debug);
43
41
  setGlobalContext(globalContext);
44
- const { development } = getFinsweetComponentsEnvironment();
45
-
46
- // Development mode debugging
47
- if (development && typeof window !== 'undefined') {
48
- globalContext.subscribe((event) => {
49
- console.log('🌍 Global Context Event:', event);
50
- });
51
- }
52
42
  </script>
53
43
 
54
44
  {#if children}{@render children()}{/if}
@@ -161,7 +161,6 @@
161
161
  margin: 0 auto;
162
162
  background: var(--background1);
163
163
  color: var(--text1);
164
- font-family: var(--font-stack);
165
164
  }
166
165
 
167
166
  .start-demo {
@@ -211,7 +210,7 @@
211
210
  cursor: pointer;
212
211
  font-size: var(--font-size-small);
213
212
  font-weight: var(--font-weight-normal);
214
- font-family: var(--font-stack);
213
+
215
214
  transition: all 0.2s ease;
216
215
  }
217
216
 
@@ -252,7 +251,6 @@
252
251
  border: 1px solid var(--border2);
253
252
  padding: var(--padding-tiny);
254
253
  border-radius: var(--border-radius);
255
- font-family: monospace;
256
254
  font-size: var(--font-size-small);
257
255
  color: var(--text2);
258
256
  display: block;
@@ -130,7 +130,6 @@
130
130
  max-width: 800px;
131
131
  margin: 0 auto;
132
132
  padding: 1rem;
133
- font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
134
133
  }
135
134
 
136
135
  .app-layout {
@@ -290,7 +290,6 @@
290
290
  cursor: pointer;
291
291
  transition: all 0.3s ease;
292
292
  width: 100%;
293
- font-family: inherit;
294
293
  font-size: inherit;
295
294
  }
296
295
 
@@ -553,7 +552,6 @@
553
552
 
554
553
  .debug-info p {
555
554
  margin: 0.5rem 0;
556
- font-family: 'SFMono-Regular', Consolas, monospace;
557
555
  font-size: 0.875rem;
558
556
  color: #495057;
559
557
  }
@@ -169,7 +169,6 @@
169
169
  background: #e9ecef;
170
170
  padding: 0.2rem 0.4rem;
171
171
  border-radius: 3px;
172
- font-family: 'SFMono-Regular', Consolas, monospace;
173
172
  font-size: 0.875rem;
174
173
  color: #e83e8c;
175
174
  }
@@ -189,7 +188,6 @@
189
188
 
190
189
  .debug-info p {
191
190
  margin: 0.5rem 0;
192
- font-family: 'SFMono-Regular', Consolas, monospace;
193
191
  font-size: 0.875rem;
194
192
  color: #495057;
195
193
  }
@@ -132,7 +132,6 @@
132
132
  background: #e9ecef;
133
133
  padding: 0.2rem 0.4rem;
134
134
  border-radius: 3px;
135
- font-family: 'SFMono-Regular', Consolas, monospace;
136
135
  color: #e83e8c;
137
136
  font-size: 0.875rem;
138
137
  }
@@ -273,7 +272,6 @@
273
272
 
274
273
  .debug-info p {
275
274
  margin: 0.5rem 0;
276
- font-family: 'SFMono-Regular', Consolas, monospace;
277
275
  font-size: 0.875rem;
278
276
  color: #495057;
279
277
  }
@@ -143,7 +143,6 @@
143
143
  cursor: pointer;
144
144
  border: none;
145
145
  background: none;
146
- font: inherit;
147
146
  color: inherit;
148
147
  }
149
148
 
@@ -296,7 +296,6 @@
296
296
  margin: 0 auto;
297
297
  background: var(--background1);
298
298
  color: var(--text1);
299
- font-family: var(--font-stack);
300
299
  }
301
300
 
302
301
  .demo-controls {
@@ -375,7 +374,6 @@
375
374
  background: var(--background1);
376
375
  color: var(--text1);
377
376
  font-size: var(--font-size-small);
378
- font-family: var(--font-stack);
379
377
  }
380
378
 
381
379
  input:focus {
@@ -413,7 +411,7 @@
413
411
  cursor: pointer;
414
412
  font-size: var(--font-size-small);
415
413
  font-weight: var(--font-weight-normal);
416
- font-family: var(--font-stack);
414
+
417
415
  transition: all 0.2s ease;
418
416
  }
419
417
 
@@ -509,7 +507,6 @@
509
507
  background: var(--background3);
510
508
  border: 1px solid var(--border2);
511
509
  border-radius: var(--border-radius);
512
- font-family: monospace;
513
510
  font-size: var(--font-size-tiny);
514
511
  color: var(--text3);
515
512
  }
@@ -519,7 +516,6 @@
519
516
  border: 1px solid var(--border2);
520
517
  padding: var(--padding-tiny);
521
518
  border-radius: var(--border-radius);
522
- font-family: monospace;
523
519
  font-size: var(--font-size-tiny);
524
520
  color: var(--text2);
525
521
  display: block;
@@ -4,6 +4,8 @@ export declare const siteInfo: import("svelte/store").Writable<{
4
4
  shortName: string;
5
5
  isPasswordProtected: boolean;
6
6
  isPrivateStaging: boolean;
7
+ workspaceId: string;
8
+ workspaceSlug: string;
7
9
  domains: Array<{
8
10
  url: string;
9
11
  lastPublished: string | null;
@@ -1,5 +1,3 @@
1
- import { getLogger } from '../../../../utils/logger';
2
- const logger = getLogger('webflow-apps-ui-utils');
3
1
  /**
4
2
  * Processes pasted component data to validate Finsweet components.
5
3
  */
@@ -38,7 +36,7 @@ export const handlePasteXSCP = (e, component) => {
38
36
  });
39
37
  }
40
38
  catch (error) {
41
- logger.error({}, 'handlePasteXSCP', error);
39
+ console.error({}, 'handlePasteXSCP failed with error', error);
42
40
  webflow.notify({
43
41
  type: 'Error',
44
42
  message: 'Invalid! You can only paste valid Finsweet Components.'
@@ -1,5 +1,4 @@
1
1
  export * from './checkIfAppModeIsDesign';
2
2
  export * from './clipboard';
3
3
  export * from './getAllAssets';
4
- export * from './getFinsweetComponentsEnvironment';
5
4
  export * from './insertWithXSCP';
@@ -1,5 +1,4 @@
1
1
  export * from './checkIfAppModeIsDesign';
2
2
  export * from './clipboard';
3
3
  export * from './getAllAssets';
4
- export * from './getFinsweetComponentsEnvironment';
5
4
  export * from './insertWithXSCP';
@@ -234,7 +234,7 @@ See console for the complete diff structure.
234
234
  <style>
235
235
  .demo-container {
236
236
  padding: var(--spacing-24);
237
- font-family: var(--font-stack);
237
+
238
238
  background: var(--background1);
239
239
  color: var(--text1);
240
240
  max-width: 800px;
@@ -261,7 +261,7 @@ See console for the complete diff structure.
261
261
  cursor: pointer;
262
262
  font-size: var(--font-size-small);
263
263
  font-weight: var(--font-weight-normal);
264
- font-family: var(--font-stack);
264
+
265
265
  transition: all 0.2s ease;
266
266
  margin: var(--spacing-8) 0;
267
267
  }
@@ -284,7 +284,6 @@ See console for the complete diff structure.
284
284
  margin-top: var(--spacing-12);
285
285
  white-space: pre-wrap;
286
286
  border-radius: var(--border-radius);
287
- font-family: monospace;
288
287
  color: var(--text2);
289
288
  font-size: var(--font-size-small);
290
289
  }
@@ -1,4 +1,3 @@
1
- export * from './auth';
2
1
  export * from './diff-mapper';
3
2
  export * from './helpers';
4
3
  export * from './color-utils';
@@ -1,4 +1,3 @@
1
- export * from './auth';
2
1
  export * from './diff-mapper';
3
2
  export * from './helpers';
4
3
  export * from './color-utils';
@@ -1,5 +1,3 @@
1
- import { getLogger } from '../../logger';
2
- const logger = getLogger('webflow-apps-ui-utils');
3
1
  /**
4
2
  * Processes pasted component data to validate Finsweet components.
5
3
  */
@@ -38,7 +36,7 @@ export const handlePasteXSCP = (e, component) => {
38
36
  });
39
37
  }
40
38
  catch (error) {
41
- logger.error({}, 'handlePasteXSCP', error);
39
+ console.error({}, 'handlePasteXSCP failed with error', error);
42
40
  webflow.notify({
43
41
  type: 'Error',
44
42
  message: 'Invalid! You can only paste valid Finsweet Components.'
@@ -1,5 +1,4 @@
1
1
  export * from './checkIfAppModeIsDesign';
2
2
  export * from './clipboard';
3
3
  export * from './getAllAssets';
4
- export * from './getFinsweetComponentsEnvironment';
5
4
  export * from './insertWithXSCP';
@@ -1,5 +1,4 @@
1
1
  export * from './checkIfAppModeIsDesign';
2
2
  export * from './clipboard';
3
3
  export * from './getAllAssets';
4
- export * from './getFinsweetComponentsEnvironment';
5
4
  export * from './insertWithXSCP';
@@ -1,8 +1,6 @@
1
1
  /**
2
2
  * Checks if sessionStorage is available in the current environment.
3
3
  */
4
- import { getLogger } from '../logger';
5
- const logger = getLogger('webflow-apps-ui-utils');
6
4
  export const isSessionStorageAvailable = () => {
7
5
  try {
8
6
  // Attempt to access sessionStorage
@@ -12,7 +10,7 @@ export const isSessionStorageAvailable = () => {
12
10
  return true;
13
11
  }
14
12
  catch (e) {
15
- logger.error({}, 'Error! window.sessionStorage is not available your browser setting, please check if you have disabled third party cookies and/or site data.', e);
13
+ console.error({}, 'Error! window.sessionStorage is not available your browser setting, please check if you have disabled third party cookies and/or site data.', e);
16
14
  return false;
17
15
  }
18
16
  };
@@ -4,7 +4,6 @@ export * from './browser-storage';
4
4
  export * from './custom-code';
5
5
  export * from './constants';
6
6
  export * from './helpers';
7
- export * from './logger';
8
7
  export * from './webflow';
9
8
  export * from './webflow-canvas';
10
9
  export type * from '../types';
@@ -4,6 +4,5 @@ export * from './browser-storage';
4
4
  export * from './custom-code';
5
5
  export * from './constants';
6
6
  export * from './helpers';
7
- export * from './logger';
8
7
  export * from './webflow';
9
8
  export * from './webflow-canvas';
@@ -1,5 +1,3 @@
1
- import { getLogger } from '../../logger';
2
- const logger = getLogger('webflow-apps-ui-utils');
3
1
  /**
4
2
  * Gets all custom attributes from a Webflow element.
5
3
  */
@@ -11,7 +9,7 @@ export const getAllWebflowElementAttributes = async (element) => {
11
9
  return null;
12
10
  }
13
11
  catch (error) {
14
- logger.error({}, 'Error in getAllWebflowElementAttributes:', error);
12
+ console.error({}, 'Error in getAllWebflowElementAttributes:', error);
15
13
  return null;
16
14
  }
17
15
  };
@@ -1,5 +1,3 @@
1
- import { getLogger } from '../../logger';
2
- const logger = getLogger('webflow-apps-ui-utils');
3
1
  /**
4
2
  * Gets the value of a custom attribute from a Webflow element.
5
3
  */
@@ -16,7 +14,7 @@ export const getWebflowElementAttribute = async (element, attributeName) => {
16
14
  return null;
17
15
  }
18
16
  catch (error) {
19
- logger.error({}, 'Error in getWebflowElementAttribute:', error);
17
+ console.error({}, 'Error in getWebflowElementAttribute:', error);
20
18
  return null;
21
19
  }
22
20
  };
@@ -1,5 +1,3 @@
1
- import { getLogger } from '../../logger';
2
- const logger = getLogger('webflow-apps-ui-utils');
3
1
  /**
4
2
  * Removes a custom attribute from a Webflow element.
5
3
  */
@@ -28,7 +26,7 @@ export const removeWebflowElementAttribute = async (element, attributeName, noti
28
26
  return;
29
27
  }
30
28
  catch (error) {
31
- logger.error({}, 'Error in removeWebflowElementAttribute:', error);
29
+ console.error('Error in removeWebflowElementAttribute:', error);
32
30
  return null;
33
31
  }
34
32
  };
@@ -1,6 +1,4 @@
1
- import { getLogger } from '../../logger';
2
1
  import { getWebflowElementAttribute } from './getWebflowElementAttribute';
3
- const logger = getLogger('webflow-apps-ui-utils');
4
2
  /**
5
3
  * Sets a custom attribute value on a Webflow element.
6
4
  */
@@ -8,7 +6,7 @@ export const setWebflowElementAttribute = async (element, attributeName, attribu
8
6
  try {
9
7
  const attributeExists = await checkAttribute(element, attributeName, attributeValue);
10
8
  if (attributeExists) {
11
- logger.error({}, `Attribute ${attributeName}="${attributeValue}" already exists on the element. Exiting`);
9
+ console.error(`Attribute ${attributeName}="${attributeValue}" already exists on the element. Exiting`);
12
10
  return;
13
11
  }
14
12
  if (element?.customAttributes) {
@@ -34,7 +32,7 @@ export const setWebflowElementAttribute = async (element, attributeName, attribu
34
32
  return;
35
33
  }
36
34
  catch (error) {
37
- logger.error({}, 'Error in setWebflowElementAttribute:', error);
35
+ console.error('Error in setWebflowElementAttribute:', error);
38
36
  return;
39
37
  }
40
38
  };
@@ -1,7 +1,5 @@
1
1
  import { noop } from '../helpers';
2
- import { getLogger } from '../logger';
3
2
  import { getWebflowElementAttribute } from './attributes';
4
- const logger = getLogger('utils');
5
3
  /**
6
4
  * Exits the current component context.
7
5
  */
@@ -132,7 +130,7 @@ export const findInstanceElement = async ({ targetIndex, instance, component, al
132
130
  return null;
133
131
  }
134
132
  catch (error) {
135
- logger.error({}, 'Error in findInstanceInsideOrOutsideComponent:', error);
133
+ console.error({}, 'Error in findInstanceInsideOrOutsideComponent:', error);
136
134
  throw error;
137
135
  }
138
136
  };
@@ -1,5 +1,3 @@
1
- import { getLogger } from '../logger';
2
- const logger = getLogger('webflow-apps-ui-utils');
3
1
  let pageStagingUrl;
4
2
  /**
5
3
  * Generates a slug for a page or folder.
@@ -80,7 +78,7 @@ export const getAllPages = async (pagesAndFolders, kind) => {
80
78
  return pagesOnly;
81
79
  }
82
80
  catch (error) {
83
- logger.error({}, 'getAllPages failed with an error:', error);
81
+ console.error({}, 'getAllPages failed with an error:', error);
84
82
  return [];
85
83
  }
86
84
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@finsweet/webflow-apps-utils",
3
- "version": "1.0.18",
3
+ "version": "1.0.20",
4
4
  "description": "Shared utilities for Webflow apps",
5
5
  "homepage": "https://github.com/finsweet/webflow-apps-utils",
6
6
  "repository": {
@@ -62,7 +62,7 @@
62
62
  "@types/node": "^22",
63
63
  "@vitest/browser": "3.2.3",
64
64
  "@vitest/coverage-v8": "3.2.3",
65
- "@webflow/designer-extension-typings": "^2.0.12",
65
+ "@webflow/designer-extension-typings": "latest",
66
66
  "eslint": "^9.18.0",
67
67
  "eslint-config-prettier": "^10.0.1",
68
68
  "eslint-plugin-simple-import-sort": "^12.1.1",
@@ -1,40 +0,0 @@
1
- export interface Subscription {
2
- id: string;
3
- product_id: string;
4
- price_id: string;
5
- status: string;
6
- canceled_at: number | null;
7
- current_period_end: number | null;
8
- current_period_start: number | null;
9
- metadata: SubscriptionMetadata;
10
- }
11
- export interface SubscriptionMetadata {
12
- siteId: string;
13
- rewardful: string;
14
- siteUrl: string;
15
- siteHostname: string;
16
- }
17
- export interface FinsweetAuth {
18
- access_token: string;
19
- expires_in: number;
20
- id_token: string;
21
- refresh_token: string;
22
- scope: string;
23
- token_type: string;
24
- expires: number;
25
- user: {
26
- userId: string;
27
- firstname: string;
28
- admin: boolean;
29
- auth0Id: string;
30
- premium: boolean;
31
- role: string;
32
- libraryAccess: ('canFavourite' | 'canManageLibrary')[] | null;
33
- folders: {
34
- favourites: number;
35
- configs: number;
36
- savedComponents: number;
37
- };
38
- };
39
- subscriptions: Subscription[];
40
- }
@@ -1 +0,0 @@
1
- export {};
@@ -1,8 +0,0 @@
1
- /**
2
- * Gets the Finsweet components environment configuration.
3
- */
4
- export declare const getFinsweetComponentsEnvironment: () => {
5
- development: boolean;
6
- coreScript: string;
7
- api: string;
8
- };
@@ -1,66 +0,0 @@
1
- import { COMPONENTS_CORE_SCRIPT, COMPONENTS_CORE_SCRIPT_LOCAL, COMPONENTS_SERVER_DEV_ENDPOINT, COMPONENTS_SERVER_DEV_ENDPOINT_LOCAL, COMPONENTS_SERVER_PROD_ENDPOINT, getLocalStorage } from '../../../utils';
2
- const DEV_MODE_KEY = 'fsComponentsDevMode';
3
- const DEV_MODE_SCRIPT_KEY = 'fsComponentsDevModeScript';
4
- const DEV_MODE_API_KEY = 'fsComponentsDevModeApi';
5
- const URL_DEV_MODE_KEY = 'dev';
6
- const URL_DEV_MODE_SCRIPT_KEY = 'script';
7
- const URL_DEV_MODE_API_KEY = 'api';
8
- let lastLogTime = 0;
9
- const LOG_THROTTLE_MS = 3000;
10
- /**
11
- * Gets a parameter value from the URL search params.
12
- */
13
- const getUrlParam = (key) => {
14
- if (typeof window === 'undefined')
15
- return null;
16
- try {
17
- const urlParams = new URLSearchParams(window.location.search);
18
- return urlParams.get(key);
19
- }
20
- catch (e) {
21
- console.error('Error getting URL parameter:', e);
22
- return null;
23
- }
24
- };
25
- /**
26
- * Throttled console log that only logs once within the throttle interval.
27
- */
28
- const throttledLog = (message, data) => {
29
- const now = Date.now();
30
- if (now - lastLogTime >= LOG_THROTTLE_MS) {
31
- console.log(message, data || '');
32
- lastLogTime = now;
33
- }
34
- };
35
- /**
36
- * Gets the Finsweet components environment configuration.
37
- */
38
- export const getFinsweetComponentsEnvironment = () => {
39
- const devFromUrl = getUrlParam(URL_DEV_MODE_KEY);
40
- const scriptFromUrl = getUrlParam(URL_DEV_MODE_SCRIPT_KEY);
41
- const apiFromUrl = getUrlParam(URL_DEV_MODE_API_KEY);
42
- const dev = devFromUrl !== null ? devFromUrl === 'true' : getLocalStorage(DEV_MODE_KEY) === 'true';
43
- let script = scriptFromUrl || getLocalStorage(DEV_MODE_SCRIPT_KEY) || COMPONENTS_CORE_SCRIPT;
44
- let api = dev
45
- ? apiFromUrl || getLocalStorage(DEV_MODE_API_KEY) || COMPONENTS_SERVER_DEV_ENDPOINT
46
- : COMPONENTS_SERVER_PROD_ENDPOINT;
47
- const isBrowser = typeof window !== 'undefined';
48
- const isLocalhost = isBrowser && window?.location?.hostname?.includes('localhost');
49
- //if localhost then use local scripts
50
- if (isLocalhost) {
51
- script = COMPONENTS_CORE_SCRIPT_LOCAL;
52
- api = COMPONENTS_SERVER_DEV_ENDPOINT_LOCAL;
53
- }
54
- const development = !!dev || isLocalhost;
55
- if (development) {
56
- throttledLog(`\n\nFinsweet Components Environment:
57
- - API: ${api}
58
- - Core script: ${script}
59
- - Development mode: ${development ? 'Yes' : 'No'}\n\n`);
60
- }
61
- return {
62
- development,
63
- coreScript: script,
64
- api
65
- };
66
- };
@@ -1,5 +0,0 @@
1
- import type { FinsweetAuth } from '../../../types';
2
- /**
3
- * Opens a popup window for cross-window authentication with Auth0.
4
- */
5
- export declare const crossWindowLogin: () => Promise<FinsweetAuth>;
@@ -1,52 +0,0 @@
1
- import { AUTH0_AUDIENCE, AUTH0_CLIENT_ID, AUTH0_LOGIN_URL, AUTH0_REDIRECT_URL, AUTH0_SCOPE, PROD_FINSWEEET_ACCOUNTS_ORIGIN } from '../../../utils/constants';
2
- /**
3
- * Opens a popup window for cross-window authentication with Auth0.
4
- */
5
- export const crossWindowLogin = () => {
6
- return new Promise((resolve, reject) => {
7
- const timeout = setTimeout(() => {
8
- window.removeEventListener('message', handleMessage);
9
- reject(new Error('Login timed out'));
10
- }, 30000);
11
- const handleMessage = (e) => {
12
- if (e.origin !== PROD_FINSWEEET_ACCOUNTS_ORIGIN) {
13
- return;
14
- }
15
- clearTimeout(timeout);
16
- window.removeEventListener('message', handleMessage);
17
- if (e.data && e.data.access_token) {
18
- resolve(e.data);
19
- }
20
- else {
21
- reject(new Error('Invalid data received'));
22
- }
23
- };
24
- window.addEventListener('message', handleMessage);
25
- // Open popup
26
- const { outerWidth, outerHeight, screenX, screenY } = window;
27
- const width = 512;
28
- const height = outerHeight / 2;
29
- const left = screenX + (outerWidth - width) / 2;
30
- const top = screenY + (outerHeight - height) / 2;
31
- const finsweetUrl = new URL(AUTH0_LOGIN_URL);
32
- finsweetUrl.searchParams.set('response_type', 'code');
33
- finsweetUrl.searchParams.set('client_id', AUTH0_CLIENT_ID);
34
- finsweetUrl.searchParams.set('redirect_uri', AUTH0_REDIRECT_URL);
35
- finsweetUrl.searchParams.set('scope', AUTH0_SCOPE);
36
- finsweetUrl.searchParams.set('audience', AUTH0_AUDIENCE);
37
- const popup = window.open(finsweetUrl.toString(), 'Finsweet Account', `width=${width},height=${height},left=${left},top=${top}`);
38
- if (!popup) {
39
- clearTimeout(timeout);
40
- reject(new Error('Failed to open popup'));
41
- }
42
- // Check if popup is closed
43
- const checkPopupClosed = setInterval(() => {
44
- if (popup?.closed) {
45
- clearInterval(checkPopupClosed);
46
- clearTimeout(timeout);
47
- window.removeEventListener('message', handleMessage);
48
- reject(new Error('Login popup was closed'));
49
- }
50
- }, 1000);
51
- });
52
- };
@@ -1,45 +0,0 @@
1
- import type { FinsweetAuth } from '../../../types';
2
- /**
3
- * Store for the Finsweet user data.
4
- */
5
- export declare const finsweetUser: import("svelte/store").Writable<FinsweetAuth | null>;
6
- export declare const isLoggingIn: import("svelte/store").Writable<boolean>;
7
- /**
8
- * Fetches user subscriptions from the server.
9
- */
10
- export declare const getSubscriptions: (token: string) => Promise<any>;
11
- /**
12
- * Fetches user data from the authentication server.
13
- */
14
- export declare const getUser: (token: string) => Promise<FinsweetAuth["user"]>;
15
- /**
16
- * Handles user login authentication flow.
17
- */
18
- export declare const handleLogin: () => Promise<void>;
19
- /**
20
- * Handles user logout and cleanup.
21
- */
22
- export declare const handleLogout: () => Promise<void>;
23
- /**
24
- * Checks if the user is logged in by validating stored session.
25
- */
26
- export declare const checkInitialLoginState: () => Promise<void>;
27
- /**
28
- * Sets a cookie with security options.
29
- */
30
- export declare const setCookie: (name: string, value: string, options?: {}) => void;
31
- /**
32
- * Gets a cookie value by name.
33
- */
34
- export declare const getCookie: (name: string) => string | undefined;
35
- /**
36
- * Deletes a cookie by name.
37
- */
38
- export declare const deleteCookie: (name: string, options?: {}) => void;
39
- /**
40
- * Checks if the user has access to a specific feature.
41
- */
42
- export declare const canAccessFeature: (loggedIn: boolean, access: FinsweetAuth["user"]["libraryAccess"] | null | undefined, required: FinsweetAuth["user"]["libraryAccess"]) => {
43
- granted: boolean;
44
- message: string;
45
- };
@@ -1,178 +0,0 @@
1
- /* eslint-disable @typescript-eslint/no-unused-vars */
2
- import Cookies from 'js-cookie';
3
- import { get, writable } from 'svelte/store';
4
- import { getLocalStorage, removeLocalStorage, setLocalStorage } from '../../../utils';
5
- import { FINSWEET_SUBSCRIPTIONS_ENDPOINT, FINSWEET_SUBSCRIPTIONS_ENDPOINT_STAGING } from '../../../utils/constants';
6
- import { getFinsweetComponentsEnvironment } from '../api';
7
- import { crossWindowLogin } from './crossWindowLogin';
8
- /**
9
- * Store for the Finsweet user data.
10
- */
11
- export const finsweetUser = writable();
12
- export const isLoggingIn = writable();
13
- const checkLibraryAccess = (user, subscriptions) => {
14
- // const fullAccess: FinsweetAuth['user']['libraryAccess'] = ['canFavourite', 'canManageLibrary'];
15
- // if (user.admin || user.role === 'agency') {
16
- // return fullAccess;
17
- // }
18
- // // cutoff date timestamp for June 5, 2024 00:00:00 UTC
19
- // const JUNE_5_2025 = 1749081600000;
20
- // if (subscriptions && subscriptions.length > 0) {
21
- // const hasFullAccess = subscriptions.some((subscription) => {
22
- // return (
23
- // subscription.status === 'active' &&
24
- // subscription.current_period_start &&
25
- // // subscription started must be before June 5, 2025 for full access
26
- // subscription.current_period_start * 1000 < JUNE_5_2025
27
- // );
28
- // });
29
- // if (hasFullAccess) return fullAccess;
30
- // }
31
- //TODO: Enable when RBAC is ready
32
- return ['canFavourite'];
33
- };
34
- /**
35
- * Fetches user subscriptions from the server.
36
- */
37
- export const getSubscriptions = async (token) => {
38
- try {
39
- const { development } = getFinsweetComponentsEnvironment();
40
- const endpoint = development
41
- ? FINSWEET_SUBSCRIPTIONS_ENDPOINT_STAGING
42
- : FINSWEET_SUBSCRIPTIONS_ENDPOINT;
43
- const response = await fetch(endpoint, {
44
- headers: {
45
- Authorization: `Bearer ${token}`
46
- }
47
- });
48
- const data = await response.json();
49
- return data;
50
- }
51
- catch (error) {
52
- console.error('Failed to fetch subscriptions', error);
53
- return [];
54
- }
55
- };
56
- /**
57
- * Fetches user data from the authentication server.
58
- */
59
- export const getUser = async (token) => {
60
- const response = await fetch('/auth0/verify', {
61
- headers: {
62
- Authorization: `Bearer ${token}`,
63
- 'Content-Type': 'application/json'
64
- }
65
- });
66
- const data = await response.json();
67
- return data;
68
- };
69
- /**
70
- * Handles user login authentication flow.
71
- */
72
- export const handleLogin = async () => {
73
- if (get(isLoggingIn))
74
- return;
75
- try {
76
- isLoggingIn.set(true);
77
- const response = await crossWindowLogin();
78
- const [user, subscriptions] = await Promise.all([
79
- getUser(response.access_token),
80
- getSubscriptions(response.access_token)
81
- ]);
82
- if (user?.userId) {
83
- const libraryAccess = checkLibraryAccess(user, subscriptions);
84
- finsweetUser.set({ ...response, user: { ...user, libraryAccess }, subscriptions });
85
- setLocalStorage('finsweetComponentsAuth', JSON.stringify(response));
86
- setLocalStorage('finsweetComponentsAuthToken', response.access_token);
87
- //dispatch login event
88
- const event = new CustomEvent('finsweetLoginUpdate', { detail: { user } });
89
- document.dispatchEvent(event);
90
- return;
91
- }
92
- throw new Error('User data is invalid');
93
- }
94
- catch (error) {
95
- const err = error;
96
- console.error('Login failed:', err.message);
97
- finsweetUser.set(null);
98
- webflow.notify({
99
- type: 'Error',
100
- message: 'Login failed. Please try again or contact support.'
101
- });
102
- }
103
- finally {
104
- isLoggingIn.set(false);
105
- }
106
- };
107
- /**
108
- * Handles user logout and cleanup.
109
- */
110
- export const handleLogout = async () => {
111
- removeLocalStorage('finsweetComponentsAuth');
112
- removeLocalStorage('finsweetComponentsAuthToken');
113
- finsweetUser.set(null);
114
- //dispatch login event
115
- const event = new CustomEvent('finsweetLogoutUpdate', { detail: { user: null } });
116
- document.dispatchEvent(event);
117
- await new Promise((resolve) => setTimeout(resolve, 1000));
118
- };
119
- /**
120
- * Checks if the user is logged in by validating stored session.
121
- */
122
- export const checkInitialLoginState = async () => {
123
- const session = getLocalStorage('finsweetComponentsAuth');
124
- if (session) {
125
- const parsedSession = JSON.parse(session);
126
- // Check if the current time is greater than the expiration time
127
- if (Date.now() > parsedSession.expires) {
128
- await handleLogout();
129
- return;
130
- }
131
- const [user, subscriptions] = await Promise.all([
132
- getUser(parsedSession.access_token),
133
- getSubscriptions(parsedSession.access_token)
134
- ]);
135
- if (user?.userId) {
136
- const libraryAccess = checkLibraryAccess(user, subscriptions);
137
- finsweetUser.set({ ...parsedSession, user: { ...user, libraryAccess }, subscriptions });
138
- return;
139
- }
140
- await handleLogout();
141
- return;
142
- }
143
- await handleLogout();
144
- };
145
- /**
146
- * Sets a cookie with security options.
147
- */
148
- export const setCookie = (name, value, options = {}) => {
149
- Cookies.set(name, value, { sameSite: 'None', secure: true, ...options });
150
- };
151
- /**
152
- * Gets a cookie value by name.
153
- */
154
- export const getCookie = (name) => {
155
- return Cookies.get(name);
156
- };
157
- /**
158
- * Deletes a cookie by name.
159
- */
160
- export const deleteCookie = (name, options = {}) => {
161
- Cookies.remove(name, options);
162
- };
163
- /**
164
- * Checks if the user has access to a specific feature.
165
- */
166
- export const canAccessFeature = (loggedIn, access, required) => {
167
- if (!loggedIn) {
168
- return {
169
- granted: false,
170
- message: "This feature is available only when you're logged in."
171
- };
172
- }
173
- if (required && required.every((r) => access?.includes(r))) {
174
- return { granted: true, message: '' };
175
- }
176
- // no message for logged in users, so tooltips are not shown
177
- return { granted: false, message: '' };
178
- };
@@ -1,8 +0,0 @@
1
- /**
2
- * Gets the Finsweet components environment configuration.
3
- */
4
- export declare const getFinsweetComponentsEnvironment: () => {
5
- development: boolean;
6
- coreScript: string;
7
- api: string;
8
- };
@@ -1,67 +0,0 @@
1
- import { getLocalStorage } from '../browser-storage';
2
- import { COMPONENTS_CORE_SCRIPT, COMPONENTS_CORE_SCRIPT_LOCAL, COMPONENTS_SERVER_DEV_ENDPOINT, COMPONENTS_SERVER_DEV_ENDPOINT_LOCAL, COMPONENTS_SERVER_PROD_ENDPOINT } from '../constants';
3
- const DEV_MODE_KEY = 'fsComponentsDevMode';
4
- const DEV_MODE_SCRIPT_KEY = 'fsComponentsDevModeScript';
5
- const DEV_MODE_API_KEY = 'fsComponentsDevModeApi';
6
- const URL_DEV_MODE_KEY = 'dev';
7
- const URL_DEV_MODE_SCRIPT_KEY = 'script';
8
- const URL_DEV_MODE_API_KEY = 'api';
9
- let lastLogTime = 0;
10
- const LOG_THROTTLE_MS = 3000;
11
- /**
12
- * Gets a parameter value from the URL search params.
13
- */
14
- const getUrlParam = (key) => {
15
- if (typeof window === 'undefined')
16
- return null;
17
- try {
18
- const urlParams = new URLSearchParams(window.location.search);
19
- return urlParams.get(key);
20
- }
21
- catch (e) {
22
- console.error('Error getting URL parameter:', e);
23
- return null;
24
- }
25
- };
26
- /**
27
- * Throttled console log that only logs once within the throttle interval.
28
- */
29
- const throttledLog = (message, data) => {
30
- const now = Date.now();
31
- if (now - lastLogTime >= LOG_THROTTLE_MS) {
32
- console.log(message, data || '');
33
- lastLogTime = now;
34
- }
35
- };
36
- /**
37
- * Gets the Finsweet components environment configuration.
38
- */
39
- export const getFinsweetComponentsEnvironment = () => {
40
- const devFromUrl = getUrlParam(URL_DEV_MODE_KEY);
41
- const scriptFromUrl = getUrlParam(URL_DEV_MODE_SCRIPT_KEY);
42
- const apiFromUrl = getUrlParam(URL_DEV_MODE_API_KEY);
43
- const dev = devFromUrl !== null ? devFromUrl === 'true' : getLocalStorage(DEV_MODE_KEY) === 'true';
44
- let script = scriptFromUrl || getLocalStorage(DEV_MODE_SCRIPT_KEY) || COMPONENTS_CORE_SCRIPT;
45
- let api = dev
46
- ? apiFromUrl || getLocalStorage(DEV_MODE_API_KEY) || COMPONENTS_SERVER_DEV_ENDPOINT
47
- : COMPONENTS_SERVER_PROD_ENDPOINT;
48
- const isBrowser = typeof window !== 'undefined';
49
- const isLocalhost = isBrowser && window?.location?.hostname?.includes('localhost');
50
- //if localhost then use local scripts
51
- if (isLocalhost) {
52
- script = COMPONENTS_CORE_SCRIPT_LOCAL;
53
- api = COMPONENTS_SERVER_DEV_ENDPOINT_LOCAL;
54
- }
55
- const development = !!dev || isLocalhost;
56
- if (development) {
57
- throttledLog(`\n\nFinsweet Components Environment:
58
- - API: ${api}
59
- - Core script: ${script}
60
- - Development mode: ${development ? 'Yes' : 'No'}\n\n`);
61
- }
62
- return {
63
- development,
64
- coreScript: script,
65
- api
66
- };
67
- };
@@ -1,16 +0,0 @@
1
- export type LoggerContext = string & Record<never, never>;
2
- export interface LogData {
3
- [key: string]: any;
4
- }
5
- export type LogLevel = 'error' | 'warn' | 'info' | 'log' | 'debug';
6
- export interface Logger {
7
- error: (context: LogData, message: string, ...args: any[]) => void;
8
- warn: (context: LogData, message: string, ...args: any[]) => void;
9
- info: (context: LogData, message: string, ...args: any[]) => void;
10
- log: (context: LogData, message: string, ...args: any[]) => void;
11
- debug: (context: LogData, message: string, ...args: any[]) => void;
12
- }
13
- /**
14
- * Create a logger instance for the given context
15
- */
16
- export declare function getLogger(context: LoggerContext): Logger;
@@ -1,39 +0,0 @@
1
- /* eslint-disable @typescript-eslint/no-explicit-any */
2
- import { getFinsweetComponentsEnvironment } from '../api';
3
- /**
4
- * Create a logger instance for the given context
5
- */
6
- export function getLogger(context) {
7
- const createLogMethod = (level) => {
8
- return (logContext, message, ...args) => {
9
- const { development } = getFinsweetComponentsEnvironment();
10
- if (development) {
11
- const contextPrefix = `[${context}]`;
12
- const consoleMethod = level === 'log' ? 'log' : level;
13
- if (typeof console[consoleMethod] === 'function') {
14
- console[consoleMethod](contextPrefix, message, logContext, ...args);
15
- }
16
- else {
17
- console.log(contextPrefix, message, logContext, ...args);
18
- }
19
- }
20
- // In production, show warnings in console
21
- if (!development && level === 'warn') {
22
- const contextPrefix = `[${context}]`;
23
- console.warn(contextPrefix, message, logContext, ...args);
24
- }
25
- // In production, only send errors to LogRocket
26
- if (!development && level === 'error') {
27
- const contextPrefix = `[${context}]`;
28
- console.error(contextPrefix, message, logContext, ...args);
29
- }
30
- };
31
- };
32
- return {
33
- error: createLogMethod('error'),
34
- warn: createLogMethod('warn'),
35
- info: createLogMethod('info'),
36
- log: createLogMethod('log'),
37
- debug: createLogMethod('debug')
38
- };
39
- }