@finsweet/webflow-apps-utils 1.0.19 → 1.0.21

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 (41) hide show
  1. package/dist/types/index.d.ts +0 -1
  2. package/dist/types/index.js +0 -1
  3. package/dist/ui/components/copy-text/CopyText.svelte +1 -1
  4. package/dist/ui/components/iframe/Iframe.svelte +3 -0
  5. package/dist/ui/components/layout/common/EditModeMessage.svelte +2 -3
  6. package/dist/ui/components/section/Section.svelte +1 -3
  7. package/dist/ui/providers/GlobalProvider.svelte +0 -10
  8. package/dist/ui/router/router.svelte.js +2 -2
  9. package/dist/ui/stores/siteInfo.d.ts +2 -0
  10. package/dist/ui/utils/api/clipboard/handlePaste.js +1 -3
  11. package/dist/ui/utils/api/index.d.ts +0 -1
  12. package/dist/ui/utils/api/index.js +0 -1
  13. package/dist/ui/utils/index.d.ts +0 -1
  14. package/dist/ui/utils/index.js +0 -1
  15. package/dist/utils/api/clipboard/handlePaste.js +1 -3
  16. package/dist/utils/api/index.d.ts +0 -1
  17. package/dist/utils/api/index.js +0 -1
  18. package/dist/utils/browser-storage/sessionStorage.js +1 -3
  19. package/dist/utils/constants.d.ts +0 -65
  20. package/dist/utils/constants.js +0 -83
  21. package/dist/utils/index.d.ts +0 -1
  22. package/dist/utils/index.js +0 -1
  23. package/dist/utils/webflow-canvas/attributes/getAllWebflowElementAttributes.js +1 -3
  24. package/dist/utils/webflow-canvas/attributes/getWebflowElementAttribute.js +1 -3
  25. package/dist/utils/webflow-canvas/attributes/removeWebflowElementAttribute.js +1 -3
  26. package/dist/utils/webflow-canvas/attributes/setWebflowElementAttribute.js +2 -4
  27. package/dist/utils/webflow-canvas/findInstanceElement.js +1 -3
  28. package/dist/utils/webflow-canvas/getAllPages.js +1 -3
  29. package/package.json +2 -2
  30. package/dist/types/auth.d.ts +0 -40
  31. package/dist/types/auth.js +0 -1
  32. package/dist/ui/utils/api/getFinsweetComponentsEnvironment.d.ts +0 -8
  33. package/dist/ui/utils/api/getFinsweetComponentsEnvironment.js +0 -66
  34. package/dist/ui/utils/auth/crossWindowLogin.d.ts +0 -5
  35. package/dist/ui/utils/auth/crossWindowLogin.js +0 -52
  36. package/dist/ui/utils/auth/index.d.ts +0 -45
  37. package/dist/ui/utils/auth/index.js +0 -178
  38. package/dist/utils/api/getFinsweetComponentsEnvironment.d.ts +0 -8
  39. package/dist/utils/api/getFinsweetComponentsEnvironment.js +0 -67
  40. package/dist/utils/logger/index.d.ts +0 -16
  41. 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';
@@ -199,7 +199,7 @@
199
199
  }
200
200
 
201
201
  .copy-button:hover:not(.copy-button--disabled) {
202
- cursor: copy;
202
+ cursor: pointer;
203
203
  }
204
204
 
