@n8n/stores 2.32.2 → 2.34.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cloudPlan.store.cjs +7 -0
- package/dist/cloudPlan.store.d.cts +534 -0
- package/dist/cloudPlan.store.d.mts +534 -0
- package/dist/cloudPlan.store.mjs +7 -0
- package/dist/cloudPlan2.store.cjs +247 -0
- package/dist/cloudPlan2.store.cjs.map +1 -0
- package/dist/cloudPlan2.store.mjs +242 -0
- package/dist/cloudPlan2.store.mjs.map +1 -0
- package/dist/composables/useBasePageRedirectionHelper.cjs +87 -0
- package/dist/composables/useBasePageRedirectionHelper.cjs.map +1 -0
- package/dist/composables/useBasePageRedirectionHelper.d.cts +16 -0
- package/dist/composables/useBasePageRedirectionHelper.d.mts +16 -0
- package/dist/composables/useBasePageRedirectionHelper.mjs +87 -0
- package/dist/composables/useBasePageRedirectionHelper.mjs.map +1 -0
- package/dist/constants2.cjs +2 -0
- package/dist/constants2.cjs.map +1 -1
- package/dist/constants2.d.cts +2 -0
- package/dist/constants2.d.mts +2 -0
- package/dist/constants2.mjs +2 -0
- package/dist/constants2.mjs.map +1 -1
- package/dist/invitation.api.cjs +4 -0
- package/dist/invitation.api.d.cts +2 -0
- package/dist/invitation.api.d.mts +2 -0
- package/dist/invitation.api.mjs +3 -0
- package/dist/invitation2.api.cjs +26 -0
- package/dist/invitation2.api.cjs.map +1 -0
- package/dist/invitation2.api.d.cts +30 -0
- package/dist/invitation2.api.d.mts +30 -0
- package/dist/invitation2.api.mjs +14 -0
- package/dist/invitation2.api.mjs.map +1 -0
- package/dist/modalOpeners.cjs +0 -0
- package/dist/modalOpeners.d.cts +2 -0
- package/dist/modalOpeners.d.mts +2 -0
- package/dist/modalOpeners.mjs +1 -0
- package/dist/modalOpeners2.d.cts +11 -0
- package/dist/modalOpeners2.d.mts +11 -0
- package/dist/notifications.store.cjs +27 -0
- package/dist/notifications.store.cjs.map +1 -0
- package/dist/notifications.store.d.cts +15 -0
- package/dist/notifications.store.d.mts +15 -0
- package/dist/notifications.store.mjs +26 -0
- package/dist/notifications.store.mjs.map +1 -0
- package/dist/onboarding.api.cjs +3 -0
- package/dist/onboarding.api.d.cts +7 -0
- package/dist/onboarding.api.d.mts +7 -0
- package/dist/onboarding.api.mjs +3 -0
- package/dist/onboarding2.api.cjs +24 -0
- package/dist/onboarding2.api.cjs.map +1 -0
- package/dist/onboarding2.api.mjs +18 -0
- package/dist/onboarding2.api.mjs.map +1 -0
- package/dist/pageRedirection.d.cts +6 -0
- package/dist/pageRedirection.d.mts +6 -0
- package/dist/rbac.store.cjs +2 -1
- package/dist/rbac.store.cjs.map +1 -1
- package/dist/rbac.store.d.cts +123 -123
- package/dist/rbac.store.d.mts +124 -124
- package/dist/rbac.store.mjs +1 -1
- package/dist/roles.store.cjs +88 -0
- package/dist/roles.store.cjs.map +1 -0
- package/dist/roles.store.d.cts +637 -0
- package/dist/roles.store.d.mts +637 -0
- package/dist/roles.store.mjs +87 -0
- package/dist/roles.store.mjs.map +1 -0
- package/dist/settings.store.cjs +6 -0
- package/dist/settings.store.d.cts +3801 -0
- package/dist/settings.store.d.mts +3801 -0
- package/dist/settings.store.mjs +6 -0
- package/dist/settings2.store.cjs +387 -0
- package/dist/settings2.store.cjs.map +1 -0
- package/dist/settings2.store.mjs +348 -0
- package/dist/settings2.store.mjs.map +1 -0
- package/dist/types/pageRedirection.cjs +0 -0
- package/dist/types/pageRedirection.d.cts +2 -0
- package/dist/types/pageRedirection.d.mts +2 -0
- package/dist/types/pageRedirection.mjs +1 -0
- package/dist/useAgentRequestStore.cjs +1 -0
- package/dist/useAgentRequestStore.cjs.map +1 -1
- package/dist/useAgentRequestStore.d.cts +1 -1
- package/dist/useAgentRequestStore.d.mts +6 -6
- package/dist/useRootStore.cjs +4 -182
- package/dist/useRootStore.d.cts +73 -73
- package/dist/useRootStore.d.mts +73 -73
- package/dist/useRootStore.mjs +4 -182
- package/dist/useRootStore2.cjs +189 -0
- package/dist/useRootStore2.cjs.map +1 -0
- package/dist/useRootStore2.mjs +183 -0
- package/dist/useRootStore2.mjs.map +1 -0
- package/dist/users.store.cjs +9 -0
- package/dist/users.store.d.cts +552 -0
- package/dist/users.store.d.mts +552 -0
- package/dist/users.store.mjs +9 -0
- package/dist/users2.store.cjs +362 -0
- package/dist/users2.store.cjs.map +1 -0
- package/dist/users2.store.mjs +353 -0
- package/dist/users2.store.mjs.map +1 -0
- package/dist/versions.store.cjs +11 -0
- package/dist/versions.store.d.cts +384 -0
- package/dist/versions.store.d.mts +384 -0
- package/dist/versions.store.mjs +10 -0
- package/dist/versions2.store.cjs +230 -0
- package/dist/versions2.store.cjs.map +1 -0
- package/dist/versions2.store.mjs +218 -0
- package/dist/versions2.store.mjs.map +1 -0
- package/package.json +13 -6
- package/dist/useRootStore.cjs.map +0 -1
- package/dist/useRootStore.mjs.map +0 -1
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
const require_settings_store = require('./settings2.store.cjs');
|
|
2
|
+
const require_constants = require('./constants2.cjs');
|
|
3
|
+
const require_useRootStore = require('./useRootStore2.cjs');
|
|
4
|
+
let __n8n_rest_api_client_api_cloudPlans = require("@n8n/rest-api-client/api/cloudPlans");
|
|
5
|
+
__n8n_rest_api_client_api_cloudPlans = require_settings_store.__toESM(__n8n_rest_api_client_api_cloudPlans);
|
|
6
|
+
let pinia = require("pinia");
|
|
7
|
+
let vue = require("vue");
|
|
8
|
+
|
|
9
|
+
//#region src/cloudPlan.store.ts
|
|
10
|
+
const CLOUD_TRIAL_CHECK_INTERVAL = 5e3;
|
|
11
|
+
const DEFAULT_STATE = {
|
|
12
|
+
initialized: false,
|
|
13
|
+
data: null,
|
|
14
|
+
usage: null,
|
|
15
|
+
loadingPlan: false
|
|
16
|
+
};
|
|
17
|
+
const useCloudPlanStore = (0, pinia.defineStore)(require_constants.STORES.CLOUD_PLAN, () => {
|
|
18
|
+
const rootStore = require_useRootStore.useRootStore();
|
|
19
|
+
const settingsStore = require_settings_store.useSettingsStore();
|
|
20
|
+
const state = (0, vue.reactive)(DEFAULT_STATE);
|
|
21
|
+
const currentUserCloudInfo = (0, vue.ref)(null);
|
|
22
|
+
const now = (0, vue.ref)(Date.now());
|
|
23
|
+
const _isInstanceOwner = (0, vue.ref)(() => false);
|
|
24
|
+
const setIsInstanceOwner = (getter) => {
|
|
25
|
+
_isInstanceOwner.value = getter;
|
|
26
|
+
};
|
|
27
|
+
const reset = () => {
|
|
28
|
+
currentUserCloudInfo.value = null;
|
|
29
|
+
state.data = null;
|
|
30
|
+
state.usage = null;
|
|
31
|
+
};
|
|
32
|
+
const userIsTrialing = (0, vue.computed)(() => state.data?.userIsTrialing ?? false);
|
|
33
|
+
const bannerConfig = (0, vue.computed)(() => state.data?.bannerConfig);
|
|
34
|
+
const bannerForceShow = (0, vue.computed)(() => bannerConfig.value?.forceShow === true);
|
|
35
|
+
const isBannerDismissed = (0, vue.computed)(() => {
|
|
36
|
+
const dismissed = settingsStore.permanentlyDismissedBanners;
|
|
37
|
+
return dismissed.includes("TRIAL") || dismissed.includes("TRIAL_OVER");
|
|
38
|
+
});
|
|
39
|
+
const shouldShowBanner = (0, vue.computed)(() => {
|
|
40
|
+
if (!bannerConfig.value) return false;
|
|
41
|
+
if (!bannerDismissible.value) return true;
|
|
42
|
+
return bannerForceShow.value || !isBannerDismissed.value;
|
|
43
|
+
});
|
|
44
|
+
const bannerTimeLeft = (0, vue.computed)(() => ({
|
|
45
|
+
show: !!bannerConfig.value?.timeLeft,
|
|
46
|
+
text: bannerConfig.value?.timeLeft?.text
|
|
47
|
+
}));
|
|
48
|
+
const showExecutions = (0, vue.computed)(() => bannerConfig.value?.showExecutions === true);
|
|
49
|
+
const bannerCta = (0, vue.computed)(() => ({
|
|
50
|
+
text: bannerConfig.value?.cta?.text ?? "Upgrade Now",
|
|
51
|
+
icon: bannerConfig.value?.cta?.icon ?? "zap",
|
|
52
|
+
size: bannerConfig.value?.cta?.size ?? "small",
|
|
53
|
+
style: bannerConfig.value?.cta?.style ?? "success",
|
|
54
|
+
variant: bannerConfig.value?.cta?.variant,
|
|
55
|
+
href: bannerConfig.value?.cta?.href
|
|
56
|
+
}));
|
|
57
|
+
const bannerIcon = (0, vue.computed)(() => bannerConfig.value?.icon);
|
|
58
|
+
const bannerDismissible = (0, vue.computed)(() => bannerConfig.value?.dismissible ?? true);
|
|
59
|
+
const currentPlanData = (0, vue.computed)(() => state.data);
|
|
60
|
+
const currentUsageData = (0, vue.computed)(() => state.usage);
|
|
61
|
+
const selectedApps = (0, vue.computed)(() => currentUserCloudInfo.value?.selectedApps);
|
|
62
|
+
const codingSkill = (0, vue.computed)(() => {
|
|
63
|
+
const information = currentUserCloudInfo.value?.information;
|
|
64
|
+
if (!information) return 0;
|
|
65
|
+
if (!("which_of_these_do_you_feel_comfortable_doing" in information && information.which_of_these_do_you_feel_comfortable_doing && Array.isArray(information.which_of_these_do_you_feel_comfortable_doing))) return 0;
|
|
66
|
+
return information.which_of_these_do_you_feel_comfortable_doing.length;
|
|
67
|
+
});
|
|
68
|
+
const trialExpired = (0, vue.computed)(() => state.data?.userIsTrialing && Date.now() >= new Date(state.data?.expirationDate).getTime());
|
|
69
|
+
const allExecutionsUsed = (0, vue.computed)(() => {
|
|
70
|
+
if (!state.usage?.executions || !state.data?.monthlyExecutionsLimit) return false;
|
|
71
|
+
return state.usage?.executions >= state.data?.monthlyExecutionsLimit;
|
|
72
|
+
});
|
|
73
|
+
const hasCloudPlan = (0, vue.computed)(() => {
|
|
74
|
+
const { n8nMetadata } = settingsStore.settings;
|
|
75
|
+
const isCloud = Boolean(settingsStore.isCloudDeployment);
|
|
76
|
+
return _isInstanceOwner.value() && isCloud && !!n8nMetadata?.userId;
|
|
77
|
+
});
|
|
78
|
+
const getUserCloudAccount = async () => {
|
|
79
|
+
if (!hasCloudPlan.value) throw new Error("User does not have a cloud plan");
|
|
80
|
+
let cloudUser = null;
|
|
81
|
+
try {
|
|
82
|
+
cloudUser = await __n8n_rest_api_client_api_cloudPlans.getCloudUserInfo(rootStore.restApiContext);
|
|
83
|
+
currentUserCloudInfo.value = cloudUser;
|
|
84
|
+
} catch (error) {
|
|
85
|
+
throw new Error(error.message);
|
|
86
|
+
}
|
|
87
|
+
};
|
|
88
|
+
const getAutoLoginCode = async () => {
|
|
89
|
+
return await (0, __n8n_rest_api_client_api_cloudPlans.getAdminPanelLoginCode)(rootStore.restApiContext);
|
|
90
|
+
};
|
|
91
|
+
const getOwnerCurrentPlan = async () => {
|
|
92
|
+
if (!hasCloudPlan.value) throw new Error("User does not have a cloud plan");
|
|
93
|
+
state.loadingPlan = true;
|
|
94
|
+
let plan;
|
|
95
|
+
try {
|
|
96
|
+
plan = await (0, __n8n_rest_api_client_api_cloudPlans.getCurrentPlan)(rootStore.restApiContext);
|
|
97
|
+
state.data = plan;
|
|
98
|
+
state.loadingPlan = false;
|
|
99
|
+
} catch (error) {
|
|
100
|
+
state.loadingPlan = false;
|
|
101
|
+
throw new Error(error);
|
|
102
|
+
}
|
|
103
|
+
return plan;
|
|
104
|
+
};
|
|
105
|
+
const getInstanceCurrentUsage = async () => {
|
|
106
|
+
const usage = await (0, __n8n_rest_api_client_api_cloudPlans.getCurrentUsage)({
|
|
107
|
+
baseUrl: rootStore.baseUrl,
|
|
108
|
+
pushRef: ""
|
|
109
|
+
});
|
|
110
|
+
state.usage = usage;
|
|
111
|
+
return usage;
|
|
112
|
+
};
|
|
113
|
+
const usageLeft = (0, vue.computed)(() => {
|
|
114
|
+
if (!state.data || !state.usage) return {
|
|
115
|
+
workflowsLeft: -1,
|
|
116
|
+
executionsLeft: -1
|
|
117
|
+
};
|
|
118
|
+
return {
|
|
119
|
+
workflowsLeft: state.data.activeWorkflowsLimit - state.usage.activeWorkflows,
|
|
120
|
+
executionsLeft: state.data.monthlyExecutionsLimit - state.usage.executions
|
|
121
|
+
};
|
|
122
|
+
});
|
|
123
|
+
const trialDaysLeft = (0, vue.computed)(() => {
|
|
124
|
+
if (!state.data?.expirationDate) return -1;
|
|
125
|
+
const differenceInMs = (/* @__PURE__ */ new Date()).valueOf() - new Date(state.data.expirationDate).valueOf();
|
|
126
|
+
const differenceInDays = Math.floor(differenceInMs / (1e3 * 60 * 60 * 24));
|
|
127
|
+
return Math.ceil(differenceInDays);
|
|
128
|
+
});
|
|
129
|
+
const trialTimeLeft = (0, vue.computed)(() => {
|
|
130
|
+
if (!state.data?.expirationDate) return {
|
|
131
|
+
count: 0,
|
|
132
|
+
unit: "days"
|
|
133
|
+
};
|
|
134
|
+
const msLeft = new Date(state.data.expirationDate).valueOf() - now.value;
|
|
135
|
+
if (msLeft <= 0) return {
|
|
136
|
+
count: 0,
|
|
137
|
+
unit: "minutes"
|
|
138
|
+
};
|
|
139
|
+
const hours = msLeft / (1e3 * 60 * 60);
|
|
140
|
+
if (hours < 1) return {
|
|
141
|
+
count: Math.ceil(msLeft / (1e3 * 60)),
|
|
142
|
+
unit: "minutes"
|
|
143
|
+
};
|
|
144
|
+
else if (hours < 24) return {
|
|
145
|
+
count: Math.ceil(hours),
|
|
146
|
+
unit: "hours"
|
|
147
|
+
};
|
|
148
|
+
else return {
|
|
149
|
+
count: Math.ceil(hours / 24),
|
|
150
|
+
unit: "days"
|
|
151
|
+
};
|
|
152
|
+
});
|
|
153
|
+
const startPollingInstanceUsageData = () => {
|
|
154
|
+
const interval = setInterval(async () => {
|
|
155
|
+
now.value = Date.now();
|
|
156
|
+
try {
|
|
157
|
+
await getInstanceCurrentUsage();
|
|
158
|
+
if (trialExpired.value || allExecutionsUsed.value) {
|
|
159
|
+
clearInterval(interval);
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
} catch {}
|
|
163
|
+
}, CLOUD_TRIAL_CHECK_INTERVAL);
|
|
164
|
+
};
|
|
165
|
+
const checkForCloudPlanData = async () => {
|
|
166
|
+
try {
|
|
167
|
+
await getOwnerCurrentPlan();
|
|
168
|
+
if (!userIsTrialing.value) return;
|
|
169
|
+
await getInstanceCurrentUsage();
|
|
170
|
+
startPollingInstanceUsageData();
|
|
171
|
+
} catch (e) {
|
|
172
|
+
throw new Error(e.message);
|
|
173
|
+
}
|
|
174
|
+
};
|
|
175
|
+
const fetchUserCloudAccount = async () => {
|
|
176
|
+
try {
|
|
177
|
+
await getUserCloudAccount();
|
|
178
|
+
} catch (e) {
|
|
179
|
+
throw new Error(e.message);
|
|
180
|
+
}
|
|
181
|
+
};
|
|
182
|
+
const initialize = async () => {
|
|
183
|
+
if (state.initialized) return;
|
|
184
|
+
try {
|
|
185
|
+
await checkForCloudPlanData();
|
|
186
|
+
} catch (error) {
|
|
187
|
+
console.warn("Error checking for cloud plan data:", error);
|
|
188
|
+
}
|
|
189
|
+
try {
|
|
190
|
+
await fetchUserCloudAccount();
|
|
191
|
+
} catch (error) {
|
|
192
|
+
console.warn("Error fetching user cloud account:", error);
|
|
193
|
+
}
|
|
194
|
+
state.initialized = true;
|
|
195
|
+
};
|
|
196
|
+
const generateCloudDashboardAutoLoginLink = async (data) => {
|
|
197
|
+
const searchParams = new URLSearchParams();
|
|
198
|
+
const adminPanelHost = new URL(window.location.href).host.split(".").slice(1).join(".");
|
|
199
|
+
const { code } = await getAutoLoginCode();
|
|
200
|
+
const linkUrl = `https://${adminPanelHost}/login`;
|
|
201
|
+
searchParams.set("code", code);
|
|
202
|
+
searchParams.set("returnPath", data.redirectionPath);
|
|
203
|
+
return `${linkUrl}?${searchParams.toString()}`;
|
|
204
|
+
};
|
|
205
|
+
return {
|
|
206
|
+
state,
|
|
207
|
+
usageLeft,
|
|
208
|
+
trialDaysLeft,
|
|
209
|
+
trialTimeLeft,
|
|
210
|
+
userIsTrialing,
|
|
211
|
+
currentPlanData,
|
|
212
|
+
currentUsageData,
|
|
213
|
+
trialExpired,
|
|
214
|
+
allExecutionsUsed,
|
|
215
|
+
hasCloudPlan,
|
|
216
|
+
currentUserCloudInfo,
|
|
217
|
+
generateCloudDashboardAutoLoginLink,
|
|
218
|
+
initialize,
|
|
219
|
+
getOwnerCurrentPlan,
|
|
220
|
+
getInstanceCurrentUsage,
|
|
221
|
+
reset,
|
|
222
|
+
checkForCloudPlanData,
|
|
223
|
+
fetchUserCloudAccount,
|
|
224
|
+
getAutoLoginCode,
|
|
225
|
+
selectedApps,
|
|
226
|
+
codingSkill,
|
|
227
|
+
shouldShowBanner,
|
|
228
|
+
bannerConfig,
|
|
229
|
+
bannerForceShow,
|
|
230
|
+
isBannerDismissed,
|
|
231
|
+
bannerTimeLeft,
|
|
232
|
+
showExecutions,
|
|
233
|
+
bannerCta,
|
|
234
|
+
bannerIcon,
|
|
235
|
+
bannerDismissible,
|
|
236
|
+
setIsInstanceOwner
|
|
237
|
+
};
|
|
238
|
+
});
|
|
239
|
+
|
|
240
|
+
//#endregion
|
|
241
|
+
Object.defineProperty(exports, 'useCloudPlanStore', {
|
|
242
|
+
enumerable: true,
|
|
243
|
+
get: function () {
|
|
244
|
+
return useCloudPlanStore;
|
|
245
|
+
}
|
|
246
|
+
});
|
|
247
|
+
//# sourceMappingURL=cloudPlan2.store.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cloudPlan2.store.cjs","names":["DEFAULT_STATE: CloudPlanState","STORES","useRootStore","useSettingsStore","cloudUser: Cloud.UserAccount | null","cloudApi"],"sources":["../src/cloudPlan.store.ts"],"sourcesContent":["import type { Cloud, InstanceUsage } from '@n8n/rest-api-client/api/cloudPlans';\nimport {\n\tgetAdminPanelLoginCode,\n\tgetCurrentPlan,\n\tgetCurrentUsage,\n} from '@n8n/rest-api-client/api/cloudPlans';\nimport * as cloudApi from '@n8n/rest-api-client/api/cloudPlans';\nimport { defineStore } from 'pinia';\nimport { computed, reactive, ref } from 'vue';\n\nimport { STORES } from './constants';\nimport { useSettingsStore } from './settings.store';\nimport { useRootStore } from './useRootStore';\n\nexport interface CloudPlanState {\n\tinitialized: boolean;\n\tdata: Cloud.PlanData | null;\n\tusage: InstanceUsage | null;\n\tloadingPlan: boolean;\n}\n\nconst CLOUD_TRIAL_CHECK_INTERVAL = 5000;\n\nconst DEFAULT_STATE: CloudPlanState = {\n\tinitialized: false,\n\tdata: null,\n\tusage: null,\n\tloadingPlan: false,\n};\n\nexport const useCloudPlanStore = defineStore(STORES.CLOUD_PLAN, () => {\n\tconst rootStore = useRootStore();\n\tconst settingsStore = useSettingsStore();\n\n\tconst state = reactive<CloudPlanState>(DEFAULT_STATE);\n\tconst currentUserCloudInfo = ref<Cloud.UserAccount | null>(null);\n\n\tconst now = ref<number>(Date.now());\n\n\t// Injected by the caller (e.g. editor-ui shim) — returns whether the\n\t// current user is the instance owner. Defaults to `false` so the store\n\t// is safe to use before injection.\n\tconst _isInstanceOwner = ref<() => boolean>(() => false);\n\n\tconst setIsInstanceOwner = (getter: () => boolean) => {\n\t\t_isInstanceOwner.value = getter;\n\t};\n\n\tconst reset = () => {\n\t\tcurrentUserCloudInfo.value = null;\n\t\tstate.data = null;\n\t\tstate.usage = null;\n\t};\n\n\tconst userIsTrialing = computed(() => state.data?.userIsTrialing ?? false);\n\n\tconst bannerConfig = computed(() => state.data?.bannerConfig);\n\n\t// Whether forceShow is enabled - shows banner even if previously dismissed\n\tconst bannerForceShow = computed(() => bannerConfig.value?.forceShow === true);\n\n\t// Check if TRIAL banner was previously dismissed\n\tconst isBannerDismissed = computed(() => {\n\t\tconst dismissed = settingsStore.permanentlyDismissedBanners as string[];\n\t\treturn dismissed.includes('TRIAL') || dismissed.includes('TRIAL_OVER');\n\t});\n\n\t// Whether to show trial banner:\n\t// - bannerConfig must exist (backend wants to show banner)\n\t// - If not dismissible, always show (regardless of previous dismissal)\n\t// - If dismissible: show if forceShow is true OR banner was not previously dismissed\n\tconst shouldShowBanner = computed(() => {\n\t\tif (!bannerConfig.value) return false;\n\t\tif (!bannerDismissible.value) return true;\n\t\treturn bannerForceShow.value || !isBannerDismissed.value;\n\t});\n\n\t// If timeLeft is set, show it; otherwise hide\n\tconst bannerTimeLeft = computed(() => ({\n\t\tshow: !!bannerConfig.value?.timeLeft,\n\t\ttext: bannerConfig.value?.timeLeft?.text,\n\t}));\n\n\t// If showExecutions is true, show the executions section\n\tconst showExecutions = computed(() => bannerConfig.value?.showExecutions === true);\n\n\tconst bannerCta = computed(() => ({\n\t\ttext: bannerConfig.value?.cta?.text ?? 'Upgrade Now',\n\t\ticon: bannerConfig.value?.cta?.icon ?? 'zap',\n\t\tsize: bannerConfig.value?.cta?.size ?? 'small',\n\t\tstyle: bannerConfig.value?.cta?.style ?? 'success',\n\t\tvariant: bannerConfig.value?.cta?.variant,\n\t\thref: bannerConfig.value?.cta?.href,\n\t}));\n\n\t// Banner icon (left side info icon) - undefined means no icon\n\tconst bannerIcon = computed(() => bannerConfig.value?.icon);\n\n\tconst bannerDismissible = computed(() => bannerConfig.value?.dismissible ?? true);\n\n\tconst currentPlanData = computed(() => state.data);\n\n\tconst currentUsageData = computed(() => state.usage);\n\n\tconst selectedApps = computed(() => currentUserCloudInfo.value?.selectedApps);\n\tconst codingSkill = computed(() => {\n\t\tconst information = currentUserCloudInfo.value?.information;\n\t\tif (!information) {\n\t\t\treturn 0;\n\t\t}\n\n\t\tif (\n\t\t\t!(\n\t\t\t\t'which_of_these_do_you_feel_comfortable_doing' in information &&\n\t\t\t\tinformation.which_of_these_do_you_feel_comfortable_doing &&\n\t\t\t\tArray.isArray(information.which_of_these_do_you_feel_comfortable_doing)\n\t\t\t)\n\t\t) {\n\t\t\treturn 0;\n\t\t}\n\n\t\treturn information.which_of_these_do_you_feel_comfortable_doing.length;\n\t});\n\n\tconst trialExpired = computed(\n\t\t() =>\n\t\t\tstate.data?.userIsTrialing && Date.now() >= new Date(state.data?.expirationDate).getTime(),\n\t);\n\n\tconst allExecutionsUsed = computed(() => {\n\t\tif (!state.usage?.executions || !state.data?.monthlyExecutionsLimit) return false;\n\t\treturn state.usage?.executions >= state.data?.monthlyExecutionsLimit;\n\t});\n\n\tconst hasCloudPlan = computed<boolean>(() => {\n\t\tconst { n8nMetadata } = settingsStore.settings as { n8nMetadata?: { userId?: string } };\n\t\tconst isCloud = Boolean(settingsStore.isCloudDeployment);\n\t\treturn _isInstanceOwner.value() && isCloud && !!n8nMetadata?.userId;\n\t});\n\n\tconst getUserCloudAccount = async () => {\n\t\tif (!hasCloudPlan.value) throw new Error('User does not have a cloud plan');\n\t\tlet cloudUser: Cloud.UserAccount | null = null;\n\t\ttry {\n\t\t\tcloudUser = await cloudApi.getCloudUserInfo(rootStore.restApiContext);\n\t\t\tcurrentUserCloudInfo.value = cloudUser;\n\t\t} catch (error) {\n\t\t\tthrow new Error((error as Error).message);\n\t\t}\n\t};\n\n\tconst getAutoLoginCode = async (): Promise<{ code: string }> => {\n\t\treturn await getAdminPanelLoginCode(rootStore.restApiContext);\n\t};\n\n\tconst getOwnerCurrentPlan = async () => {\n\t\tif (!hasCloudPlan.value) throw new Error('User does not have a cloud plan');\n\t\tstate.loadingPlan = true;\n\t\tlet plan;\n\t\ttry {\n\t\t\tplan = await getCurrentPlan(rootStore.restApiContext);\n\t\t\tstate.data = plan;\n\t\t\tstate.loadingPlan = false;\n\t\t} catch (error) {\n\t\t\tstate.loadingPlan = false;\n\t\t\tthrow new Error(error as string);\n\t\t}\n\n\t\treturn plan;\n\t};\n\n\tconst getInstanceCurrentUsage = async () => {\n\t\tconst usage = await getCurrentUsage({ baseUrl: rootStore.baseUrl, pushRef: '' });\n\t\tstate.usage = usage;\n\t\treturn usage;\n\t};\n\n\tconst usageLeft = computed(() => {\n\t\tif (!state.data || !state.usage) return { workflowsLeft: -1, executionsLeft: -1 };\n\n\t\treturn {\n\t\t\tworkflowsLeft: state.data.activeWorkflowsLimit - state.usage.activeWorkflows,\n\t\t\texecutionsLeft: state.data.monthlyExecutionsLimit - state.usage.executions,\n\t\t};\n\t});\n\n\tconst trialDaysLeft = computed(() => {\n\t\tif (!state.data?.expirationDate) return -1;\n\n\t\tconst differenceInMs = new Date().valueOf() - new Date(state.data.expirationDate).valueOf();\n\n\t\tconst differenceInDays = Math.floor(differenceInMs / (1000 * 60 * 60 * 24));\n\n\t\treturn Math.ceil(differenceInDays);\n\t});\n\n\tconst trialTimeLeft = computed((): { count: number; unit: 'days' | 'hours' | 'minutes' } => {\n\t\tif (!state.data?.expirationDate) {\n\t\t\treturn { count: 0, unit: 'days' };\n\t\t}\n\n\t\tconst msLeft = new Date(state.data.expirationDate).valueOf() - now.value;\n\t\tif (msLeft <= 0) {\n\t\t\treturn { count: 0, unit: 'minutes' };\n\t\t}\n\n\t\tconst hours = msLeft / (1000 * 60 * 60);\n\n\t\tif (hours < 1) {\n\t\t\treturn { count: Math.ceil(msLeft / (1000 * 60)), unit: 'minutes' };\n\t\t} else if (hours < 24) {\n\t\t\treturn { count: Math.ceil(hours), unit: 'hours' };\n\t\t} else {\n\t\t\treturn { count: Math.ceil(hours / 24), unit: 'days' };\n\t\t}\n\t});\n\n\tconst startPollingInstanceUsageData = () => {\n\t\tconst interval = setInterval(async () => {\n\t\t\tnow.value = Date.now();\n\t\t\ttry {\n\t\t\t\tawait getInstanceCurrentUsage();\n\t\t\t\tif (trialExpired.value || allExecutionsUsed.value) {\n\t\t\t\t\tclearInterval(interval);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t} catch {\n\t\t\t\t// Silently ignore polling errors — the next interval will retry\n\t\t\t}\n\t\t}, CLOUD_TRIAL_CHECK_INTERVAL);\n\t};\n\n\tconst checkForCloudPlanData = async (): Promise<void> => {\n\t\ttry {\n\t\t\tawait getOwnerCurrentPlan();\n\t\t\tif (!userIsTrialing.value) return;\n\t\t\tawait getInstanceCurrentUsage();\n\t\t\tstartPollingInstanceUsageData();\n\t\t} catch (e) {\n\t\t\tthrow new Error((e as Error).message);\n\t\t}\n\t};\n\n\tconst fetchUserCloudAccount = async () => {\n\t\ttry {\n\t\t\tawait getUserCloudAccount();\n\t\t} catch (e) {\n\t\t\tthrow new Error((e as Error).message);\n\t\t}\n\t};\n\n\tconst initialize = async () => {\n\t\tif (state.initialized) {\n\t\t\treturn;\n\t\t}\n\n\t\ttry {\n\t\t\tawait checkForCloudPlanData();\n\t\t} catch (error) {\n\t\t\tconsole.warn('Error checking for cloud plan data:', error);\n\t\t}\n\n\t\ttry {\n\t\t\tawait fetchUserCloudAccount();\n\t\t} catch (error) {\n\t\t\tconsole.warn('Error fetching user cloud account:', error);\n\t\t}\n\n\t\tstate.initialized = true;\n\t};\n\n\tconst generateCloudDashboardAutoLoginLink = async (data: { redirectionPath: string }) => {\n\t\tconst searchParams = new URLSearchParams();\n\n\t\tconst adminPanelHost = new URL(window.location.href).host.split('.').slice(1).join('.');\n\t\tconst { code } = await getAutoLoginCode();\n\t\tconst linkUrl = `https://${adminPanelHost}/login`;\n\t\tsearchParams.set('code', code);\n\t\tsearchParams.set('returnPath', data.redirectionPath);\n\n\t\treturn `${linkUrl}?${searchParams.toString()}`;\n\t};\n\n\treturn {\n\t\tstate,\n\t\tusageLeft,\n\t\ttrialDaysLeft,\n\t\ttrialTimeLeft,\n\t\tuserIsTrialing,\n\t\tcurrentPlanData,\n\t\tcurrentUsageData,\n\t\ttrialExpired,\n\t\tallExecutionsUsed,\n\t\thasCloudPlan,\n\t\tcurrentUserCloudInfo,\n\t\tgenerateCloudDashboardAutoLoginLink,\n\t\tinitialize,\n\t\tgetOwnerCurrentPlan,\n\t\tgetInstanceCurrentUsage,\n\t\treset,\n\t\tcheckForCloudPlanData,\n\t\tfetchUserCloudAccount,\n\t\tgetAutoLoginCode,\n\t\tselectedApps,\n\t\tcodingSkill,\n\t\tshouldShowBanner,\n\t\tbannerConfig,\n\t\tbannerForceShow,\n\t\tisBannerDismissed,\n\t\tbannerTimeLeft,\n\t\tshowExecutions,\n\t\tbannerCta,\n\t\tbannerIcon,\n\t\tbannerDismissible,\n\t\tsetIsInstanceOwner,\n\t};\n});\n"],"mappings":"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"}
|
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
import { t as STORES } from "./constants2.mjs";
|
|
2
|
+
import { t as useRootStore } from "./useRootStore2.mjs";
|
|
3
|
+
import { t as useSettingsStore } from "./settings2.store.mjs";
|
|
4
|
+
import * as cloudApi from "@n8n/rest-api-client/api/cloudPlans";
|
|
5
|
+
import { getAdminPanelLoginCode, getCurrentPlan, getCurrentUsage } from "@n8n/rest-api-client/api/cloudPlans";
|
|
6
|
+
import { defineStore } from "pinia";
|
|
7
|
+
import { computed, reactive, ref } from "vue";
|
|
8
|
+
|
|
9
|
+
//#region src/cloudPlan.store.ts
|
|
10
|
+
const CLOUD_TRIAL_CHECK_INTERVAL = 5e3;
|
|
11
|
+
const DEFAULT_STATE = {
|
|
12
|
+
initialized: false,
|
|
13
|
+
data: null,
|
|
14
|
+
usage: null,
|
|
15
|
+
loadingPlan: false
|
|
16
|
+
};
|
|
17
|
+
const useCloudPlanStore = defineStore(STORES.CLOUD_PLAN, () => {
|
|
18
|
+
const rootStore = useRootStore();
|
|
19
|
+
const settingsStore = useSettingsStore();
|
|
20
|
+
const state = reactive(DEFAULT_STATE);
|
|
21
|
+
const currentUserCloudInfo = ref(null);
|
|
22
|
+
const now = ref(Date.now());
|
|
23
|
+
const _isInstanceOwner = ref(() => false);
|
|
24
|
+
const setIsInstanceOwner = (getter) => {
|
|
25
|
+
_isInstanceOwner.value = getter;
|
|
26
|
+
};
|
|
27
|
+
const reset = () => {
|
|
28
|
+
currentUserCloudInfo.value = null;
|
|
29
|
+
state.data = null;
|
|
30
|
+
state.usage = null;
|
|
31
|
+
};
|
|
32
|
+
const userIsTrialing = computed(() => state.data?.userIsTrialing ?? false);
|
|
33
|
+
const bannerConfig = computed(() => state.data?.bannerConfig);
|
|
34
|
+
const bannerForceShow = computed(() => bannerConfig.value?.forceShow === true);
|
|
35
|
+
const isBannerDismissed = computed(() => {
|
|
36
|
+
const dismissed = settingsStore.permanentlyDismissedBanners;
|
|
37
|
+
return dismissed.includes("TRIAL") || dismissed.includes("TRIAL_OVER");
|
|
38
|
+
});
|
|
39
|
+
const shouldShowBanner = computed(() => {
|
|
40
|
+
if (!bannerConfig.value) return false;
|
|
41
|
+
if (!bannerDismissible.value) return true;
|
|
42
|
+
return bannerForceShow.value || !isBannerDismissed.value;
|
|
43
|
+
});
|
|
44
|
+
const bannerTimeLeft = computed(() => ({
|
|
45
|
+
show: !!bannerConfig.value?.timeLeft,
|
|
46
|
+
text: bannerConfig.value?.timeLeft?.text
|
|
47
|
+
}));
|
|
48
|
+
const showExecutions = computed(() => bannerConfig.value?.showExecutions === true);
|
|
49
|
+
const bannerCta = computed(() => ({
|
|
50
|
+
text: bannerConfig.value?.cta?.text ?? "Upgrade Now",
|
|
51
|
+
icon: bannerConfig.value?.cta?.icon ?? "zap",
|
|
52
|
+
size: bannerConfig.value?.cta?.size ?? "small",
|
|
53
|
+
style: bannerConfig.value?.cta?.style ?? "success",
|
|
54
|
+
variant: bannerConfig.value?.cta?.variant,
|
|
55
|
+
href: bannerConfig.value?.cta?.href
|
|
56
|
+
}));
|
|
57
|
+
const bannerIcon = computed(() => bannerConfig.value?.icon);
|
|
58
|
+
const bannerDismissible = computed(() => bannerConfig.value?.dismissible ?? true);
|
|
59
|
+
const currentPlanData = computed(() => state.data);
|
|
60
|
+
const currentUsageData = computed(() => state.usage);
|
|
61
|
+
const selectedApps = computed(() => currentUserCloudInfo.value?.selectedApps);
|
|
62
|
+
const codingSkill = computed(() => {
|
|
63
|
+
const information = currentUserCloudInfo.value?.information;
|
|
64
|
+
if (!information) return 0;
|
|
65
|
+
if (!("which_of_these_do_you_feel_comfortable_doing" in information && information.which_of_these_do_you_feel_comfortable_doing && Array.isArray(information.which_of_these_do_you_feel_comfortable_doing))) return 0;
|
|
66
|
+
return information.which_of_these_do_you_feel_comfortable_doing.length;
|
|
67
|
+
});
|
|
68
|
+
const trialExpired = computed(() => state.data?.userIsTrialing && Date.now() >= new Date(state.data?.expirationDate).getTime());
|
|
69
|
+
const allExecutionsUsed = computed(() => {
|
|
70
|
+
if (!state.usage?.executions || !state.data?.monthlyExecutionsLimit) return false;
|
|
71
|
+
return state.usage?.executions >= state.data?.monthlyExecutionsLimit;
|
|
72
|
+
});
|
|
73
|
+
const hasCloudPlan = computed(() => {
|
|
74
|
+
const { n8nMetadata } = settingsStore.settings;
|
|
75
|
+
const isCloud = Boolean(settingsStore.isCloudDeployment);
|
|
76
|
+
return _isInstanceOwner.value() && isCloud && !!n8nMetadata?.userId;
|
|
77
|
+
});
|
|
78
|
+
const getUserCloudAccount = async () => {
|
|
79
|
+
if (!hasCloudPlan.value) throw new Error("User does not have a cloud plan");
|
|
80
|
+
let cloudUser = null;
|
|
81
|
+
try {
|
|
82
|
+
cloudUser = await cloudApi.getCloudUserInfo(rootStore.restApiContext);
|
|
83
|
+
currentUserCloudInfo.value = cloudUser;
|
|
84
|
+
} catch (error) {
|
|
85
|
+
throw new Error(error.message);
|
|
86
|
+
}
|
|
87
|
+
};
|
|
88
|
+
const getAutoLoginCode = async () => {
|
|
89
|
+
return await getAdminPanelLoginCode(rootStore.restApiContext);
|
|
90
|
+
};
|
|
91
|
+
const getOwnerCurrentPlan = async () => {
|
|
92
|
+
if (!hasCloudPlan.value) throw new Error("User does not have a cloud plan");
|
|
93
|
+
state.loadingPlan = true;
|
|
94
|
+
let plan;
|
|
95
|
+
try {
|
|
96
|
+
plan = await getCurrentPlan(rootStore.restApiContext);
|
|
97
|
+
state.data = plan;
|
|
98
|
+
state.loadingPlan = false;
|
|
99
|
+
} catch (error) {
|
|
100
|
+
state.loadingPlan = false;
|
|
101
|
+
throw new Error(error);
|
|
102
|
+
}
|
|
103
|
+
return plan;
|
|
104
|
+
};
|
|
105
|
+
const getInstanceCurrentUsage = async () => {
|
|
106
|
+
const usage = await getCurrentUsage({
|
|
107
|
+
baseUrl: rootStore.baseUrl,
|
|
108
|
+
pushRef: ""
|
|
109
|
+
});
|
|
110
|
+
state.usage = usage;
|
|
111
|
+
return usage;
|
|
112
|
+
};
|
|
113
|
+
const usageLeft = computed(() => {
|
|
114
|
+
if (!state.data || !state.usage) return {
|
|
115
|
+
workflowsLeft: -1,
|
|
116
|
+
executionsLeft: -1
|
|
117
|
+
};
|
|
118
|
+
return {
|
|
119
|
+
workflowsLeft: state.data.activeWorkflowsLimit - state.usage.activeWorkflows,
|
|
120
|
+
executionsLeft: state.data.monthlyExecutionsLimit - state.usage.executions
|
|
121
|
+
};
|
|
122
|
+
});
|
|
123
|
+
const trialDaysLeft = computed(() => {
|
|
124
|
+
if (!state.data?.expirationDate) return -1;
|
|
125
|
+
const differenceInMs = (/* @__PURE__ */ new Date()).valueOf() - new Date(state.data.expirationDate).valueOf();
|
|
126
|
+
const differenceInDays = Math.floor(differenceInMs / (1e3 * 60 * 60 * 24));
|
|
127
|
+
return Math.ceil(differenceInDays);
|
|
128
|
+
});
|
|
129
|
+
const trialTimeLeft = computed(() => {
|
|
130
|
+
if (!state.data?.expirationDate) return {
|
|
131
|
+
count: 0,
|
|
132
|
+
unit: "days"
|
|
133
|
+
};
|
|
134
|
+
const msLeft = new Date(state.data.expirationDate).valueOf() - now.value;
|
|
135
|
+
if (msLeft <= 0) return {
|
|
136
|
+
count: 0,
|
|
137
|
+
unit: "minutes"
|
|
138
|
+
};
|
|
139
|
+
const hours = msLeft / (1e3 * 60 * 60);
|
|
140
|
+
if (hours < 1) return {
|
|
141
|
+
count: Math.ceil(msLeft / (1e3 * 60)),
|
|
142
|
+
unit: "minutes"
|
|
143
|
+
};
|
|
144
|
+
else if (hours < 24) return {
|
|
145
|
+
count: Math.ceil(hours),
|
|
146
|
+
unit: "hours"
|
|
147
|
+
};
|
|
148
|
+
else return {
|
|
149
|
+
count: Math.ceil(hours / 24),
|
|
150
|
+
unit: "days"
|
|
151
|
+
};
|
|
152
|
+
});
|
|
153
|
+
const startPollingInstanceUsageData = () => {
|
|
154
|
+
const interval = setInterval(async () => {
|
|
155
|
+
now.value = Date.now();
|
|
156
|
+
try {
|
|
157
|
+
await getInstanceCurrentUsage();
|
|
158
|
+
if (trialExpired.value || allExecutionsUsed.value) {
|
|
159
|
+
clearInterval(interval);
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
} catch {}
|
|
163
|
+
}, CLOUD_TRIAL_CHECK_INTERVAL);
|
|
164
|
+
};
|
|
165
|
+
const checkForCloudPlanData = async () => {
|
|
166
|
+
try {
|
|
167
|
+
await getOwnerCurrentPlan();
|
|
168
|
+
if (!userIsTrialing.value) return;
|
|
169
|
+
await getInstanceCurrentUsage();
|
|
170
|
+
startPollingInstanceUsageData();
|
|
171
|
+
} catch (e) {
|
|
172
|
+
throw new Error(e.message);
|
|
173
|
+
}
|
|
174
|
+
};
|
|
175
|
+
const fetchUserCloudAccount = async () => {
|
|
176
|
+
try {
|
|
177
|
+
await getUserCloudAccount();
|
|
178
|
+
} catch (e) {
|
|
179
|
+
throw new Error(e.message);
|
|
180
|
+
}
|
|
181
|
+
};
|
|
182
|
+
const initialize = async () => {
|
|
183
|
+
if (state.initialized) return;
|
|
184
|
+
try {
|
|
185
|
+
await checkForCloudPlanData();
|
|
186
|
+
} catch (error) {
|
|
187
|
+
console.warn("Error checking for cloud plan data:", error);
|
|
188
|
+
}
|
|
189
|
+
try {
|
|
190
|
+
await fetchUserCloudAccount();
|
|
191
|
+
} catch (error) {
|
|
192
|
+
console.warn("Error fetching user cloud account:", error);
|
|
193
|
+
}
|
|
194
|
+
state.initialized = true;
|
|
195
|
+
};
|
|
196
|
+
const generateCloudDashboardAutoLoginLink = async (data) => {
|
|
197
|
+
const searchParams = new URLSearchParams();
|
|
198
|
+
const adminPanelHost = new URL(window.location.href).host.split(".").slice(1).join(".");
|
|
199
|
+
const { code } = await getAutoLoginCode();
|
|
200
|
+
const linkUrl = `https://${adminPanelHost}/login`;
|
|
201
|
+
searchParams.set("code", code);
|
|
202
|
+
searchParams.set("returnPath", data.redirectionPath);
|
|
203
|
+
return `${linkUrl}?${searchParams.toString()}`;
|
|
204
|
+
};
|
|
205
|
+
return {
|
|
206
|
+
state,
|
|
207
|
+
usageLeft,
|
|
208
|
+
trialDaysLeft,
|
|
209
|
+
trialTimeLeft,
|
|
210
|
+
userIsTrialing,
|
|
211
|
+
currentPlanData,
|
|
212
|
+
currentUsageData,
|
|
213
|
+
trialExpired,
|
|
214
|
+
allExecutionsUsed,
|
|
215
|
+
hasCloudPlan,
|
|
216
|
+
currentUserCloudInfo,
|
|
217
|
+
generateCloudDashboardAutoLoginLink,
|
|
218
|
+
initialize,
|
|
219
|
+
getOwnerCurrentPlan,
|
|
220
|
+
getInstanceCurrentUsage,
|
|
221
|
+
reset,
|
|
222
|
+
checkForCloudPlanData,
|
|
223
|
+
fetchUserCloudAccount,
|
|
224
|
+
getAutoLoginCode,
|
|
225
|
+
selectedApps,
|
|
226
|
+
codingSkill,
|
|
227
|
+
shouldShowBanner,
|
|
228
|
+
bannerConfig,
|
|
229
|
+
bannerForceShow,
|
|
230
|
+
isBannerDismissed,
|
|
231
|
+
bannerTimeLeft,
|
|
232
|
+
showExecutions,
|
|
233
|
+
bannerCta,
|
|
234
|
+
bannerIcon,
|
|
235
|
+
bannerDismissible,
|
|
236
|
+
setIsInstanceOwner
|
|
237
|
+
};
|
|
238
|
+
});
|
|
239
|
+
|
|
240
|
+
//#endregion
|
|
241
|
+
export { useCloudPlanStore as t };
|
|
242
|
+
//# sourceMappingURL=cloudPlan2.store.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cloudPlan2.store.mjs","names":["DEFAULT_STATE: CloudPlanState","cloudUser: Cloud.UserAccount | null"],"sources":["../src/cloudPlan.store.ts"],"sourcesContent":["import type { Cloud, InstanceUsage } from '@n8n/rest-api-client/api/cloudPlans';\nimport {\n\tgetAdminPanelLoginCode,\n\tgetCurrentPlan,\n\tgetCurrentUsage,\n} from '@n8n/rest-api-client/api/cloudPlans';\nimport * as cloudApi from '@n8n/rest-api-client/api/cloudPlans';\nimport { defineStore } from 'pinia';\nimport { computed, reactive, ref } from 'vue';\n\nimport { STORES } from './constants';\nimport { useSettingsStore } from './settings.store';\nimport { useRootStore } from './useRootStore';\n\nexport interface CloudPlanState {\n\tinitialized: boolean;\n\tdata: Cloud.PlanData | null;\n\tusage: InstanceUsage | null;\n\tloadingPlan: boolean;\n}\n\nconst CLOUD_TRIAL_CHECK_INTERVAL = 5000;\n\nconst DEFAULT_STATE: CloudPlanState = {\n\tinitialized: false,\n\tdata: null,\n\tusage: null,\n\tloadingPlan: false,\n};\n\nexport const useCloudPlanStore = defineStore(STORES.CLOUD_PLAN, () => {\n\tconst rootStore = useRootStore();\n\tconst settingsStore = useSettingsStore();\n\n\tconst state = reactive<CloudPlanState>(DEFAULT_STATE);\n\tconst currentUserCloudInfo = ref<Cloud.UserAccount | null>(null);\n\n\tconst now = ref<number>(Date.now());\n\n\t// Injected by the caller (e.g. editor-ui shim) — returns whether the\n\t// current user is the instance owner. Defaults to `false` so the store\n\t// is safe to use before injection.\n\tconst _isInstanceOwner = ref<() => boolean>(() => false);\n\n\tconst setIsInstanceOwner = (getter: () => boolean) => {\n\t\t_isInstanceOwner.value = getter;\n\t};\n\n\tconst reset = () => {\n\t\tcurrentUserCloudInfo.value = null;\n\t\tstate.data = null;\n\t\tstate.usage = null;\n\t};\n\n\tconst userIsTrialing = computed(() => state.data?.userIsTrialing ?? false);\n\n\tconst bannerConfig = computed(() => state.data?.bannerConfig);\n\n\t// Whether forceShow is enabled - shows banner even if previously dismissed\n\tconst bannerForceShow = computed(() => bannerConfig.value?.forceShow === true);\n\n\t// Check if TRIAL banner was previously dismissed\n\tconst isBannerDismissed = computed(() => {\n\t\tconst dismissed = settingsStore.permanentlyDismissedBanners as string[];\n\t\treturn dismissed.includes('TRIAL') || dismissed.includes('TRIAL_OVER');\n\t});\n\n\t// Whether to show trial banner:\n\t// - bannerConfig must exist (backend wants to show banner)\n\t// - If not dismissible, always show (regardless of previous dismissal)\n\t// - If dismissible: show if forceShow is true OR banner was not previously dismissed\n\tconst shouldShowBanner = computed(() => {\n\t\tif (!bannerConfig.value) return false;\n\t\tif (!bannerDismissible.value) return true;\n\t\treturn bannerForceShow.value || !isBannerDismissed.value;\n\t});\n\n\t// If timeLeft is set, show it; otherwise hide\n\tconst bannerTimeLeft = computed(() => ({\n\t\tshow: !!bannerConfig.value?.timeLeft,\n\t\ttext: bannerConfig.value?.timeLeft?.text,\n\t}));\n\n\t// If showExecutions is true, show the executions section\n\tconst showExecutions = computed(() => bannerConfig.value?.showExecutions === true);\n\n\tconst bannerCta = computed(() => ({\n\t\ttext: bannerConfig.value?.cta?.text ?? 'Upgrade Now',\n\t\ticon: bannerConfig.value?.cta?.icon ?? 'zap',\n\t\tsize: bannerConfig.value?.cta?.size ?? 'small',\n\t\tstyle: bannerConfig.value?.cta?.style ?? 'success',\n\t\tvariant: bannerConfig.value?.cta?.variant,\n\t\thref: bannerConfig.value?.cta?.href,\n\t}));\n\n\t// Banner icon (left side info icon) - undefined means no icon\n\tconst bannerIcon = computed(() => bannerConfig.value?.icon);\n\n\tconst bannerDismissible = computed(() => bannerConfig.value?.dismissible ?? true);\n\n\tconst currentPlanData = computed(() => state.data);\n\n\tconst currentUsageData = computed(() => state.usage);\n\n\tconst selectedApps = computed(() => currentUserCloudInfo.value?.selectedApps);\n\tconst codingSkill = computed(() => {\n\t\tconst information = currentUserCloudInfo.value?.information;\n\t\tif (!information) {\n\t\t\treturn 0;\n\t\t}\n\n\t\tif (\n\t\t\t!(\n\t\t\t\t'which_of_these_do_you_feel_comfortable_doing' in information &&\n\t\t\t\tinformation.which_of_these_do_you_feel_comfortable_doing &&\n\t\t\t\tArray.isArray(information.which_of_these_do_you_feel_comfortable_doing)\n\t\t\t)\n\t\t) {\n\t\t\treturn 0;\n\t\t}\n\n\t\treturn information.which_of_these_do_you_feel_comfortable_doing.length;\n\t});\n\n\tconst trialExpired = computed(\n\t\t() =>\n\t\t\tstate.data?.userIsTrialing && Date.now() >= new Date(state.data?.expirationDate).getTime(),\n\t);\n\n\tconst allExecutionsUsed = computed(() => {\n\t\tif (!state.usage?.executions || !state.data?.monthlyExecutionsLimit) return false;\n\t\treturn state.usage?.executions >= state.data?.monthlyExecutionsLimit;\n\t});\n\n\tconst hasCloudPlan = computed<boolean>(() => {\n\t\tconst { n8nMetadata } = settingsStore.settings as { n8nMetadata?: { userId?: string } };\n\t\tconst isCloud = Boolean(settingsStore.isCloudDeployment);\n\t\treturn _isInstanceOwner.value() && isCloud && !!n8nMetadata?.userId;\n\t});\n\n\tconst getUserCloudAccount = async () => {\n\t\tif (!hasCloudPlan.value) throw new Error('User does not have a cloud plan');\n\t\tlet cloudUser: Cloud.UserAccount | null = null;\n\t\ttry {\n\t\t\tcloudUser = await cloudApi.getCloudUserInfo(rootStore.restApiContext);\n\t\t\tcurrentUserCloudInfo.value = cloudUser;\n\t\t} catch (error) {\n\t\t\tthrow new Error((error as Error).message);\n\t\t}\n\t};\n\n\tconst getAutoLoginCode = async (): Promise<{ code: string }> => {\n\t\treturn await getAdminPanelLoginCode(rootStore.restApiContext);\n\t};\n\n\tconst getOwnerCurrentPlan = async () => {\n\t\tif (!hasCloudPlan.value) throw new Error('User does not have a cloud plan');\n\t\tstate.loadingPlan = true;\n\t\tlet plan;\n\t\ttry {\n\t\t\tplan = await getCurrentPlan(rootStore.restApiContext);\n\t\t\tstate.data = plan;\n\t\t\tstate.loadingPlan = false;\n\t\t} catch (error) {\n\t\t\tstate.loadingPlan = false;\n\t\t\tthrow new Error(error as string);\n\t\t}\n\n\t\treturn plan;\n\t};\n\n\tconst getInstanceCurrentUsage = async () => {\n\t\tconst usage = await getCurrentUsage({ baseUrl: rootStore.baseUrl, pushRef: '' });\n\t\tstate.usage = usage;\n\t\treturn usage;\n\t};\n\n\tconst usageLeft = computed(() => {\n\t\tif (!state.data || !state.usage) return { workflowsLeft: -1, executionsLeft: -1 };\n\n\t\treturn {\n\t\t\tworkflowsLeft: state.data.activeWorkflowsLimit - state.usage.activeWorkflows,\n\t\t\texecutionsLeft: state.data.monthlyExecutionsLimit - state.usage.executions,\n\t\t};\n\t});\n\n\tconst trialDaysLeft = computed(() => {\n\t\tif (!state.data?.expirationDate) return -1;\n\n\t\tconst differenceInMs = new Date().valueOf() - new Date(state.data.expirationDate).valueOf();\n\n\t\tconst differenceInDays = Math.floor(differenceInMs / (1000 * 60 * 60 * 24));\n\n\t\treturn Math.ceil(differenceInDays);\n\t});\n\n\tconst trialTimeLeft = computed((): { count: number; unit: 'days' | 'hours' | 'minutes' } => {\n\t\tif (!state.data?.expirationDate) {\n\t\t\treturn { count: 0, unit: 'days' };\n\t\t}\n\n\t\tconst msLeft = new Date(state.data.expirationDate).valueOf() - now.value;\n\t\tif (msLeft <= 0) {\n\t\t\treturn { count: 0, unit: 'minutes' };\n\t\t}\n\n\t\tconst hours = msLeft / (1000 * 60 * 60);\n\n\t\tif (hours < 1) {\n\t\t\treturn { count: Math.ceil(msLeft / (1000 * 60)), unit: 'minutes' };\n\t\t} else if (hours < 24) {\n\t\t\treturn { count: Math.ceil(hours), unit: 'hours' };\n\t\t} else {\n\t\t\treturn { count: Math.ceil(hours / 24), unit: 'days' };\n\t\t}\n\t});\n\n\tconst startPollingInstanceUsageData = () => {\n\t\tconst interval = setInterval(async () => {\n\t\t\tnow.value = Date.now();\n\t\t\ttry {\n\t\t\t\tawait getInstanceCurrentUsage();\n\t\t\t\tif (trialExpired.value || allExecutionsUsed.value) {\n\t\t\t\t\tclearInterval(interval);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t} catch {\n\t\t\t\t// Silently ignore polling errors — the next interval will retry\n\t\t\t}\n\t\t}, CLOUD_TRIAL_CHECK_INTERVAL);\n\t};\n\n\tconst checkForCloudPlanData = async (): Promise<void> => {\n\t\ttry {\n\t\t\tawait getOwnerCurrentPlan();\n\t\t\tif (!userIsTrialing.value) return;\n\t\t\tawait getInstanceCurrentUsage();\n\t\t\tstartPollingInstanceUsageData();\n\t\t} catch (e) {\n\t\t\tthrow new Error((e as Error).message);\n\t\t}\n\t};\n\n\tconst fetchUserCloudAccount = async () => {\n\t\ttry {\n\t\t\tawait getUserCloudAccount();\n\t\t} catch (e) {\n\t\t\tthrow new Error((e as Error).message);\n\t\t}\n\t};\n\n\tconst initialize = async () => {\n\t\tif (state.initialized) {\n\t\t\treturn;\n\t\t}\n\n\t\ttry {\n\t\t\tawait checkForCloudPlanData();\n\t\t} catch (error) {\n\t\t\tconsole.warn('Error checking for cloud plan data:', error);\n\t\t}\n\n\t\ttry {\n\t\t\tawait fetchUserCloudAccount();\n\t\t} catch (error) {\n\t\t\tconsole.warn('Error fetching user cloud account:', error);\n\t\t}\n\n\t\tstate.initialized = true;\n\t};\n\n\tconst generateCloudDashboardAutoLoginLink = async (data: { redirectionPath: string }) => {\n\t\tconst searchParams = new URLSearchParams();\n\n\t\tconst adminPanelHost = new URL(window.location.href).host.split('.').slice(1).join('.');\n\t\tconst { code } = await getAutoLoginCode();\n\t\tconst linkUrl = `https://${adminPanelHost}/login`;\n\t\tsearchParams.set('code', code);\n\t\tsearchParams.set('returnPath', data.redirectionPath);\n\n\t\treturn `${linkUrl}?${searchParams.toString()}`;\n\t};\n\n\treturn {\n\t\tstate,\n\t\tusageLeft,\n\t\ttrialDaysLeft,\n\t\ttrialTimeLeft,\n\t\tuserIsTrialing,\n\t\tcurrentPlanData,\n\t\tcurrentUsageData,\n\t\ttrialExpired,\n\t\tallExecutionsUsed,\n\t\thasCloudPlan,\n\t\tcurrentUserCloudInfo,\n\t\tgenerateCloudDashboardAutoLoginLink,\n\t\tinitialize,\n\t\tgetOwnerCurrentPlan,\n\t\tgetInstanceCurrentUsage,\n\t\treset,\n\t\tcheckForCloudPlanData,\n\t\tfetchUserCloudAccount,\n\t\tgetAutoLoginCode,\n\t\tselectedApps,\n\t\tcodingSkill,\n\t\tshouldShowBanner,\n\t\tbannerConfig,\n\t\tbannerForceShow,\n\t\tisBannerDismissed,\n\t\tbannerTimeLeft,\n\t\tshowExecutions,\n\t\tbannerCta,\n\t\tbannerIcon,\n\t\tbannerDismissible,\n\t\tsetIsInstanceOwner,\n\t};\n});\n"],"mappings":"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"}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
const require_settings_store = require('../settings2.store.cjs');
|
|
2
|
+
require('../constants2.cjs');
|
|
3
|
+
require('../metaTagConfig2.cjs');
|
|
4
|
+
require('../useRootStore2.cjs');
|
|
5
|
+
const require_cloudPlan_store = require('../cloudPlan2.store.cjs');
|
|
6
|
+
require('../invitation2.api.cjs');
|
|
7
|
+
require('../onboarding2.api.cjs');
|
|
8
|
+
const require_users_store = require('../users2.store.cjs');
|
|
9
|
+
const require_versions_store = require('../versions2.store.cjs');
|
|
10
|
+
let __n8n_composables_useTelemetry = require("@n8n/composables/useTelemetry");
|
|
11
|
+
let __n8n_frontend_constants_urls = require("@n8n/frontend-constants/urls");
|
|
12
|
+
|
|
13
|
+
//#region src/composables/useBasePageRedirectionHelper.ts
|
|
14
|
+
/**
|
|
15
|
+
* Injectable page-redirection composable. The app-facing `usePageRedirectionHelper`
|
|
16
|
+
* wraps this and supplies the guard, which keeps this base free of any feature
|
|
17
|
+
* dependency.
|
|
18
|
+
*
|
|
19
|
+
* It lives in `@n8n/stores` rather than `@n8n/composables` because its body is
|
|
20
|
+
* store orchestration end to end — all four stores it reads are in this package,
|
|
21
|
+
* and `@n8n/composables` sits *below* the stores tier (see that package's
|
|
22
|
+
* `packageBoundary.test.ts`), so it cannot reach them.
|
|
23
|
+
*/
|
|
24
|
+
function useBasePageRedirectionHelper({ guard }) {
|
|
25
|
+
const usersStore = require_users_store.useUsersStore();
|
|
26
|
+
const cloudPlanStore = require_cloudPlan_store.useCloudPlanStore();
|
|
27
|
+
const versionsStore = require_versions_store.useVersionsStore();
|
|
28
|
+
const telemetry = (0, __n8n_composables_useTelemetry.useTelemetry)();
|
|
29
|
+
const settingsStore = require_settings_store.useSettingsStore();
|
|
30
|
+
/**
|
|
31
|
+
* If the user is an instance owner in the cloud, it generates an auto-login link to the
|
|
32
|
+
* cloud dashboard that redirects the user to the /manage page where they can upgrade to a new n8n version.
|
|
33
|
+
* Otherwise, it redirect them to our docs.
|
|
34
|
+
*/
|
|
35
|
+
const goToVersions = async () => {
|
|
36
|
+
if (usersStore.isInstanceOwner && settingsStore.isCloudDeployment) {
|
|
37
|
+
location.href = await cloudPlanStore.generateCloudDashboardAutoLoginLink({ redirectionPath: "/manage" });
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
window.open(versionsStore.infoUrl, "_blank", "noopener");
|
|
41
|
+
};
|
|
42
|
+
const goToDashboard = async () => {
|
|
43
|
+
if (usersStore.isInstanceOwner && settingsStore.isCloudDeployment) {
|
|
44
|
+
const dashboardLink = await cloudPlanStore.generateCloudDashboardAutoLoginLink({ redirectionPath: "/dashboard" });
|
|
45
|
+
location.href = dashboardLink;
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
/**
|
|
49
|
+
* If the user is an instance owner in the cloud, it generates an auto-login link to the
|
|
50
|
+
* cloud dashboard that redirects the user to the /account/change-plan page where they upgrade/downgrade the current plan.
|
|
51
|
+
* Otherwise, it redirect them our website.
|
|
52
|
+
*/
|
|
53
|
+
const goToUpgrade = async (source, utm_campaign, mode = "open") => {
|
|
54
|
+
if (!await guard()) return;
|
|
55
|
+
const { usageLeft, trialDaysLeft, userIsTrialing } = cloudPlanStore;
|
|
56
|
+
const { executionsLeft, workflowsLeft } = usageLeft;
|
|
57
|
+
const deploymentType = settingsStore.deploymentType;
|
|
58
|
+
telemetry.track("User clicked upgrade CTA", {
|
|
59
|
+
source,
|
|
60
|
+
isTrial: userIsTrialing,
|
|
61
|
+
deploymentType,
|
|
62
|
+
trialDaysLeft,
|
|
63
|
+
executionsLeft,
|
|
64
|
+
workflowsLeft
|
|
65
|
+
});
|
|
66
|
+
const upgradeLink = await generateUpgradeLink(source, utm_campaign);
|
|
67
|
+
if (mode === "open") window.open(upgradeLink, "_blank");
|
|
68
|
+
else location.href = upgradeLink;
|
|
69
|
+
};
|
|
70
|
+
const generateUpgradeLink = async (source, utm_campaign) => {
|
|
71
|
+
let upgradeLink = __n8n_frontend_constants_urls.N8N_PRICING_PAGE_URL;
|
|
72
|
+
if (usersStore.isInstanceOwner && settingsStore.isCloudDeployment) upgradeLink = await cloudPlanStore.generateCloudDashboardAutoLoginLink({ redirectionPath: "/account/change-plan" });
|
|
73
|
+
const url = new URL(upgradeLink);
|
|
74
|
+
if (utm_campaign) url.searchParams.set("utm_campaign", utm_campaign);
|
|
75
|
+
if (source) url.searchParams.set("source", source);
|
|
76
|
+
return url.toString();
|
|
77
|
+
};
|
|
78
|
+
return {
|
|
79
|
+
goToDashboard,
|
|
80
|
+
goToVersions,
|
|
81
|
+
goToUpgrade
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
//#endregion
|
|
86
|
+
exports.useBasePageRedirectionHelper = useBasePageRedirectionHelper;
|
|
87
|
+
//# sourceMappingURL=useBasePageRedirectionHelper.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useBasePageRedirectionHelper.cjs","names":["useUsersStore","useCloudPlanStore","useVersionsStore","useSettingsStore","N8N_PRICING_PAGE_URL"],"sources":["../../src/composables/useBasePageRedirectionHelper.ts"],"sourcesContent":["import { useTelemetry } from '@n8n/composables/useTelemetry';\nimport { N8N_PRICING_PAGE_URL } from '@n8n/frontend-constants/urls';\n\nimport { useCloudPlanStore } from '../cloudPlan.store';\nimport { useSettingsStore } from '../settings.store';\nimport type { CloudUpdateLinkSourceType, UTMCampaign } from '../types/pageRedirection';\nimport { useUsersStore } from '../users.store';\nimport { useVersionsStore } from '../versions.store';\n\n/**\n * Guard consulted before an upgrade redirect. Resolves `true` to proceed, `false`\n * to abort. Required and injected by the caller, so this composable carries no\n * feature dependency of its own (e.g. the AI builder streaming confirmation).\n */\nexport type UpgradeRedirectGuard = () => Promise<boolean>;\n\n/**\n * Injectable page-redirection composable. The app-facing `usePageRedirectionHelper`\n * wraps this and supplies the guard, which keeps this base free of any feature\n * dependency.\n *\n * It lives in `@n8n/stores` rather than `@n8n/composables` because its body is\n * store orchestration end to end — all four stores it reads are in this package,\n * and `@n8n/composables` sits *below* the stores tier (see that package's\n * `packageBoundary.test.ts`), so it cannot reach them.\n */\nexport function useBasePageRedirectionHelper({ guard }: { guard: UpgradeRedirectGuard }) {\n\tconst usersStore = useUsersStore();\n\tconst cloudPlanStore = useCloudPlanStore();\n\tconst versionsStore = useVersionsStore();\n\tconst telemetry = useTelemetry();\n\tconst settingsStore = useSettingsStore();\n\n\t/**\n\t * If the user is an instance owner in the cloud, it generates an auto-login link to the\n\t * cloud dashboard that redirects the user to the /manage page where they can upgrade to a new n8n version.\n\t * Otherwise, it redirect them to our docs.\n\t */\n\tconst goToVersions = async () => {\n\t\tif (usersStore.isInstanceOwner && settingsStore.isCloudDeployment) {\n\t\t\tlocation.href = await cloudPlanStore.generateCloudDashboardAutoLoginLink({\n\t\t\t\tredirectionPath: '/manage',\n\t\t\t});\n\t\t\treturn;\n\t\t}\n\n\t\twindow.open(versionsStore.infoUrl, '_blank', 'noopener');\n\t};\n\n\tconst goToDashboard = async () => {\n\t\tif (usersStore.isInstanceOwner && settingsStore.isCloudDeployment) {\n\t\t\tconst dashboardLink = await cloudPlanStore.generateCloudDashboardAutoLoginLink({\n\t\t\t\tredirectionPath: '/dashboard',\n\t\t\t});\n\n\t\t\tlocation.href = dashboardLink;\n\t\t}\n\n\t\treturn;\n\t};\n\n\t/**\n\t * If the user is an instance owner in the cloud, it generates an auto-login link to the\n\t * cloud dashboard that redirects the user to the /account/change-plan page where they upgrade/downgrade the current plan.\n\t * Otherwise, it redirect them our website.\n\t */\n\n\tconst goToUpgrade = async (\n\t\tsource: CloudUpdateLinkSourceType,\n\t\tutm_campaign: UTMCampaign,\n\t\tmode: 'open' | 'redirect' = 'open',\n\t) => {\n\t\tconst shouldProceed = await guard();\n\t\tif (!shouldProceed) return;\n\n\t\tconst { usageLeft, trialDaysLeft, userIsTrialing } = cloudPlanStore;\n\t\tconst { executionsLeft, workflowsLeft } = usageLeft;\n\t\tconst deploymentType = settingsStore.deploymentType;\n\n\t\ttelemetry.track('User clicked upgrade CTA', {\n\t\t\tsource,\n\t\t\tisTrial: userIsTrialing,\n\t\t\tdeploymentType,\n\t\t\ttrialDaysLeft,\n\t\t\texecutionsLeft,\n\t\t\tworkflowsLeft,\n\t\t});\n\n\t\tconst upgradeLink = await generateUpgradeLink(source, utm_campaign);\n\n\t\tif (mode === 'open') {\n\t\t\twindow.open(upgradeLink, '_blank');\n\t\t} else {\n\t\t\tlocation.href = upgradeLink;\n\t\t}\n\t};\n\n\tconst generateUpgradeLink = async (source: string, utm_campaign: string) => {\n\t\tlet upgradeLink = N8N_PRICING_PAGE_URL;\n\n\t\tif (usersStore.isInstanceOwner && settingsStore.isCloudDeployment) {\n\t\t\tupgradeLink = await cloudPlanStore.generateCloudDashboardAutoLoginLink({\n\t\t\t\tredirectionPath: '/account/change-plan',\n\t\t\t});\n\t\t}\n\n\t\tconst url = new URL(upgradeLink);\n\n\t\tif (utm_campaign) {\n\t\t\turl.searchParams.set('utm_campaign', utm_campaign);\n\t\t}\n\n\t\tif (source) {\n\t\t\turl.searchParams.set('source', source);\n\t\t}\n\n\t\treturn url.toString();\n\t};\n\n\treturn {\n\t\tgoToDashboard,\n\t\tgoToVersions,\n\t\tgoToUpgrade,\n\t};\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AA0BA,SAAgB,6BAA6B,EAAE,SAA0C;CACxF,MAAM,aAAaA,mCAAe;CAClC,MAAM,iBAAiBC,2CAAmB;CAC1C,MAAM,gBAAgBC,yCAAkB;CACxC,MAAM,8DAA0B;CAChC,MAAM,gBAAgBC,yCAAkB;;;;;;CAOxC,MAAM,eAAe,YAAY;AAChC,MAAI,WAAW,mBAAmB,cAAc,mBAAmB;AAClE,YAAS,OAAO,MAAM,eAAe,oCAAoC,EACxE,iBAAiB,WACjB,CAAC;AACF;;AAGD,SAAO,KAAK,cAAc,SAAS,UAAU,WAAW;;CAGzD,MAAM,gBAAgB,YAAY;AACjC,MAAI,WAAW,mBAAmB,cAAc,mBAAmB;GAClE,MAAM,gBAAgB,MAAM,eAAe,oCAAoC,EAC9E,iBAAiB,cACjB,CAAC;AAEF,YAAS,OAAO;;;;;;;;CAYlB,MAAM,cAAc,OACnB,QACA,cACA,OAA4B,WACxB;AAEJ,MAAI,CADkB,MAAM,OAAO,CACf;EAEpB,MAAM,EAAE,WAAW,eAAe,mBAAmB;EACrD,MAAM,EAAE,gBAAgB,kBAAkB;EAC1C,MAAM,iBAAiB,cAAc;AAErC,YAAU,MAAM,4BAA4B;GAC3C;GACA,SAAS;GACT;GACA;GACA;GACA;GACA,CAAC;EAEF,MAAM,cAAc,MAAM,oBAAoB,QAAQ,aAAa;AAEnE,MAAI,SAAS,OACZ,QAAO,KAAK,aAAa,SAAS;MAElC,UAAS,OAAO;;CAIlB,MAAM,sBAAsB,OAAO,QAAgB,iBAAyB;EAC3E,IAAI,cAAcC;AAElB,MAAI,WAAW,mBAAmB,cAAc,kBAC/C,eAAc,MAAM,eAAe,oCAAoC,EACtE,iBAAiB,wBACjB,CAAC;EAGH,MAAM,MAAM,IAAI,IAAI,YAAY;AAEhC,MAAI,aACH,KAAI,aAAa,IAAI,gBAAgB,aAAa;AAGnD,MAAI,OACH,KAAI,aAAa,IAAI,UAAU,OAAO;AAGvC,SAAO,IAAI,UAAU;;AAGtB,QAAO;EACN;EACA;EACA;EACA"}
|