@finsweet/webflow-apps-utils 1.0.19 → 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.
- package/dist/types/index.d.ts +0 -1
- package/dist/types/index.js +0 -1
- package/dist/ui/providers/GlobalProvider.svelte +0 -10
- package/dist/ui/stores/siteInfo.d.ts +2 -0
- package/dist/ui/utils/api/clipboard/handlePaste.js +1 -3
- package/dist/ui/utils/api/index.d.ts +0 -1
- package/dist/ui/utils/api/index.js +0 -1
- package/dist/ui/utils/index.d.ts +0 -1
- package/dist/ui/utils/index.js +0 -1
- package/dist/utils/api/clipboard/handlePaste.js +1 -3
- package/dist/utils/api/index.d.ts +0 -1
- package/dist/utils/api/index.js +0 -1
- package/dist/utils/browser-storage/sessionStorage.js +1 -3
- package/dist/utils/index.d.ts +0 -1
- package/dist/utils/index.js +0 -1
- package/dist/utils/webflow-canvas/attributes/getAllWebflowElementAttributes.js +1 -3
- package/dist/utils/webflow-canvas/attributes/getWebflowElementAttribute.js +1 -3
- package/dist/utils/webflow-canvas/attributes/removeWebflowElementAttribute.js +1 -3
- package/dist/utils/webflow-canvas/attributes/setWebflowElementAttribute.js +2 -4
- package/dist/utils/webflow-canvas/findInstanceElement.js +1 -3
- package/dist/utils/webflow-canvas/getAllPages.js +1 -3
- package/package.json +2 -2
- package/dist/types/auth.d.ts +0 -40
- package/dist/types/auth.js +0 -1
- package/dist/ui/utils/api/getFinsweetComponentsEnvironment.d.ts +0 -8
- package/dist/ui/utils/api/getFinsweetComponentsEnvironment.js +0 -66
- package/dist/ui/utils/auth/crossWindowLogin.d.ts +0 -5
- package/dist/ui/utils/auth/crossWindowLogin.js +0 -52
- package/dist/ui/utils/auth/index.d.ts +0 -45
- package/dist/ui/utils/auth/index.js +0 -178
- package/dist/utils/api/getFinsweetComponentsEnvironment.d.ts +0 -8
- package/dist/utils/api/getFinsweetComponentsEnvironment.js +0 -67
- package/dist/utils/logger/index.d.ts +0 -16
- package/dist/utils/logger/index.js +0 -39
package/dist/types/index.d.ts
CHANGED
package/dist/types/index.js
CHANGED
|
@@ -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}
|
|
@@ -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
|
-
|
|
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.'
|
package/dist/ui/utils/index.d.ts
CHANGED
package/dist/ui/utils/index.js
CHANGED
|
@@ -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
|
-
|
|
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.'
|
package/dist/utils/api/index.js
CHANGED
|
@@ -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
|
-
|
|
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
|
};
|
package/dist/utils/index.d.ts
CHANGED
package/dist/utils/index.js
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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.
|
|
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": "
|
|
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",
|
package/dist/types/auth.d.ts
DELETED
|
@@ -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
|
-
}
|
package/dist/types/auth.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -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,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,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
|
-
}
|