205
205
  .copy-button:focus-visible {
@@ -61,6 +61,9 @@
61
61
  {src}
62
62
  {width}
63
63
  {height}
64
+ sandbox="allow-scripts allow-same-origin"
65
+ loading="lazy"
66
+ referrerpolicy="no-referrer"
64
67
  class={iframeClasses}
65
68
  onload={handleLoad}
66
69
  {...restProps}
@@ -1,7 +1,6 @@
1
1
  <script lang="ts">
2
2
  import { Pencil, WarningTriangleOutlineIcon } from '../../../icons';
3
3
  import { useAppContext } from '../../../providers';
4
- import { BRAND } from '../../../../utils';
5
4
 
6
5
  import { Notification } from '../../notification';
7
6
 
@@ -26,7 +25,7 @@
26
25
  <div class="edit-mode">
27
26
  <Notification
28
27
  variant="warning"
29
- title="You are in edit mode for {title} {BRAND.COMPONENT}."
28
+ title="You are in edit mode for {title} Component."
30
29
  message={`Make your edits and click on the "Update ${title}" button. You can review and confirm all changes before we proceed with the updates.`}
31
30
  richTextMessage={true}
32
31
  icon={Pencil}
@@ -40,7 +39,7 @@
40
39
  <Notification
41
40
  variant="warning"
42
41
  title="Component instance not found"
43
- message="We have detected {BRAND.COMPONENT} as valid, but we couldn't find the associated configurations. This may be a {BRAND.COMPONENT} from another project. Click the 'Repair' button to fix it."
42
+ message="We have detected Component as valid, but we couldn't find the associated configurations. This may be a Component from another project. Click the 'Repair' button to fix it."
44
43
  icon={WarningTriangleOutlineIcon}
45
44
  showCloseButton={false}
46
45
  />
@@ -4,8 +4,6 @@
4
4
  import type { PartialOptions } from 'overlayscrollbars';
5
5
  import { OverlayScrollbarsComponent } from 'overlayscrollbars-svelte';
6
6
 
7
- import { BRAND } from '../../../utils';
8
-
9
7
  import { WarningCircleOutlineIcon } from '../../icons';
10
8
  import { Tooltip } from '../tooltip';
11
9
  import type { SectionProps } from './types.js';
@@ -128,7 +126,7 @@
128
126
  // Default disabled message
129
127
  let defaultDisabledMessage = $derived(
130
128
  disabledMessage ||
131
- `This option is disabled in edit mode. If you want to change it, please generate a new ${BRAND.COMPONENT}.`
129
+ `This option is disabled in edit mode. If you want to change it, please generate a new Component.`
132
130
  );
133
131
 
134
132
  // OverlayScrollbars options
@@ -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}
@@ -200,7 +200,7 @@ export class Router {
200
200
  pathname: '/',
201
201
  search: '',
202
202
  hash: '',
203
- url: new URL('http://localhost/'),
203
+ url: new URL('https://finsweet.com/'),
204
204
  params: {},
205
205
  query: new URLSearchParams()
206
206
  };
@@ -233,7 +233,7 @@ export class Router {
233
233
  /** Create a URL object from a pathname */
234
234
  #createURL(pathname) {
235
235
  if (!browser)
236
- return new URL('http://localhost/');
236
+ return new URL('https://finsweet.com/');
237
237
  const baseURL = window.location.origin;
238
238
  let fullPath = pathname;
239
239
  // Handle base path
@@ -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';
@@ -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
  };
@@ -1,66 +1 @@
1
- /**
2
- * Wized
3
- */
4
- export declare const WIZED = "wized";
5
- export declare const WIZED_LEGACY = "w-el";
6
- export declare const WIZED_ELEMENTS_SITEMAPS = "wized-elements-sitemaps";
7
- export declare const WIZED_ATTRIBUTES_ENDPOINT = "https://server.wized.com/v2/site/attributes";
8
- export declare const WIZED_ATTRIBUTES_ENDPOINT_STAGING = "https://ss.wized.com/v2/site/attributes";
9
- export declare const WIZED_REVERSE_PROXY_URL = "https://server.wized.com/v2/page/proxy?url=";
10
1
  export declare const FINSWEET_REVERSE_PROXY_URL = "https://api.finsweet.com/cors?url=";
11
- export declare const WIZED_V2_SITE_CONFIGURATION_ENDPOINT = "https://server.wized.com/v2/extensions/configuration";
12
- export declare const WIZED_V2_SITE_CONFIGURATION_ENDPOINT_STAGING = "https://ss.wized.com/v2/extensions/configuration";
13
- export declare const FINSWEET_SUBSCRIPTIONS_ENDPOINT = "https://accounts.finsweet.com/v1/subscriptions";
14
- export declare const FINSWEET_SUBSCRIPTIONS_ENDPOINT_STAGING = "https://test-accounts.finsweet.com/v1/subscriptions";
15
- export declare const WIZED_PROD_SUBSCRIPTIONS_API = "http://accounts.finsweet.com";
16
- export declare const WIZED_DEV_SUBSCRIPTIONS_API = "http://test-accounts.finsweet.com";
17
- export declare const WIZED_PROD_SUBSCRIPTION_PAGE_URL = "https://my.finsweet.com/subscriptions/create?product=finsweet-community";
18
- export declare const WIZED_APP_CONFIGURATOR_STAGING = "https://sa.wized.com/configurator";
19
- export declare const WIZED_APP_CONFIGURATOR_PROD = "https://app.wized.com/configurator";
20
- /**
21
- * Finsweet Components
22
- */
23
- export declare const ACCOUNTS_API_PRODUCTION = "https://accounts.finsweet.com/v1/components/verify?";
24
- export declare const ACCOUNTS_API_DEV = "https://test-accounts.finsweet.com/v1/components/verify?";
25
- export declare const COMPONENTS_SUBSCRIPTIONS_ENDPOINT_DEV = "https://test-my.finsweet.com/subscriptions/create";
26
- export declare const COMPONENTS_SUBSCRIPTIONS_ENDPOINT_PROD = "https://my.finsweet.com/subscriptions/create";
27
- export declare const PROD_FINSWEEET_ACCOUNTS_ORIGIN = "https://accounts.finsweet.com";
28
- export declare const AUTH0_DOMAIN = "finsweet.auth0.com";
29
- export declare const AUTH0_CLIENT_ID = "5xTAnXb3mwUby3YGJRKJpVaNCMWqXtb1";
30
- export declare const AUTH0_REDIRECT_URL = "https://accounts.finsweet.com/v1/auth0/oauth2/fs-components";
31
- export declare const AUTH0_SCOPE = "openid profile email offline_access";
32
- export declare const AUTH0_AUDIENCE = "https://sso.finsweet.com";
33
- export declare const AUTH0_LOGIN_URL = "https://sso.finsweet.com/authorize";
34
- /**
35
- * Finsweet Components Server
36
- */
37
- export declare const COMPONENTS_SERVER_DEV_ENDPOINT = "https://fs-components-api-dev.finsweet.workers.dev/v1/";
38
- export declare const COMPONENTS_SERVER_PROD_ENDPOINT = "https://fs-components-api-prod.finsweet.workers.dev/v1/";
39
- export declare const COMPONENTS_CORE_SCRIPT = "https://cdn.jsdelivr.net/npm/@finsweet/fs-components@2/fs-components.js";
40
- /**
41
- * Finsweet Components Local
42
- */
43
- export declare const COMPONENTS_SERVER_DEV_ENDPOINT_LOCAL = "http://localhost:8787/v1/";
44
- export declare const COMPONENTS_CORE_SCRIPT_LOCAL = "http://localhost:3000/fs-components.js";
45
- /**
46
- * Finsweet Components Brand
47
- */
48
- export declare const BRAND: {
49
- FINSWEET: string;
50
- COMPONENT: string;
51
- COMPONENTS: string;
52
- FULL: {
53
- SINGULAR: string;
54
- PLURAL: string;
55
- };
56
- };
57
- /**
58
- * Webflow App Origins
59
- */
60
- export declare const FINSWEET_COMPONENTS_WEBFLOW_APP_ORIGINS: string[];
61
- export declare const ACCEPTED_WEBFLOW_ELEMENTS_FOR_INSERTION: string[];
62
- /**
63
- * List of domains that are considered staging.
64
- */
65
- export declare const STAGING_DOMAINS: string[];
66
- export declare const FINSWEET_LOGO_URL = "https://cdn.prod.website-files.com/61819aaca0e7ac73f85a2d54/6865d68f194e84da9c6452e5_Components%20White%20Logo.svg";
@@ -1,84 +1 @@
1
- /**
2
- * Wized
3
- */
4
- export const WIZED = 'wized';
5
- export const WIZED_LEGACY = 'w-el';
6
- export const WIZED_ELEMENTS_SITEMAPS = 'wized-elements-sitemaps';
7
- export const WIZED_ATTRIBUTES_ENDPOINT = 'https://server.wized.com/v2/site/attributes';
8
- export const WIZED_ATTRIBUTES_ENDPOINT_STAGING = 'https://ss.wized.com/v2/site/attributes';
9
- export const WIZED_REVERSE_PROXY_URL = 'https://server.wized.com/v2/page/proxy?url=';
10
1
  export const FINSWEET_REVERSE_PROXY_URL = 'https://api.finsweet.com/cors?url=';
11
- export const WIZED_V2_SITE_CONFIGURATION_ENDPOINT = 'https://server.wized.com/v2/extensions/configuration';
12
- export const WIZED_V2_SITE_CONFIGURATION_ENDPOINT_STAGING = 'https://ss.wized.com/v2/extensions/configuration';
13
- export const FINSWEET_SUBSCRIPTIONS_ENDPOINT = 'https://accounts.finsweet.com/v1/subscriptions';
14
- export const FINSWEET_SUBSCRIPTIONS_ENDPOINT_STAGING = 'https://test-accounts.finsweet.com/v1/subscriptions';
15
- export const WIZED_PROD_SUBSCRIPTIONS_API = 'http://accounts.finsweet.com';
16
- export const WIZED_DEV_SUBSCRIPTIONS_API = 'http://test-accounts.finsweet.com';
17
- export const WIZED_PROD_SUBSCRIPTION_PAGE_URL = 'https://my.finsweet.com/subscriptions/create?product=finsweet-community';
18
- export const WIZED_APP_CONFIGURATOR_STAGING = 'https://sa.wized.com/configurator';
19
- export const WIZED_APP_CONFIGURATOR_PROD = 'https://app.wized.com/configurator';
20
- /**
21
- * Finsweet Components
22
- */
23
- export const ACCOUNTS_API_PRODUCTION = 'https://accounts.finsweet.com/v1/components/verify?';
24
- export const ACCOUNTS_API_DEV = 'https://test-accounts.finsweet.com/v1/components/verify?';
25
- export const COMPONENTS_SUBSCRIPTIONS_ENDPOINT_DEV = 'https://test-my.finsweet.com/subscriptions/create';
26
- export const COMPONENTS_SUBSCRIPTIONS_ENDPOINT_PROD = 'https://my.finsweet.com/subscriptions/create';
27
- export const PROD_FINSWEEET_ACCOUNTS_ORIGIN = 'https://accounts.finsweet.com';
28
- export const AUTH0_DOMAIN = 'finsweet.auth0.com';
29
- export const AUTH0_CLIENT_ID = '5xTAnXb3mwUby3YGJRKJpVaNCMWqXtb1';
30
- export const AUTH0_REDIRECT_URL = 'https://accounts.finsweet.com/v1/auth0/oauth2/fs-components';
31
- export const AUTH0_SCOPE = 'openid profile email offline_access';
32
- export const AUTH0_AUDIENCE = 'https://sso.finsweet.com';
33
- export const AUTH0_LOGIN_URL = 'https://sso.finsweet.com/authorize';
34
- /**
35
- * Finsweet Components Server
36
- */
37
- export const COMPONENTS_SERVER_DEV_ENDPOINT = 'https://fs-components-api-dev.finsweet.workers.dev/v1/';
38
- export const COMPONENTS_SERVER_PROD_ENDPOINT = 'https://fs-components-api-prod.finsweet.workers.dev/v1/';
39
- export const COMPONENTS_CORE_SCRIPT = 'https://cdn.jsdelivr.net/npm/@finsweet/fs-components@2/fs-components.js';
40
- /**
41
- * Finsweet Components Local
42
- */
43
- export const COMPONENTS_SERVER_DEV_ENDPOINT_LOCAL = 'http://localhost:8787/v1/';
44
- export const COMPONENTS_CORE_SCRIPT_LOCAL = 'http://localhost:3000/fs-components.js';
45
- /**
46
- * Finsweet Components Brand
47
- */
48
- export const BRAND = {
49
- FINSWEET: 'Finsweet',
50
- COMPONENT: 'Component',
51
- COMPONENTS: 'Components',
52
- FULL: {
53
- SINGULAR: 'Finsweet Component',
54
- PLURAL: 'Finsweet Components'
55
- }
56
- };
57
- /**
58
- * Webflow App Origins
59
- */
60
- export const FINSWEET_COMPONENTS_WEBFLOW_APP_ORIGINS = [
61
- 'http://localhost:1337',
62
- 'https://6544eda5f000985a163a8687.webflow-ext.com',
63
- 'https://64b2e4cfe025c96ef1c8baf4.webflow-ext.com',
64
- 'https://654d8ce9d9b49c7fd929a451.webflow-ext.com'
65
- ];
66
- export const ACCEPTED_WEBFLOW_ELEMENTS_FOR_INSERTION = [
67
- 'Body',
68
- 'Block',
69
- 'DOM',
70
- 'Section',
71
- 'Container',
72
- 'BlockContainer'
73
- ];
74
- /**
75
- * List of domains that are considered staging.
76
- */
77
- export const STAGING_DOMAINS = [
78
- 'webflow.io',
79
- 'webflow-ext.com',
80
- 'localhost',
81
- 'canvas.webflow.com',
82
- 'server.wized.com'
83
- ];
84
- export const FINSWEET_LOGO_URL = 'https://cdn.prod.website-files.com/61819aaca0e7ac73f85a2d54/6865d68f194e84da9c6452e5_Components%20White%20Logo.svg';
@@ -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.19",
3
+ "version": "1.0.21",
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
- }